From 51b954afd17cc6c57084a78a38b91ed060cd4440 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 18 Dec 2025 14:20:52 +0000 Subject: [PATCH] Skip trace --- core/__pycache__/admin.cpython-311.pyc | Bin 212 -> 1999 bytes core/__pycache__/forms.cpython-311.pyc | Bin 0 -> 681 bytes core/__pycache__/models.cpython-311.pyc | Bin 209 -> 3101 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 348 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 2281 bytes core/admin.py | 28 ++- core/forms.py | 7 + core/migrations/0001_initial.py | 48 +++++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 2943 bytes core/models.py | 37 +++- core/templates/base.html | 5 + core/templates/core/index.html | 176 ++++-------------- core/urls.py | 4 +- core/views.py | 29 ++- static/css/custom.css | 58 +++++- 15 files changed, 242 insertions(+), 150 deletions(-) create mode 100644 core/__pycache__/forms.cpython-311.pyc create mode 100644 core/forms.py create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index cd6f855b12f4883b1ba9de01c54245c53aacd714..970ca6c16c44c81069433efb1129f51060c1f9b8 100644 GIT binary patch literal 1999 zcma)6OK;mo5Z>iOlqJea{EE}Wj+;kOB4~sH%_S`g#BJ&}tzDoAa^QuaxNDmZMXE~@ zjeF7|KOndG7q}=4^taf64#J)a^pu+n`_h~`LyEL5t3XKc)9%jhw=>_&?jMatjllD7 z{agPpm5_h1Q#_SX<7AZ*@|G~dXh1sDrj#&+se#f_ZMCD>T1U5aN))n2nD&}5oztCS zE!hXw1NidCHWUKZYSHJ~K5!qvmp>Ut1vm_tHC2pWudW_kGLB(fsCKCRZAG!gA2%?}CvJxk5 zl47(Ff5JiG#G(Rs*{}>Tjm|U?t^i0g@Z-c`e%uY*U0Kh1K$UQjg((d`OI|GIaY+`* zHEdlkz=TG;0&ph8-?MAIp9V8ay&nh7yNA>FdTaRRi*em#8Ib$33?l)|QPJkHS7dF| z7vOgm?^NIxO`|9#&GVC8siP85OuzeG$AikSRB;D(5qA;p0c=?Mm>>cxTsC6v3U7N< zH{-Em+6BTaeDNZ{`Pg4T>~oKL>-gp|@2Tn(esZR`dY<5Pn;zFfJ?ES&aprB!TyLeuNv(-F6zdVsvTXfs<9ix1db9 zkhOI@;F$_}31+#-oV)1o`|4NuMe()x0x0kTi@ygPs+7_JSvkD;8<0nb|Nk3SG|1g8cxrw(?q$_n}5Ch#yp}+eY!MMRQkz~T!uZpzxe4f8cq?8RiZ4H^UZ?A zIHHSvx;Ru6`sI*ZhBpuUvv-csaEgE|*UR~}f~9#xSNe1XeOaaG%p}}<*uQZf9a^R6 O(JDos&fI_F4 zkoq44Q2PfkFf#|KLv$+>TdH*G#5+5#gy5a;yZ8A$zwh1i=X!k^(7s=OF!+JzFHI`5 z7tZ_+I)}i35djhL2>}Bh0W;nMGdUR=)dyn};0SkVzR9c}H0|G-Hi@z~V;QC4B3c|v z3o?I>&LME{2?O6SfSW_BN@S$qRX3>1%mF#J#st-Hmv(HAv5%vRUVMi+sJ^7?opk#} zB4WzAsK2+`J8*C$A0nTSIPF%n9ndcD``JmuvM_kDe|~?y ze*gUYykEYLM#CJWpChx%7k-ZW9Shy$>tr5%3YnW6;RvsCYy2Y5a~^JQ>LQTag?c#g_Pf(0%edWc=8dE39H6RH}e&QQ){XS#nv z@g_&PMV@er9uG&ot3p>uc;X?REpOjceg8}4?^6i_`wH}_29Fs0U#d`_$~SPtFoEq` zjF13qQP2)#bge3vst*Y)x_HNHhu7qfC6#K+)fL;fq{`Y=ThMB%`tUChJRAX2;=B6; zPyB#*Kbiz{llz2Qg{Pao1Q&qvj`~aPYcGuH$v@#!X^$N)E6k`$n!HBskScewcX(Sc zs9HAgwbYYCQ!Dx!ovJO>v}$dNeoRZXs?Mga>FlaekxO){q%%6@e&0it>vlkrj4G3) z^>}AphdLDz=+1ZHI+hM zl%x-9vWoMSB!+9YLzxws%_&qREDmKhgp~oA5JnBd7D`I>y6rQna+TV_b)_Pezz-R2 z;T?{>fG-TAL05DP_G$bCroQuQC-!ZQT8Vv)!ad>sw3*1Y5;-f8tDkKTr8fQ6P^yt> zR_{-mL-Vbnd249Cex@DUvr)EUdm8(j#ruL8%eG=!E0(R#w1&-T26g?`^!{bQRCG;#n)6t>?A{ z-uKov_pEVOg$pXdy_0re`wXgjuq}gwe8VI8R9Nk5;G_WH;OpPrahyd&NmvbZ`y&GN z65p1;4@-pPpQ^xCu&s9^^PEz32v%Ftocywmy=a01jjz#W7PoU@1+3sZC! zI4LS?)B(y4ml%Z#BFR;TquG80sb;X(up68i+k>XZQ3{J_VsIPlV0s*Fdwiq*ZLVwT z`E8L)9z?VbGy$ult;A6)aTKtM?%ud$MRzxn%?}>DXGSl#qL;1c<@#KEEPZR#8cR0| z=GaVYY{nX!F@;eC;RJ%vZ`^6&WCnxa2j}jA@btM&eT0W71Oe7fTb@2g?~55U2!Zu^ zdN(dOp&NT70`U#NC*sVarwR;IiH<7TnHooeTcJM4VvYjOLnk@CgujEZe|IPJFAk9i zfS4d6IA_$3?|9fd)BxYN0{|O54RBSFQPpt+H%{o91fd*=vy%qUD^(F+sUvroDKb1K z9Kz;+pI4xe_OKAv;o1hX^g6Ws7fZc=E)d8%R7Kngr^-4@tp`(zmO{+ZUf|gctG0Jl zUt+J~=mX(;v2W>Jz7D_}2KqPhb@Ep6tM|?LNw}KRKOX%NK*PKlJlO#(*$0>lRCo?z zqq3|m(CZEs5bIABGN)#<>=@1m4_r2b#=$FE)@vHj)(Kt_w^&)xHEN5ebzP;h=8_py z49RJ=LuU&Y@@}QbX~+IFUGUIw*%&pv*xAutxLp=(N>IFF$zI#WO8%P8kuZ*?@iw)=Ey>8 zWWgF)sGn~qCpHgS$%)326F8H(Rx)QLbM=Ma;u9FuCK_*<@x!h7VJm*Po@)>9-#lUs z?{7>ti{|jL*6=ZF_*nfM;(dxoz6V*Caa>V8?YBc@Ro0gELuAR_ecyTf)9LPV3N+5r z`}X8X@PzyK;%$}%2?jjl2Qb@Sp6A=#xcT(8ErfUoyU&`9^5^OwSpT@!I4bgRC_QU7 gkK8!%2i8CCHI9dQT;O24S-t_CW833@Q8*j%H{|@+MgRZ+ literal 209 zcmZ3^%ge<81S>LrWmp2~#~=<2FhLogg@BCd3@HpLj5!Rsj8Tk?3@J>(44TX@K?*b( zZ?Wa(r=;c-`)M-W;!Md(%uCPLOGzqX21>4E_zY6>OHV%|KQ~psG^sSNq*On(A~m_R zB)>?%JijQrxF9h(RX;huC{-U~j9x+IFAf_ZyEG@&u80Guoe_wOWr4&8W=2NF8w@fR Ku%RM0pb7xTsWln^ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 1f807fae1897c89361c99c5e868a26d00799b73f..da7f310f91a21f95fadc328dc80fe47029160d49 100644 GIT binary patch delta 86 zcmcc3bccy|IWI340}!0!cFD}0$Xme1nwgi9S~0O{v6;jL1{Cyxje(W3!KFi}BXoxN a1s27NEQ(iH6hAOC@iR4WgJ2O4&>#R#ycjzG delta 85 zcmcb^beoBHIWI340}vcY|CNz7k+*=AB_lsKbz<{kGw}-yDCh$l11o2PONUTL$PBg% ZEb|?6)=H6(svfvmLR>iYn{_tWrHm)vey{mvzGr@o zMA{InzxWA-1Q7b05$^KrBCqZM@&w69=2Vnwe7O_{v`6)5-jt7HJg@540;zx&Oa&d< zr-rm}Dh#+^4ybJ!pW+=ns0vyn6#+c-0HxYxZW_hIFWFVsoO*Gh+tVEI72}tL=_De3?0AZ;1Dn(A=>H65R!eZ(rKi(H~ZK6 zKJWvrHNE4lomRay7RPs1t4_&V^veF-n0n-Z&dI@&kG^#oWh1VM|D5!{Cl>9le)G5W z>{_&0=HhawH43GG94`83pDRbG)e1fSR+8;-@m8Ipzv!g{t_-2oF}M!3x4Bn;&@{2ar75R7L^_W}RnlcepA*dt!B`g; z6*@1nmcT>=iHP+Dg&4Yqbt=l3N{VVGY~Rfr(=&D`V=kocDk_G~=`e^gr|6REFw(lD zVcV}j3oaD|DVJMR3WeoF#?b80ST1*)QFi#UDpA##Q!)kq3|uZzET<(}aGFqLT?o&z zJ8w?ixH>sLlb)EI9-m6yoJroeUif%SG!-qUVv!n#3P3cWaYf2HSIihXl`_;6?-D~3 zC2@TE8a-=X*;Bt=>dAknHsAGCAm|=O8WYRiulN9s`Vm z1*ikU230&{2MPW@k4;LB0!;)4SaXsC41B;q4*)yJ5`mYf$sRB6t~Y0f<_!%GPH$Ua+DU9{Os0^rw*@M;?u?jMh;we6rSc?3dD7%IZ4%@XOZ$6gg}O z;j-A?yovOwLt=M2WSrg+M-))H(E8@k+gO3OQJW~E@r>$e<^rOT| zqCEZ&-(~T=+x+n@{&`uvM(WiT8r(6 zT|dA_19b$TeC72aBy>C;s2n-HF<0e>Eq=J-8-4}BMDZvYWYLWSumg=kCu~kM>LAwO zB+Pk(P)L&Lq`y&8!mcb&VH`B-$SZO-R`wfvHh9>~L34I3QyoxW8 zVIbMRAMb^ei Ld>y?DoHzdq7v3z* delta 776 zcmZ`%K~EDw6rS1L?rw{1Z7>yx6_5r}O{yn}N(8NyV6-I#6XntnW}vOxU7ej$Y_@@e ze}L@43kSVmOb=f5V!V4P2?sNY-nlg)df=jO3O%6l%gnd$ef#a3eJ^tm+Yd$Fg~K5P z__TIZno_qT19)b8;tIuxAfj1D)m$2+GM6oeZn+gxe z{1_G0A64RJQze?G@Sy)&84SysC#dN1^`@tKm`8geLKU+YlK|0op?<4-hE)IKGye7w zbH{9IyuVio!OxSRr|m*JE!k2RFq=@r|Ex~?m$l^eV2;*D7WhkxivIaR{y{dgSiF~A z$Q0)07w7Uhfkdn)&po;`n=L*rJWQGXSIygOL{}U}ua;q&8|f0STB(pQ<*ZAN%SFI) z>Xb1#7@^uuoke71KDU7;G_AV616*_!E?RBPskO~Nc(HAx9au$P}g(bzM)mU+C zPB*wKD~}Tw*nm<4JQ33#`yRbWp6mMKb-lV7~Xl> zp1Aq(?p|VgKQY~j1*3Wg0d39xJm@v@ zuJN+vcAM*-{T{K4(scpo$egM=q-N3EYz$I)wcJ%dZ>DF)+UV5!hDO_`S4TgKCp+k0 H>X!cltu3~G diff --git a/core/admin.py b/core/admin.py index 8c38f3f..f6de161 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,29 @@ from django.contrib import admin +from .models import Contact, SkipTraceJob, SkipTraceResult -# Register your models here. + +class SkipTraceResultInline(admin.TabularInline): + model = SkipTraceResult + extra = 0 + readonly_fields = ('contact', 'found_address', 'found_phone', 'is_found') + can_delete = False + + +@admin.register(SkipTraceJob) +class SkipTraceJobAdmin(admin.ModelAdmin): + list_display = ('id', 'original_file_name', 'status', 'created_at') + list_filter = ('status',) + inlines = [SkipTraceResultInline] + + +@admin.register(Contact) +class ContactAdmin(admin.ModelAdmin): + list_display = ('first_name', 'last_name', 'address', 'city', 'state', 'zip_code') + search_fields = ('first_name', 'last_name', 'address') + + +@admin.register(SkipTraceResult) +class SkipTraceResultAdmin(admin.ModelAdmin): + list_display = ('job', 'contact', 'is_found') + list_filter = ('is_found',) + search_fields = ('contact__first_name', 'contact__last_name') diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..067c582 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,7 @@ +from django import forms + +class CsvUploadForm(forms.Form): + csv_file = forms.FileField( + label='Select a CSV file', + widget=forms.ClearableFileInput(attrs={'accept': '.csv'}) + ) diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..6caadf5 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 5.2.7 on 2025-12-18 14:12 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Contact', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(blank=True, max_length=100, null=True)), + ('last_name', models.CharField(blank=True, max_length=100, null=True)), + ('address', models.CharField(blank=True, max_length=255, null=True)), + ('city', models.CharField(blank=True, max_length=100, null=True)), + ('state', models.CharField(blank=True, max_length=100, null=True)), + ('zip_code', models.CharField(blank=True, max_length=20, null=True)), + ], + ), + migrations.CreateModel( + name='SkipTraceJob', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('status', models.CharField(choices=[('pending', 'Pending'), ('in_progress', 'In Progress'), ('completed', 'Completed'), ('failed', 'Failed')], default='pending', max_length=20)), + ('original_file_name', models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name='SkipTraceResult', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('found_address', models.CharField(blank=True, max_length=255, null=True)), + ('found_phone', models.CharField(blank=True, max_length=20, null=True)), + ('is_found', models.BooleanField(default=False)), + ('raw_response', models.JSONField(blank=True, null=True)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='skip_trace_results', to='core.contact')), + ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='results', to='core.skiptracejob')), + ], + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1be56c63cccf37dee506ea233a4a8fd5d81de68d GIT binary patch literal 2943 zcmbVOJ#Z686uvu2r(c6)47QAA$>zt%i7gYHgd!7y?Z`F(Vk6rLYHrTjwS4Aur`(+& zFqsKOij;J?NWr8alZgu#DO{vb>2fu*g=Q;eQZZ@7Kt+?hy^~Bpo(W{7d$&K|d;8w^ z_UC@->4^wX{)*0NUxfwXPu}R1K)dpM4k`}?Bp^{2iXyxvU8?wszKXx-7X?X}7m)7< z0r|0StD_@4_6fpo@OY&dKw?422A=Zf^{m7q6|HQkj%FG*lPe~|x?O5x-B+UBc>WXE zcqm|Z-lBxWqOU9z{gQwKTXIJMNyrC1!L86ikBCI%M}Zyru^;?^$158W3c5&$)hmDt zA#o@Cy1#&nyd^H$g^L|(ucr%l_`FBn5_hx<7e8#?a&RZ{SON~<@e1huo4ek3;O>|^ zr@LafEts$Gu?V)|@e1&E{B^&|0y^=ti26}{XP}GYTMoD)h@6s-{DyoOj<= z#tS)E+BCHiwpkG24Yj5_7SB8DH7%{I8LF;qfR;;AR`iCB9)xiN+n~UDHq4rVxZ~U( z7WJCdP168MG+S}opnZ-Tj#=s*1#ne3mT^|H_(bQ7ao?z^awemTHtuCZTl}as!2X z43_@o!tCX_&soH*;`ZJ4tMD9V7hYb|P@yqYphE=` zUuh=#Niw^Af+n-O{`#@~X_8!OB$sG%iNu$ii2*V=zI~Psj_>x>PwmfXgKmr0P%v0*1)TX({C5?1s?H* zdLK#W8|gev=Sh6NnMjh8?`?lXPrla@gbx+z4XH^M@A_W4?1R_PjPIE%U$_!_60^Q$ z;tU!4_|a`T_Hq3J8Jlm6&C{`Y5?^SA1KjNpcN@eDE?T{>+#Y=kw=-n)gGXoS=m&d! z`=`jt*JSi&WAr8+y-DK5W@4CRrXI;OGqvmNOFWI4wMJ%*X1p{4qf?yGslDSQb*YiM zL{pbY{Ig~vO-9Z?IzdOy@A>P~WMrW+vOq@`NPN*v?gUTn#Gd>|m|k3<7nkY9n`HAl zh;>F<;#{PbB_IJLkN}dCa6@V)PLP4@woC`IyZPT2>GT|(zDB243910V7V{jJoadS# zK@%j`T#yb;?!;)XeE$mnSqq&lkd;}|+kum4ebW1Qoa}5vYX)E}d@$}F2<{o+?V)*Y z#Wl4EwU?n!yyN9l>nb$)cZ|IbqU94su_X)Q2oW;gzbTv}hy7b}R+L*pw|Eet@zc-v Lz>7mhT_64dJc1ZD literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index 71a8362..544dace 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,38 @@ from django.db import models -# Create your models here. +class Contact(models.Model): + first_name = models.CharField(max_length=100, blank=True, null=True) + last_name = models.CharField(max_length=100, blank=True, null=True) + address = models.CharField(max_length=255, blank=True, null=True) + city = models.CharField(max_length=100, blank=True, null=True) + state = models.CharField(max_length=100, blank=True, null=True) + zip_code = models.CharField(max_length=20, blank=True, null=True) + + def __str__(self): + return f"{self.first_name} {self.last_name}" + +class SkipTraceJob(models.Model): + STATUS_CHOICES = [ + ('pending', 'Pending'), + ('in_progress', 'In Progress'), + ('completed', 'Completed'), + ('failed', 'Failed'), + ] + created_at = models.DateTimeField(auto_now_add=True) + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') + original_file_name = models.CharField(max_length=255) + + def __str__(self): + return f"Job {self.id} - {self.original_file_name}" + +class SkipTraceResult(models.Model): + job = models.ForeignKey(SkipTraceJob, related_name='results', on_delete=models.CASCADE) + contact = models.ForeignKey(Contact, related_name='skip_trace_results', on_delete=models.CASCADE) + found_address = models.CharField(max_length=255, blank=True, null=True) + found_phone = models.CharField(max_length=20, blank=True, null=True) + # Add other fields that the skip tracing service might return + is_found = models.BooleanField(default=False) + raw_response = models.JSONField(blank=True, null=True) + + def __str__(self): + return f"Result for {self.contact} in Job {self.job.id}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..ce2c063 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -14,12 +14,17 @@ {% endif %} {% load static %} + + + + {% block head %}{% endblock %} {% block content %}{% endblock %} + diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..a3c2cab 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,43 @@ {% extends "base.html" %} +{% load static %} {% block title %}{{ project_name }}{% endblock %} -{% block head %} - - - - -{% endblock %} - {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+ +
+

Skip Trace with Ease

+

Upload your CSV file, and we'll find the information you need. Fast, reliable, and easy to use.

+
+ +
+
+
Start a New Job
+
+ {% csrf_token %} +
+ {{ form.csv_file }} +
+ +
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
-{% endblock %} \ No newline at end of file + + {% if jobs %} +
+

Recent Jobs

+
    + {% for job in jobs %} +
  • + {{ job.original_file_name }} + {{ job.get_status_display }} +
  • + {% endfor %} +
+
+ {% endif %} + + +{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..8e0d0ae 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,7 @@ from django.urls import path -from .views import home +from .views import index urlpatterns = [ - path("", home, name="home"), + path("", index, name="index"), ] diff --git a/core/views.py b/core/views.py index c9aed12..a21bba6 100644 --- a/core/views.py +++ b/core/views.py @@ -2,24 +2,45 @@ import os import platform from django import get_version as django_version -from django.shortcuts import render +from django.shortcuts import render, redirect from django.utils import timezone -def home(request): +from .forms import CsvUploadForm +from .models import SkipTraceJob + +def index(request): """Render the landing screen with loader and environment details.""" + if request.method == 'POST': + form = CsvUploadForm(request.POST, request.FILES) + if form.is_valid(): + csv_file = request.FILES['csv_file'] + # For now, we'll just create a job and save the file name. + # Processing will be handled in a future step. + SkipTraceJob.objects.create(original_file_name=csv_file.name) + # In a real app, you'd trigger a background task here. + # For now, we just redirect to the same page. + return redirect('index') + else: + form = CsvUploadForm() + host_name = request.get_host().lower() agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" now = timezone.now() + + jobs = SkipTraceJob.objects.all().order_by('-created_at') context = { - "project_name": "New Style", + "project_name": "Skip Tracing", "agent_brand": agent_brand, "django_version": django_version(), "python_version": platform.python_version(), "current_time": now, "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), + "project_description": os.getenv("PROJECT_DESCRIPTION", "A simple tool to skip trace contacts from a CSV file."), "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + "form": form, + "jobs": jobs, } return render(request, "core/index.html", context) + diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..6cb6ab2 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,56 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +:root { + --primary-color: #0B2545; + --secondary-color: #134074; + --accent-color: #EEF4ED; + --highlight-color: #8DA9C4; + --heading-font: 'Poppins', sans-serif; + --body-font: 'Lato', sans-serif; } + +body { + font-family: var(--body-font); + background-color: var(--accent-color); +} + +.main-container { + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + color: var(--accent-color); +} + +.hero-section h1, .hero-section .lead { + color: white; +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--heading-font); + font-weight: 600; +} + +.btn-primary { + background-color: var(--secondary-color); + border-color: var(--secondary-color); +} + +.btn-primary:hover { + background-color: var(--highlight-color); + border-color: var(--highlight-color); + color: var(--primary-color); +} + +.card { + background-color: white; + border: none; +} + +.job-list-section { + background-color: #ffffff; + color: var(--primary-color); +} + +.job-list-section h2 { + color: var(--primary-color); +} + +.list-group-item { + border-color: var(--accent-color); +} \ No newline at end of file