From 45224212930e08c7c1e726892ba5aaeaf3a4846b Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 22 Jun 2026 20:09:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8=E4=BA=AE?= =?UTF-8?q?=E8=89=B2/=E6=9A=97=E8=89=B2=E4=B8=BB=E9=A2=98=E5=88=87?= =?UTF-8?q?=E6=8D=A2=20+=20=E6=B8=85=E7=90=86=20pyc=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新建 store/theme.tsx: 亮色/暗色/跟随系统三种模式 - App.tsx: ThemeProvider + ConfigProvider 暗色算法 - MainLayout: 侧边栏主题切换按钮,Sider/Content 随主题变化 - 所有页面硬编码颜色替换为 antd token - AssignmentsPage: Tag 用预设颜色名适配暗色,未选中背景用 colorBgContainer - LoginPage: 暗色深色渐变背景 - 从 git 移除所有 __pycache__/*.pyc 文件 Co-Authored-By: Claude Fable 5 --- .../__pycache__/__init__.cpython-312.pyc | Bin 152 -> 0 bytes .../__pycache__/database.cpython-312.pyc | Bin 3463 -> 0 bytes web/backend/__pycache__/deps.cpython-312.pyc | Bin 2427 -> 0 bytes web/backend/__pycache__/main.cpython-312.pyc | Bin 2035 -> 0 bytes .../__pycache__/models.cpython-312.pyc | Bin 4943 -> 0 bytes .../__pycache__/permissions.cpython-312.pyc | Bin 2662 -> 0 bytes .../__pycache__/schemas.cpython-312.pyc | Bin 6136 -> 0 bytes .../__pycache__/security.cpython-312.pyc | Bin 2334 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 160 -> 0 bytes .../__pycache__/accounts.cpython-312.pyc | Bin 17312 -> 0 bytes .../routers/__pycache__/auth.cpython-312.pyc | Bin 3355 -> 0 bytes .../routers/__pycache__/login.cpython-312.pyc | Bin 7497 -> 0 bytes .../routers/__pycache__/proxy.cpython-312.pyc | Bin 13168 -> 0 bytes .../routers/__pycache__/users.cpython-312.pyc | Bin 6698 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 161 -> 0 bytes .../__pycache__/login_service.cpython-312.pyc | Bin 11579 -> 0 bytes web/frontend/src/App.tsx | 24 ++++- web/frontend/src/index.css | 5 + web/frontend/src/layouts/MainLayout.tsx | 97 +++++++++++++----- web/frontend/src/pages/AssignmentsPage.tsx | 23 +++-- web/frontend/src/pages/CookiePage.tsx | 7 +- web/frontend/src/pages/DashboardPage.tsx | 7 +- web/frontend/src/pages/LoginPage.tsx | 10 +- web/frontend/src/pages/LoginTasksPage.tsx | 32 +++--- web/frontend/src/pages/ProxyPage.tsx | 15 +-- web/frontend/src/store/theme.tsx | 65 ++++++++++++ 26 files changed, 212 insertions(+), 73 deletions(-) delete mode 100644 web/backend/__pycache__/__init__.cpython-312.pyc delete mode 100644 web/backend/__pycache__/database.cpython-312.pyc delete mode 100644 web/backend/__pycache__/deps.cpython-312.pyc delete mode 100644 web/backend/__pycache__/main.cpython-312.pyc delete mode 100644 web/backend/__pycache__/models.cpython-312.pyc delete mode 100644 web/backend/__pycache__/permissions.cpython-312.pyc delete mode 100644 web/backend/__pycache__/schemas.cpython-312.pyc delete mode 100644 web/backend/__pycache__/security.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/__init__.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/accounts.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/auth.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/login.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/proxy.cpython-312.pyc delete mode 100644 web/backend/routers/__pycache__/users.cpython-312.pyc delete mode 100644 web/backend/services/__pycache__/__init__.cpython-312.pyc delete mode 100644 web/backend/services/__pycache__/login_service.cpython-312.pyc create mode 100644 web/frontend/src/store/theme.tsx diff --git a/web/backend/__pycache__/__init__.cpython-312.pyc b/web/backend/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 15c429fb55844d42f900b996788282b652c9703f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152 zcmX@j%ge<81PAt8WP#|%AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdWv(AuoLW?@UzwYu zpPZkPTCAUvUs_ojpOc@SnHOJBsb8L&q@R?SoSmANq8}fhnU`4-AFo$Xd5gm)H$SB` ZC)KWq6=)745Ep|OADI~$8H<>KEC4CYB=7(L diff --git a/web/backend/__pycache__/database.cpython-312.pyc b/web/backend/__pycache__/database.cpython-312.pyc deleted file mode 100644 index 562d44a902497556fbe68289f6618e52f82d00ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3463 zcma)8eNYtV8GrZVcJKC%0}c>DdR)b?8v|FH_|c3_dw?b?5XYc1q3!G}yDQvrdxyJw zfn%V9PK=;LP$z=1Om&)86OFNHQyg*9CY|X&?H@2O!?|Oo$%Mo6uUO4YjMG2*ynDBR z!D`-{ectcqeeZeR-|u<;nUljITpnx*H`o#S((Gh~EnDCB5(o_=2{j>!kjMz3kWD0k z+f;;7=qB21(-E7(G%*U>#1e=^GAY|H!9HBVo=m-1e%~?4*5yP6a>0!m*(Et)G-rM^2S(XTS>;V` z$^ANN%9V0K=1F-V^QC-{o`lC=5ck5exwo#)y?G^d{Z#74TXUz5&t5w|d*ki&2cx&I zoWDKv#vQE4PZ;!WL2rdRM^t4&mw7qb5{k-x(r{_AriEfrMQD>%BTtgWh@c93=rx&d z7BtzQB|#Uum=3wQN@{L|4Q#uh%28c2>~d#F)A?9i7pEPFgmn4&Kpt}>4TlF9Z>PDx@VS<14&Us@qv?-Me|6*Sxxt~?kI&A#AY=KjZVaS97@Pa!q1)r9=0<;; zKJs4b=*86GKiwIA|I6M(4cHv7WQ<-H6NQLj6C*KA2Ir7cvxfhc@8RaaUQJfDKthQG z#F!*&0Vx(w#Q8`J+{U*j0^pB8vmmy~Q7M2ugnd=jo-mjeS?8r@wFuM{!l(H`q|t+3 zH0vlj=IyP%OH#Iiq&x4Z{c}4vXz#bb$vx;JGmZahc*`N@7UDQvfllUcA%5rCNPR?Y zAs+Dtwk-ZkZ-6JDnJMAy%eVTt4qJ#`G^jIH=Q3g8l|Z_~8eQ;{?p!*SApMm2@>Ap2 z)8{Yx*85U#oJk%2eX4IXb>UdX7hq>Uq2|Em20vra)%Ydb6Tj-5Iyjub^OT95@xN|LT#C3BkCc# ziSWFs7FLk(pe4#Or&afm-DE8qq(rg>iR7<9a}U)`NpuNpJV6dPXw*aZP?D{ievMGq zK0z~MX|!qp84;d$&%!;do0{|g@1Crs#j3yOJ?&4ur^C`{)la`CP&51%Xgk4)5NbrS zhw1=nwJOjCq!As^e-*q16vAcb!S9S$!oQ#Afb?Gv-o7vn+%S9XdTQ*$x!?4|Bb^%? zPaQosclv6oZy4UDih+VzS(iKYt`)oY1YfKV`T)fdnGZ$x$JPm=7>fhR`tM*qFeqJU z>3Tj`*SKwuuQ6C%x6NlQ@C9pYeKjxF?X7Qs{Vl$I!96uE1^2Am^qk*UyKQ@LZ(XBr z?b@#8OOJ?Sg7F(3F|O$`g>RQtC1gedtt+_rBy-*3W0r34?R@3shWX67t^j^;*nkb zy9Vm-GRU*c()ZIT?+a7;KYN0{@^c-N&Zjtb~@&(jxxmJH`FU16PL&KEpsKEXkRC&N!%V?}s?Fn&RqFmh*nBz@(b^j{7` z0+s&rA5w#3sgncg3n$b4A7bRLgoPNnI6mWis#VZh`F26mI%2A1*aS%lMGd=IZTRuC zhEt0JvUs!K7{^h0LI3p&nH(*3V#IGV>=vH zP}>^(oWUrN97Hs=3KSc54FIKv^n@CKu8PfP*bc;HHDTEHhg1#FBuJ9F4o~9j*iW1L zGOMwn)E|M+a2#5|SQ#G2Vl$qLfxs9m`;1;YpHR3Up~%f2?CkFxp^yD~CbwcTw_-YX z_07WN$r9g9@A`{7r@Wh!MJtn~-ehsr*G{I$-M8(o8|CB2eS5=-)B0 zYiUmMP;m4fg{1RK-+9 z#V=3A(H88iv`Hb=T; zB)4XUtDNL2uQHR|rfbV5xnM7wMC=jwLH7(QoJ55qjTdVtP~kM%@P%VplF1t?9&$|3 zrAg1~bMcA%%A~{nHA{13FY_N4$}2m!?CQ3^?VZlu)$6*+7EiGyz4SeXAqwt!Xu@^R Pokx`3U*jPP%$xrY+KFL* diff --git a/web/backend/__pycache__/deps.cpython-312.pyc b/web/backend/__pycache__/deps.cpython-312.pyc deleted file mode 100644 index fae3d62a90d9a47f5c827201a734ba1b211d8a71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmZ`)U2GIp6uvXFGrR5VU$bDx$qSzvKzumw^iX-CmI}Kc{ltf&97lT-Y z1z8-j4l>yo{H3tM;?n%L@wFiBU}YP2%XVy$9oX3+$j$24?U5RPFjAh!c5 zm2ogCLPdR*2SI8&9Z+%MiSjhN=VcA9$ zoi~uq%I&&9uofeoL6&YNHz1*igJ({LSo)EcJ4}SM1+B0tuUwdEl4UN$44DS0HHKnavj!x=8YCD{afj!AIgqO9)Xx6ChSni8h0W)Vs-VcTM@EY|G#wY*KZB)?La z3tC}UVKtAmvOG$d@?K7CL<{kT%k%QWJeY%L_ym8}n&87r3$i>?vwP%QPzBPAf}xU1 zL^uY~-S?ng?k&{Ac!lN|4Pm-}VERhm%(e5gcW=&qdv@x*Z>B%Ed&+s_$dPJFAl#{i zf|7=HA;%z27qc7-P=e@!j5R5w=;q^Ck}*+rPK~vDZG`5E@bJ>hC_@9=w`>ixHScO` z-GA`#0sr1cB2pO#JR%l~_>(bA;>1d^&=FEJOmsFR>s+W))A^1NQ8m3NqyizeP&f7p z!~vSbN!1-ef@K<~q^JSh8`RBRQe25jvTimg3SLYUsFY(KV?5jDqfAzP@rdH1`%ryy zG!~Bq4BiI1;=Uf-?rWEVKzrFI<1V$PE3P{!>w_^u;AaN=NfmgcF{s1vN}_oSDzBVy zFCTYr8F6n(JJzR5DhA$6Icw(4rg9;9FjH*dS5LUA2JonBbDuday83peU29X;wdwNJ z{ii=ZJ@C?Kx%W9ihC|jBnPOzMU#z=Oce(NXhH=p|B6@DRzbgNtd}z;i=E2uT*4B-R zFOQ2mN5q|@;;v+4+AJm$SGV72xYm%iuS!`~rA0^bwWsqoWOe_A7=CqjHNydXrqWCd zRPL@ozf@Rv`#8P0P}9MMG6Wr(O`}Ac0KE4Jg$Q2M zdp2&M39bhs097}5y}I?eG|}RGVJoGuIM)lWD@;H1i7=r54%MdRx(YI`lOb*}*Nx6G z8a)nUEb1}L1vbHSGsO9vo#_Jm8M@9cwoV|}INuz)1P2_WRG$6e_SD7Usp0QuZl8ty zdRaoR075G?MiWHK)HtDfkC!8BsLUua+MQql8VA%6O`J;B16FC=9#4`~Qh_;m90Qff zsfrhmu4ac44MOEK)Z~;lQS*K9dYVLO$BJ=B)$fj~3D=rCds1}=##~J)Ytw|Ya^UEw zv$l^JE>&T2j^)Fiu%k%z-BwAq~i=7o)~ue>6;D{EVLI z+n#Kwt`{RD)zkw#Dm8(q9#w4~tA1s)s^JL|_?4f_89M#C{ck#D?8sW0Y$lsQwb@&) zn*#wk8Vm$FxBnqNkvlNNFwo?D2Whyqv)n^ z6liAjD~l{?Qo977w8!d}1#6ltU5G$WQPgZZ6ASgE5}GgF7NwVDZ9t{|F|*C{*vzrzl3q7MSF&W`45XDL%%Zu5{l={6x9|n Nr32gM5llub{{l{ca9{uc diff --git a/web/backend/__pycache__/main.cpython-312.pyc b/web/backend/__pycache__/main.cpython-312.pyc deleted file mode 100644 index 483a9b246bc1b36aba655778c4df3c2858a97bb7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2035 zcmbVMU2IfE6rQ<1d$;@7cDH|kNTZ-`qq_w}2oR8fMnWtE@WK0XbGtKbZ+m|>bMK{W zpNc5~U!;AI)n{WOX-V`=qrRK?Qnis~VxtKb?b||mP@g<=cekseG3jjf%sJ=IIdjhW z&Y7>%=>&qsmk&+8rXX}r2(6_xnT_)jLRCbNjtC}_jdcvWY)g);%UI|XTX9rfjd<0L zIhw8kA0wI_cRKWrh>zO|C#ff$l%8_ZdfLh88K+b4bh`8|jHpaHs5&N*#GJC&yjJg) z5LHQ%q-gh2dQonu^(@U!KHCbhy;F^3Nawgjx=8mp7XPK}qT2Wl{V>P33y&?a{Mq<0SK19Thdn|cl* z76&W`T3<1$NEIpHA7;SItEL~EICpw*?dpeXH$GSwen;|{=S;uimP(!*(93~iy5=}# zpw^nlfz6yed;Y@f79lpBHW^(Pu-$?amTLtD8O_JIVury4S3{pNpT|w`7P^7YRoff4 zT&|Xxce%o~lIKlX)aSBUE|;3vizpCuJ(7WJh$cCMFw8)(`MsSBLARBgxQZbwbX%Ur zc|5|z=;Sf$gv}QwgMaKVz9GUWRvf!n@(A^d#0x8-5yfJZE5&I#S{yY?Q`99z$F$r+ zxx(YNHAeli>9Q<1NeOSFWWS={X3@_|a_;o1(($_wbBo^U&f#zXnEN-Y>z{ma|LxD# zuig0N{m<9Fe0OdBowXYu&!~F~!-e6z%+|mk

M9J@E~o7w+S8|cyug$0p;Zp9`ge;2z@SjQ@0S?DGmuU)(wQm z8ot;r5Cmp^8ptgADb+JimXkY{l^yI!(ERPL7%0Tkvhfm-zXCidqWH%Wkr0_EOX{L1 zIxGQtJ~lGb1Mn4^@D&7nhoPHhG^n`vSuaCK7oqlwC@ojY9t(JkQQI>~UgBDK$trow zZ|Z43qv0AL~$-rtl8&gMWBAS9oOCzQvD8JMFcG;lmJ zWnLHnf~*51CO~3IK}3TxQFA7`H0s%C1bD_I#Atiw8Otr%A)!XY5tJfw$mMYwMCe5c zi)>uep^$DIR?*NZ+OdlEt)ZPiq7!$} ziFyo4y>&^#iTAXJ2(}HmrFf7)TBerRT}$O^>E1`0qDixIJ%g}v2W7uO*_x8A<%X7@ zKe?PeRqNYc%k|CgiAX((aPAR`VX2Awke&%t_!RoPvV=L$>k&Ak*|4RS$o!{a92NK3lh-?Pxf_oUp_#Cdsk&?PT U^R2w?uA*Iir7k07dsM+c0lsd_+W-In diff --git a/web/backend/__pycache__/models.cpython-312.pyc b/web/backend/__pycache__/models.cpython-312.pyc deleted file mode 100644 index 1f10992f8896721988d2dbe2945a5e0fd9f3362a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4943 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 diff --git a/web/backend/__pycache__/permissions.cpython-312.pyc b/web/backend/__pycache__/permissions.cpython-312.pyc deleted file mode 100644 index 5375917d04d7bf17ecf47be8a56b17666daaaa3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2662 zcmZuy-EUJz7N6_S*f)ty?2x2^#I#9>lY;5el~&Oz)fVwki9*$=FQ}5`cy5Ei@r~}i zE_H-f-Y!{^r75OcnuMk$X$fQ()%1%^!J+&C`(l(zP^%9}^|hTRE~QU?>NzvEv+pXUw}1d;t&4)@g6WMeDe3rg;ep~ zn|k_U{^m^nyZ1|1KPb(7y_uOWr7!c{Nk?3jl%cmH(#d!W+FV*GE}kuZxLTNA)2HW3 z%d3+jLxdG6q)G8c!06K->zP{|Q?Zw5L}Po!^^Z#5pReq3ODaXBn&r~w!sW_t8}l1d z)yP;ZI3X$H5m4orS~=q%n^Utq#@bPO_tjF>r}3a-W}$TEKl<8N#fztFzVex=3K6MU z@KtWE`ihKC$O_L_zrLCXy_vs=ig$f>vzqw-iJHZ&U2 z!pGRf=;zLtZmbn%Zf>4AS6s;Gw=a~NIR@{Jk3Y+$7?$M|5s4Q`Q_aM8fGwAsD%;XKj1>eRD`#$10gV%i{7zzMJQNF!Ni3Os z=JR5T@qRm9OfQ38cAq>J(WGcZ)v7>buefkqPtEGH7x0d%*tiR0xN)|0{X%V@7vDFT zV&+mQ{XIbIs##Ajm(t6HxfT7+oZnn--a1K>RBh6wCR9xtA5tYvi^Rs%NoOby<;>Fc zi;4*jQ_LtVD6A;3+bHB$ji?pocW5@0=ah z8B>@>>AzFOTUR*;`uX`ddM@2bl~OBA<>ivIC~{QF*%V2OE3t5;e*lsYj0uB#ycfhA z(LnNX99N$hr=aIt!+c#x2tGV;oi!y`HKn56jy#SP9>49Qm>3cLZ$L=7ayqk*tYB{e|hcp@HTr5Bt? z1Wrn$fzeR-gcPHJx);B9B9Zfgw;-lj-wKrN;CC1gz+y;}yx4h9?7k~@FIkpGH$;Ed z;(rVq=`G5*&0|JO%|RwE7&NbeJ)+P)cqi?GQFoKas36PyCUCJn3Z)aa4!}&t2 zy7Jut6Sylus}=VtQf2z>tzs>Fo`ip>O0mvg*Hc$`$rdi9IE7fO0?W^DVi_vvS;aGb zKAvCmv5;Dqn$iV(uOi3;B1s;Itv__^S*05t`?KQytYtsT;ILoJ*@HnUhl9bKSpN(x z*t2q$6H-D|&_hmSFXhl*UOspT9*L?coNgpAXBm~{C_C}rg!$zmHT-#8rtzpWtn3C9 zQlQEp4YME!Kav5%*6A`mu(-0@dJQY6hK*QTQp1KF^#)>fr@9OW>Q25cqTWcXUGsl6 znoxHWYg@K`*w}`X7Gm9z-Fd|D;KWO;t*MyNiu!iYv)lI=Z8&M?8y%?c0JmAsZeu4- zx)^Go(Tx)yu|AXS95#00qz6xb$>>GBk668_ps^eE0b=!Jz5T`@PM&9>1dKg6*-P5` zAGGz}Z|VExk1$V)kA{i2eO|oR-ha2ff1`b1!!!7csjTdCxvcwIJ zyuJ6gb=-HgJ+fQS)@U{f1M{ju;IpKy9#~F1M%8fIg~6qsC3P8k1*nGCB)mB9LD-9{ O&#}*!J-_0NUC3{1bhVEF diff --git a/web/backend/__pycache__/schemas.cpython-312.pyc b/web/backend/__pycache__/schemas.cpython-312.pyc deleted file mode 100644 index 0239c89cd7706d2aaaa9c93eac9a04c8aac220af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6136 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 E5BxSBA^-pY diff --git a/web/backend/__pycache__/security.cpython-312.pyc b/web/backend/__pycache__/security.cpython-312.pyc deleted file mode 100644 index 691f99386fe9c2045e39b43f2dc0f0a9cdd8f868..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2334 zcma)7Urbw77(ci7-nN%g%AZyTGl*_;>s;5!{)(FkV?}UUHp-l9mfVzkF3|3_w>kIL zQc@ONHY14%EPJ3c)3LZj3}o`)151{uZzjG#N-}oExWwSxlPEqIp8U@3A2!s*FX=hw ze&=`o{l4$_^?RqY0)fqZb2xUHL+EGvQ8HU`u=XhoCJ;tpgc)p6m^c$=;+C)_&W2fr z`dEdF^I_f`bBZ-=1s|{2;`XpTE`$Z}Tf-ID7It8JxDpGp6IaO2J`OuBap5Xl3ExiB z=jyZKD)3dym3<6$$u+oIt~Ie%Tyu#J*Wp?d$ICVKa3|QI4$$rl=XIxE0LRMh(Ur?n zzf9d+`DEg^yC1K7`N6}<_gAidxH9)q)5}e7p6Pi+pX6l?JC5kG9*xU}KwB&;dc?5P z;gFh;y^LY+O6pNH5mAC(i^0ayx?zXq0YX$Vv;(WDOv;y*dwrTL5n1<11Cd0(?29IR zNuuJEM3)+TN2vM0!AD!*M8lqpXj)n&*suaVMG_K2Z&EZKdKP|b*P)p}SrmJGwg|$^ zbkRG^WEqUGr2!2yI$dX448phBvX9SOH_sw8U35)b3WJ#NPt3--Az&`J&ZqP~-{D6c zfb{Z)RZd7MmJMsKL^4U;unt7Dfn?gS^~(t@qJRU-6yUWG2dprJWEzXT8C}*idS+A8 z`XT>mO(vQ@6Ic8csrgNMMMdq8Cd6dM4?O#OBhq;}f&IXDibVCy-eksb(xb!@vE*6U z&Iv#5b!bM=QuUSz*A>^KEnmHBr1L>_eQsN>dAw?*bJuZ271FL z4am~@WSUgdFCj1}$!3N_V5pQx12n~ukY^~w^`1q5$y@;%UbyrR{xh)N_jnOdAdF} zXpGrmyG>Ton@%&=v@A1IR^bqMhS{toMw4!nVM~^cmXQq7=~GRMQTjJo)}q&zTsmdg zv>A4~sBO?47lfL`n`{^?kON;rMCn&S3j=Yl!{8(}nIRN!un9FyC`$&L(j`Kxf?-W1 zX~843q8AdNA{1!r4)lm80%r}O^{qF$x;uM1-iBm(oMkER3Eb1yql=uL$6@FR}8Y)Bggm6W;>Hy(6J!9ua&t2bjW6!lcdFRd<@0@RO zcgKRWW2AkFbKc|J3!Hmg&b>1(E^<4T9aUp3qb=jnTMb`j79FkgTq`k4DQ}+h@AVVI zng2(QI(>*~8yV0~V_Rk%Bv#IdvcynXVip>YigE-rFJIu6Mvr)Dvzs<_3ok?VLZ{IR zQ6jET6Q3mR6_|gK0x7y6FZZ&mc5G;LD7WKQ!`=Eh$D-@_y!|*Rsg5eiecx3_mE>O6 zDq+dRrfujm!Oz}i{H)hw*hCSlk|>%MSh*U22+#~?J6|z3Wm9lc0NSS3#j==wDkw%{0TKaaPA+eSgNcW z5tg27oJaMmR*q?Ba&4=K_LFUEX1`j+F`nE$>hw&pW;e^xDbH#ZY6&sF!|)iB!*u2t iGiw5mG4p4_6myKB%iTGR&blWDXStgf{-i_m(tiUqS_y3c diff --git a/web/backend/routers/__pycache__/__init__.cpython-312.pyc b/web/backend/routers/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index eecbfe6cb4b639ec27bc1da5b8a6442f4a4dfc99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmX@j%ge<81PAt8WP#|%AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdWv?GvoLW?@UzwYu zpPZkPTCAUvUs_ojpOc@SnHOJBsb8L&q@R?SoSmANqFS^`oWAD@|*SrQ+wS5SG2 f!zMRBr8Fniu80+A9wQJJgBTx~85tRin1L(+qNFH0 diff --git a/web/backend/routers/__pycache__/accounts.cpython-312.pyc b/web/backend/routers/__pycache__/accounts.cpython-312.pyc deleted file mode 100644 index 7248339788ba6125fe9a7f1cebe95b4c3266526b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17312 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 StH;-$(Tcj(Z?hm-YyKZShV3E% diff --git a/web/backend/routers/__pycache__/login.cpython-312.pyc b/web/backend/routers/__pycache__/login.cpython-312.pyc deleted file mode 100644 index 3f5eaf1691553f8f6c35de357fe98e27dffc9e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7497 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 XZ8@_hhoHDje?tl)zTzI?tIP3!zssfH diff --git a/web/backend/routers/__pycache__/proxy.cpython-312.pyc b/web/backend/routers/__pycache__/proxy.cpython-312.pyc deleted file mode 100644 index 51b96069819af436bfb0e109a34a6aee4b4bceb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13168 zcmeG?X>=1un%(NwElaX|-|_)i1}q#1For+?8!%T$xV_0}WOv)hNS4zr#n?y_lQ6+% zAlQ=$HWM;2n`C1Wk~llF8z#pKNyt2Q^4^YwoF~!4Y{(mIVE>E>cpQfd02nd`1b!pp$Sp@M1{D=irG;_ORA)snH~sshkx=lYi9JzA!Q7#mNByFEi{vUh;A%p z3)||WvrI}D6PtN9BZdunP_SvQkrDuY!9Rz|jFrUF7MX}Wi!}iD>_hU`q8J;?p_hgv z^wI3!+)ECdCH9mHJt>&Hq@HF$Pn%Qplph--Q^2a2Lbe1(SagVvk8loC%%(FXEZMd- zMQbyZKQyx(`Ywevtoj?-|reXPd8|e1E+E*!Zz$Z~o}m_4nVn@%Ee7fBKer zu6Y;Rw9VbTkM)?x-}w2&;6G0czC8ZH;7weBEf%?;UbVI1A-C7Va)Pps?O@v(UPxQN zef!q>{mpEL$Kh@l)NvF-Mm$^R;G5m;?QFBhLJG=lEYAbzO*{+mt!QOEHm1o!3G@yg zFl)DR?)_bB-0dxnRzbDO%Q!rn+^rUwpiioJ!0QpxlfHL!Fm?|M*i0PzsMo=!JND}K^P^2r zc7_oY&2E>=;SrRucCg%gEix_#5DQduODm7lHk<#n+=_I;Tf1CNYcpWrt&H2-<+VB8 zt&VnEN0+seZL&7mfo$6uD<_gCFKt$JN0*?tA$_?yTQkQ3iE!nBGz zM62)Fa2t>j0+O>nMm07U&bC`8l1;74-fnMY1=7|W-%Mx`-~L?q7$iLL&G*H(dKEykNvxN@NR14UP_Hf#MPbGeFcs+|dxa{GqatwkSXsaTVBx zg0mtho4p*zwtJf61OrtlSn>OI07f)rTybLYQ$Q@qa{+J+KFXFfi#A#+O^yK~-VSgm zlIx^AK*UD_5HT^I1PBmu%m5*(2uanD1&H_|0SMjHTKoctc;5h_PYDq}Fg~&^eI`WG z(IDG0X4dmC69;A0M_+)KJ2GatR;{HzysMMULUW=~5ls>+Dl+-rDLT`yt zrB`H|f<&V>iEu2mp!C9lvpE<+g_(A{ixm{e&VauwJa!I9&7v2{QBbn&_9iFG2uk3P zA_t}SdORJ19AjQc@7(L~uucc>vBdz>5=CCnKvKH3HZpx z8yvTd1bJ8a5+mX#L4Q2}2k(Szka|ikhZYIRlS<+w_`YA}lkxY$A&MUt=r(H0;h=~TTjs#ps~y{{5Tw>W9cDOeAqiNQ}F6G^no)Wp#PFzYxQO~qJzU;)ME zMG{@)65{B;!~a+Ce-Zv}`0s|lrJV4@*=L(Ewrh#B0?wl-`BUvJ*flfu7S7`daW$3@ zNJD#wqq{nZ{nQ?!lZ3ude-Z=WrNmk$srIj!QLNSLR3~Xk^WFZw&Wp@hg1GkXyW>YrUpsef{Pm&nQzK_&g51eI z2C9qF1-dKBaWyC(Hc)W9>`mlTXF#p>I9x0!AKd-$jk+H1b$VKVb`ry{RtoC9tex{T zfeONb6-!vO$Wc*g=CTo<0-h?UdC*{NZ9K49d9%~av%ppPuJ&e!TTpe{9UfbYn-k=` zlVv*u-FB(FdK@~3TO&{%?hcEbTLyU!O-ay1fmLv;#X1+?%A-6)Mj7Rlx=voyPEnEK zxouE+Km7TJL44mJzV0C=6@)f3tjP~*@_|!^>B0bAcukud))oe}g+seS+F3nym$in7 zJ}0a%4eCor)&=h06)f8w((ehY_5@UWpys%{&mGd2gjFR0RY^ppzgkj0yfIj^pr>Jy z*2^ssy=hXWN_&vJQdk}?oEI#dH?rr=N6tL*n(chkSYbmryP=r` zI&7>C7^|;lWDhPGSTeLEluXiL89!`s(bkDle$Y8=5n`=rdL2WDOxN`g&4Ds2jZTf@e!A>-Cb3ah`prY#0QdD>-_4oc){ z-`-J7@AE(S-@+^`%q2RQS^tJ9L$%Jb#nT{G7aYEll2twp|!Fu zjrb^stW(k-<>q330a>S}KdM;(`Hul!OMhHOV}3RT@E=>qdK2++RW4w-K#>^B#aKxK z%mwHRVyzgbRn-&Jg(YNNt>VH`Ip*(^0fq}JNyvXfAhu5^b-jW5L?;8BpXf=<8z{`1 za_g(8PpT-uFA8Fb(rBmK-7!U(MB)^c$)CXKK1?2#4HCU%uMF%}@{kHSIPh2inI8BI z8K`I|JrZ0@ETI{BqNGa!t>auHfrHmUc~m`0l)}l_m>PaR$?HTem!gfI7W-8)Dj)qE z@w_b2yC=>Q6B6NJ7>!@<2Oo@&^2s?FqizRf&8JATy2~t5sJR>uqm6Ut#5_2hT?&;J zdXoE<-_a(8q!HVwJaM%VTBjI^Pw7)J8Xt95`&v}37UxO(6+W6v6KAAmbkoMn(pc9JpqVKI17jRZb_ z{hbf4kNo)Bxz{K9Ub%7ls3biki2!n9if)Dbj_UsHoe(_>6rC{LQc+`{ER{~+BTz;s zG^4&GO79}h$hL4R0s9$>+XRV_%X!;DMMneI(GGrvydL-SL?(p(^yNhgyNwO7DLR2qzx|{7zenmA_w?ebqD55|DTu~Xqs>-0M zGNQ{mzPWGnaQ$d&Fn>izw=$wLekG^W8c{ptRsgsc&CKYMoqBb=A3RDU+*&9T<=qy6 zcC@#+y_ryO^VOp_-aL5o`I8ed30-Rzl)M+jA3LFcmXx7j@& z*3|*t6ctL}7H@mA7wK8*bo@B>SZnqcK+(jhS0&F@wC>dC`13szy(hqb^%XXWDgy64 zF@Ek`t=XdC?twyX5k{y-aHyn6Ls*Qt_&7K`C4xHc?t+#`JBbD79u@(l#YKmb%)O6$ zXbKL2WO+Q&<{$h(6vi=eY?!t!++G0s0sQ$*Ad$c6A->Yna?PY}w!9z$*2#e*2QKT3 z{W*dBxnsI{n9Uu!XG~Wd(V0MW=?ur09$DJY4|e^e3+$8^R3}xJa_0}Pd8OfWLvI5@ zX9o(bqw0|ZfxKm7y5(20XAgIUvTOR*^{(!xp#EgjK;Cfc2tTGaFO*=k@aFz@0M#t_uvq;C$*8{xsj6j zk)q;AUeO(`qFCRzrMIDLvm2&8Q9?tbnwRsPpkw3%NLGI;?O?HbY#KRVnT$gUbw&5go@Rrx_x{|bxUQHuv#Jc@k94b6KypEA!njynub?i>$*L!*Pe?iBrwB7-jiNC7Phf*6 z%ns)cqT65Q1Y<-@Nk0uK<&?Q7zuW~3l8lKv8pNGa6n80Dx+w0Hc=<3zP$(G?JBgAm zS!%{F3WOBQJ&skKzyZv0239DOr^XDWDe%Uy`Bfq|4Wo^ffDl!Em#0J&8*0A>+xgTW z9yKU{Ky+xPvT&c87h$H)KiXfCs9yhTy`}7?AkK{%%nEG<3 zw(ZO1cSq~8Vq=60r|df7kqw}581Fh$Ba_4AGI+F=98z^r42LM%Q_-K2(J;l+XAQJeKCL78 zjIX!JgOW-Ny}2zUQ*ubw3- z$Gqu%h&@c>W}wm)#>Nj0fgHafI^#^AVd@A$fs^?SKQ#1{N1u{%2^DS{78>0O0Cy~= z;!UeBiS{CA=1=cs<``rBcFCsqYN_^Cz}ROhj??@NpgVGCp=^OmBIB-@Lv*uvA;1Y) z=(uP1gLUudus!CmON!b5wX(_Wf&p^7G5R}*rs|ENQqx^3>L&?z?M&5i7@I$W5w44* z6(UzotjA2n(2LIPxVjdH+|f{H-LbKL5BGhjmQ*^?cM}HyP431AKc9H|4|LE-X_XirbLZh1~gSk3Hk4l}SC<4~;XO4}( z^V3@MO}uFKB9pxK?$hyF3E6n>sD!U!E2^%YcCH;R6}{+}PC&l-_QYFHjKB2OjbFYD zT+~cJ31h0XFc7#S~Wzlr|g zZVle8&0p0DH$dIm&F*f8(`mQfTfG1-n(ComP=eozf!nw4ipqzX12yv&`X8>oYsPXD zG*v>{(!t@0Up$*?c3$)`PTh`L^OQ?bG{I5-zm4X@vt-P5{RrHS;N@njD^ezYU)Co> zu6lwTBuV0EJ`IjfbP$3IPu8$?%NdfxYriv;Agf*=kQ`bPVEVw(<54u4%~3;1y&M*V z-QU5j=$`$ZWFLnchvqy|%h#gsERePGtikALSx*+1 zl3u*ph!gGjkKQtSks{3#&!4{W#_0I_&!%1yGzF8E1Qd$DbV+#fXs!=@PU6B8#TJJ1 z07C9Dj5;BjvJBh-DEUhl;3l?4y&$>(`3S zUqAhZMdS@;sR$jmM}Gx|AHcl-%y{3iT639rxXUbmeDCPQbHAK8F$x%vW8jgGW0h*) zkm3eNOk;fXDYF-~Kl8-f;0qpx6CVek(SE%D=)~)A$hl@{V960w_yz$CYq<93SRoT^ zcD7o)vaXJEPp%C>xqTQ-wJ-&Pc$E`ZVd*&Nq`m1x`wG+ughPvAEySb{FmKMWOJ3Ic`Ju-s+$z(@f-EDAgx zQNjg2-VUO_980((2r7-sy-!ey0|eJK*A3-7YTgN}IchvdllvtPM@EX%$_+xh6Nq37 z9P&T)5Vv)NyySOu+UNA9uV~Sx-bRW>b=XjG$xwmjCYaULV>;^;%M+~bu)%!EU>>2u zm9>{DYomaR$8<}k0DfUA8(tVLUlc4~G};_qygs;ieaO_%tGory;I!VIfvkJRR0|`f zys*gOOr5qel2bf*VBo;;!dI4^UUp8_e;|~zte=kL6byC^bPYZ}@OUVvvY$p{ zduO0z!D!}a^C&0U+(paBjQ3qBTRiFsl`S6tHLHL5<&2U@$=v?+mosyRvIFI-&o4b+ z6)4?2mbvAYhA`&hxUvIzYsYl!Zp-LgeLpp+QKlC~3d&wsc5>M;Kf3C??xHKO^5LOn zp@K*H>mr54FEpHN2+ZDm(evA`f9VPp?&+_;oKqMnuf)NQJo@5_A=TyFB5>P7lnxkg z6-K*(?U=dBVCwG-~>%KA7iZ8ULD_MCVWLOYgyeE{krFU&4BX6*FpmwNbxG9uj>8*&EFRs5>8(6yYGvlr=a7l-1hxZOQ2CVhc z+D6QCUNM|DjH*KB?*(;5z3cjS!^)p*9mpG55?H+MqUwBiV9`Tkx^3tgiMm7XJVFwg zMR;eiQXFic?0e@*&t(M6_l1osE*V#Ri}w{Pzr9mN2u0~d-`-hH=(7F_ zS4t0@tLKV0W)kmILGEBQ5*2E*Cz2J!{P} zNPbhQ-bhlvsnTs&PW@)F0!x<5q2yDNg8ZkndSkl$(=;(}Br%^Z<}=kBms6h>Wo=wS zeY!*r`EI#*H9kdWM&;&7_}{(7Itea?>pl)A_t8E%L!FX&;(iw&wH)v#T=c1Y9UgS8ioqvC3@zY3KP!)0 z{0g6<4fWG$A=WE+ZP4AWI3?Rgh!?6#?>YblH}3e65lN?&e5QYVuXp^tCqUduK5~$& zl2)7abWpl`m7Wg%@x4C0V!eqIJ|j!`NwR>CD-((<86Iy zKX!)o#X)`X5I-yn=*xT7T`}eirVXS$W9VtPqBVuJ~LC9Fs5kTUWI{Jtb)>JW8BR)n>1f> zg18WZvc(Q3y2HVNVn=W^MskesEJ%+c^!%evyR&&O>*}g@b1n{T4?zWwh3!ptuzWT6 zsSsak@|+f1A*bTdCndc-Q}Wo>&U46&IlSW%Xol_JIkaL0W0Gz!aRoFir0XM8&_S;i z-=j)giDtk)7bwu*1%u6IZ*O;d?D(jThl!PAJJj;Ucbi-z=4vrohS4^RaGQnnRZY+y z9^=(N1}6I^OLoy{GOQgInfv-8oyARhUNvTR|n>= z8B^EwC_v>ZtLRDV_4Kb9%It6GdptyxPb!q8p}%vIfFw}9@HVECnS@MrIR9XN@9Lo+ z_T-1i>Mu-rL$jZ;Ue;#?vnxl6L)lA1`tRM6(`0c(WtgNOy{goHiQl&=LS~(mK@OgA zOv3`|a7Mm}C$k_}SUvK?P~nPD=E_^j4AKx$=TB0QUIlz|NMWpc)0bEi#fW7K0ArX; z50dEt)9esAXHu3=T81r?1SF%)Ut)sLm16niiiKoBM4dNDL3-7Yeca#YpOix$Py;j9 zlm|8Cx0U$qB%8@7C}!fY_%Q`oEZ7P?s16q#Ea=@8BC}#EGj&FCBUvM^45U}n(!a!S q99j0H404mRqZk5d#UZj}3W|VrWvKA}Q0A&zcf(=6g*Zg7-G2e~HohbP diff --git a/web/backend/routers/__pycache__/users.cpython-312.pyc b/web/backend/routers/__pycache__/users.cpython-312.pyc deleted file mode 100644 index 109c854ee097211d185dc540660caafc8d00e129..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6698 zcmcIp>u(#!5x?V+JW_n^TM4hox ze`&1DUluF(ms6TGS`n-CSH@g^SFFlkMQJ6`>R64xCRXdOWf=n_8U&kQ?_=j27hzVI z{B>eoWP@5S&IPCF7OU!jG*_zih4GwdxyY*h@C$x5LYYR<%3gy|E}Df3v82~1RGu(h z%rW*ifUGUWQq(%gs`^1GE{(fZf|M$;l1i!uNoJv@NYY~<>3JPVwT~dFPLrUOAgNw# z0%@+iG>hOalGY5;I`pJz9KL7g8nkw;%t^xCQ`h7vlCt7^PUeChVoM_+w9cIVH(1j<*Rj^D+Vc{#<} zzPD>%JRyrj;dh7wV!t3Mj?M!I_I4Z%i34&t-tT1fdAQ4R=)yavU1 zP=b+`_Jk0YyW@S(<~SUb4hIH;lJrKL2q3|>@1^dJKzI9#9o_pC+un|Sd%E`T?|P|c zzv4nR31AQy5J@adMMyBB1etCpVo(;<`oRGK>lUPU_4md>a0L-xON5D7G*l@=exU>* zV!z7wScxw<5cZ)6DPdo>C&0u!K*ZkgQN<_+`y>Td<|Lvt5bu}7KrAkZ(PLH|yZQC7 z_=aK-4k>IPlru5hKE??@4u1EJgZWG|Lrf%RM%bt&IX^->xQIz>E0l#^5p#j6)$${) z8l_NbhB$2KV}`jQ!w%-vHyCEvIK)M4gzuPJ!Cebux)Yb|;>osbjoHJass9#z?mU(B;$P97&L7jUDGWS{( zLs(EOcy|54n5Y;@JSr;IuoMV}cHDQ3-%Q$ z`-<~BF6=tDD{WuBV1FiMe1s;Z~` zlm1M3#dP&#b*8#z`pD#wOr>kOZL;mXZ8IcOQ#(C0IdrXdb@JtOtuNEqw9vRN)wu3{ zxwWR`8^&t2WjV%KnXP8*6(f7@!K9dPZPez}lTkRZbA`_tbqI}3OX!QK@%@!}t67SAMS4T?>YgK|O&AW|r1L6n2x z=mEeQT%zL8JaYj3w2Ds@nkYy;4P9o93Xc{T2n*^EGlFKkUop!;0v?t^>?}`VPZ#8x zfr*N5l?0cl;-$Ga9EB)DWohaS6Gc|+h92Zapgayg31W3bL_1?CIeB#S z=#=rTUo7wqDZb&%f%jiM{c19FDLNZXc{Zo{Eem{mif_NdZ@=brC%O6comZS)^Omlg zw$eju=J{hhX%UGMKcz5BzOg*EM|HSHPqst;Y4 zJs)}QbFBRZ_CCX!+F9&N8Qip0W^APso5nZI(0N1Gx{vBW>~!m7YtnVeJ?s9=yZIBt zHP@=7EA48{xEmMTYg6vE_pK(oIm?(#X0jUg17fE)b80aBtr`Z25af|f&=$(s8dMo3 zkHZl_Gr(cPPlv;gin$Q{7^R2cE?^o)gUb@BmrFI0eh&>>hKzw+5CTZY>e={cxjr36 z=6wb9&;bj6~a5mgqK?}s(#?+C-16GfUE@? z*^b#p%up%FX2`s*0wR+wNX4BYTQQ?x{2bO$TL?ZMEDvAtAjtEWy@1&^%qSkCYf+TlYn#1CbE6$zsmYp~Fl9NNnhpu^^O0K)Kb#`mo z(>7+jVyVvn9ngKAcV}ER)18x@W5#!^NE{v=p68n~bq()(PJ4jpMB=g0WAnTxQ(ZS5 znT!C@2E+y4lj1$|yf@SG_(Drts)aIc%meTvA@~zX`O@(0Fe3Oi1n}qc!~b9SoeQJk z5-ZB$1A#L_7eF<0?+>ueKW*Ur$biiaaSsJ-P7kmJBl3SBz%~iy;s6`qE)VIj;#`t3 za-c~+$ONj6X$!o5I5%g}ft>$2tQM?7iC{ZpfPl~5L(nS7PR!7{_|0oYWmB9Fm-@x`8_bH2>hh;kkKIQ$6J1e zx1Agu9Xz$?Grl>82`^u9?whyl`w{Wfm~i5yLTpykl9W@n_4CH{YKTsPoBZsvt&tq|B+KB4td3v7Z4JR{>1G81EmS(cG=?h6A8furYdOgszS?)+nF z@wdOfH9m6d%=qF2Jm)2E{qC*1r%&BJ{+GpxU*Ea#-ktG}@BVG(&IjjJ`mLF>iyxl& za^yHcmjO>(W%M1c=>5%WAkEOEl;P`0@m#$eZ6JH0mEe03^u#+JB}j1FhFDsK?=t$d zP_#_44_b%eC*h@Wg!#tIn0z;DS~3l*mrNYSms~Es?D0OX@PU934+R1W-y4KW%Rrdm zt`OV;>W&nr^jb6+4ILI^gROBABj}wK3p@q}4+Y_hf=H&A=}VnNZyD4ZDHchD2ZOLY zsCqJ7B*8d_u7y6ofUYCcphOTJ2wv!@`%;X8I3N+Ueo_e;JjbYSqa0j(6eF&dKA|Ya zfjCt0?x1i330dL7{W3xSMfPBZ`b@WCmZ6%W?v`aMOf?Y|w~<58jtU|D3Gyt*vg}o6 zXI5TkI#W#Nb!KCV*?67V^o6xzW_7ZE{^{qgShtOsvu4I% zIaxniKlb8`e75uSFGlLqZ0i>lbu&-=#&^|Om8xEqbf>E~q@5d=Oyz7v#!{N)puEA` zzQ*r+9Aofh4N%LjLQd{c_t?I(mJxTF^)8v2%6iJjK*n%9N${LWiO`BVHvKHsHcFFP}$2ZdrThgwrOV(!K=qSr_P~HH} zCMbcUwJghH&4RqK5At4@H6X1M{`Ih&^o)AOhSF@q_fEBx-9Q;bNv8^BZmLj2cAl&O wX)AM6owqlp*`}+FPo$oFc7F5z^pgkDjR%()Gi#nPevJi=X2KczG$)vkyYXdojH7lRldnHd=wi_v%VO zL^iV*bk29)=X~co-|L)z%gNCb@QvMB*U7pG;!l{6K4l7c_yGVz1WB|Jq>PjYWoNd3u>nVepE=`+8fK@?lm#$4G!0MpB%g|;JU`^22mD83Z zz}ldx%iLz}vb5z2XJCy2 zMS5hsmh>?c6X>E4-rdav!XaM}V9kCi5`hGO`pw~JZ**t)XdncgYFhmMa5Tj5hCOun zWbdYMs3UL`YUR;XBpf_Jd3(b2@j&RPw;PKeAR;^pS_cuY6Z$ydiyWtMuc49Y7)+;| zqPqgZV1CF=f3_6#@IL?;A}9hjo4}23Q|Jikk1Qk=l#*0ZDoR}l^+>0O>pP(|xA_p;RxFI?|bGKqxg(>JBSuJfmvM!Od+mktXQhOldllq~(mV%}nM} z7U&@tYeTLa;|@7#g)%E?gL&AgTry9pLFPk$TCxC2ZKMPGvjbTa@fHC$8-0xb*uH2e zMA6YB(9P`GUp@H#xfHnwn?5rJ5+)UhfC00qXD`>E(?A9HzZ=I7sofF5gM-Q3^;W z!gy(lp#xNeHwqgKM1_RF>w@8<-WQ@&l;V}aaJZW{K!HC>(^Sac>lcoA3cVVL74Um_ zOosa#lf?*cs)!(Ba!5hG_{9{EN*yUEQ$h+`3SUeGDTzT4F*T%A=`szZ)ajHKQaGyc zF}V`dX_cT%d_4tr+B10)L;_POBA_pWl*8bb3m++GoDv+-fZ5^jVt|q{$#_`5sHp9 z^mYXs{9%%cG?2*0U@%~0-tOLp9_mQL5ug7!6(Sp;=81qG>WHPO zJyp2yh%S|i5Jiz!AUI7V9fU2fUpb)RoYnoxX|01RazoP071v_2kgHsSu`8V}tbk$@ zXLmrPyX`2xsvp*0GA10gtfO|+Hd+yP)I&+mZD;9)7hbO%IX<>xs$$KQbFI+%?Yz<< z?|JW39*i}hzg<#&_3-fFsS;>0tu5k;oc+p|%@1K-ggg>nY4;A5S{>h%x;0$PsJHp)Yy`1Rm9#lcn)RdPDv| zn0L_85F7?N9AyF_$}66th_8d<72Qz=q$y%L(@6xe19UH9UFYqNMvftspDOwi>eFQ_ zp-E&T1b}~o`CRjh%@@e4fs29LMq9#I#~SN6i+#v+-juLZu$GF^r^kEP$}Lltt(dJl zulsM6BFB_e5M{Of&Ek%!K^#Qs&^$Ur{0ek-0Cr;0oyuPX=UH|yBI^Yyk(FANFxG-E zvRKbq_MKk$_4_?3i{#4|qm(Rt_sM`(KwZ5oClxW-CE|*_L%x5p_SyxDfF%7AsqB-( z52Rq$wd=FAS+z)AWc~|2SdSbOSr}uHHff2KX_#)K$jH$}T4z}iNOxRI7PUwG? z+hPCvWPQq*jMhl_izyLvq*{!7WgboRzhF*!iRs^e^R?L@58i$MwR?l#d+^b&0cxC3&k6pE*nnDKrOr0ymS3IBq>C>(2T@S7d&z}C4*dFxqdzapw{lOcl_SkSv z)s{Wm()I3-eFydTtO~H}!B5W2zIGbt@%^99yf`{DI57LOH|`C8I5YV2%*(IN>2Y>w zB-3MR&aL4PRp+Xy@ucek1L1*-@XBKh)6J_ej6_jb-~I3gOk(Z|np|`f6nK=p#@8M2 zM(H4*({n7qP{9DGZz#o0bCSm?kafT{ydBYyzty7`z$f|gqh5GJ7|JINaAoye zVae6f;nGJsRjKK0YyY;v$friaQpmYHW82t*<_Sf-U{l<(iL(`4unjiGjm3A&1tNde zFkp6}j-~}wA2gbdFt5*?2wug68DG$!mW_Z{D0MFKNvzIQz(gFADC0pLj9b*QD@rf2&P1ui&O(* z1MVWk##Ee>icJ`&q=XsDEpyVjZ(FaYVW7EX6f>dxxqh#W@ZP!y8V4p6g>#WR_ zNRWijK7CBz>6UUcF}8wsBkLigS;3mWa!pcAPjPe`Ob@+sFTH*5`b(m34!kg; zOAaJ@+PNaSTR`xOk~vlX;u+WGjjp>NT)h8_E1-SwnjRk=0t-2c2l(#$?}JBh=DlCe zeCzV;&wheR!+ZY#KAk2PuZ@CD8uE2ft-J=z18hPULla&p@N(I6ysROL2Gt?g%m=4u z-h4?M9$R+%A`x)PfzeKN`2s=SBt+hHcCMHXbosiyX!ugJpf~X5Ir-gTntAY_a0uU0 z(>q}ldM^h1FxZd50Sumo08|r|AXfzE0k4Tf{a{u{qNsPK{8;^iGcR5}B|qefA_H^H z&E?e{FhdHbO4DIFYR*)cdHtRH@4nIGnwR&%w`a!3n_QkE(GXP!BCrBR&^>r#%7Y2M z249d@flrF=rEx?UBoG9*120EMMn`~-fMdcR3`Zzl9btS-G{URFMcNf$XgpoC2LqHp zv=#$&ihzNNUIh9e!caMUJU|Hs9j|-xq@NPps9+W|G>!6)S4SCtDBQyvI>40>IR>sZ zALB8KX53TQ=N1gMVt~}e>(GY^ei87@DN%0o8qtHsfF_snzG{RCz#_o#ibR79FQX!e zV@VapSk$SEUP^HOQeIFdPnCRGqncBU&gn=9H1E^I9WV=<&Nhi!)3l+KGg{8Io^8F* z7_Z$pvF_$}cGENQjnBrb4^A7~IHUEh-Swl^eqB<&LRZS!iib9w-|%|ll&wBtTgBQ| zy?gMz_IKJRo?%z-oU-jo*!Huw{ZqE5`!|1VE8r~o$-^=tC;!~;v%7B@OOnsY2&cP$ z^S}OrS(s;v0wtCZK^|lF`bJxY|n_2gUN%vC|D<9=(oYq0j zBP-#o;_OcF^>DRyiP|UF+9w`qlvtG16Gi1$ONL7>l?|%z*b0Z5f7r}bEE(MV$_}og z_Rach^#WMA9HO1z1sZBS-#XGbCL606D;%#Fe|DmieSB|x{l54PjJ_W4lU8;;j?PupL3WFlO( zSHC&@&8f0w{hOza#dGlt`fPe9K6_dQNM&;?zj(A!M%YXKLMQ-dTxr#y@)g7FvWk)A zmrej^O!*2f^o*8|ZW(PH+cPbaLcZD91RV?@7FN!pRyv?GqLOYac3%=uE zO42SU%Z7b5se!&q7c_z7e9L0sHKtsu1KtEBXj56odRr&?ANt@XAuGPKXrD2)gl9pY z&$dfd(&(93!XLCzbk=0@B`BuOx-VH*3pl8i+GS$MO>0~8a_cfF34*#yB{&nOG zLxAl}H<4D*?>hCke9v(V_KxSb#9cPOf0PpT2x56u*R>XCMZYUYQZP4mnd^J(PsqSog?f;2kr&z-*%~HChpvofh9 zhQ4G(XkEAl}xcvlM(xaqtuDm|;5Pf#~DDJN`0M z1&1}-$AZ;+@BMx-dBJCmeMeDUSx^(qJQ;7m7YL$t6p5mrXEBp`=ImQ{KO9a?0f|Gf z8=n#EDnO@bH%2v3;F|gQz-<4Zr%u3taFr|?kcuD`5^uzDHZ$orQ_AUZrp%Ht!bLXwohV! zcg!^MNBR&3!sg%=qF`at0fag+ID!Fcxq?Ydw*v%bZS)A5vovNaF~Cisk3!(Fh-N76 zzIbb|7d^$`A&&40AKvN%P0&FsM;0iUsgg$@T=?LCV5lzoI27?((UgQ|Mw*T&TnEDI z5VZ)5u#WHVGU{wp9*MOtuXp*LL|M zg3#@dgS}JX?$?9IJYlQ6WvlGp#98x)YR=aT)t|3_-8f~fPgqy6)>ZGezvq3&dsD%# z-Z5p}nXv9-t^1~|2l_XCY|G~?j=Q$<5qF|uC0nsFzWT{&+f$q^A8p_f^3CwI@T6^Z z+O&%=+dQ%VH|@V}pJuH|!Y@Vp#Y933}G_f^JlQk{l{!eo>CDu<>`ZCjB34M+^Swq;} z$!0>Ab53(sgBXUV47V+|!R@Q?AvlwxnM_xb0(uU8=Zdq;c9<54D8LnMp(Oh+Vo1X__o=`gMAMwejkwCVD51 z$KBBL{y#V>29>vqYcI79g1w=C7k0+`98V!~N7((~^{4NxpsqpBs%6C`Ef9q~pzo$y^yK>9! zCgtyz%K`pMc$qgP28b^{CJ59b1D=FSE=?a)p%47Q1rL9wmv{+ z=E=i{IOzZMdf}yzw<}CWg9sbF@Y>85OqFQ7UNY?WdTC_r@Bj@iI(bDP#L&keO{+1} zvM2LwQRL#QFk7`(c(azNFsZ?mmdJA?bqMK+f}*4WAtO;*p3FhWL==?8%Np4HWl1xpErh-J!j`MM zhIg^H$CA02WhKl7gFT6YWi0%gmM3kPX(#dvAL6KgStU~yCe%#&VZ}&dLl7}Z` z?J`xBhz-O6ybeOCDAfgfDv>O972Y74xi6FByB{xI~ro<{p2E3Z-?M9cku!W|` z3qiQ7JVtf(E)CON;%4jd`Rr2RiI?D~#fOKG0fa&YBcl5jZBgDLyk?z41iU5Fa;fOL zHV8wenx4c-pyZ~{VYVUjTs0y}d|aULj@Ea?2mW(GJimhV>oHg&l&%*EwwVTdjgY}F zf}$Kwk4*M4LH>y_{eiIjfiV1$*zgHa@(JObAu48w@;?$!d_t`FBk?RtJo^bz` setAuthVersion((v) => v + 1), []); const isLoggedIn = !!getToken(); + const { isDark } = useTheme(); return ( - + } /> @@ -43,4 +53,12 @@ function App() { ); } +function App() { + return ( + + + + ); +} + export default App; diff --git a/web/frontend/src/index.css b/web/frontend/src/index.css index f60ecaf..b5bdcd8 100644 --- a/web/frontend/src/index.css +++ b/web/frontend/src/index.css @@ -6,4 +6,9 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + transition: background-color 0.3s, color 0.3s; +} + +html[data-theme='dark'] body { + color-scheme: dark; } diff --git a/web/frontend/src/layouts/MainLayout.tsx b/web/frontend/src/layouts/MainLayout.tsx index 5d4bc3c..39930d4 100644 --- a/web/frontend/src/layouts/MainLayout.tsx +++ b/web/frontend/src/layouts/MainLayout.tsx @@ -1,13 +1,15 @@ import { useEffect, useState } from 'react'; -import { Layout, Menu, Avatar, Space, Typography, Button, Modal } from 'antd'; +import { Layout, Menu, Avatar, Space, Typography, Button, Modal, Dropdown } from 'antd'; import { DashboardOutlined, UserOutlined, LogoutOutlined, CloudServerOutlined, TeamOutlined, ApiOutlined, KeyOutlined, MenuFoldOutlined, MenuUnfoldOutlined, SwapOutlined, + SunOutlined, MoonOutlined, DesktopOutlined, } from '@ant-design/icons'; import { useNavigate, useLocation, Outlet } from 'react-router-dom'; import { getUser, clearAuth, hasPerm, type AuthUser } from '../store/auth'; import { authApi } from '../api/modules'; +import { useTheme, type ThemeMode } from '../store/theme'; const { Sider, Content } = Layout; const { Text } = Typography; @@ -18,11 +20,18 @@ const ROLE_LABELS: Record = { support: '客服', }; +const THEME_OPTIONS: { key: ThemeMode; label: string; icon: React.ReactNode }[] = [ + { key: 'light', label: '亮色', icon: }, + { key: 'dark', label: '暗色', icon: }, + { key: 'system', label: '跟随系统', icon: }, +]; + export default function MainLayout({ onLogout }: { onLogout?: () => void }) { const navigate = useNavigate(); const location = useLocation(); const [user] = useState(getUser()); const [collapsed, setCollapsed] = useState(false); + const { mode, isDark, setMode } = useTheme(); useEffect(() => { if (!user) navigate('/login'); @@ -84,17 +93,21 @@ export default function MainLayout({ onLogout }: { onLogout?: () => void }) { }); }; + const siderTheme = isDark ? 'dark' : 'light'; + const siderTextColor = isDark ? '#fff' : undefined; + return ( - +

{collapsed ? '鱼' : '斗鱼登录后台'} @@ -104,11 +117,11 @@ export default function MainLayout({ onLogout }: { onLogout?: () => void }) { size="small" icon={collapsed ? : } onClick={() => setCollapsed(!collapsed)} - style={{ color: '#fff', flexShrink: 0 }} + style={{ color: siderTextColor, flexShrink: 0 }} />
void }) { style={{ flex: 1, overflow: 'auto', marginTop: 8 }} />
- + } size="small" /> {!collapsed && ( <> - {user.username} - + {user.username} + ({ROLE_LABELS[user.role] || user.role}) )} {collapsed ? ( - + + ({ key: o.key, label: o.label, icon: o.icon, onClick: () => setMode(o.key) })) }} + trigger={['click']} + > + + + + )}
- + diff --git a/web/frontend/src/pages/AssignmentsPage.tsx b/web/frontend/src/pages/AssignmentsPage.tsx index 2e7f672..2c9ee32 100644 --- a/web/frontend/src/pages/AssignmentsPage.tsx +++ b/web/frontend/src/pages/AssignmentsPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState, useMemo } from 'react'; import { Card, Table, Button, Select, Input, Tag, Row, Col, Statistic, - message, Space, Tabs, Typography, Badge, + message, Space, Tabs, Typography, Badge, theme, } from 'antd'; import { UserOutlined, CheckCircleOutlined, TeamOutlined, @@ -28,6 +28,7 @@ interface AccountItem { } export default function AssignmentsPage() { + const { token } = theme.useToken(); const [accounts, setAccounts] = useState([]); const [supportUsers, setSupportUsers] = useState([]); const [selectedUser, setSelectedUser] = useState(null); @@ -219,12 +220,12 @@ export default function AssignmentsPage() { - } /> + } /> - } /> + } /> @@ -258,22 +259,22 @@ export default function AssignmentsPage() { padding: '10px 14px', borderRadius: 6, cursor: 'pointer', - border: `1px solid ${isSelected ? '#1677ff' : '#f0f0f0'}`, - background: isSelected ? '#e6f4ff' : '#fff', + border: `1px solid ${isSelected ? token.colorPrimary : token.colorBorderSecondary}`, + background: isSelected ? token.colorPrimaryBg : token.colorBgContainer, transition: 'all 0.2s', }} onMouseEnter={(e) => { - if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = '#1677ff'; + if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = token.colorPrimary; }} onMouseLeave={(e) => { - if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = '#f0f0f0'; + if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = token.colorBorderSecondary; }} > - + {user.username} - + ); })} @@ -295,7 +296,7 @@ export default function AssignmentsPage() { {selectedUser ? ( <> 已选中客服: - + {selectedUser.username}(已分配 {selectedUser.assigned_count} 个) @@ -308,7 +309,7 @@ export default function AssignmentsPage() { bodyStyle={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, padding: 0 }} > {/* 筛选栏 */} -
+
([]); const [loading, setLoading] = useState(false); const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -184,7 +185,7 @@ export default function CookiePage() { @@ -193,7 +194,7 @@ export default function CookiePage() { diff --git a/web/frontend/src/pages/DashboardPage.tsx b/web/frontend/src/pages/DashboardPage.tsx index 10818c0..88f6a8a 100644 --- a/web/frontend/src/pages/DashboardPage.tsx +++ b/web/frontend/src/pages/DashboardPage.tsx @@ -1,8 +1,9 @@ -import { Card, Col, Row, Statistic } from 'antd'; +import { Card, Col, Row, Statistic, theme } from 'antd'; import { useEffect, useState } from 'react'; import { accountApi, loginApi } from '../api/modules'; export default function DashboardPage() { + const { token } = theme.useToken(); const [stats, setStats] = useState({ accounts: 0, tasks: 0, success: 0, failed: 0 }); useEffect(() => { @@ -34,12 +35,12 @@ export default function DashboardPage() { - + - + diff --git a/web/frontend/src/pages/LoginPage.tsx b/web/frontend/src/pages/LoginPage.tsx index c19668a..c4245c4 100644 --- a/web/frontend/src/pages/LoginPage.tsx +++ b/web/frontend/src/pages/LoginPage.tsx @@ -4,12 +4,14 @@ import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import { authApi } from '../api/modules'; import { setAuth, type AuthUser } from '../store/auth'; +import { useTheme } from '../store/theme'; const { Title } = Typography; export default function LoginPage({ onLogin }: { onLogin?: () => void }) { const [loading, setLoading] = useState(false); const navigate = useNavigate(); + const { isDark } = useTheme(); const onFinish = async (values: { username: string; password: string }) => { setLoading(true); @@ -38,9 +40,11 @@ export default function LoginPage({ onLogin }: { onLogin?: () => void }) { display: 'flex', justifyContent: 'center', alignItems: 'center', - background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + background: isDark + ? 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)' + : 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', }}> - + 斗鱼批量登录后台 @@ -57,7 +61,7 @@ export default function LoginPage({ onLogin }: { onLogin?: () => void }) { -
+
默认管理员: admin / admin123
diff --git a/web/frontend/src/pages/LoginTasksPage.tsx b/web/frontend/src/pages/LoginTasksPage.tsx index 3fd46ac..bf3ef18 100644 --- a/web/frontend/src/pages/LoginTasksPage.tsx +++ b/web/frontend/src/pages/LoginTasksPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState, useRef, useMemo, useCallback } from 'react'; import { - Table, Button, Select, message, Tag, Space, Spin, InputNumber, Tooltip, Popconfirm, + Table, Button, Select, message, Tag, Space, Spin, InputNumber, Tooltip, Popconfirm, theme, } from 'antd'; import { PlayCircleOutlined, StopOutlined, FilterOutlined, ThunderboltOutlined, ReloadOutlined, DownOutlined, UpOutlined, DeleteOutlined } from '@ant-design/icons'; import { accountApi, loginApi } from '../api/modules'; @@ -39,6 +39,8 @@ export default function LoginTasksPage() { const logEndRef = useRef(null); const user = getUser(); + const { token } = theme.useToken(); + const canBatch = hasPerm(user, 'login:batch'); // 从账号中提取所有标签 @@ -259,7 +261,7 @@ export default function LoginTasksPage() { return (
{/* 标题 + 筛选栏 */} -
+

登录任务

{canBatch && (
@@ -314,7 +316,7 @@ export default function LoginTasksPage() { }} dropdownRender={(menu) => ( <> -
+
@@ -327,13 +329,13 @@ export default function LoginTasksPage() { )} /> {selectedTags.length > 0 && ( - + 标签选中 {accounts.filter((a) => selectedTags.includes((a.tag || '').trim())).length} 个 )} - + {/* 概览 */} -
+
{tasks.length} 个任务 - 成功 {successCount} - 失败 {failedCount} + 成功 {successCount} + 失败 {failedCount} {batchId && 批次: {batchId}}
{selectedRowKeys.length > 0 && ( @@ -410,14 +412,14 @@ export default function LoginTasksPage() {
{/* 实时日志 - 底部可折叠 */} -
+
setLogVisible((v) => !v)} > 实时日志 {logVisible ? : } - {logs.length > 0 && {logs.length} 条} + {logs.length > 0 && {logs.length} 条} {wsConnected && 连接中}
{logVisible && ( @@ -428,7 +430,7 @@ export default function LoginTasksPage() { fontFamily: 'monospace', fontSize: 12, padding: 4, - backgroundColor: '#fafafa', + backgroundColor: token.colorBgLayout, borderRadius: 4, }} > @@ -440,10 +442,10 @@ export default function LoginTasksPage() { key={i} style={{ color: - log.level === 'error' ? '#ff4d4f' : - log.level === 'success' ? '#52c41a' : - log.level === 'warning' ? '#fa8c16' : - 'rgba(0,0,0,0.65)', + log.level === 'error' ? token.colorError : + log.level === 'success' ? token.colorSuccess : + log.level === 'warning' ? token.colorWarning : + token.colorText, }} > {log.message} diff --git a/web/frontend/src/pages/ProxyPage.tsx b/web/frontend/src/pages/ProxyPage.tsx index c7856e6..ca96ab5 100644 --- a/web/frontend/src/pages/ProxyPage.tsx +++ b/web/frontend/src/pages/ProxyPage.tsx @@ -1,10 +1,11 @@ import { useEffect, useState, useRef } from 'react'; -import { Form, Input, Switch, Button, Card, message, Row, Col } from 'antd'; +import { Form, Input, Switch, Button, Card, message, Row, Col, theme } from 'antd'; import { proxyApi } from '../api/modules'; const WS_BASE = `ws://${window.location.hostname}:8000`; export default function ProxyPage() { + const { token } = theme.useToken(); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [testing, setTesting] = useState(false); @@ -100,10 +101,10 @@ export default function ProxyPage() { const logColors: Record = { - error: '#ff4d4f', - success: '#52c41a', - warning: '#faad14', - info: '#333', + error: token.colorError, + success: token.colorSuccess, + warning: token.colorWarning, + info: token.colorText, }; return ( @@ -171,10 +172,10 @@ export default function ProxyPage() { styles={{ body: { height: '100%', overflow: 'auto', fontFamily: 'monospace', fontSize: 12, padding: '8px 16px' } }} > {logs.length === 0 ? ( - 点击"测试代理"或"测试白名单"查看日志 + 点击"测试代理"或"测试白名单"查看日志 ) : ( logs.map((log, i) => ( -
+
{log.message}
)) diff --git a/web/frontend/src/store/theme.tsx b/web/frontend/src/store/theme.tsx new file mode 100644 index 0000000..7e1271e --- /dev/null +++ b/web/frontend/src/store/theme.tsx @@ -0,0 +1,65 @@ +import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'; + +export type ThemeMode = 'light' | 'dark' | 'system'; + +const STORAGE_KEY = 'theme_mode'; +const DEFAULT_MODE: ThemeMode = 'system'; + +interface ThemeContextValue { + mode: ThemeMode; + isDark: boolean; + setMode: (mode: ThemeMode) => void; + toggle: () => void; +} + +const ThemeContext = createContext({ + mode: DEFAULT_MODE, + isDark: false, + setMode: () => {}, + toggle: () => {}, +}); + +export function ThemeProvider({ children }: { children: ReactNode }) { + const [mode, setModeState] = useState(() => { + const saved = localStorage.getItem(STORAGE_KEY); + return (saved as ThemeMode) || DEFAULT_MODE; + }); + + // 监听系统主题变化 + const [systemIsDark, setSystemIsDark] = useState(() => + window.matchMedia('(prefers-color-scheme: dark)').matches + ); + + useEffect(() => { + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + const handler = (e: MediaQueryListEvent) => setSystemIsDark(e.matches); + mql.addEventListener('change', handler); + return () => mql.removeEventListener('change', handler); + }, []); + + const isDark = mode === 'dark' || (mode === 'system' && systemIsDark); + + const setMode = useCallback((newMode: ThemeMode) => { + setModeState(newMode); + localStorage.setItem(STORAGE_KEY, newMode); + }, []); + + const toggle = useCallback(() => { + setMode(isDark ? 'light' : 'dark'); + }, [isDark, setMode]); + + // 同步到 HTML root,方便 CSS 使用 + useEffect(() => { + document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light'); + }, [isDark]); + + return ( + + {children} + + ); +} + +export function useTheme() { + return useContext(ThemeContext); +}