o1ICaa@*cOE{^)ig?$`V5_bL}h)YJePs^@=*n);r-8Y-0y zP~}}+ecyq-d(<`l(W|Lj0X4qb^ELQ;*rmN%u{ZM`vp;AX{cu63WBl^{kM|+ri@OrQ zK@By4I#2@$a0P7qTy;qUvOn+lgSdUN(nK^rus^hSl+`e5Mu>HE2QLqPJFP5m24_AA zweXwH7wg6|XPl0ryI5&DAK1oKq_CFlpSD6ut5O3#O?+-u-m~!e_obehwGozk_Vmbu z54;OJEn$=CdzUAfrZ3;L8RXGmj!zH-{r_GoP4)SN^!;$%XYuyfIa<_f7~Hb z?VqGu^;fp8o2|D9v!Tq#$dCW5@O3H@QT(&wkr$)X1|u{%-U;TH&QVe;4u4hHu!#Rk z^x_KQ!6l6t9H`p!-#OWbb^%c~M;G95rVxWK@#Aav2sc|^(DHwpp1CgedM+sPzW0Lq zRD=jahV?lIj5Ze=9Lo4c+-yE0e0N7LRkGey+5di<{jPB3f&V&>?s;>@q+${0oxA63 zNiDCzR}5>>GPsYH>8?zFaQ;S|`8Vv4N|WyU)BTdqaOZ5ovOXpx8|2OMbW|p8`-Aao zKKMr^pEYKR(0-vbCWk5qI?a$yW{)X<+jfLPea`uHA%j=UW-D!@8q8>RX4j7KU#O0A z6{m)AGqY(d3$E^^H}y=fSHp(@Ez>tXYHT{E0Q=IZiP5fsa*#hg8-1^2?C5C)%oEh# zDu(dggO>~MN-_5f@#Nk;P)RSP{jV^|;f}<-@wMl5sc$0UR-MT44?t(a&rCFo7BWnt z3g1(U>s#BMKfan0Bazr+pu(Cz)lPuEY-HSKo|#F&iHElyH89i!e{-ycHPiXDCmFqo z@FM}CcDttAt-I9?duB7&5&JD=5XZ$Us(6R9oJCW*A9ogQdUpZ3oh}}Z_A>zw*B-~#r(urw@cE?lh z#~Lf2Z;zC01Kn^t6YFVflD=yDT(hvjTLQ+;nq#*ad!b~feP(;=H{vc}Xgv-YMZ{;* z?4hpijgP{W``ubQgz1#o29$dPqljGiR#J3Dtkp?mVjO734?XJ_bss5uQY|Jt!$jq! zzqXEhZ35>Nip #BY?$VV!9oLA1gcE^h?vrJQ*Ry4=MSQUa2eR$B d7q ze5y@Uy_#UXKyMnm1>)W~w)X5(>CrT~65MVt0a;v_Tk#8XO xlUK9ob92 zmG6N%&QwmCkY;2XKDByDE6%pt5*C6_i)JJdvl#T09hiltrmOkq5dy3jWBSzdEJbp$ zBo9sblr#z9=U*|5z$dvqCu-XURVC?DVbL|njlyZJnk}MBexFsD&3thFTI^yzBYH={ z3wL@?gnnJ!8?nN>{V^YxTvx0CUB{LO5d2qe`L0vwJ~!8Q=!>r2ls#MC*~*k37Een| zzZ1FW&%#IN91f8`$SzcZ*z3wCpG-6s<>yCnRF$d!CsQHZN&nPz5cU-=B-FBs8YMft zeLcB`*M8mb?oL+vu}r(Nbk7yvcO3pSFXEw G{5ESBJ9XW9>SSMy#JI0peB# z9dtv33CUC>&2^aJT|;qQ&z+{fBs?g vl^@kruRM5Vq#6oF&pYM~Y2wF@92P2i*%`qj ~LUv z(^*j-h?N8k*faFLM2{Jxl+iZRG>uTk(H(040^kldIePW Ww#;N6OH1h#8 zZ7MPxL1kVSyLX~UGsLWNhHW7wfrdm{neh|41z?Bw{d-Pn44eurO6ed3INoLcin-Q% z5MH~96=gL2YJ#+FyhC#)*V|23<)XP9md_X3FsK;rtGJs}iP$ fv_r<)HQi=F}68HP3 zGCmWuQ&EO!W0ZVW6Y3T3CQ?WuVoDy0z0c87d@3i%x`*odrC$-ycs$QBQ@=Lzi@WTy znO(r`QQ^((C$RhoOYo?rSI<$?EX->0B+7PrA;POA+uR)5#cwYnJ0K<&2XQa%N>~RN zq{h)`5-nvp$H3s(U*_WLnuXf$-cSnsb)3PItG*c5e8+kD(KfpGw`bX9lWi8(0x-%- z{1OPRZa=gcb6Vv8z^%I{guSuSn4BDs^J?z`>MZbR&4V&2C;RpvLcOHwqN^c}N3VwU zS&k2NDw67L1PyB?%Pe6h&UX4ubse|hZAhp%8Dw%b34&VHtLDERsh2IcVgo+b3}u8} zXy-3q&G0-kU}vu= CEyjzR0vCCK6?gHH&-zX< zvnyP1w|PE%8mg?2*aTs1(jwZhDA^w{g5LK1)_VFcA*C>e9M?!vgp1&vrHzHzj5#fX z*EyJ`qN;5Ctx};!!5y-_q&RtPju+9$I7y3?6cV?cXje)_6rxw6Io-<0j17U86Y{Yb zR1%R+u}t4E;hIarUX(Z4NPC*#Nhj;IB?7YTY~j?#OjblLr3ci~cS3NaCXK%6Vm5Ph z-zk`%5Vs5!$kW0?5Nn~XVl5WTy(!v-kRWo`9!JnfQQ1@@vl7@B?d;@KOcLrOn>h|g z@q;SrXhtOgW{N2^nu+VuT95?UhJ0LlUU?ZI&5_541SgC{BmwhM!IQ0_^&pexW$tK+ zfko}8RFx7JpMk>
&hMvBLN!Fe2mKSD}2^#>?eEkncLej6vpz>V6fvUalV z%4Ul8MH;fQ3&dckG7f1>DB1 &N&j*q1R&S z0gU~0_R$%|mB9Y0m Qgs3_CaNcm &AFd%r&Uub{prw*1uud3j-iXa*{ zA!Lk7V$g`$R8xv&(e`VH(+RKpF|)dhF+r4Jd4~b_BErRb>#!;)3_W3o&MKohxI>y3 z4NsixLkg4EmNUa&o-ID^*WGj6e{nEUJTWOnH{~AZ%x@378tfdmW3)3Cbndnhs@gx! zaJ=AdzF-aqQxQ>Ziy0iK+LT@wHoFVz$_r)7=e5isrZ_8;xVYz5VI4#~nPX035_5}| z)6hq0kIUWb`s1H3jgD*`-=1Y%TX+*QRp41-@=X9}3NnU$CDZVz{Ja6(v>KF=F@H{J zB4#!;DRu zUhs`nn%MSyc@zSeSp`+SWFAk|n9w=5(F)w@DT%W=SYZozB(BR??|J0x)hs z2+;!8Zu(e!Tu$oX+B %6WpYc>c8Zm=OGQB_6Ea#nf$NfKy78$|ER+c{Wxm>@Qj?P-zSsw5+hn-v?vrOm zyVuvmjZoZyC>$zE!l>lO!(;uRt2tF&5s1cU`wTK`WFLi)8|w0f9X6;_G|NeQ=&93b z)jlhG>L%CsITvNO>h+`X=Of3r=DBr`l<(LfvkYo+LkzU%ugQw=3rzLX=>B-q&yBHm z 9*ZNszk^N?hyeO0n!ph6&$R3!xE>tuhhr(Pmgq6Bj#{dpkcbH*?3uSy~%A zYQ_!GhKewze~MjNicT?}p#^k FzF6((hA_+q3r@}!wO`&{;6HFwK9us1?K$~RTdW{ z*&E39I5gz2q^yuupTpMbOAK#PTp1tY*JQ^VttKmJs9^?^NX3^_0sHKdjbbv+!$>l_ zX25~Ks!JL^YB)7C5_iy%9I|GpdoVV3qZhOba4`s*?%V}Dam`FD^H|7Hl`P7BJI&J6 zdR5<0FK2!XuG%tF;<{4ATNX-Or(cV(PX*F3oZGGy-Y%FW%Jb=AA9}ZVOMx8R9h`C( zFm8Tn&gZA#t+Tkf?HU;2L4r?oq`2wma@m&S7S2FVwiU|l #cWz;k@YaLD8$oSPrad(}J97=I;T=uH{= zp{xqqP~{%$Wm_R~YZH5Vl~#6tsg4>TA~7Qj29s atAi;5{bdFVp^BBAp5zK) zBgHnd366uIlGmptWsKab9
B@V2&}| z8BI-O5b=1aL`jDj5gEw&RzZ(4B62%)7qAw7V~v-exSarxiyFxlX$!SmGllwE1*w=Y zR`k}JQRKMXkeo97PQ&cpd{#7x+7OXygjd~eWraCKG~3uCgJ2tINFj+ycmM`AijSM_ z0@_X=5{qr#z^}*f{csD89^F}xrAU5JDkdg6D!VQ`89xVf!~&O)H@Yf+eqCu;#~Al& z)+=4{<-a;^Oo&l#U|Io}hXlMtrcDUToNUe4cK35@bxW_6;F9c*yjijgW{pe7IGlqb zG$}P<2FUX`aj>kX;~taf6e~l>a!`eZ%uH^ZRC{V%M6{lQ#c%EcwuZn8Dc$?t&qvM@ t>-F;d0$E08g+x5fEPL$F|L@7(9Pzx&*C?m73K=ic9Q?w_82`@epn zjNQ9W 4q{7iceVpPGi@1(?^h z+ms&lAEK8ujn098zWV3|Xa7m^_ZE&Zv3LIbt725L>qbXO381X9+x?#??@?0uX79dT zB}8>MhO+YBeS7zPv4H#&L{(+aZj1}CYu^CXZa;d_^Yhi{iqWOLhDPUp`Ri?n`py90 zu*$AeRTWi$17P`iB}~O`9~J;Okb&=KsE5E(9Wv|ZAJEM>BDL0LR7ac0JO#Pc-o)^l zJWV&BM)W3G2q?^qgKIvI`a93`XWYOdOcq9R7n;vCmwcKZKj7J`6 -Nnbd2-Qow_6GdKeHLNZvW&U7>X8@x;R^=m1q-egwgzjtgDtxLQC|8wxzg5o z`bz-M3Pj8CEcA`QLz@4c@n-lfbY?~~8gFx*;v5B*Q%U4vIc64FTKEGfZv6NU$CTh_ zAH!54v3@;zhBn_NZeA?zOQDwq;o@AEsV3BfoU9)YhI=uyqv}g)vidnQyo08_#Ia2s ztcffby&jitkoHp0$e8SrhI936n$FG3tTPsptn{y H1Rb=_fX%5X! zG4BC(<&g;^_TLt{^MSx#__ gUFz>A?L(9RJm8#(6 z&z#QEl{Km6#ve<1FO%#RnEKWILyaEBLlfLA0 n51C;aKB6!#&f2Z3+fA zl%ZCdaLD&<1vy~{0Ox~Bxv<9=os(CyF3|^5kY%;AdD*dxp~oFAyNs--ZxP5??A0xM zg~G)9K4|pv_SvNB;Ib~s!P1oJ=88>+6Qfk@itTxj1&`Ch*QFYeM-G8DRmjNeVNJ(m zfndX7xVszgW~BSMxrdXk0+ybqYP-<~iRQh 8R*I<}R=jczL;$7?zozC;@|7}yV>4+r zRq&=K;+DyerN@*N--^~CB1`9rAiO&xkcY0AA;&=TSPh&`m@OowW_C8N!7O2M2k@tR ze{dgWY%N#apWIm*C2w3Tq1r@8>WIPMUYi%U9f*BHE|ZNcs{Mh@XzbhRo095zt)}yC z^{1;7bs85p2hjMMi(>-`(^b+!e9pb1{WV)ZtUlI6P@HL(>O!?a^VD UhbS4D4dT{3-rA;3HfpwOXVT2h{&tFNT>(m7rO;{ z)n_hqO{H+?3-2hm<#|iG67J%>>bKQ3`McZqK5HmPe0Tof=dX#VT8b&=y{pa`;_w5Z z3gGO0cg20GkPYu3RCUI?uYllQVuwF3eRH=c_bzyhHOB&eG%E1;JFwfN+T+WM)YIx5 z6{u=G8D^T)a4OqG|1eMY$*SfX>$&ML50m&WX4}X9izh_qv9ayI2bV%CH-g{n(igV; z@$>M)&K1)Q^2il*27h^W!vHh)6~O~BBhyb#0uMOOXops&wKp-r&u5#ym{JTd=%9a0 zcX0=BFe7WVlvOu*z{zXrV(8EO^n68pdO)Znzp-d{0BdH&8-(ou?mD=1*T{~29XYat z5JSs nYoEc zVLL&*C pLG@m(`~ep70J@8kKF5mfpw=0>D>#E(Ht!Djp*+p!Y@3vh+Iw)zkX|LP?Dk$XD< zmt14+Qx}L;8=?}&!-*)XhbVpoh2}PPruw7OpSKcCdSwTfOuH!iOiN9%5r#hsEXNCn z<_1wn;{+pk9DkGAMG(2~4ft( gfEIww+$ga?ro4H*6V9`&8=<1eUtZV4e zTo7PzQEZHEKM{?OJ?v}-w6Vf%M8^Hw=`29$seu63SIiD%AWoA7wg^*d9)WB%m@IQ% zQ2~N ;$#TIw%6{+d@}SP@zy%v>C;Q{fU?v?sp6$O8l2ml(c!$&G2cJ3= zj&-UsHk|o@jwG(mHl!p(zU9u*d+**H2?ARO28apEgj^D1h+<_0_NE=|@`g7Wb2l~4 z_~EMf+}QBK1Cvn4>UF;a2ybCla!6wtGXu-Dmij%wVH0WhP+_#S&@kaM<`tYaH9ZTL ztO0&gCS $$YVj5AtdwAe}}!PIk;iReKc%rrLm zB=i^sbXMl+U5xinMz5ipQ(|e?kUots<)5?!LwKN(;Uv2TnZ(Fm4yPAOyLxmtr17Dq zSR5oF7+!ss*7G =_oki!n6)Jb2G^kgvKQ-|1pG1?T1G M1IwQ^SOT2&54czuo?#1)iX2VBZ2{wa@ZT_$n0!7x|hk2h _U!otLFKGYVc0yJ|V zD~T+CyXo+L=R_|3yf{y+9$Y;WC;-nl<}}B~lx9vbQe~s0^)%gO=r3j0 g vCE2Zg@y3+9o98>Asv3{43!3&Q zE3D6aJ@;^MrGM5QYtr`@m!k2I5)hpIzHx27iGvb&@nbR> no{t8)TV#q6-g2!#zPxP;pfX zCHZM4C@zd>T|PcZ(K((ug}o`fxipbG*OPeWb?phwv)CVf8!_kDX$he4YOtd}Eu0?y zKqz^tht6NO!!5` wsl?M;IpnpiXcK!Qs-eQgpHmYEPlq=rPb zJ;dT}PLTpCC}ZIXXUF$0x{ma2p_uc^nRDYrRBD$ZB9nZIQR*0371 62E~^oZDs z0d=QOo(PzZ(&_2K*9<-#8fP54F5S}e#9nS`d*51N5E9IsLVa+Vzq!;IC&5~gT>0JW zFOG9RLTp|AB+(Gv4lRM0ixzB@kjpm2s?f{kMGW_&_>yaW)pk>f->3(TZxc_Erbso? zt|7V9iccU*z&b` JX&hH&DWSrCKT$>yoZbSKMcM;t#d{>9FKL-_!#AV z1LibDvc!C<1J-<;r8^{6b=y&1wz_n6pe8 MXUhzCi5RV`FjLK zLn$X7;C0Ydu1Vac5@cLF7Ty^R1_D7KU^_-CRQxbpSYXmy?dE@_BC4RagB5WPZ$G>d z$@hYTRnhbkDj^TglE&SeRsp&f;D2HFMh>vN(*|+ANm9umjXO^dA50!yA)gE@y4u(( zko|a*UFS1!??wS*Q2wk;NGHw<3&dXT%dO6od`E!=>N+2SMOc{*h+vJLK%m#kd=(EP zej3i>tEys}>DG;U4 {+3P@^$Mrw71d`u-3M$ zg0w9*)>qZhA6FGbCz1(xGHEPvFf7~kM6&ORJau75bHet >wMOcxkcALow$LL>5l(wI={$wPMd~3 zd*pso0C9H=q?=>xLUHNx@U3UUi1id^Ml~yFXmumGUdD&3yFoa7IJj!Jcs)M03HSWc zz+PP|;MuebwUsaxm=ac_&|#*PE0PzaPalqsUhCFSY}a9(QyiS~lee+5OHYDC17!mK z=LydqZAfrAM F6*We|7MZLbc^t$6h5;9FoR{S z?f}+dqcRLldE~=dS;@9WibMPFMLk%`)~hQ&=o#$*OdZOxf|^q`vJwZ%8JBg}_zZly z!314mG7H5XG3c8cR3D7#D3``>IZV6`Sl+kh@E#FzJ+8X>k7FC#{^7i^P0;7Zb4_k* zyrlb!waJPV=F0q<4K_9-Y2d;yI-rkzkQq*JoD-#vay)L1Sd(UH^+nfR*K8a4oq*Q< zZO_#3Hnwwp+ wQ(K0@6*G)2idW U z=`$1**k+|j&@4o913YTdTfDR)$LJ2zH;J+%SMygR<=$b;Q&d5H7-67zwklr!$4^$4 zRUN pjgj^vRB*v2{Gvr}^1q6ixugYJ}!w C^sKZQa{MH{wmdibl3q zXI!VQRXAzAPaUh~!N7VrQ-#NpJ(8REO1P{*{Hm^V_vxb}du2n^D35ed6p@ze<%nqz zb@L5|u{fVm$$L7{gr)As^5Q#zTrn1$Zj*hEH!U*5#@^S(m?@Ye($4mz5-O?~KV@fk zqZL8Uj0vL;TX<@k^#pKLtD(Hu0Xx79zUi5UXw+@4q!J=XF&PmxSrZ1+DbG$7`3IAt z@_p+xX7I)2NiR++`NFL)-;aOfvA@bS?7q|Sf~ZMI4;1do;fQ8YG_YYF9l5~i>{<;C z+b$25$NxLDIX7WD4jvOelGC3VmWi}i)d4 &it9sK4L6P-Cr zn#nXaB@@X=n;1g>GWZP=O<;o{2u)+8Q8L}eV+Y{=`Y2og>4V2da=pY@sB;(h#JUBt z%g)NOx~gRe)Zi$4Kw>?R+dPNH&z*pb%hdxOvfim>aBTxXz1B5COv2)GmC9Jl?SWE3 zLM`(qUk#=X1FEVn4u-EaO@s!&uZv {@io4!tG4gDqg#p5B z6oJ6VV7CmaO;7OiEXHB6vK>I@JN>fyxS6?I3uCAWq!SETyIb0#j0tqB?8jZ_JsSJy zC0|+|Jv2E_+O$h0vwN^V9@|5DObZm4c6X7{{H3`Z%ap*nkEgbbO1JF7M@PGUfVr90 z@kaDL_LimvK9Yxaagr=M`$Vw3VuZIw5yB=-_%Sdi5M*a0bm;X~Jp9zD;!G}5 zHgb;@36EJYRX^v9?B`Sp8M|vF^mT!~UNY zL0W?w7B<2Viz6sv1IE45tv_d^KYOuOF4oI{zWgQL%hSuRIQDF%RxKoaQ~ qjW1YHcvYLL5Gq4a5-9(=e1tZ zE9k297_|%eZhS7LGWpkccpFQ*9l)rV13}F#^cM}+CoLC-0gk4A+I`~DSlPbcs%m?o zM%1w-t`)SnE;dYI(=aRC5G^IA&o_iqqeX7bpNJv%m->5W=0Yx&B$c-$RXb~F=-$lB zTVgQ`&y>v#-1Dy1HVB;>ZXlZA@_Z9djnTC8W>r0?CG)Bdic6~cf42 4&c_?I!bgtbXCbUYa)Rx&^P$gg)ViL)fKxC090&*X#f^3ErA_?EC!x6R$(izT2gH zxSouxEA(c@jimG2jnn_b`iq-od)d7$S;!eS@Qyw8>b@o&kJS>+4>iN5^rI?itCT9u z($z#T*vNF-q9<6*uiCO0Urb;oyYgI1tx4laGf=F0MTx()A_;SW7hk?g&?RsupIs z&psU7pPSC?$V3j?J?lGpl6JU1Ta4Y@6tS97fyXX(cL*o}q9c}~$sWf+E{BCsxBk%W zn 52n~yLuX=SL`*R{+OT-k)Olm*3zv@R8(ytA}Vggu1A-gzI-oK T^T(e2E&eM+*&j}AvZ`t2L+o*h7i{_)tjLtfX=YVdp-zr6@5 zdrA?wcKgUZWOwT*tHR3qGK;k)8gjTTXINM`S6qZ3^^LN5cSbZ~fk(}1^iy9t9Jv9m zcK<#olXkCdt@Tx5t)wApx>16&>syhu2nFPi(CGeQQ({AiXGP3}%i@AZs#iCobJ9Ss z(Dk|weO9}S{tSF*33UV#4AelKcWU%h3?==#%M^&+f9MycFs0yR&q4%Vt-s1$WKRHU k(I8U}$@JCSn><_HLIe11H;On+`Or_hS7b`%*iQfd0I#)mdjJ3c diff --git a/client/src/pages/os.tsx b/client/src/pages/os.tsx index fab6f5c..07c7deb 100644 --- a/client/src/pages/os.tsx +++ b/client/src/pages/os.tsx @@ -30,6 +30,7 @@ interface WindowState { zIndex: number; accentColor?: string; desktopId: number; + iframeUrl?: string; } interface Toast { @@ -250,6 +251,7 @@ export default function AeThexOS() { }, []); const [showLoginPrompt, setShowLoginPrompt] = useState(false); + const [isDesktopLocked, setIsDesktopLocked] = useState(true); useEffect(() => { const bootSequence = async () => { @@ -461,14 +463,18 @@ export default function AeThexOS() { }, [clearanceMode, addToast, playSound]); const openApp = useCallback((app: DesktopApp) => { + const appToOpen = (isDesktopLocked && app.id !== 'passport') + ? apps.find(a => a.id === 'passport') || app + : app; + playSound('open'); - const existingWindow = windows.find(w => w.id === app.id); + const existingWindow = windows.find(w => w.id === appToOpen.id); if (existingWindow) { setWindows(prev => prev.map(w => - w.id === app.id ? { ...w, minimized: false, zIndex: maxZIndex + 1, desktopId: currentDesktop } : w + w.id === appToOpen.id ? { ...w, minimized: false, zIndex: maxZIndex + 1, desktopId: currentDesktop } : w )); setMaxZIndex(prev => prev + 1); - setActiveWindowId(app.id); + setActiveWindowId(appToOpen.id); return; } @@ -476,14 +482,14 @@ export default function AeThexOS() { const offsetY = (windows.length % 5) * 40 + 50; const newWindow: WindowState = { - id: app.id, - title: app.title, - icon: app.icon, - component: app.component, + id: appToOpen.id, + title: appToOpen.title, + icon: appToOpen.icon, + component: appToOpen.component, x: offsetX, y: offsetY, - width: app.defaultWidth, - height: app.defaultHeight, + width: appToOpen.defaultWidth, + height: appToOpen.defaultHeight, minimized: false, maximized: false, zIndex: maxZIndex + 1, @@ -492,9 +498,9 @@ export default function AeThexOS() { setWindows(prev => [...prev, newWindow]); setMaxZIndex(prev => prev + 1); - setActiveWindowId(app.id); + setActiveWindowId(appToOpen.id); setShowStartMenu(false); - }, [windows, maxZIndex, playSound, currentDesktop]); + }, [windows, maxZIndex, playSound, currentDesktop, isDesktopLocked, apps]); const closeWindow = useCallback((id: string) => { playSound('close'); @@ -590,7 +596,7 @@ export default function AeThexOS() { const renderAppContent = (component: string) => { switch (component) { case 'terminal': return ; - case 'passport': return ; + case 'passport': return ; case 'files': return ; case 'network': return ; case 'metrics': return ; @@ -607,12 +613,13 @@ export default function AeThexOS() { case 'chat': return ; case 'music': return ; case 'pitch': return setLocation('/pitch')} />; - case 'networkneighborhood': return ; - case 'foundry': return ; - case 'devtools': return ; + case 'networkneighborhood': return ; + case 'foundry': return ; + case 'devtools': return ; case 'mission': return ; case 'intel': return ; - case 'drives': return ; + case 'drives': return ; + case 'iframe': return null; case 'settings': return { setShowLoginPrompt(false); setIsBooting(false); + setIsDesktopLocked(false); const randomTip = DAILY_TIPS[Math.floor(Math.random() * DAILY_TIPS.length)]; setDailyTip(randomTip); setTimeout(() => setShowDailyTip(true), 1000); @@ -678,6 +686,7 @@ export default function AeThexOS() { const handleLoginFromBoot = () => { setShowLoginPrompt(false); setIsBooting(false); + // Keep desktop locked until login succeeds const randomTip = DAILY_TIPS[Math.floor(Math.random() * DAILY_TIPS.length)]; setDailyTip(randomTip); setTimeout(() => { @@ -687,6 +696,31 @@ export default function AeThexOS() { }, 500); }; + const unlockDesktop = () => { + setIsDesktopLocked(false); + }; + + const openIframeWindow = (url: string, title: string) => { + const windowId = `iframe-${Date.now()}`; + setWindows(prev => [...prev, { + id: windowId, + title, + icon: , + component: 'iframe', + x: 100 + Math.random() * 100, + y: 100 + Math.random() * 100, + width: 900, + height: 600, + minimized: false, + maximized: false, + zIndex: maxZIndex + 1, + desktopId: currentDesktop, + iframeUrl: url + }]); + setMaxZIndex(prev => prev + 1); + setActiveWindowId(windowId); + }; + if (isBooting) { return ( @@ -807,6 +841,32 @@ export default function AeThexOS() { ))}+ {isDesktopLocked && windows.length === 0 && ( ++ + )} ++++++ Desktop Locked
+Sign in with your Passport to continue
+ +{windows.filter(w => !w.minimized && w.desktopId === currentDesktop).map((window) => ( @@ -883,6 +950,7 @@ export default function AeThexOS() { onClearNotification={(idx) => setNotifications(prev => prev.filter((_, i) => i !== idx))} onClearAllNotifications={() => setNotifications([])} desktopWindowCounts={[0, 1, 2, 3].map(d => windows.filter(w => w.desktopId === d).length)} + openIframeWindow={openIframeWindow} />setWindows(prev => prev.map(w => w.id === window.id ? { ...w, x, y } : w))} onResize={(width, height) => setWindows(prev => prev.map(w => w.id === window.id ? { ...w, width, height } : w))} onSnap={(x, y) => handleWindowSnap(window.id, x, y, window.width, window.height)} - content={renderAppContent(window.component)} + content={window.component === 'iframe' && window.iframeUrl ? ( + + ) : renderAppContent(window.component)} /> ))} @@ -1347,6 +1415,7 @@ interface TaskbarProps { onClearNotification: (index: number) => void; onClearAllNotifications: () => void; desktopWindowCounts: number[]; + openIframeWindow?: (url: string, title: string) => void; } function Skeleton({ className = "", animate = true }: { className?: string; animate?: boolean }) { @@ -1554,7 +1623,7 @@ function OnboardingTour({ step, onNext, onClose }: { step: number; onNext: () => ); } -function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isAuthenticated, notifications, showNotifications, onToggleStartMenu, onToggleNotifications, onWindowClick, onAppClick, onLogout, onNavigate, currentDesktop, onDesktopChange, clearanceTheme, onSwitchClearance, activeTrayPanel, onTrayPanelToggle, volume, onVolumeChange, isMuted, onMuteToggle, batteryInfo, onClearNotification, onClearAllNotifications, desktopWindowCounts }: TaskbarProps) { +function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isAuthenticated, notifications, showNotifications, onToggleStartMenu, onToggleNotifications, onWindowClick, onAppClick, onLogout, onNavigate, currentDesktop, onDesktopChange, clearanceTheme, onSwitchClearance, activeTrayPanel, onTrayPanelToggle, volume, onVolumeChange, isMuted, onMuteToggle, batteryInfo, onClearNotification, onClearAllNotifications, desktopWindowCounts, openIframeWindow }: TaskbarProps) { return ( <> @@ -2079,14 +2148,12 @@ function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isA .aethex namespace - openIframeWindow?.('https://aethex.studio', 'The Foundry')} className="block w-full text-center px-4 py-3 bg-yellow-500 hover:bg-yellow-400 text-black font-bold uppercase tracking-wider transition-colors text-sm" > Upgrade Now — $500 - + Hint: Check the terminal for promo codes@@ -2725,9 +2792,16 @@ function TerminalApp() { ); } -function PassportApp() { - const { user, isAuthenticated } = useAuth(); - const { data: profile, isLoading } = useQuery({ +function PassportApp({ onLoginSuccess, isDesktopLocked }: { onLoginSuccess?: () => void; isDesktopLocked?: boolean }) { + const { user, isAuthenticated, login, signup, logout } = useAuth(); + const [mode, setMode] = useState<'view' | 'login' | 'signup'>('view'); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [username, setUsername] = useState(''); + const [error, setError] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + + const { data: profile } = useQuery({ queryKey: ['os-user-profile'], queryFn: async () => { const res = await fetch('/api/metrics'); @@ -2736,6 +2810,143 @@ function PassportApp() { enabled: true, }); + useEffect(() => { + if (isAuthenticated && isDesktopLocked && onLoginSuccess) { + onLoginSuccess(); + } + }, [isAuthenticated, isDesktopLocked, onLoginSuccess]); + + useEffect(() => { + if (!isAuthenticated && isDesktopLocked) { + setMode('login'); + } + }, [isAuthenticated, isDesktopLocked]); + + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + setIsSubmitting(true); + try { + await login(email, password); + setMode('view'); + if (onLoginSuccess) onLoginSuccess(); + } catch (err: any) { + setError(err.message || 'Login failed'); + } finally { + setIsSubmitting(false); + } + }; + + const handleSignup = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + setIsSubmitting(true); + try { + await signup(email, password, username || undefined); + setMode('login'); + setError('Account created! Please sign in.'); + } catch (err: any) { + setError(err.message || 'Signup failed'); + } finally { + setIsSubmitting(false); + } + }; + + if (mode === 'login' || mode === 'signup') { + return ( +++ ); + } + return (++++ + + ++++ + {mode === 'login' ? 'Sign In' : 'Create Account'} +
+AeThex Passport
++ ++ + {isDesktopLocked && ( ++ ++ )} +- openIframeWindow?.('https://aethex.studio', 'The Foundry')} className="text-xs text-yellow-500 hover:text-yellow-400 transition-colors uppercase tracking-wider flex items-center gap-1" > Join@@ -2770,6 +2981,26 @@ function PassportApp() { )}++ {!isAuthenticated ? ( + + ) : ( + + )} ++Issued by Codex Certification Authority@@ -3811,7 +4042,7 @@ function ProfilesApp() { ); } -function NetworkNeighborhoodApp() { +function NetworkNeighborhoodApp({ openIframeWindow }: { openIframeWindow?: (url: string, title: string) => void }) { const { data: founders = [], isLoading } = useQuery({ queryKey: ['network-neighborhood'], queryFn: async () => { @@ -3880,14 +4111,12 @@ function NetworkNeighborhoodApp() { [{String(founders.length + idx + 1).padStart(3, '0')}] {slot.name}- + ))} @@ -3898,7 +4127,7 @@ function NetworkNeighborhoodApp() { ); } -function FoundryApp() { +function FoundryApp({ openIframeWindow }: { openIframeWindow?: (url: string, title: string) => void }) { const [viewMode, setViewMode] = useState<'info' | 'enroll'>('info'); const [promoCode, setPromoCode] = useState(''); const [promoApplied, setPromoApplied] = useState(false); @@ -4004,17 +4233,15 @@ function FoundryApp() { )} - openIframeWindow?.('https://aethex.studio', 'The Foundry')} className="block w-full px-6 py-3 bg-yellow-500 hover:bg-yellow-400 text-black text-center font-bold uppercase tracking-wider transition-colors" > Complete Enrollment - + - Redirects to aethex.studio for payment + Opens enrollment form
@@ -4023,7 +4250,7 @@ function FoundryApp() { ); } -function DevToolsApp() { +function DevToolsApp({ openIframeWindow }: { openIframeWindow?: (url: string, title: string) => void }) { const tools = [ { name: "Documentation", desc: "API reference & guides", url: "https://aethex.dev", icon:}, { name: "GitHub", desc: "Open source repositories", url: "https://github.com/aethex", icon: }, @@ -4038,12 +4265,10 @@ function DevToolsApp() { {tools.map((tool, idx) => ( - tool.url !== '#' && openIframeWindow?.(tool.url, tool.name)} + className="w-full flex items-center gap-4 p-4 border border-purple-500/20 bg-purple-500/5 hover:bg-purple-500/10 transition-colors rounded-lg text-left" >@@ -4200,7 +4425,7 @@ REVENUE MODEL ); } -function DrivesApp() { +function DrivesApp({ openIframeWindow }: { openIframeWindow?: (url: string, title: string) => void }) { const [selectedDrive, setSelectedDrive] = useState{tool.icon} @@ -4053,7 +4278,7 @@ function DevToolsApp() {{tool.desc}- + ))} (null); const drives = [ @@ -4277,14 +4502,12 @@ function DrivesApp() { Join The Foundry to reserve your namespace in the AeThex ecosystem.- openIframeWindow?.('https://aethex.studio', 'The Foundry')} className="inline-flex items-center gap-2 px-4 py-2 bg-yellow-500 hover:bg-yellow-400 text-black text-sm font-bold uppercase tracking-wider transition-colors" > Join The Foundry- +