From 2cde12db3f71b133ce71027dddefa121ccc7f98b Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 6 Mar 2026 14:14:04 +0100 Subject: [PATCH 01/20] Various changes to begin work on v1.5.0 - Added a show/hide button for objects - Added colors for objects - Now uses user theme for UI - Focusing a comm file will now focus its corresponding webview too - Added file names to the webview titles --- resources/icons/3d_light.svg | 1 + resources/icons/eye.svg | 1 + resources/icons/eye_off.svg | 1 + resources/image.png | Bin 0 -> 32633 bytes resources/visu_vtk/index.html | 79 ++-- resources/visu_vtk/js/Controller.js | 7 + .../visu_vtk/js/commands/VisibilityManager.js | 93 +++-- resources/visu_vtk/js/core/VtkApp.js | 45 ++- resources/visu_vtk/js/data/CreateGroups.js | 21 +- resources/visu_vtk/js/data/Group.js | 19 +- resources/visu_vtk/js/data/ObjLoader.js | 4 +- .../js/data/create/FaceActorCreator.js | 15 +- .../js/data/create/NodeActorCreator.js | 8 +- .../visu_vtk/js/settings/GlobalSettings.js | 68 +++- resources/visu_vtk/js/ui/UIManager.js | 92 +++-- resources/visu_vtk/styles.css | 44 ++- resources/visu_vtk/tailwind.css | 356 ++++++------------ src/VisuManager.ts | 19 + src/WebviewVisu.ts | 18 +- 19 files changed, 528 insertions(+), 363 deletions(-) create mode 100644 resources/icons/3d_light.svg create mode 100644 resources/icons/eye.svg create mode 100644 resources/icons/eye_off.svg create mode 100644 resources/image.png diff --git a/resources/icons/3d_light.svg b/resources/icons/3d_light.svg new file mode 100644 index 0000000..0712340 --- /dev/null +++ b/resources/icons/3d_light.svg @@ -0,0 +1 @@ + diff --git a/resources/icons/eye.svg b/resources/icons/eye.svg new file mode 100644 index 0000000..7f8ae5a --- /dev/null +++ b/resources/icons/eye.svg @@ -0,0 +1 @@ + diff --git a/resources/icons/eye_off.svg b/resources/icons/eye_off.svg new file mode 100644 index 0000000..90b2c3c --- /dev/null +++ b/resources/icons/eye_off.svg @@ -0,0 +1 @@ + diff --git a/resources/image.png b/resources/image.png new file mode 100644 index 0000000000000000000000000000000000000000..70d90681d3b4be2fa29554ce7972a1af43dd3534 GIT binary patch literal 32633 zcmeFZWmr}1yDvH^0g+TdQjl&C=@LY`Q&MS=?vhYIx}>GMyBi4!>F(~Dbi+Ik?|-ko z&RN%9>#V)c*YiQW#&FKb7-K%qegEnvP(e-{{VCy72n2#IDIux^fxuxwAn+S8b`~%l*oo5JvcwtD2 z3ahy29xS+Ot4zSUkEd7}JLnV1UI(BZ-nLlNY0iFc%umS9j`6f)V;>kVdb_7paxFWS znow_Trg3;%LYuMtoh*R%HCba(tI!jgt@em8cm&Us@NRz6L7pvL+|8z~dHbPe_3CD5 zowhF)Rl(Y-eDsIx@ARDXjF&@cL49`QzE|qTeemSIE-E-=A}E=X-YDcD)NrqTS$`o0 zV6~h6w@zxy(D=GgdT4br1RElPx9XN7OY9%8>RbEM1^Z!TE0mM8YjdA+`8zXGooGTJ zx~fEDlTh?s&YcnqdS6yyB$Db*-1jz{uNKXZwA~)YvzbtZpPKsP|0N^ z%AZJlu_N|(V%z|)SvNG<>6>$W1=p6|8n@loKfYOYaPj2eZn5pppoTiLl>gbdsFk?R zs?)g9;e5lNh4{U?hTCP$boxVF58F}|w9x8iJ9fps7h2v){AEEMe6e<1n++vJV)tQZ z#N0?*C%TZ%g~0XjiLv^xo~~$-T5GwfG--N2mL3-C8o$jeA;z@G9K@V!9d0&Yfo_!u+Ra|LTS2D?Fqy7F(FkmarVAaM;?N zxA#`#Tx|43#bdqyx{tnUKvC~O;XCF(6_pTKGIwYzNYwuJg@!j{3P(i1Fnh!0d1CXs zE&OhU#mry2jb8RNywS~CTec75sSR(SUu0kM=vC|T9bY}na>oUmT*52lDw?>RkrrAg z<;~A)KWN`0bzeL@^-lI-C{863`#b1UJ~~a8xD}NW+j-pFYUglir}T3bVtPN%s{4{v zaz-US?=@NkfdP@dkidt_7PSs$hr@GHT!yJJ^Gj{&pJ#XOl7u+Xs^Hlw4f?j?#kT$&!WZW8PCj zSFP|qYd0}blncRKElCV99*GQvlG4rHqfp&7HA7a2?Cixx%v8(xZ7b@Sih?(PjGrN< zKk~btdV#wuBWq8X<5M#_R5wQ?NomRD%TKvSYjMrz?LP1qI-0(pcsjDv-ZvbPm5!wf zHAj8&x{J_KR6n1kSqL^d7>b&{-NMmvfru{E_0MKU@z}3B+u2KR5`0F6>1Lo|g73iP z-e=>weQke4wm)S!g{l&{ax)iJW_a=0Sl)DKCNuGDR%0&Opz|t5<-`oqme8@sQ(>N< zOQh(=9|LhslM2OiL+g+u{Wzcwt^Ew1uiF7>jq}{s7PnR;8q7QUc%@oN=Ynz5^r;d? zNom>j{>Y`?-rgrA zFt3kh7U#3XbGHmcv9e@r4>h{3`gfL`jEQM{`>t(L2HktF7`q!apF=M01jEPIy+o9w zN#!}-L7s&D>duqr+HTQ%{GYg)SG8;N$4ibzTVb%l{qVW+t;_m`3MoPKm*+cAz-x0E z7>a+@LI;q?xOQ}*GIxH2=d-)JQBkWsgMEl(D^_pgSnljM3siF-LXsHwL;w}WlcKaSaawPlKB{p2Hll;Q)bSD2&jYM#%d}Y4C*zBgr z%OArNF|=3!=SmU5C3v$nN4-7n1a^M%dS@fJ2~|RP8;bp;lK#QpeklmK3Z*lr4Hel- z807mWsF0Scor)6TuH&!5jEqIwu+2C`;@h?S8fnQOgVVm!=n1!3XCkT7i{_Xvh<3e8 zba7!TTwCK81YJ+Z*Lbmn?WIY2Ye6g!8#?F*7?;Us%QeV5n`O9~QWz;@sIU6?)d@kY z+GG}GSNU$PyhM|8?r`fV+y=3Pdu#gs{iz8vGKpBW(u!6sdh#ci=URL;3!K>M@|9Oa z2fvayb^MRN!tS1@Aj35K!$K?Jj$U2hf_*SCk<8PSBKubesjc+VrCGuC^IU-$@lqp> zcP&lHn1`V64qXKg*85!!_Y~A6(rhhgxPuW_`{0hBccRM)^0A9vvR4*J?=5JF?gT3ntTMeu~~|4e-vJ)}Va9 z5O52hAS!9S+ZA14Y>~>&(3$!@Jss=5dr&ZGQ8HzjgC!_~Rd{A^R^>lqw;y`#&Ri(xrg z?f%ht)1%@IJA}K=9_jJ@Ub$D5Umv_s1Zz|G{h41WJZ=2?E5Q6)pZ@EP?*aAaLouV6 z)RwCB?3o?AONNG723yPU@0h9BB^g818R0}0_ucRDnjN5fwcCExvOLY4eLRlt5!0Ib6j_ADMEPogs%l|y?SoPIEO1?{tadQy}i^N z*Qu4pV4Zwxx{ggIYMqD?DiX=ojHr!2>R&l`b2PyyohrU|8J08a{xj3iJCzfJ9m49- zg-7;5cqWh}nPIreBlT_fZ<)DutQ2m;yG;*6d zm~6wPdAUW;p`}!7hS}3d@?Pc2Rc8U=T8m~`Oi^7v zX`41VOOHzYy!|Qu9B9m?@rfYaD-b1yJ^C_ zR*7>gIndQ>R&0?J#y&9HQdG!iYlCoH4%3FMflESIybF4oG6BcRRhwmSIhC(iTg^;M ztixYcRRNc#6ypY}n3yv+hf^P+F2Nf~=O7L)uDCpu1AQhcH0e<07pnBQ^f4>p!r`8& zX`Ho)pKlvVV9+>F;!OH754M!eD%0WEwKbS*)7n`I&O1~-?9VUnBpL@oW4sq$A% zrJ9)p6JPEtJ*la7mhg}7iNv>pst!1bz4z4R%FV8Guc97#n|S1N66?4}r;ZR~P~ zjx?%v`9(|lK@X}9UZUX@ad(+a@79{$y4M!nIZ=V{9F@8)c4m3N`)%S(SNKZnXhvr~ zxD^TW;8w3s&cbr--JTr6iQ{VS0tVTMCK+7!Lp_gDq1?T#LrK~cH3!c(l0Jb0G?a1NoXAM_599 ze8J{%^4NqK0_W%o=|4+#i3|iTN4@gKrZG=8IXn|ia}F(r5kfU@**zzP#X>&yde?5U z>fcHI8RC`5oP2OQILysG@>*&w(VEfBEl<@}Q4bP`fgB%|pud|>M)B0T!Z7zD>|U6I z75)0E;%x0-d68>-S93(NdT7db>f<4_Z!F5XC3lzYzLeo%tvz3LN#Hs?W)%nUR=Q5> zt{7cRAxD-|M_8XRxB)C|w=fPNdHusPxI5<{A+#34jM`#*R~BuCtL>V4cfRiv($sHE zG=*AVOphrLa2aot&1`;O22UfA7ftvlYr+~T&Z;OmAKo+%8!h4CsWtImDPtUHACJ$TyBj>25|Oj9 zXnlYw=6lqpkDHB4*7g*VO>$yfVcyGdEeY$A5zp6)lrA7}?AD~u{e^Bbk+T#v`}yGt zAb-u`(pO}rbhlwkKFMhE(u%GzKfTY)$Nv<$O%m1jnL zsjJgxP*bQ@Nzi>+y7h3cVpN^dH$kXW??ypPTz%OoA$haqf4ICYmKi%Vwg3}I(h)eX zsjRA?<~e2#L}dd@Aq`aaZJppP-LHvwBsZT+xSvNQCcd9fCd$g5r{Lm3h7ir!jhoFU zq}&UQqS1I4{_b|18jUVh@B;-DJ|ZglgTyi%&hsig^?J?s{0v*K&IJ^z)y%){)zGj# z;MqFA2Hk93Y??=8@L&btRN{r^Bo8mf_34yP-0l|aaqyRq@aM25w#9L7%xnGft;=?F z3oXg6%jPGvGZis1DWrwbGT~s|w|lG#)`)hyZC~K!Eyk)NwFqOGBc}!{oagSu8?yC6 zZ%B4-PHydJDwK-Suq7f9QJz>8Sm>D*Cw_Im8nRQ~7(G}?q+e=rjk%hZNYZY$xjgGC z&S1giH_zy8tPzja?II+@>@gtmr6rQ0d`B9AERCwz5M%1ikM+D*U~XkIU8tAFm(>yp zsYh7@`Gk9(zd+grMN#a9J7CCt7^qm}z9W?He6hr$AlM==W#L6p^xpoToOE9$dYV7b zHmK?M2Z!-QNJI@qvCq)>z1tJY+>M{b%_~ALy3qYBIOzG4RHwBbuR!f%-tR@i$HOlt zLPz&{V#oo-Vt!G{6)Gr-vD`Cew+-ZCNCC4ljRxeRGh2qa2d7AE3fkO!<{g2QzO?So z&RsL%MNfy`Z}?#iLEd{T=0PG+mB~|>e%v%E0^W}$0q!rw_aE|4jZdaEIcPBJ;*}G6 zY4Ug0weJhLFDly?I(Mq6@A5nRf$N>zvCK)LZGk#&8=+bb8==lEorAwMO0`iGn>1BJ zmGKh(pse2|+{=(aOVPsRJQ23nxgg%&&l}@;7gJA7E*NTXvOj#>M%wHr{F`O_zzEwx zd-G;AMmFUaLL(=uS&|SrzT9q~2y>F*D7P2J{w(0i{Pj4mzTLH0!6mBQr@1dVZ@akN zv?8^=O7zsf51MJ!;h_wPmBr%GI33bIsn? z2h{Ni38EPI`2a>H@i+L4(Oh6XCqea|olh!gIp3MC#uQZDOHtH4Z7E=ohKi*vF$%pPp|C9lnxi`1FZ*sT&a}$i+^|p9&F&VMp2iKtmug~-FvYy5@7k*F%;r#w3GK1sdXHF0kE!E5prj0tm2(PGZ2xr^n+f%&ko&(m5_ z`5KL&vrP6*Z7TX|^LP2#iv)7t4y}Z#eciax>I97XB7iuuOOmrIpvHTB#YU+DR$n#mu9u z-(w$01T><*TXq{AOQ010R$8W?p=wIM%3frJener;Wk0QePX4DHr`TgcD) zTpKQlWfH?!^sUlcUqE$582vA-atx+grf2weCt|2Z6sJDE@p=kD@b{27{}p;BMtC`< zeCVM0vsF$I4$5Vzv{ zBSc_1C;BagsdBp0+u7Um)LEmYs}G*;9)<4=SIf5?L1?$OrQ~7QM!ft0|4(0cTN@fL znrsKi9~Vz>FX;uv{P~gcU_G2=gfB<3AUQpO=5{XMkvzv$XSYM_NLZC2c0fHZUH3OM zps>$412MXXyx(UKHYjet^Ds)(_r+(I%PKrKj)f-NV#|14RhQuC>^&v9;15e8yfv*x zRFcLE&!X#4u<^<)MjXDHbFSZ1e}3R{eoYg8kR`n4^ik8SXJCNpZuY}u$yJK1IbOw9 z=>+k7qhFT0t&8eKSNo_`ZE0Rl;oaq5XIAC>6ZA&30%@rbgTelCQE@-TVljk=#fGF$ zUJt)?yh>KrM@aGp2J%1V?;6~DWmx|xzb&13Yd#Z$XW6)g7LMHC-*01E+*Ut^4CIF# zr)E6j`R2&fO}W*{0ULms>`bB1{cCe{yiL682O-$z-Au=PNS%~Pt0#A~{mK^!2K&4P?+X;NpGtKv0kC)%-3G);1Dqfl0ct@|EuewZ2x9LPl^tY=DgLT-c1;-@V)yQPvg5~EJB-UQrQY5_YM@FbC0Se?Xm|f~jgpj;ON)aM zoe{kW`&CV7zd!7RchCCGx9;Ue38~f>DIA74kB;*)>8ANhOWoaDyh%No`F^4lwT&Sf2U1#uYuA?Xs)G8!1_zL zG(1=B9kA~6ar2|wsS+KRZ7&ng|EXS>egWx&@ z*X!}0U^}i6GI%~{LYLwb6aS9*c(Iyndevdu`VD&CzdXBfnRWI|DC&P^XIEVd15ZwW zFDG@T#*A*l{H_x zLB|GL=m-)CMC?J1id)tlLH3p{+^RU5E2pH{6l!rJ<6#Q}`^@Ncw;ocbezxM%D;+(M z5=0cKURG1yF;d@Du^YL*xo&eZ&8)l6{&Q!kcx`P6-vGMYU(F!AKil#P6oQwRz5JTa z+aEHGNeJHF8R!!61o~cmd|0emE$4L+X4c`CjrrpElEVs5R?9KlsBz2n(#JY~u8bpB zet%P}6L*99$pT7iNU{e{lFmYm>h(v>FE)1c@?w8HDk>{&>@PEPGda2I>kP8XbJP}$ z$IZu|a5=MVKAW)@Fy#a65DPiy23T^s6g8XlLi*x1si#5Iv>XD zdGA^eGu5{ix23xZDOor-|822!;-zw0JcJyDH#$=)bWT{Et~Eq{MtYWV*gw8w(1^nC z;a%J9DY^6;mJW8bgO}~g4sluXV_km#3mC>bkvkIRCnULgQ5Vm?dhmz-a?Db$_56CY z17Dz0ntSUWtQ3fd($;^?=ji`fLrgZK$$b$?)Hx|Ax4GGKpRKG%9zYztcF>Inm+~zx z#Tsi=69e>mrDT->lD#>&GplO))JhKwxE>v)iC zZ3qex8)!qTvlC=EtI+KU0cLe)`CqjcV|*%XwPjhB-MRq2+8y+{HedLG${<$E*`49d zleQWGmRh|savA7DCfNlIcHmjkyQ!^=c8wVt8E;!Ezj#=@FmGA9UA>NS+|$skaZj-e zD{-5vt9RGeGyC8sg|mMDNiKCd^b!2uFR{8@Pzx~mfhMI;sz}uIBDX+*UM>C0dBc1N z%ErUJ7Y5CnH_$zg<9Mx)cykHAanP{5zm>`x_WL45I2YJVMw9Q)v?!^!n%qhm%MysF zEY@zuqoTdMx)Ig!Q0xUtPo+1eF<3lilYhd&LOVLU*+M8@*V6K;U;{sOJCBv0zwom) zG;0d4tzSl#3c5>4vp~VD##e8_c=>d3dU`W;%+9IUyV>V?IU84us^6QlN?HuM-pe{S zDh21OlQy4@cyskZd-mO5i<}>Rj};aiUOp_V7Fx0QpKN{teJ3z9aJB6)v`F)TsWLaz zaK%fAnte@>t=9V8qRFz817eEqgpC~=e}=S72nFW_o=F%~@8q`mTx9R`7@^ML_!%l{ zx#7HgW>O|Y^=>uU)g5Xq?5$5g*=IXD(grj;HrfjaDk|?_5#4)kyU%D4SqfU;_$T_G2v)r#S^MBRs27xtxb@@uR z`G;lnL_}>{&!VspCD=DTJ$2!s#qYnFI6$=f)P3i*D=JcoDm67V^^A>|H_^j;JI1ym z-!oBABzL;oa`QImUq`pxm*}9szHn0cmTWe(WZpa2x2nWO{Ab*JTI|x@>*&kUHEur> zqolmF-Z^Yw^R{%+U?|Md(8O4w)mE#anN@;|{Aol?jIf;&JjO;6nvQ5(f^8}&Uxb`y zL!e~hU%6$&OpA&SfF$5L0+V%X;t$zN$G=`mlE1zPuC2#%2?5T?MoF+}IdV^I^(hK? zFsrWw_1CPI5SBNTgXN9y#O4McBDhXmSaHneW>Ue49HPO4x%yw$xtKJR+b)sX7V5oo z_}*>o{wcF8!r5;+WQwUds796}_}JJ;*{d7c-sk3$GcoyvgxrSXGRHJ|u(7jKT-_ae z-D`9%HOs0P(&9E33dF3~%gJ&6-U>G`*m@Tgt8)?x`Bn23gAZB!JA8O#QgqsU(==kz zthmB5+mmOv5kn>qeI*y7#e4V_pD$h>&WF9rEH~b0#aeM}Rly3$EY@0-H3AIK?e`?gb5dQVL3puNLp}oNW`0kCv)c9O=M}S9G_jeFP zKM3CV8tA^f+(ro#Rsud6CTYhgW zLkQn~k%oSQZV&Team+7LE~ zbpV2EFW%lmdLTuAELgUugH0Tp(n;D2sJzZq5~VzDY10UZpD!{zs`fH;W}J7oKlNX` zz4(@U33p@%W9z?K0Sn-WhUM}VLR-x8SpW5|rIY2<6R}2SkN9SZxd$_L@S)P-4-i0= zq)T*p)t76bKFU_%?EsnP6gNc1$G5fU5P=#qTG)z1+~(J2@Yq?zX}BQ!2gx>0wp*H} z5sNzu;PGM{ES?Qd-ekNk!ExD4TWsYaXZ`_zS!exMBv9@Pr&?HJV+m8db~qrOS{LY3 zB}qeW54adq%t z9O474?eA}sfcoNQJUXzE`(^G~a2P_-IXN!?p4i(o4N?kZq(m?s&0w%P)J@`Pi30dD ziTjRba5h+;YNH%o$Qt)x(+hF0^ zT*|$5cP=s6N^MoFb`#J&=&6X6NvS3&9;;ZH+FfCFz&Y8!n6u?W3c! z6|mlu_$z$cynRHMP$(#`-sXlM8g>+1&j&rt)rpJS*`H!rA|LHK?G6kNPIuk23jb>Q zNQ0JIS-NGiGn8vvJ_=OX?CKGQqEB^v4{Y*Ga6{KJuryHLN9$Gj!eJt}Pqp4o2at9h z0YP8vd2r7_FEtYffitG{?psqN??SB)N1 z8EfPvG$$(2eY(DSy(a4WDaRvD-E_E0z(oFF>h`k`3YL87ZqxXsCHxTade4KUb|a1` z5~lSN^joYY&6}0GJncUB;ik}6o12^SAH z)Dt*{-Zye7HF}~EavYf2AnNC+MMb&-K?Gw(X%V5ck0VIno%Ub#&Vgo}IG-UbhYOUc z4iVF_bee%Vhpqkm`#RO5QKX)Z)Nf^l!hnp549`%^2L@({B~z>9>te?AJqxX73QcsR zWIq)o$CtNXnO9^+O8q_4mAvS)*imRF3rw~z_Vzf>*B<-RDV#q_i_KGHar_%}0`+Ah zWch+L2wi#b4k?~J-*;RgSt{CPG6=^PF3@-;la2DH>IB{|{R&EKtksu31|*4C$W!QB z!NlH(^O0Bdgb086cjg@SKnNUgV%OtR1-IHt9NjiZ8ZOqVYje^$Ylj)|Z%Aq00X3pN zHKl-Y(!kQvCwiKyt3rO0{@wP1HSbYFJbDgBf-Vwy2z9{f3VaCZ7yJIByhC)sn7y`sQ`IvunE-@qtxBuws${9AZz5&pUVTt;+X z9jp7oURJ4=UXB=i$F%{j@J+(Ztof&(V|M3iX@citbv1;zq=WSP#Z>&hvXJEt2|oBo&=$pm{@X0`eGS{ zrwdxEc$)@oCJ2e3JU7Z4BEltmqetIa*`<)mMGqbpJdig#qaq&V&VhA!L%?8Vh@eAN z#}5`7eDWGhzO3Y8Ohzn0;#$-+f65(JDBZVI zb5cLH>erMEdJS{y?p~H0Hq-J*2HM_T-6MiZu^VGvWN9{%LzLWb-XUd>sqXxF>dD3a z$L=0Bc2EN_{Px8yt>j#}MTK@gekDjyI+MRx>0Q&d-7m#%G12t z^b`nc_9}%>Yih(V4NnoKY5mr4Ls*@-y0aneVv3bd7YKL{#p>(_%^K+Wu&$_NPhIMt ze1pcanwoUoC?}P(f*(L{Q&Kv_#&HPxOAa?~IZY@n&9J~ZRf_Z+&n+^Csc~6B&Rs%t z*puE(wd402y0c;Lx`flNkz$cffUQfNUf zU2Z{m+U#IKKx=BmJt~6_atG#9oPup2$Fqk?qQpd)+GZM>Cwsd}~LH6!U^yMjmJ(0Co&dPtzBMs6Dct0j4?+c5MwRDTV)~UXZ%t z@jvx~F9+Kl%^8@lWOOsYeY{gMe&T;=iIip*%-r`SlZU(Ev-zj6>G;Gx`hPAR0;sO! zWmDjAlz0uheIJ&{_b`S;@TDguDF4{T&}e8qd&0g2RpES2MY;b4D{=CnC#PDd!gGVT zC4uv2T3hBbmjeXA_2?6W-{f?{BYs}qdrrWv2L}NUEuO;&#l5C4_k2Ntd^ zk~iCPJl3Q0zy>$P6P#589!Epu+^~JJ<#oY%fu`%_F{JUl1<{$aKtp5Wh~#9y8RaA` zZ26LD1WG{AD|4Q$^n7E2yfxeDK7(0h+fDF7iazqILXi~ezmVj>oEZR5gTr#8^VWDG z#+c#4VYL{@;x*lQ2Av#nUvAXKMAJJ6f&!YP$m#Lgw!BtSu0fnC)k_X7_^0|lT!qmA zKe+kIEC2B6tGP>v%k}tb6hZ4qO{LI!C_ib4=&aMl7C5o8p^WD3!KZ$DaJB;WP+ahV z46wE2#?*9<_juxm8Mb(A*R26VjTs2}85Jc9WMk8}oGKUj`9*kCdD94n?Ps5C9ZwNI z@7?$@#tZ!5tEB(}+#`F?CE&)BxBdhug)3kdVj zwG2$P-d(X>v+6*&nh<@u)to{xa`ycY4KA_6PoVz~1N`6jSL98U(motKtNV!Htm6(s zTYjb&+t!{UV#*?N+u!?c)-`{jgyW9Xrg^Vt5cTi!>|2GkGu1joFAo~d^e$doy6b5& zGI2P#>tO-oc>ijR>mNshR0FIfWG8FG0hT4j-bP*>x3f4Ntmn%5(ld!w+n}4`1DZ{_ zqf1PK0Sm0IW}0~Mcjofo<3NR9R6y8Mq|fWq)(*d4OAY!^ZOaW>jhhWil@6vSp=rz{ zAQCV6goctVs#f`@`Y{>F2LzK-QwK$$<)YNv1ZCdVmK)u}>Tv90XU{cBA0XJLiKGID5BNDtW*vTsAhO1)7!q_$|Au<5l-GA2%HrHg#Gj z%NBA#J<0E&)Et}_Hdx-Eit6R4?G09po6o1DTg!G0ENGQyV`bF6aNuc`L_~Q9P-5%d z84t2k@fZVixcXITGY5Kgy`OG9R)$N0gExN}SZNCdV|bP+TT}^9tai%iAkdKFb3k_& zrBMW7)5QM}TQyekHZ*3C1`RIZp9Ys@Li_Irl(_=Qf2+W|eE#`A!>xB;D;|9`y#KS- z-pBk;YsW5SbgRG)z*?R8&x5qH&r|=XCVoqn>y6 z$jI2{VP6m9V5YxVD>CACNYc(f4sy@5}9=1aw~ZS1%p8w<_bTn_vL zbNr=Kn?Qvu(qc;lr2&}hcRYXOw6mtfq8|l?$)YQkIF^*(6UDD%3dhB=)uIxUWmP(H ze^q@At4Y>XvZ9uvi+UPyDPBbZS{VeO_LWdJc3Y=o1x^IAL#wyaTORFxZ4?l0-p14W zpYMUi5>FyeY9LnYje{C-Bg-qYD6xLo z{c*4SanJOu{T3AM&DUwAqN9_v(B^>UI~)N5T4QySV3`=J)GYS?QTM^n(cP4ifC#Z% zg*-Y7)EU0{LJv0c;|y#UeJ3J3)BH0w)sFsg+)g$Obdso`gg-h-U#83hvtz0&=+=v| zHQrdmgT95>2D)hKfOe?`bx=aEInww)d~;(u{U9qhcXdY<9Sx1aXiVI0cN+r(dYg<5 zmCJSX*9GKEx!IVa;AV1d`uBmMk%>~K)AJ4Rj8y({1ZBJ-4jwBUqhm@a%`e&pdI}L! zX5_o1CTtxGv!<9qlS6C0#RP6B+&1vLLT=A!nmIEJ0UKA$*3|hjVI~EnF#JK%jh=_% zyopU0fV^ZZmvIK+vvRY`JpRHIv)u$VtKEgI<+>&(zX9Vou$Ab2^B+q#uG--_wHM)_ z!gLO{^V@7*VQdcEm{@iXM=I}}+QZ)eG@xcolav-(aM$AnJq)$gDN=~@ zUgj*672J@)@KJbqxoZ_mZv0&2-CJiIGdjsW`ecB_LOi|jE-L8jMPE4J<@~Ez1Jgaz zW6HB?=jaV2a)tbk-wS@KR0nYw=*+-EJ=%1yJUYoodbgbonJm2vi@Oa^S8I-K@Cg1H zmz>dwKEv(A+B$H0i}opwj5&$R|4<3rb4bTgAoTLR*kSgt<=BX?_1+s zz-v_n?-#e^{X?fhoWB_o(;*;SX-Q!IK=#IDBRB00jtx zpr8Lxe-hR;Hir+IJm~eY*aj`andMYWObIc;x#f4=LlW}Rzb6KwP{+Jf4|U@q)w9H* zf5bGj^MG9&ZSSz6cIG&$6csbkE{c1Lg4k9%wKv~v9|bgPtHrv$u2XSaCTO7hhgU#< zkc=bs*%>upt=|2DDPMw^YCO{}*--roH226OT0H`S9pF210HLp}+;Ot9NWu2%^m?z}g6ID~A271@} zVX~=M(!1D|b`#t#{30mLMU)1)f7p;$0!ozV>Gyh``UGKK10y zQ*pT+?<}3d`dTmWVPa**(zW*zvaDRG42Hs`z4>6wM!D3O@Mmv@Xke|G`{{9k|3_`b4 zkMmk2+V;5ju^*4XiRcE1c5nQQHg@^>0Y$L^WO|ec!3jJ<(wB|VIw;5cJ98rLe}DK3 zjG&0399#V7F`|P&`L%+7O9(yOAHM?hJT9TQ`GSgvN!=Q0S6L|39KeBxP5J6TIurv-EA%N1pHV(m2BU4o*oEVJpjcEVICYBzR1EdX&26FSr`6dw zP5yW;3DCpK-BXYr`lF-)bc?_L$_i1-__@^l>pYeS8F*+eIR8uqC1`sC<{xghcAvnx zmPSKiAvBu9&clq)hMnTQ{lhE-O>-PCEFjAujMA_JSA=e%Y@SMdr!j~=3;p4M2 zFEnpZZ#!>rD;*sleEu9OwK_XO{dPcTVMDCb=;EO{%sd^xrzy3h@HAgHPS0A_vuN;@ z>pc!=cEmLJT#sHaFanEt&%PFU1myk&635|GCJJ{wk@v}=?imqp%BE$?l)3#$kJDsv z{6O+tB;>8t1F-=O^Qbw6lp2U51FEQZ8@mBK@_gMwY~Z9rRt>E6%*;N(rUYGz23sx1 zaDXPVR$TsR^-xhmgGtI;5~=5wVm1=XnaH~VefH>2d;)i)3vD7CmNVC{>{G!Nk!5TM zaq_~oXD>Nm%OY0dpSE)AqmGIf;ujH?Jc`m-4e$GSv>ORKw=YffSWZ7tr$0iEO4dgn zj)n;mC#NIh8&5hA+Ge_Z!gH9r0e6Q`b}ksN)EdMLh@t}Bm>f8cVzPYvF-KV0;(#9a zQp~}*Y-QFzBYeoOm`xMz5ZXu%-)w(>i-4kQ!S z?s&?~eJb)<;daA?h`G+CLYga@6o8iEgkpanMaDKV#p7zoXH1XFu~(zQNjD6Pu#d-M zDv({S9f>^*7P`a$oX^09J@Sjve#S4?C8cWPlsQA5^hwCmf+P7|QS3~5fj`u)s|2}WVJifvgQFus{wL`J_9Urz9_(8z4Y%K`Gh*Q*(&FB4;fF^?wg@%(XJ>}5Zf zJ~ownW_h~YeXL4}Qes-AI7+i!3h%iV|D=Q{eCOGV7i3+Yc*Z~)1kljr81q&6aV-=M zfR!#9cF#;p6R#d3SN?dY>A#H5A93sI~>Hu{eV$3ot4oo!&x8oVh=2wBBwy|4? zOFiu6qx;70c@+gf72LAak=f?gb576?5i)h+1p9TfELo%$L6D*j=;ldD{wX4eAYK5H zXfMHLPfA)i+ZCNr0E`|kY=5qEwf+^tXX6~>wldU)i5$%Rx$8W{=DV1Ysf)BEtZ2?;cYduKS?AVI_)M zs4#;3Xp(d-kn=P80+VDuu>PBKjOL@WiJs`-Qgrl=T2WR>I4X~d7vA;1)vc9=Q93E% z5y|)%qCR=vBq20T?!-86&xTJe{`xUHFH))tWfe?5H~fx{EZ0HV78 zQ7g}cr)1aq_hv;Y@c#dH0Q#c_$h>y^)5j?JkXNH(vO(9Q71Vg_dMe(KtgJ1m02IYP zk8~fzW|2``$#F>Hq?LZHNaB%;?)*$Zmo&p7iPJK5`Mj^>MBZ7MYaQ%jG!hjG81oS4 ze;)Tuxq4eN`)t2R)s*qKNO2LM>74&v*}i4`|46oHjG+Q|*8h)GZ`iI9U=sWfhCv}m z1idDvRQQ5 zlHMmyI`8wt>iTQ=s>I`=-xG-RQ-0z!t#A$}M38qN_6vf&L!gc0Y6Xtc0<(5Q$m4gD z25d!Fq^RPi9Lyq}ZsnvVoG1!Whn{ZP9T6BkSL~GfigKe7PIu(wgb4y$J0h^Zgos=PlA?VzW zD=R=k0Fl!9&n^&v7mh%WziQ?t_V%rtV+7&TiUeBtgoMj_M+SI#=q`xcNNX^q*iyZL zCs+hI5+E!jLL)YofXbkQPx_ZrS5YlESB7tg#|NNzpy<4{u-K20CH?Dj-?h{{@Q5o? zot+NaO3?Rb%EKa|9>OB+IuElANp*a+3W>Nnwk zW;GAl6z74FAQ<0-co`%JvCtHV1KJA}51UtmKm^dN+O4}QT+g*3^9(mfzt^dN=n_!1 zI~+yL)M#_qFKjGJ)EkK~*V7}R&grh7KyZmF=#|7JCZ7qyZ*MIpVz?F)e&jkkejg+y zCl`F=cYwc$RR2O(1VcayHCcEDGT*LqoJsPZBK2cU$6Q|Hn9Y%Vfrnc;t#kpn6% zcy0j6tyM=xl~vm>hldKWpPq7|KI0aZ3;WhxLzFLl`3=ZTJBxGEASF>ro=?}CMNP9? zjZ0Pf|LPZ{C-1!kW&*;e)VxCcE^*+%R9dkwrq+R|nwPJbLC3F+rE=E+5uhkV4}|Jl zSqZz=-ksX2sZD|*>YvfkX+=0xMgNI+pn3qGh8vu_+YF&sFYb7>6M*ai5n(}M{o5As z;RO>rJNquzm%nv^r>5gY6uIHh&FOR@py_A4VMovyQY-*76pzdSKsCmP6$;LW3jv6( zVD**ZA8Vj3V7gL-BU41yB;Q|y6E4@L^5lpAGY(Y;(oo-lyneQSPYn`0SYKCEBKreT z#()R$M(?JyuE7<)%<*0Xub&j;qOnci)`Yw~MK66u9GqLrlCs#+^u~sf;?GwfF#~B$ z%{L7A@&?!8sUR``y)cmmNZ|$Z&9q{hn|NS`Il60=;NM+r`Y64uBnq z_=poaz-xek^x<(r9V9PU?fVk@6F6c+3pXpx4#F8zgc4u_*Dw6-g3gzg8Hve=>%YtZ%oX5d+IY zM!alaN#q`c$1+jOYdNy%s@s<+ftz#id*dAJ%NSMO&_w49=rW8p_ye8dzaxWWQP5zm z{^M_|P=x!LP|S!e5^eO)WXsP72P+tvFD=!-z`*|x4gMd{Kr^Cfwr=Gt93WwkIM@WQ#8d<(BXJq*#sn{w*Cgh(L(n&v!YiyDl&2qq;ao} zXC;1;5=N3vSAPRM61Cn&sno;F4tV!Dp8OF&x9p>jGWZFHgN@g3Eo3f^5BfQq#TkCT zj%N}}%hI1{4I(g7^lr*&?#BmAOS2}B%p6P>YztrV>d(4#XMa@2|6D)T)JJ5XZ;%n4 z7_CvxrUVOp*O1zy4DQk(y_>pS}NCjh8lV8PoIa;S7{;T>pQ+KTf{8|&B zE?@vgR61V-W~Y0BV{7>pcK#Ar#ffZ zkIqh(hj6Z?k@EWf@n4Yx9k*xW3@qmQRv*f|E~)vO3)x*dMf-Rf=o6PW54*sxXZQ`Kx^(8e z7##Afi-2jWke=ZNMy4je^v6V0QqoY-CgP&TBoL6?-vIVfc{-#DKrKTe3KB5N{5S6Y zvcBK_nOm0##ZyF$1On{_mtO@OgrA|yAz*%h zaz1ngr0I>uUa#$F_=V}XKX>Das07+*A(|r#c`TUYdE@x~0w%O`zxdcq@&Xw8aw4WY zflbY}k?AQzxHaVbDQr_@nazkj896l{+Ull$d8^BRIri1x6&Tz}Jmvl~V`96r0|^{8 zZ9`L0p#SvtH_1Dw(CVqfOEx&Gs~>Kz_%!>luP6WEpagRne6>|V+)(=JmY!%G`KaZo(9h2| z19^!2>dtmysHP`hrOI@SB$d8;y3&Bj8M>%cL#yyO!Z=9SJri|ny12{p_&LBxqvoX# z@mrGb!GHFc=YSpfYoqXs1=lPPupfoUL&ST)`%-?i zyclduU9$2m-ZHsN8gv+WCW~AmZUq$aA@h}6I9?ZpN{JoHsgu*Q4bpK?P?NmwvwDF? zr_(EJUp+lN<46m3av<)%*49!X1j(W7*j_d{H5IH){<^1aulEi%E>wXztFEs1-In_DQ5j2Ll8x^hppT7a$0bLw*go}r z!~@-Hcnryc{6m!U&h%Q#@6@1UEC;WX0Kbn=fh}_kDH(iY#2p{83U~?izK)AaevrV# z!0>vk@0dVW$Yb=_QAGGq1~F|Q*K({FB>@7>FV?$(yM;rqNc&5UbtIIWd2NFaLk*7T z?|&<#Iy#iuteb0>lii*Def#mZ=EsQn2P50-s}(&{*GFw|r7YI#nv??$8G_ilSh;=u zc7^oL3My4IE|cy4bk#2*5YZQlSlA9P@iMNZzEp8wiwjB$DZK~z273cxCDAulPNNJc zc&Hp4en&w+G#zW}84ke*J&J#N^!Q92a;Wq!wh$z&%NUN9e%=D$as$ z6`BIzm9(WMKe|Oe8*f{NA!clR3Q=AMm}`s-%K;JzBHqg85<#{>$G(``s-M(>Ys1KH zD%Zmmk5C!PcT3XKPIcwL1 zh7n=k@VEm85+5iVfZK5NR$m0Z(W)!Y+69*C=2~%l)`rF5YXvsnw*4#j@co+wiaT?4 z4T)B39S(J{r-JiAJSG!^FZ^jrUn08v?s~TvZR4Lg@!Bw?-zKF+q5)zLkO4;%M9?x35Eq7<77cTB{&v>8F*` zheboWDhcqJo#>lcP)#Ln#umvF(n-$jQ<{#y4GavxN-i^S0kkv%GKa5q;a%)dHFDon zAgBmgIrh!ZSBG~3E>k|!oef*W`^mIu>m|CYQ2;ltyf_Faw(_Z|J=zTBcbuBdUmiZ= zLO_G;y#au_%r&T>JgxXl2kKb2Tupz=B4Cr{0=IyBYu#Cj!_$bQjn!LElbiyS#g}Q1 zz+>38wQ#-ni{mQK1*BK!w#!1Fp6?MIpPCGbm;@N~y9jg>{(hnP2+{C{A-_&5zQoAosM#c_7&o_LnqlOlJMu~q z0Xr-g*UBu#BZ@_svS4@ut!bKW;m%sRO?B_o)D)rXjLK`rCso}ad!iWG1RW06#`G#Q z*9Krm<{=~dA;(QvZUHFiz2QCz?R)0tuOp&A^tBO!gqs^pjxIV4s*n$06x=fa5oceV zFyj93n$_A}S~Q#&a=nVGV2i75r1xgsIhYFK5gWddFHs5&93Z?;tS^I$Dsz2@P!HR! zFhN0nspLqnvQl`lh}0zjGz1BcYLwQQ$$6K3f-{A|Anlf9J1V2v*5MC)`7m~c-nd9t zms;VuM`TQ?8^wl&P_$cK>?d7b3@`_t%LO;O{#lDq@Xs9ZXI5p!*0)uz=SpLP{Hv;} zYQxZ*1jp_g~54}Gcj15UG7^yc{>vyMxL3N02WJ2v_Ra! zPa_knb_D35=RW?J3m)`Nwa`MR&*SGhPaHe9>V$3eZ=Y^wK_+Bw7R7;ZnDeu)kVsoz z=PfL9v)|XOG06=4H-4MzV?~6tnu@KGi7*5CY}_i|Mzm6 zZD3=l3Z(a5^fEyheu!0}qtEJ0k|G_UghIm5(rpQ|UIyQHZ~95DSxo%JQP#K{#bNhr z133BTE(NNeMjUYv zHbF<`VPk_V)9rKiP%;1$yvD~@uej}4Qu;^6iHYlk%1z1#8_L7NxC*SGy)``m33^b^wqk`kqKKHP z4Pn%->|Qrx;ZCsC`<`vh%J00UjO9;(-||gKDVr?XmHtR6=uYd41?e{o7_Ym#@8Pcu)U=6uSJ(E$!8%x7{OYuk zJWE87e1sP`tPqY3p7P+eZRQE9Ij*$2;8DrlhBc zosZFP-#WeR%#jN?#pI81l`WIsW#$r;R1k*;A$vibh!}K&R$Z5_IHSTxY*8?aKr=V6 zU0H&HL85qPPO2<^v$`oVTXrkh%Fm!P%gfF67_2=Y!4UBB_-<4e^CJ2 z;*pGwC2lr8O}4IpwMBB}hgfbV5NU1&jzCmeSghkqxXJ0=*A*W%3dq1jx_!jPJ}q1b zujd|jK;grqi!9?it&0cfZBpl>+)zP0oymon#>|+BtGhNgR9}C%XKo6~5fK#yN8(f4 ztd8F6Jih14UM7Tw9qG~5QeB$TKiik5uRQtPxX@cP0&Wg0_P6>Bs^>(vOi*oSmS(#< zDjqs*-m47a?zZiIhgs5xq0(4_rQwN|J3^W%fQq+ZzCxU`Tn9vb5*+s2T;aRBLO?nG zUSS~NIuS8ZESKlKc=g1J_>Ej>-`>waQ0D8W!{5%tNoHzps#O$NfUmQA!5hD}+tMMe z?}4ni_|-`E*h%AY7!5k-h3}s=W6>xl*zrZJFY^30_7+bd$DA7!xD!e(c;Jf+dE{G9 zTzKJd3{j6|N=v|SCIx^YBtqEH9}w};OI*{6=_)o+#wtHLNBvGCJmzSzz2? z&d28XcJv!8+Y|*R<2eL&4t?>@I96xmz$RQoP0~{P^*n6PluWZ5XFZoCI&X(<9_mti zrd;R!qK7A-0RA7i^O~y8P}2Q!DWJYpKB+^xf}G-uSy9(WQFrnj!<2z8c9AcDP}qP$^6o6vsZGUS)ketR9S zmTuz!a!{#+?qQXNp;UZG60E6{yjEI}&3*$!Jr*f_nitq%umvK(H+w3{&odxMSpkeW zQ^7$n(QF)+5meyDaFQIiU6#2tbt{1-GOq&QSg<-KYVBNgk3HA$Gr|Fzc`AYPcLi4I zkm$#$eO&^H8#$o|B^bXlQ^3+QblqlD&IRWQvmW?1!te+;l)jG^lZ8aoy_Gjmc3DZh z?h%VRH)(N&Sxj+*aON>E>0R6Yz@m0)RY_o3*u|4z5PRL&tCyJZakElk^t%wov zXIx)T$g@tGWjb+MNiw4oolm1ht%n?%FyS5Ueh9|s5JGl>MJ^I{5F5tA$AxVpD{5{ZYuYI(4X=4iAia%WYE|7oEI${qr9 z;+cJ9JM6>TYC3(r#UNN9uU zh%R}dv41CETVp%J$hx}C4FV*Qc(3{eG1sbsp#ulzILS-XL*7m2DB+M zt%A1@A$pYVh06nlujYIZgv5ANbtkR;MSlH3rnfF9EC+HTN)dqb<)>eM?ny(T*)!cq<6| zcTLSeA~T4Ja42|GGZt)goE1DZ)!^&fM0bKiO_3a_#8Bd9lQN{6#id-g8VNox z{uTUA3nqf))lH8A#g{F}ko;fZLpO$tNKE2FTXE&>P88xb5$(rtugD`qU zRy47C!~N^^*#NA8G)FB<^3=WhUQ^Ev8$J=LF5mg{KRKOUS!X;C+oQu5&~H&WZrj5F zUpfn%s_CG%Vyu1A)Y4{C^aH@Mefy%MdW{Camp4}`Ua&~b1EaFhe4LVFIiOWjE4>&I zFI*JU_}u_Cj#ljgoh|CFtF0j-2w9%v1eI?gxKXm1@QmS?4}P&#PPM6acHbvTNq$t_ z+nv!BUMAFQM?aaDS1blnziSq;6{CwW7W7V=CJ zLa0c@TLT(L>X4A>J=a0p5og40t~|PJvNbO4DUd4~>8p&PQXwZJ=t7fZ#iSSpo9T#q zc@S(IZK7K9(jop==C0dRr%>epjl)aK@bM1jW%iwvm39dk2yAQfdiY}v2^)F%(DC#o zL9Pp^vB6u~U)FJj4agp+$E4Z_0euMFs3oVv5Md&V?TrS({{vYa91xf!;9(!1Cm8=k z>AN$mWWi`>;a8k^5K<-=I5<@0;l4k)pedJ~bu$bfm6URMA%eiw`qXFAles&E#Kfi39q3cTOrZz}wFxa*ENs*z)6_>op#N{PUgIG5U zL{)#n-W#*izUMGgV?gE~jsdp@uD~s-jdLh~g_7m;un~ z@joLLEZDj=h)XLUB8Mdlubpe9cT!#y=#_g)SfinJL{HJSU;?vXzi7sm>UbA)wCn4oYG#Kk2HyWt0H75-m57Ghm#T4wWiO*v6t$`q?SW zLoE1f?f*CBs1ZS^BH*ZGcC3+t0s1p0fosR~JAQ<Y5#m zwy0|9RuvNPuE>6J=Ur(NeX}{RU*mUj3YSRR0hr@pSBLEeSsBjPKXq!q6kB>ZeLJp5w)%Q59~15cQ6 zJYqW z_cj*A8+%K)03jp{t|RdQA>c(`ODta*MU1=EO{;|uS6+?oBuxF|ll~m9sX^9! zn`6w*^_bVwiYI04m7SxP5uu%n?dN+(<_HH<6v#>YpY|yfla`Cx?NHF;QUSyd$zf@G zy|ZES3iB{OBC$Z94ZTPA?(!Z%0sdjjBN-w^*Wy+#JjIXKroM>`xNxFa(>%7Av7BFG-KMc!%JKNaQ za%rKC2WTOcwhk$1UXq}M4ascYof@(66ihkO#k6I#w5Hjz_cNXwf~t5h?n1B>fpxO& z;!`Q$gD~NV$bwe;9u_62TNL=KhjHK^0pIJC+8SAwUu^QD#4r8*g3Rgufsl!^H|>4< z4tj|dd;;4|?eB(Lr|dXTYl9!>Ate{ZSz5rc@0>N`?06B7dOh&D^o3#N0?2PYRFHbR zz(}afD=;)!GiFoo$I+cTI_rIJre6x8h>#`$N8#Jmd&d2ZSAS`Zm0{pDkKX@n-8v_RXGIAJh%ojEg>(k_uh-imHdM zE4V>`yP5Cdx!;N5qh8x`=+noD_%_RRJ$*in*_d^ti7|SWy-^y$T0oyqsqa*ifVciN zB>0SYXY;u7GQhTC80mRyZrb6+&-Ok?*DO9ubWvV3=S}EMHq;Tct11lRHKNsn{ZSN@ zLWOv!AEmq~sN{Kz?ZlMBpWk^vwuc^?-I5!#K$?j0Q>Y8xp!1_ZV6;FV3IN{GDhCi; z6$M$BAZ3qlEaq`)f!>(wn`qAF>=g-TebmWODZ!!(!@6?|%g!j60NIELS7?040y`5kt-OalrDVe4% ziyCAyi0<@JwpYuVOZllwbO&^RKOmbuK+uXu?wL0G&7^4ayOQ&2Jq6TkI{Vd z-u;^Dba~a34pW$EXyhghypS*`APB>f)IQ?udJ%YtaZ%8oMgJY2=j%Aag!|!doA=7R z7VcV@-g=;Tq1t1Ap$hZ8bex&HwLc+4{bkG~kSmvti>hh2uwvFPj6^76tLB~TfA2q^ zDRSbbWDVwtD793nEqI&<>rK=JM{JW$#QZ^Z`t&n7>MCqn`7?iMIk{QHxIX_)P1%W# z%!EYLbH5sGtl6*^I~Yd8{#Oj6fh;G6(GO(|^VRR}!_g_OUo2!U%?gK4i(`LCwQc^* z^feMwQTMOrkaw;`8ktx^!6)X?zjxr-(8F&(vrRY+JPZ*hqK}?E4zLIzqM8V+Ztu`>XXsl3ng(JdY9U5qNCZB@ zUG**wOXKmw#l$#8MR)FKca)lH6^n?L1;!0c+ z?3{koAng-p3jMsu%QuDXT{U2L;4{a(v-ABrP!Z5IiEimQLOxvtH`5P$fQ-5a`iVzf&w41+_0d8Gl585jLLgedW;i9X#p?FS$-lt-nrKXHil*+{7_3)? z`H3}M@?2hL|FYvwLsnnBow|6D+mW9GQE z{b-m{DWx|JsP`24H9AFQ<%w_QV|EW8))bi0o1&H6-Eo;- zuH0=dmdc<1_FR6nC*qbQ&dJ!2+OECrZFt`0$D3c=^1&lzl!3?o?+|c-x;UDO1#`oM zvm^ifJj@N0FgF;Q!XWHsovQk4Y?!=VVPs|5Ytb}HWd)ORP+qZ$wl>*8ksBF=&~~M_ z%bqwG!ic`_n*G#Obg$quRHSU8(S6flyXHODYlUrQhQ&@mT$={`+T`BfC|VEhXaR4g z?HI@3F0oAFf_SgKqa)&F>S4l=&0a$L?v${oG=WV^;OCM)k6qFiQaym{ zp5LiT2Q%){aJf7m%K_gHBI7;Nb*)%obo}FNFR{3vY!SDBN&O!2C=sGVWgvWs?M7MJ z=1`~YZiQ5rTxc_yqBu+)!*TcjF?D!+Ur~)FU}USS>>&1;qtL=w%j^j^rC{&+K79^8 zj|*QA3hjgv-3CfjCxexgp}zVvZd}PW{g(YDNP5!JoOJ*YcgB0479N2Yahw4^g9jJl zqTRj@4~Ig0fl9U!h0d4d$_AH;yIcF85ur9jqBS-(so2m3X#;)j+o*<&CC$g@aZz~W zE~ra9Qr=uPAj{(3uP^ib(S?!HHd>P~)^=?^od;%mvFtcz?N%L^+EjTqh^uKHDJh8P z5hQJ+F&Q{c=>Tz<^x>@4$fsSI>3RLQx9FIM;2*O1)Ciy1mS2=#I!Pj37U4tV$gCSX zN*C(!tueojB<5w^fB-FLYeV4tC<;kwPImg{+-$kd`w!-O9XLNV2ExYjs8;a*-gIws8Lx(Z}2YVV9lg*dn5US~$>3jZ`u5+cL#;(lj()^*MlqG>V z4G9nkz(0Llx_urob0N30t#k1glZ1WabNmUDBAR};hVo_KBcqbb8r1M_i$t}@3E^La@(t-gy zwhRz*2iPAXk7)3}?Vb%J3uI}5_Oux+HyH*;RNw?_Xl$bsTp-_f&YW#$Yrdk@<`0S- zBWwD0k}FD#c5I5^58ks}F}!XufM*_w`;Qq&qMqAxEAmyrbvUMg9AdAp4n2%+G_=Yt zJ?&_I*Uusk?F6P{LKWfzhOoDxHQ<64aB?(1>dTD-qtB^tdDaAij&A~0>&oi)D4QPR8J{x*dO_N@a8yHN+QvShu;mvInHpJBsh0E&NZ}yWjV(l zTJ1U3Ir}4Hn#VVAL1G0CI7TR76JC~c$iTGxw}B}_uyn0S*7RET*^B8eT3ob}ja-cq zQD>ktgGhm2Q(DQ`u=9XTA{m|HV=>?~@KgHLfdp@o` zR5P+=n*iLz=mVCA74l{Jm4g-EKQi@i^vOKqYW)*Cw_FZ^8;OUB=>+-DWxf2j+^ne& z3*t9!|L2a`KOqWRGX$d0<5#j*JCa$#p$&>xRTy}_I8X@llQBr|fUtj`7X)hysBB4_ zjNxs)qS0PAvR7{}vOg}R?+R)-)lc@f^bgD9tf2DON$6tJ2F1vQh|yK~?j2M|A|UL` zkP*Nryg0x=UzLRgidsQHRx!omD`~*N!dy!&se0m)PTjfvS?RU`l?b)N<`Yuv3`2nc zNG5vWxvBt_7UPuyJ7^jP*6ZczsyJ@iutPqcPW}#9Bg)~y-}*wpk3Rk&Jktkd>L>ou z%e*@mUO$n(^v@y$?(*S+;C6v|)R2&$|wyx|oQ z+Z7>|;)d<84W~H9l~klb9hDzoTSR8_t?I-7yAoW&FQ8kcL{{Vx_H@4{5h8!b10s@&|qXu%F z09hCcR<7T<`_r%d1=VPf0JqHILVBO&*{?G^4m5-EW4(CK8ydbTEdcP9o{$L`%uWBnp#0idquhBIjp?qQ$f zc?Bv&NHQKwv92}1Jf?KU- zNQ!wS!>g5 z?P*bsb6rz_HK82muK_`F1O&+l;;V;4B+|<9kievB8E+gng)Z)u)CmAz^6(;~570YJ zx?(O^(ou}Mx@QjD@h~(h9f(2712XSOkT=YDQw_<<+b0<8d#t-O6ne+w5+4iX6Q@-F zVoxv?NEJ`m6VVlhEqfFNbAc%1CAMF18UUvQk z@o@b=NEE#P8i~^WuOv$Q-$@kHCwX&?(qOtZ|JNw8zfCC0p5$780yz3V{QpeQYboqKk$b|YzbHHFJAwxjK{}fAY3^AYs7vK3e!Fkf*{^;@g046N{h|1=w2*nc;|EsU&q_3YS@$=Dj6fQm4ODC|O3X z@#F;7w0_Jsi~^?uu?c222@J8mrs@a_IwQ<}83g#@l#n+--b;Uh10Ko?%UdjaH1UE5 zVeJ*rKGS&b`oX|nI=pHPfks&mP7$CT?Cs3^8{{Acgg?iF9!}Z;;{2uZc5yL~AmMM% zHO%xlU;qX=wQ0-S2@n&EKd3ZyTjWYPU2Duy5AN(4vd0P~6+n8ZhjYgC%E(ZYu`i4I z)(7oHo73g6ALFtR!^uAoNRd3O4zUksUx88^H8*^yfe`w$0lx_SgTd3_O2JUdS^+~Q zXcBb5eH`9%I!(0%2Q=lg9%aKn*p`->Czd9ap7)NZsOBdc82x*=$Ug=FqVZ{sxD>Yd z?=6j9diWiWa4xb6vc!J%k+^Q#69K-MCQBnaMRqajH(|QF64v(2r3M!`(1Wp%+BrTs z*%o455gHo$5lqnb_IUyT1MT30k$3PWP#Lm;5N8$_XmOj|n{p7(&&NDD* z!wA%?0o6_&5~mh;EL$hMbPIo>4nqVK=E_vmM^F&N9b(N7;&e@DRz44D-)4k31t^T* z`N4&_MIiEEK43OCkbew4vQVg_Sd@TjPrzE}N8Lyw7vK#qBt~;>wt~}9;4o@}iaWo) zfemA^(@?bT9VFBh0MRFaUi3!%-qn?0?UL4W9~7AsfsHZQEQ*?%SdkECnJ&-9q7LVv zk}!h!V5;)oCq(HyeT;M32P+u;c^Qhe`!uG(e$;^I%5+IQKBv}1HXWFvY@@l%0LLh+sd;~NNLh3mD>+Lzb ze*z2N<89vos6K%9I(_EH17J7L!on|QZ8qL3TXk6@ZAoEBi31`jm`P8)G%}l8DHZDu zRzbmCe9RzX1mNg@++$P4rG`SvKwJHb_Yj10L-fiVNnl^#FDVA)N+9rE&|MQ&UlCwH zAD#R*8hkbS7zd`)6A>!tz#N2^fcIz%-kT$>pSZ5ZHAk*WaCneVb0xl705azip8=ps>SMwO8aq&Md0_J^O_^ z$!3#JuDc7vdGYY8ARlnM1fY+NRDg-8sRVl!3vsu0-~`i_;BPLhliqz8*nFM|HlU)Ir+UC!bulQt;j6wG)pC*O4RwD~acIF}V7 pI@{lsvz-r@Qs(`a@ayGcj561#!gU)R92ESKlTwn*62JT8{{eSJqhSC5 literal 0 HcmV?d00001 diff --git a/resources/visu_vtk/index.html b/resources/visu_vtk/index.html index 4e057b5..bbce194 100644 --- a/resources/visu_vtk/index.html +++ b/resources/visu_vtk/index.html @@ -10,11 +10,12 @@ MeshViewer - +
+
@@ -55,28 +65,34 @@
-
+
@@ -85,11 +101,15 @@ @@ -192,7 +216,8 @@
Select the groups that should be shown in the sidebar @@ -206,13 +231,19 @@
@@ -227,6 +258,8 @@ + + diff --git a/resources/visu_vtk/js/Controller.js b/resources/visu_vtk/js/Controller.js index f729690..6841b13 100644 --- a/resources/visu_vtk/js/Controller.js +++ b/resources/visu_vtk/js/Controller.js @@ -58,6 +58,13 @@ class Controller { CameraManager.Instance.init(this._groups); } + refreshThemeColors() { + if (!this._groups) return; + for (const group of Object.values(this._groups)) { + group.applyThemeColor(); + } + } + getGroupNames() { if (!this._groups) { return []; diff --git a/resources/visu_vtk/js/commands/VisibilityManager.js b/resources/visu_vtk/js/commands/VisibilityManager.js index 5f5b834..2bfbbaa 100644 --- a/resources/visu_vtk/js/commands/VisibilityManager.js +++ b/resources/visu_vtk/js/commands/VisibilityManager.js @@ -20,14 +20,19 @@ class VisibilityManager { init(groups, objects) { this.groups = groups; this.visibleGroupsByObject = {}; + this.hiddenObjects = {}; + this.highlightedGroups = new Set(); for (const object in objects) { this.visibleGroupsByObject[object] = 0; + this.hiddenObjects[object] = false; } } /** * Sets visibility for a given group and updates associated object transparency. + * The highlighted state is tracked independently from actor visibility so that + * hiding/showing an entire object does not corrupt the highlight state. * @param {string} groupName Name of the group to modify. * @param {boolean} visible Optional visibility state; toggles if omitted. * @returns {Object} Current visibility info: {visible, color, isFaceGroup} @@ -62,35 +67,40 @@ class VisibilityManager { const color = group.getColor(); const isFaceGroup = group.isFaceGroup; - // Store the previous visibility state before changing it - const wasVisible = actor.getVisibility(); + // Determine new highlighted state from the tracking set, not from actor visibility. + // This ensures correctness even when the whole object is hidden. + const wasHighlighted = this.highlightedGroups.has(groupName); + const isHighlighted = + typeof visible === "boolean" ? visible : !wasHighlighted; - if (typeof visible === "boolean") { - // If 'visible' is set, set the new visibility accordingly - actor.setVisibility(visible); + // Update the highlighted tracking set + if (isHighlighted) { + this.highlightedGroups.add(groupName); } else { - // Else, toggle visibility - actor.setVisibility(!actor.getVisibility()); + this.highlightedGroups.delete(groupName); } - // Make the whole object transparent (except from the selected groups) if at least one group is selected - // Or make it opaque if no groups are selected - const isVisible = actor.getVisibility(); + // Apply to actor only if the parent object is not globally hidden + if (!this.hiddenObjects[object]) { + group.setVisibility(isHighlighted); + } - // Only update the counter if visibility actually changed - if (wasVisible !== isVisible) { + // Update transparency counter when highlight state actually changes + if (wasHighlighted !== isHighlighted) { const visibleGroupsCount = this.visibleGroupsByObject[object]; - if ( - (visibleGroupsCount === 0 && isVisible) || - (visibleGroupsCount === 1 && !isVisible) - ) { - this.setTransparence(isVisible, object); + if (!this.hiddenObjects[object]) { + if ( + (visibleGroupsCount === 0 && isHighlighted) || + (visibleGroupsCount === 1 && !isHighlighted) + ) { + this.setTransparence(isHighlighted, object); + } } - this.visibleGroupsByObject[object] += isVisible ? 1 : -1; + this.visibleGroupsByObject[object] += isHighlighted ? 1 : -1; } // Change group button highlight status - if (isVisible) { + if (isHighlighted) { UIManager.Instance.highlightButton(groupName, color); } else { UIManager.Instance.highlightButton(groupName); @@ -99,7 +109,43 @@ class VisibilityManager { // Re-render the VTK window VtkApp.Instance.getRenderWindow().render(); - return { visible: isVisible, color, isFaceGroup }; // Unused, is this really necessary ? + return { visible: isHighlighted, color, isFaceGroup }; + } + + /** + * Toggles the visibility of an entire object (mesh). + * When hidden, all actors for the object are invisible. + * When shown, the file group and any highlighted sub-groups are restored. + * @param {string} object Name of the file group (e.g. "all_mesh.obj"). + * @returns {boolean} True if the object is now visible, false if now hidden. + */ + toggleObjectVisibility(object) { + // Toggle hidden state + const nowVisible = this.hiddenObjects[object]; // was hidden → now visible + this.hiddenObjects[object] = !nowVisible; + + // Show/hide the file group actor (the full mesh) + const fileGroup = this.groups[object]; + if (fileGroup) { + fileGroup.actor.setVisibility(nowVisible); + if (nowVisible) { + // Restore the correct opacity based on whether any groups are highlighted + const opacity = this.visibleGroupsByObject[object] > 0 ? 0.2 : 1.0; + fileGroup.setOpacity(opacity); + } + } + + // Show/hide sub-group actors based on their highlighted state + for (const [groupName, group] of Object.entries(this.groups)) { + if (group.fileGroup === object) { + group.actor.setVisibility( + nowVisible && this.highlightedGroups.has(groupName) + ); + } + } + + VtkApp.Instance.getRenderWindow().render(); + return nowVisible; } /** @@ -108,7 +154,7 @@ class VisibilityManager { * @param {string} object Name of the object. */ setTransparence(transparent, object) { - if (!this.groups) { + if (!this.groups || this.hiddenObjects[object]) { return; } const meshOpacity = transparent ? 0.2 : 1; @@ -136,7 +182,10 @@ class VisibilityManager { UIManager.Instance.highlightButton(groupName); } - // Make all objects opaque + // Reset highlighted tracking + this.highlightedGroups.clear(); + + // Make all visible objects opaque for (const object in this.visibleGroupsByObject) { this.setTransparence(false, object); this.visibleGroupsByObject[object] = 0; diff --git a/resources/visu_vtk/js/core/VtkApp.js b/resources/visu_vtk/js/core/VtkApp.js index b9a97db..422e241 100644 --- a/resources/visu_vtk/js/core/VtkApp.js +++ b/resources/visu_vtk/js/core/VtkApp.js @@ -15,23 +15,60 @@ class VtkApp { * Initializes the full-screen renderer in the given HTML scene * @param {HTMLElement} scene - The HTML element to attach the renderer */ + _readEditorBackground() { + const raw = getComputedStyle(document.body).getPropertyValue("--vscode-editor-background").trim(); + const match = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i); + if (match) { + return [parseInt(match[1], 16) / 255, parseInt(match[2], 16) / 255, parseInt(match[3], 16) / 255]; + } + return [0.4, 0.6, 1.0]; + } + + updateBackground() { + this.renderer.setBackground(this._readEditorBackground()); + } + init(scene) { if (!window.vtk) {return;} this.fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({ rootContainer: scene, - background: [0.4, 0.6, 1.0], + background: this._readEditorBackground(), }); this.renderer = this.fullScreenRenderer.getRenderer(); this.renderWindow = this.fullScreenRenderer.getRenderWindow(); - Controller.Instance.getVSCodeAPI().postMessage({ - type: 'debugPanel', - text: 'vtkAppInitialized' + this.updateCameraOffset(); + + // Keep the offset in sync if the window or sidebar resizes + const controls = document.getElementById("controls"); + new ResizeObserver(() => this.updateCameraOffset()).observe(controls); + window.addEventListener("resize", () => this.updateCameraOffset()); + + // Refresh scene colors when VS Code theme changes + new MutationObserver(() => { + this.updateBackground(); + Controller.Instance.refreshThemeColors(); + this.renderWindow.render(); + }).observe(document.body, { attributes: true, attributeFilter: ["class"] }); + + Controller.Instance.getVSCodeAPI().postMessage({ + type: 'debugPanel', + text: 'vtkAppInitialized' }); } + /** + * Offsets the camera so the scene appears centered in the area to the right of the sidebar. + */ + updateCameraOffset() { + const sidebarWidth = document.getElementById("controls").offsetWidth; + const offset = sidebarWidth / window.innerWidth; + this.renderer.getActiveCamera().setWindowCenter(-offset, 0); + this.renderWindow.render(); + } + /** @returns {vtkRenderer} The VTK renderer */ getRenderer() { return this.renderer; diff --git a/resources/visu_vtk/js/data/CreateGroups.js b/resources/visu_vtk/js/data/CreateGroups.js index 3fa5556..2ac7a10 100644 --- a/resources/visu_vtk/js/data/CreateGroups.js +++ b/resources/visu_vtk/js/data/CreateGroups.js @@ -45,29 +45,34 @@ class CreateGroups { for (const fileGroup in groupHierarchy) { const groupId = faceGroups.indexOf(fileGroup); - const actor = FaceActorCreato.create(fileGroup, groupId); + // Record the color before create() increments the object index + const _oc = GlobalSettings.Instance.objectColors; + const objColor = _oc[GlobalSettings.Instance.objIndex % _oc.length]; + groupHierarchy[fileGroup].color = objColor; - const groupInstance = new Group(actor, fileGroup, true); + const { actor, colorIndex: fileColorIndex, isObjectActor: fileIsObj } = FaceActorCreato.create(fileGroup, groupId); + + const groupInstance = new Group(actor, fileGroup, true, null, null, fileColorIndex, fileIsObj); this.groups[fileGroup] = groupInstance; const size = this.computeSize(actor); for (const faceGroup of groupHierarchy[fileGroup].faces) { - const groupId = faceGroups.indexOf(faceGroup); + const groupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}`); - const actor = FaceActorCreato.create(faceGroup, groupId); + const { actor: faceActor, colorIndex: faceColorIndex, isObjectActor: faceIsObj } = FaceActorCreato.create(faceGroup, groupId); - const subGroup = new Group(actor, faceGroup, true, fileGroup, size); + const subGroup = new Group(faceActor, faceGroup, true, fileGroup, size, faceColorIndex, faceIsObj); this.groups[`${fileGroup}::${faceGroup}`] = subGroup; } for (const nodeGroup of groupHierarchy[fileGroup].nodes) { - const groupId = nodeGroups.indexOf(nodeGroup); + const groupId = nodeGroups.indexOf(`${fileGroup}::${nodeGroup}`); - const actor = NodeActorCreato.create(groupId); + const { actor: nodeActor, colorIndex: nodeColorIndex } = NodeActorCreato.create(groupId); - const subGroup = new Group(actor, nodeGroup, false, fileGroup, size); + const subGroup = new Group(nodeActor, nodeGroup, false, fileGroup, size, nodeColorIndex, false); this.groups[`${fileGroup}::${nodeGroup}`] = subGroup; } } diff --git a/resources/visu_vtk/js/data/Group.js b/resources/visu_vtk/js/data/Group.js index 9aa424c..03a8f7c 100644 --- a/resources/visu_vtk/js/data/Group.js +++ b/resources/visu_vtk/js/data/Group.js @@ -10,12 +10,23 @@ class Group { * @param {string|null} fileGroup - Parent fileGroup name (null if this is a fileGroup) * @param {number|null} parentSize - Size of the parent fileGroup (null if this is a fileGroup) */ - constructor(actor, name, isFaceGroup, fileGroup = null, parentSize = null) { - this.actor = actor; - this.name = name; - this.isFaceGroup = isFaceGroup; + constructor(actor, name, isFaceGroup, fileGroup = null, parentSize = null, colorIndex = null, isObjectActor = false) { + this.actor = actor; + this.name = name; + this.isFaceGroup = isFaceGroup; this.fileGroup = fileGroup; this.size = parentSize; + this.colorIndex = colorIndex; + this.isObjectActor = isObjectActor; + } + + applyThemeColor() { + if (this.colorIndex === null) return; + const colors = this.isObjectActor + ? GlobalSettings.Instance.objectColors + : GlobalSettings.Instance.meshGroupColors; + const color = colors[this.colorIndex % colors.length]; + this.actor.getProperty().setColor(color); } /** diff --git a/resources/visu_vtk/js/data/ObjLoader.js b/resources/visu_vtk/js/data/ObjLoader.js index 624fffe..34979f5 100644 --- a/resources/visu_vtk/js/data/ObjLoader.js +++ b/resources/visu_vtk/js/data/ObjLoader.js @@ -65,14 +65,14 @@ class ObjLoader { case 'g': // New face group groupId++; const faceGroupName = ss[1] || `group${groupId}`; - faceGroups.push(faceGroupName); + faceGroups.push(`${skinName}::${faceGroupName}`); groupHierarchy[skinName].faces.push(faceGroupName); break; case 'ng': // New node group nodeGroupId++; const nodeGroupName = ss[1] || `nodeGroup${nodeGroupId}`; - nodeGroups.push(nodeGroupName); + nodeGroups.push(`${skinName}::${nodeGroupName}`); groupHierarchy[skinName].nodes.push(nodeGroupName); break; diff --git a/resources/visu_vtk/js/data/create/FaceActorCreator.js b/resources/visu_vtk/js/data/create/FaceActorCreator.js index 762d8fd..5a7e2d8 100644 --- a/resources/visu_vtk/js/data/create/FaceActorCreator.js +++ b/resources/visu_vtk/js/data/create/FaceActorCreator.js @@ -26,10 +26,10 @@ class FaceActorCreator { mapper.setInputData(polyData); actor.setMapper(mapper); - this.setProperty(actor, groupName); + const { colorIndex, isObjectActor } = this.setProperty(actor, groupName); VtkApp.Instance.getRenderer().addActor(actor); - return actor; + return { actor, colorIndex, isObjectActor }; } @@ -76,11 +76,16 @@ class FaceActorCreator { setProperty(actor, groupName) { const prop = actor.getProperty(); + let colorIndex, isObjectActor; if (groupName.includes("all_")) { - prop.setColor(GlobalSettings.Instance.surfaceOutsideColor); + isObjectActor = true; + colorIndex = GlobalSettings.Instance.objIndex; + prop.setColor(GlobalSettings.Instance.getColorForObject()); } else { + isObjectActor = false; + colorIndex = GlobalSettings.Instance.grpIndex; prop.setColor(GlobalSettings.Instance.getColorForGroup()); - prop.setOpacity(0.8); + prop.setOpacity(1.0); actor.setVisibility(false); } @@ -89,6 +94,8 @@ class FaceActorCreator { prop.setInterpolationToPhong(); prop.setSpecular(0.3); prop.setSpecularPower(15); + + return { colorIndex, isObjectActor }; } } diff --git a/resources/visu_vtk/js/data/create/NodeActorCreator.js b/resources/visu_vtk/js/data/create/NodeActorCreator.js index 380f257..d9d131f 100644 --- a/resources/visu_vtk/js/data/create/NodeActorCreator.js +++ b/resources/visu_vtk/js/data/create/NodeActorCreator.js @@ -25,10 +25,10 @@ class NodeActorCreator { const actor = vtk.Rendering.Core.vtkActor.newInstance(); actor.setMapper(mapper); - this.setProperty(actor); + const colorIndex = this.setProperty(actor); VtkApp.Instance.getRenderer().addActor(actor); - - return actor; + + return { actor, colorIndex }; } /** @@ -80,10 +80,12 @@ prepare(groupId) { */ setProperty(actor) { const prop = actor.getProperty(); + const colorIndex = GlobalSettings.Instance.grpIndex; prop.setRepresentation(0); prop.setOpacity(1); actor.setVisibility(false); prop.setColor(GlobalSettings.Instance.getColorForGroup()); + return colorIndex; } } diff --git a/resources/visu_vtk/js/settings/GlobalSettings.js b/resources/visu_vtk/js/settings/GlobalSettings.js index 2a2e89e..c544404 100644 --- a/resources/visu_vtk/js/settings/GlobalSettings.js +++ b/resources/visu_vtk/js/settings/GlobalSettings.js @@ -8,6 +8,7 @@ class GlobalSettings { constructor() { this.grpIndex = 0; + this.objIndex = 0; } // scene @@ -34,33 +35,76 @@ class GlobalSettings { selectHelperColor = [1, 1, 1]; // #ffffff selectionPointColor = [1, 0, 0]; // #ff0000 - // couleurs des groupes - meshGroupColors = [ + get isDark() { + return document.body.classList.contains('vscode-dark') || + document.body.classList.contains('vscode-high-contrast'); + } + + // Group colors — vivid for dark mode, toned down for light mode + _meshGroupColors = [ [0.902, 0.098, 0.294], // #e6194b [0.235, 0.706, 0.294], // #3cb44b - [1, 0.882, 0.098], // #ffe119 + [1, 0.882, 0.098], // #ffe119 [0.941, 0.196, 0.902], // #f032e6 [0.961, 0.510, 0.192], // #f58231 [0.569, 0.118, 0.706], // #911eb4 [0.275, 0.941, 0.941], // #46f0f0 [0.737, 0.965, 0.047], // #bcf60c [0.980, 0.745, 0.745], // #fabebe - [0, 0.502, 0.502], // #008080 - [0.902, 0.745, 1], // #e6beff + [0, 0.502, 0.502], // #008080 + [0.902, 0.745, 1 ], // #e6beff [0.604, 0.388, 0.141], // #9a6324 [0.263, 0.388, 0.847], // #4363d8 - [1, 0.980, 0.784], // #fffac8 - [0.502, 0, 0], // #800000 - [0.667, 1, 0.764], // #aaffc3 - [0.502, 0.502, 0], // #808000 - [1, 0.847, 0.694], // #ffd8b1 - [0, 0, 0.463], // #000075 + [1, 0.980, 0.784], // #fffac8 + [0.502, 0, 0 ], // #800000 + [0.667, 1, 0.764], // #aaffc3 + [0.502, 0.502, 0 ], // #808000 + [1, 0.847, 0.694], // #ffd8b1 + [0, 0, 0.463], // #000075 [0.502, 0.502, 0.502], // #808080 ]; + get meshGroupColors() { + if (this.isDark) return this._meshGroupColors; + return this._meshGroupColors.map(([r, g, b]) => [r * 0.72, g * 0.72, b * 0.72]); + } + getColorForGroup() { - let idx = this.grpIndex % this.meshGroupColors.length; + const idx = this.grpIndex % this._meshGroupColors.length; this.grpIndex++; return this.meshGroupColors[idx]; } + + // Object base colors — muted for light mode, vivid for dark mode + _objectColorsLight = [ + [0.400, 0.620, 0.820], // steel blue + [0.280, 0.700, 0.580], // teal + [0.880, 0.560, 0.280], // amber + [0.600, 0.400, 0.800], // lavender + [0.380, 0.720, 0.420], // sage green + [0.820, 0.380, 0.440], // rose + [0.380, 0.680, 0.820], // sky + [0.820, 0.620, 0.380], // bronze + ]; + + _objectColorsDark = [ + [0.440, 0.720, 0.980], // bright steel blue + [0.240, 0.880, 0.700], // bright teal + [0.980, 0.660, 0.320], // bright amber + [0.720, 0.500, 0.980], // bright lavender + [0.400, 0.900, 0.500], // bright sage green + [0.980, 0.420, 0.520], // bright rose + [0.360, 0.800, 0.980], // bright sky + [0.980, 0.740, 0.440], // bright bronze + ]; + + get objectColors() { + return this.isDark ? this._objectColorsDark : this._objectColorsLight; + } + + getColorForObject() { + const idx = this.objIndex % this.objectColors.length; + this.objIndex++; + return this.objectColors[idx]; + } } diff --git a/resources/visu_vtk/js/ui/UIManager.js b/resources/visu_vtk/js/ui/UIManager.js index 11d7a64..a5a6bfd 100644 --- a/resources/visu_vtk/js/ui/UIManager.js +++ b/resources/visu_vtk/js/ui/UIManager.js @@ -73,9 +73,11 @@ class UIManager { */ addGroupButtons(objects) { // Hack to retrieve necessary icons - const objectIconUrl = document.getElementById("object").src; - const faceIconUrl = document.getElementById("face").src; - const nodeIconUrl = document.getElementById("node").src; + const eyeIconUrl = document.getElementById("eye").src; + // Inline SVG paths for face/node icons (fill="currentColor" inherits button text color) + const faceSvgPath = "M161-366q-16-12-15.5-31.5T162-429q11-8 24-8t24 8l270 209 270-209q11-8 24-8t24 8q16 12 16.5 31.5T799-366L529-156q-22 17-49 17t-49-17L161-366Zm270 8L201-537q-31-24-31-63t31-63l230-179q22-17 49-17t49 17l230 179q31 24 31 63t-31 63L529-358q-22 17-49 17t-49-17Zm49-64 230-178-230-178-230 178 230 178Zm0-178Z"; + const nodeSvgPath = "M580-120q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Zm0-80q17 0 28.5-11.5T620-240q0-17-11.5-28.5T580-280q-17 0-28.5 11.5T540-240q0 17 11.5 28.5T580-200Zm80-200q-92 0-156-64t-64-156q0-92 64-156t156-64q92 0 156 64t64 156q0 92-64 156t-156 64Zm0-80q59 0 99.5-40.5T800-620q0-59-40.5-99.5T660-760q-59 0-99.5 40.5T520-620q0 59 40.5 99.5T660-480ZM280-240q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T360-400q0-33-23.5-56.5T280-480q-33 0-56.5 23.5T200-400q0 33 23.5 56.5T280-320Zm300 80Zm80-380ZM280-400Z"; + const eyeOffIconUrl = document.getElementById("eye_off").src; // Get group buttons div const groupButtonsDiv = document.getElementById("groupButtons"); @@ -89,25 +91,57 @@ class UIManager { const objectLabel = document.createElement("span"); objectLabel.id = `obj_${objectName}`; objectLabel.classList.add( - "relative", "h-4.5", "w-full", + "self-stretch", "flex", - "justify-center", "items-center", + "gap-1", + "pl-1.25", + "pr-0.5", "mb-2", "not-nth-of-type-[1]:mt-1", "text-xs", - "text-black/70", "font-bold" ); + objectLabel.style.color = "var(--ui-text-primary)"; - const icon = ``; - const text = `${objectName}`; - objectLabel.innerHTML = icon + text; + const groupCount = faces.length + nodes.length; + + const [r, g, b] = objects[object].color ?? [0.537, 0.529, 0.529]; + const colorCss = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; + const objSvgPath = "M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"; + const icon = ``; + const text = `${objectName}`; + const eyeBtn = ``; + objectLabel.innerHTML = icon + text + eyeBtn; groupButtonsDiv.appendChild(objectLabel); + // Eye button toggles full mesh visibility + document.getElementById(`eyeBtn_${object}`).addEventListener("click", () => { + const nowVisible = VisibilityManager.Instance.toggleObjectVisibility(object); + document.getElementById(`eyeIcon_${object}`).src = nowVisible ? eyeIconUrl : eyeOffIconUrl; + }); + + // Create collapsible container for group buttons + const groupContainer = document.createElement("div"); + groupContainer.id = `grpContainer_${object}`; + groupContainer.classList.add("w-full", "flex", "flex-col", "items-center", "space-y-1"); + + // Create collapsed summary shown in place of the buttons + const groupCountEl = document.createElement("div"); + groupCountEl.id = `grpCount_${object}`; + groupCountEl.classList.add("hidden!", "w-full", "text-center", "text-[0.7rem]", "font-normal", "mb-2"); + groupCountEl.style.color = "var(--ui-text-muted)"; + groupCountEl.textContent = `${groupCount} groups`; + + // Name span toggles group container visibility + document.getElementById(`objName_${object}`).addEventListener("click", () => { + const collapsed = groupContainer.classList.toggle("hidden!"); + groupCountEl.classList.toggle("hidden!", !collapsed); + }); + // Create group buttons for the current object const groups = faces.concat(nodes); groups.forEach((groupName) => { @@ -118,10 +152,7 @@ class UIManager { "flex", "items-center", "justify-center", - "hover:bg-white/50", "rounded-sm", - "bg-white/30", - "text-black/70", "text-xs", "px-2", "pt-0.75", @@ -129,10 +160,20 @@ class UIManager { "w-full", "cursor-pointer" ); + btn.style.background = "var(--ui-element-bg)"; + btn.style.color = "var(--ui-text-primary)"; + btn.addEventListener("mouseover", () => { + if (!btn.dataset.highlighted) { + btn.style.background = "var(--ui-element-bg-hover)"; + } + }); + btn.addEventListener("mouseout", () => { + if (!btn.dataset.highlighted) { + btn.style.background = "var(--ui-element-bg)"; + } + }); - const icon = ``; + const icon = ``; const text = `${groupName}`; btn.innerHTML = icon + text; @@ -140,8 +181,11 @@ class UIManager { VisibilityManager.Instance.setVisibility(`${object}::${groupName}`); }); - groupButtonsDiv.appendChild(btn); + groupContainer.appendChild(btn); }); + + groupButtonsDiv.appendChild(groupContainer); + groupButtonsDiv.appendChild(groupCountEl); } } @@ -156,16 +200,16 @@ class UIManager { if (color) { // If the button was not highlighted, highlight it - btn.classList.add("font-semibold", "hover:brightness-90"); - btn.classList.remove("bg-white/30"); - btn.style.backgroundColor = `rgb(${color[0] * 255}, ${color[1] * 255}, ${ - color[2] * 255 - }, 0.8)`; + btn.classList.add("font-semibold"); + btn.dataset.highlighted = "1"; + btn.style.background = `rgb(${color[0] * 255}, ${color[1] * 255}, ${color[2] * 255}, 0.8)`; + btn.style.color = "var(--ui-highlight-text)"; } else { // Else unapply the highlight - btn.classList.remove("font-semibold", "hover:brightness-90"); - btn.classList.add("bg-white/30"); - btn.style.backgroundColor = ""; + btn.classList.remove("font-semibold"); + delete btn.dataset.highlighted; + btn.style.background = "var(--ui-element-bg)"; + btn.style.color = "var(--ui-text-primary)"; } } diff --git a/resources/visu_vtk/styles.css b/resources/visu_vtk/styles.css index b01555f..1ea9b2c 100644 --- a/resources/visu_vtk/styles.css +++ b/resources/visu_vtk/styles.css @@ -1,5 +1,47 @@ @import "tailwindcss"; +:root { + --ui-bg: var(--vscode-sideBar-background, var(--vscode-editor-background, #e8eaf0)); + --ui-fg: var(--vscode-sideBar-foreground, var(--vscode-editor-foreground, #1f1f1f)); + --ui-btn-bg: var(--vscode-button-background, #0078d4); + --ui-btn-fg: var(--vscode-button-foreground, #ffffff); + --ui-btn-hover-bg: var(--vscode-button-hoverBackground, #005fa3); + --ui-popup-bg: var(--vscode-editorWidget-background, var(--vscode-editor-background, #f3f3f3)); + --ui-border: var(--vscode-widget-border, var(--vscode-editorWidget-border, rgba(0,0,0,0.1))); + --icon-filter: none; + + /* Text contrast levels */ + --ui-text-primary: color-mix(in srgb, var(--ui-fg) 90%, transparent); + --ui-text-secondary: color-mix(in srgb, var(--ui-fg) 70%, transparent); + --ui-text-muted: color-mix(in srgb, var(--ui-fg) 55%, transparent); + + /* Element backgrounds */ + --ui-element-bg: color-mix(in srgb, var(--ui-fg) 10%, transparent); + --ui-element-bg-hover: color-mix(in srgb, var(--ui-fg) 18%, transparent); + + /* Text on highlighted group buttons — light mode: dark 0.72× colors → white text */ + --ui-highlight-text: rgba(255, 255, 255, 0.9); +} + +body.vscode-dark, +body.vscode-high-contrast { + --icon-filter: invert(1); + /* Dark mode: bright vivid colors → dark text for contrast */ + --ui-highlight-text: rgba(0, 0, 0, 0.8); +} + kbd { - @apply text-blue-500 bg-white/30 px-1 py-px rounded-sm; + @apply px-1 py-px rounded-sm; + color: var(--vscode-textLink-foreground, #0078d4); + background: color-mix(in srgb, var(--ui-bg) 70%, transparent); +} + +#groupButtons, +#helpPopup * { + scrollbar-width: none; +} + +#groupButtons::-webkit-scrollbar, +#helpPopup ::-webkit-scrollbar { + display: none; } diff --git a/resources/visu_vtk/tailwind.css b/resources/visu_vtk/tailwind.css index 2cc1253..9e81726 100644 --- a/resources/visu_vtk/tailwind.css +++ b/resources/visu_vtk/tailwind.css @@ -1,4 +1,4 @@ -/*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */ +/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme, base, components, utilities; @layer theme { @@ -7,12 +7,11 @@ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --color-red-500: oklch(63.7% 0.237 25.331); --color-red-600: oklch(57.7% 0.245 27.325); + --color-green-500: oklch(72.3% 0.219 149.579); --color-green-600: oklch(62.7% 0.194 149.214); --color-blue-500: oklch(62.3% 0.214 259.815); - --color-blue-600: oklch(54.6% 0.245 262.881); - --color-slate-500: oklch(55.4% 0.046 257.417); - --color-slate-700: oklch(37.2% 0.044 257.287); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; @@ -22,6 +21,7 @@ --text-sm--line-height: calc(1.25 / 0.875); --text-base: 1rem; --text-base--line-height: calc(1.5 / 1); + --font-weight-normal: 400; --font-weight-semibold: 600; --font-weight-bold: 700; --radius-sm: 0.25rem; @@ -183,6 +183,9 @@ .collapse { visibility: collapse; } + .invisible { + visibility: hidden; + } .visible { visibility: visible; } @@ -198,35 +201,32 @@ .static { position: static; } + .start { + inset-inline-start: var(--spacing); + } + .end { + inset-inline-end: var(--spacing); + } .top-1 { top: calc(var(--spacing) * 1); } .top-1\/2 { - top: calc(1/2 * 100%); + top: calc(1 / 2 * 100%); } .top-2 { top: calc(var(--spacing) * 2); } - .top-\[0\.5px\] { - top: 0.5px; - } .right-2 { right: calc(var(--spacing) * 2); } .right-full { right: 100%; } - .left-1 { - left: calc(var(--spacing) * 1); - } .left-1\.5 { left: calc(var(--spacing) * 1.5); } - .left-1\.25 { - left: calc(var(--spacing) * 1.25); - } .left-1\/2 { - left: calc(1/2 * 100%); + left: calc(1 / 2 * 100%); } .left-full { left: 100%; @@ -279,9 +279,6 @@ .my-2 { margin-block: calc(var(--spacing) * 2); } - .mt-0 { - margin-top: calc(var(--spacing) * 0); - } .mt-0\.5 { margin-top: calc(var(--spacing) * 0.5); } @@ -334,25 +331,14 @@ width: calc(var(--spacing) * 4.5); height: calc(var(--spacing) * 4.5); } - .size-5 { - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - } .size-5\.5 { width: calc(var(--spacing) * 5.5); height: calc(var(--spacing) * 5.5); } - .size-6 { - width: calc(var(--spacing) * 6); - height: calc(var(--spacing) * 6); - } .size-6\.5 { width: calc(var(--spacing) * 6.5); height: calc(var(--spacing) * 6.5); } - .h-4 { - height: calc(var(--spacing) * 4); - } .h-4\.5 { height: calc(var(--spacing) * 4.5); } @@ -365,23 +351,14 @@ .h-screen { height: 100vh; } - .max-h-2 { - max-height: calc(var(--spacing) * 2); - } .max-h-2\/3 { - max-height: calc(2/3 * 100%); - } - .w-2 { - width: calc(var(--spacing) * 2); + max-height: calc(2 / 3 * 100%); } .w-2\/3 { - width: calc(2/3 * 100%); - } - .w-3 { - width: calc(var(--spacing) * 3); + width: calc(2 / 3 * 100%); } .w-3\/4 { - width: calc(3/4 * 100%); + width: calc(3 / 4 * 100%); } .w-full { width: 100%; @@ -389,29 +366,21 @@ .w-screen { width: 100vw; } - .flex-grow { - flex-grow: 1; + .flex-1 { + flex: 1; + } + .shrink-0 { + flex-shrink: 0; } .grow { flex-grow: 1; } - .border-collapse { - border-collapse: collapse; - } - .-translate-x-1 { - --tw-translate-x: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } .-translate-x-1\/2 { - --tw-translate-x: calc(calc(1/2 * 100%) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .-translate-y-1 { - --tw-translate-y: calc(var(--spacing) * -1); + --tw-translate-x: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } .-translate-y-1\/2 { - --tw-translate-y: calc(calc(1/2 * 100%) * -1); + --tw-translate-y: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } .transform { @@ -441,6 +410,9 @@ .justify-center { justify-content: center; } + .gap-1 { + gap: calc(var(--spacing) * 1); + } .space-y-1 { :where(& > :not(:last-child)) { --tw-space-y-reverse: 0; @@ -483,31 +455,17 @@ margin-inline-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse))); } } - .divide-y { - :where(& > :not(:last-child)) { - --tw-divide-y-reverse: 0; - border-bottom-style: var(--tw-border-style); - border-top-style: var(--tw-border-style); - border-top-width: calc(1px * var(--tw-divide-y-reverse)); - border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - } - } - .divide-black { - :where(& > :not(:last-child)) { - border-color: var(--color-black); - } - } - .divide-black\/5 { - :where(& > :not(:last-child)) { - border-color: color-mix(in srgb, #000 5%, transparent); - @supports (color: color-mix(in lab, red, red)) { - border-color: color-mix(in oklab, var(--color-black) 5%, transparent); - } - } - } .self-end { align-self: flex-end; } + .self-stretch { + align-self: stretch; + } + .truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } .overflow-y-auto { overflow-y: auto; } @@ -536,41 +494,14 @@ border-left-style: var(--tw-border-style); border-left-width: 1px; } - .border-black { - border-color: var(--color-black); - } - .border-black\/5 { - border-color: color-mix(in srgb, #000 5%, transparent); - @supports (color: color-mix(in lab, red, red)) { - border-color: color-mix(in oklab, var(--color-black) 5%, transparent); - } - } - .border-blue-600 { - border-color: var(--color-blue-600); - } - .border-green-600 { - border-color: var(--color-green-600); - } - .border-red-600 { - border-color: var(--color-red-600); + .border-blue-500 { + border-color: var(--color-blue-500); } - .border-slate-500 { - border-color: var(--color-slate-500); + .border-green-500 { + border-color: var(--color-green-500); } - .border-slate-500\/50 { - border-color: color-mix(in srgb, oklch(55.4% 0.046 257.417) 50%, transparent); - @supports (color: color-mix(in lab, red, red)) { - border-color: color-mix(in oklab, var(--color-slate-500) 50%, transparent); - } - } - .bg-black { - background-color: var(--color-black); - } - .bg-black\/10 { - background-color: color-mix(in srgb, #000 10%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-black) 10%, transparent); - } + .border-red-500 { + border-color: var(--color-red-500); } .bg-black\/20 { background-color: color-mix(in srgb, #000 20%, transparent); @@ -578,24 +509,6 @@ background-color: color-mix(in oklab, var(--color-black) 20%, transparent); } } - .bg-blue-500 { - background-color: var(--color-blue-500); - } - .bg-white { - background-color: var(--color-white); - } - .bg-white\/30 { - background-color: color-mix(in srgb, #fff 30%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 30%, transparent); - } - } - .bg-white\/70 { - background-color: color-mix(in srgb, #fff 70%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 70%, transparent); - } - } .p-1 { padding: calc(var(--spacing) * 1); } @@ -617,14 +530,11 @@ .py-1 { padding-block: calc(var(--spacing) * 1); } - .pt-0 { - padding-top: calc(var(--spacing) * 0); - } .pt-0\.75 { padding-top: calc(var(--spacing) * 0.75); } - .pr-1 { - padding-right: calc(var(--spacing) * 1); + .pr-0\.5 { + padding-right: calc(var(--spacing) * 0.5); } .pr-1\.5 { padding-right: calc(var(--spacing) * 1.5); @@ -632,23 +542,20 @@ .pr-2 { padding-right: calc(var(--spacing) * 2); } - .pb-1 { - padding-bottom: calc(var(--spacing) * 1); - } .pb-1\.25 { padding-bottom: calc(var(--spacing) * 1.25); } - .pl-1 { - padding-left: calc(var(--spacing) * 1); - } .pl-1\.5 { padding-left: calc(var(--spacing) * 1.5); } + .pl-1\.25 { + padding-left: calc(var(--spacing) * 1.25); + } .pl-5 { padding-left: calc(var(--spacing) * 5); } - .align-middle { - vertical-align: middle; + .text-center { + text-align: center; } .align-top { vertical-align: top; @@ -665,6 +572,9 @@ font-size: var(--text-xs); line-height: var(--tw-leading, var(--text-xs--line-height)); } + .text-\[0\.7rem\] { + font-size: 0.7rem; + } .text-\[0\.65rem\] { font-size: 0.65rem; } @@ -672,6 +582,10 @@ --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); } + .font-normal { + --tw-font-weight: var(--font-weight-normal); + font-weight: var(--font-weight-normal); + } .font-semibold { --tw-font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold); @@ -679,56 +593,32 @@ .whitespace-nowrap { white-space: nowrap; } - .text-black { - color: var(--color-black); - } - .text-black\/50 { - color: color-mix(in srgb, #000 50%, transparent); - @supports (color: color-mix(in lab, red, red)) { - color: color-mix(in oklab, var(--color-black) 50%, transparent); - } - } - .text-black\/70 { - color: color-mix(in srgb, #000 70%, transparent); - @supports (color: color-mix(in lab, red, red)) { - color: color-mix(in oklab, var(--color-black) 70%, transparent); - } - } .text-blue-500 { color: var(--color-blue-500); } .text-blue-500\! { color: var(--color-blue-500) !important; } - .text-blue-600 { - color: var(--color-blue-600); - } - .text-green-600 { - color: var(--color-green-600); + .text-green-500 { + color: var(--color-green-500); } .text-green-600\! { color: var(--color-green-600) !important; } - .text-red-600 { - color: var(--color-red-600); + .text-red-500 { + color: var(--color-red-500); } .text-red-600\! { color: var(--color-red-600) !important; } - .text-slate-700 { - color: var(--color-slate-700); - } - .text-white { - color: var(--color-white); - } .lowercase { text-transform: lowercase; } .uppercase { text-transform: uppercase; } - .underline { - text-decoration-line: underline; + .opacity-40 { + opacity: 40%; } .shadow { --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); @@ -763,10 +653,6 @@ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } - .backdrop-filter { - -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - } .select-none { -webkit-user-select: none; user-select: none; @@ -783,93 +669,71 @@ } } } - .hover\:bg-blue-600 { + .hover\:text-white { &:hover { @media (hover: hover) { - background-color: var(--color-blue-600); + color: var(--color-white); } } } - .hover\:bg-green-600 { + .hover\:opacity-90 { &:hover { @media (hover: hover) { - background-color: var(--color-green-600); + opacity: 90%; } } } - .hover\:bg-red-600 { - &:hover { - @media (hover: hover) { - background-color: var(--color-red-600); - } - } - } - .hover\:bg-white\/20 { - &:hover { - @media (hover: hover) { - background-color: color-mix(in srgb, #fff 20%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 20%, transparent); - } - } - } - } - .hover\:bg-white\/40 { - &:hover { - @media (hover: hover) { - background-color: color-mix(in srgb, #fff 40%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 40%, transparent); - } - } - } +} +:root { + --ui-bg: var(--vscode-sideBar-background, var(--vscode-editor-background, #e8eaf0)); + --ui-fg: var(--vscode-sideBar-foreground, var(--vscode-editor-foreground, #1f1f1f)); + --ui-btn-bg: var(--vscode-button-background, #0078d4); + --ui-btn-fg: var(--vscode-button-foreground, #ffffff); + --ui-btn-hover-bg: var(--vscode-button-hoverBackground, #005fa3); + --ui-popup-bg: var(--vscode-editorWidget-background, var(--vscode-editor-background, #f3f3f3)); + --ui-border: var(--vscode-widget-border, var(--vscode-editorWidget-border, rgba(0,0,0,0.1))); + --icon-filter: none; + --ui-text-primary: var(--ui-fg); + @supports (color: color-mix(in lab, red, red)) { + --ui-text-primary: color-mix(in srgb, var(--ui-fg) 90%, transparent); } - .hover\:bg-white\/50 { - &:hover { - @media (hover: hover) { - background-color: color-mix(in srgb, #fff 50%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 50%, transparent); - } - } - } + --ui-text-secondary: var(--ui-fg); + @supports (color: color-mix(in lab, red, red)) { + --ui-text-secondary: color-mix(in srgb, var(--ui-fg) 70%, transparent); } - .hover\:text-white\/70 { - &:hover { - @media (hover: hover) { - color: color-mix(in srgb, #fff 70%, transparent); - @supports (color: color-mix(in lab, red, red)) { - color: color-mix(in oklab, var(--color-white) 70%, transparent); - } - } - } + --ui-text-muted: var(--ui-fg); + @supports (color: color-mix(in lab, red, red)) { + --ui-text-muted: color-mix(in srgb, var(--ui-fg) 55%, transparent); } - .hover\:brightness-90 { - &:hover { - @media (hover: hover) { - --tw-brightness: brightness(90%); - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - } + --ui-element-bg: var(--ui-fg); + @supports (color: color-mix(in lab, red, red)) { + --ui-element-bg: color-mix(in srgb, var(--ui-fg) 10%, transparent); } - .hover\:brightness-95 { - &:hover { - @media (hover: hover) { - --tw-brightness: brightness(95%); - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - } + --ui-element-bg-hover: var(--ui-fg); + @supports (color: color-mix(in lab, red, red)) { + --ui-element-bg-hover: color-mix(in srgb, var(--ui-fg) 18%, transparent); } + --ui-highlight-text: rgba(255, 255, 255, 0.9); +} +body.vscode-dark, body.vscode-high-contrast { + --icon-filter: invert(1); + --ui-highlight-text: rgba(0, 0, 0, 0.8); } kbd { border-radius: var(--radius-sm); - background-color: color-mix(in srgb, #fff 30%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-white) 30%, transparent); - } padding-inline: calc(var(--spacing) * 1); padding-block: 1px; - color: var(--color-blue-500); + color: var(--vscode-textLink-foreground, #0078d4); + background: var(--ui-bg); + @supports (color: color-mix(in lab, red, red)) { + background: color-mix(in srgb, var(--ui-bg) 70%, transparent); + } +} +#groupButtons, #helpPopup * { + scrollbar-width: none; +} +#groupButtons::-webkit-scrollbar, #helpPopup ::-webkit-scrollbar { + display: none; } @property --tw-translate-x { syntax: "*"; @@ -916,11 +780,6 @@ kbd { inherits: false; initial-value: 0; } -@property --tw-divide-y-reverse { - syntax: "*"; - inherits: false; - initial-value: 0; -} @property --tw-border-style { syntax: "*"; inherits: false; @@ -1102,7 +961,6 @@ kbd { --tw-skew-y: initial; --tw-space-y-reverse: 0; --tw-space-x-reverse: 0; - --tw-divide-y-reverse: 0; --tw-border-style: solid; --tw-font-weight: initial; --tw-shadow: 0 0 #0000; diff --git a/src/VisuManager.ts b/src/VisuManager.ts index f87de08..6627639 100644 --- a/src/VisuManager.ts +++ b/src/VisuManager.ts @@ -120,12 +120,16 @@ export class VisuManager { const testDir = path.resolve(__dirname, ".."); + const commName = path.basename(commUri.fsPath, path.extname(commUri.fsPath)); + const visu = new WebviewVisu( "meshViewer", testDir, "resources/visu_vtk/index.html", fileContexts, objUris.map((uri) => path.basename(uri.fsPath)), + undefined, + commName, ); this.views.set(key, { commUri, objUris, visu }); @@ -144,6 +148,21 @@ export class VisuManager { } public listenCommFiles() { + vscode.window.onDidChangeActiveTextEditor((editor) => { + if (!editor) { + return; + } + const filePath = editor.document.uri.fsPath; + if (!isCommFile(filePath)) { + return; + } + const entry = this.getViewer(editor.document.uri); + if (!entry || entry.visu.panel.active) { + return; + } + entry.visu.panel.reveal(undefined, true); + }); + vscode.window.onDidChangeTextEditorSelection((event) => { const editor = event.textEditor; const filePath = editor.document.uri.fsPath; diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index 32522b7..374aaa3 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -38,7 +38,8 @@ export class WebviewVisu implements vscode.Disposable { htmlFileName: string, fileContexts: string[], objFilenames: string[], - viewColumn?: vscode.ViewColumn + viewColumn?: vscode.ViewColumn, + title?: string ) { viewColumn = viewColumn || vscode.ViewColumn.Beside; @@ -52,9 +53,11 @@ export class WebviewVisu implements vscode.Disposable { // Get HTML file path const htmlFilePath = path.join(resourceRootDir, htmlFileName); - // Extract title from HTML file - let htmlFileContent = fs.readFileSync(htmlFilePath, { encoding: "utf8" }); - const title = this.extractHtmlTitle(htmlFileContent, "Visualizer"); + // Use provided title or fall back to the HTML tag + if (!title) { + const htmlFileContent = fs.readFileSync(htmlFilePath, { encoding: "utf8" }); + title = this.extractHtmlTitle(htmlFileContent, "Visualizer"); + } // Create webview panel with icon this.panel = vscode.window.createWebviewPanel( @@ -63,9 +66,10 @@ export class WebviewVisu implements vscode.Disposable { viewColumn, options ); - this.panel.iconPath = vscode.Uri.file( - path.join(resourceRootDir, "resources", "icons", "3d.svg") - ); + this.panel.iconPath = { + light: vscode.Uri.file(path.join(resourceRootDir, "resources", "icons", "3d.svg")), + dark: vscode.Uri.file(path.join(resourceRootDir, "resources", "icons", "3d_light.svg")), + }; console.log("[WebviewVisu] Webview panel created"); // Set HTML content for the webview From de8a01080d9cb08c0c19f16db5eeba51f7d0ed64 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet <ulysse.bouchet@simvia.tech> Date: Fri, 6 Mar 2026 16:02:31 +0100 Subject: [PATCH 02/20] Improve filter popup --- package.json | 8 + resources/icons/filter.svg | 2 +- resources/icons/settings.svg | 1 + resources/visu_vtk/index.html | 127 +++++-- resources/visu_vtk/index.js | 1 + .../visu_vtk/js/commands/VisibilityManager.js | 33 +- .../visu_vtk/js/settings/GlobalSettings.js | 2 + resources/visu_vtk/js/ui/UIManager.js | 316 +++++++++++++----- resources/visu_vtk/styles.css | 41 ++- resources/visu_vtk/tailwind.css | 117 +++++-- src/WebviewVisu.ts | 14 +- 11 files changed, 521 insertions(+), 141 deletions(-) create mode 100644 resources/icons/settings.svg diff --git a/package.json b/package.json index dae7cf8..6734737 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,14 @@ "default": "python3", "markdownDescription": "Specifies the python executable used to run the language server." }, + "vs-code-aster.viewer.hiddenObjectOpacity": { + "order": 10, + "type": "number", + "default": 0, + "minimum": 0, + "maximum": 0.5, + "markdownDescription": "Opacity of objects hidden via the eye button in the mesh viewer (0 = fully invisible, 0.5 = 50% visible as a ghost)." + }, "vs-code-aster.enableTelemetry": { "order": 100, "type": "boolean", diff --git a/resources/icons/filter.svg b/resources/icons/filter.svg index 3daaa2b..5e25d81 100644 --- a/resources/icons/filter.svg +++ b/resources/icons/filter.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M440-240q-17 0-28.5-11.5T400-280q0-17 11.5-28.5T440-320h80q17 0 28.5 11.5T560-280q0 17-11.5 28.5T520-240h-80ZM280-440q-17 0-28.5-11.5T240-480q0-17 11.5-28.5T280-520h400q17 0 28.5 11.5T720-480q0 17-11.5 28.5T680-440H280ZM160-640q-17 0-28.5-11.5T120-680q0-17 11.5-28.5T160-720h640q17 0 28.5 11.5T840-680q0 17-11.5 28.5T800-640H160Z"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z"/></svg> diff --git a/resources/icons/settings.svg b/resources/icons/settings.svg new file mode 100644 index 0000000..3347a28 --- /dev/null +++ b/resources/icons/settings.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg> diff --git a/resources/visu_vtk/index.html b/resources/visu_vtk/index.html index bbce194..9140fed 100644 --- a/resources/visu_vtk/index.html +++ b/resources/visu_vtk/index.html @@ -25,13 +25,13 @@ <!-- Action buttons --> <div - class="absolute left-full top-1 flex flex-col rounded-r-sm border-l" + class="absolute left-full top-1 flex flex-col items-center rounded-r-sm border-l" style="background: color-mix(in srgb, var(--ui-bg) 85%, transparent); border-color: var(--ui-border)" > <div class="group flex items-center"> <button id="selectGroupsBtn" - class="size-6.5 p-1 cursor-pointer" + class="size-5.5 p-1 cursor-pointer" style="--hover-bg: var(--ui-element-bg)" onmouseover="this.style.background='var(--ui-element-bg)'" onmouseout="this.style.background=''" @@ -99,21 +99,39 @@ </div> </div> - <button - id="helpBtn" - class="absolute right-2 top-2 z-10 p-1.5 rounded-full cursor-pointer group flex items-center" - style="background: color-mix(in srgb, var(--ui-bg) 85%, transparent)" - onmouseover="this.style.background='color-mix(in srgb, var(--ui-bg) 100%, transparent)'" - onmouseout="this.style.background='color-mix(in srgb, var(--ui-bg) 85%, transparent)'" - > - <img class="size-3" src="../icons/question_mark.svg" style="filter: var(--icon-filter)" /> - <span - class="absolute right-full pr-1.5 hidden group-hover:inline whitespace-nowrap" - style="color: var(--ui-text-secondary)" + <!-- Top-right button stack --> + <div class="absolute right-2 top-2 z-10 flex flex-col items-center space-y-1"> + <button + id="settingsBtn" + class="p-1.5 rounded-full cursor-pointer group flex items-center" + style="background: color-mix(in srgb, var(--ui-bg) 85%, transparent)" + onmouseover="this.style.background='color-mix(in srgb, var(--ui-bg) 100%, transparent)'" + onmouseout="this.style.background='color-mix(in srgb, var(--ui-bg) 85%, transparent)'" + > + <img class="size-3" src="../icons/settings.svg" style="filter: var(--icon-filter)" /> + <span + class="absolute right-full pr-1.5 hidden group-hover:inline whitespace-nowrap" + style="color: var(--ui-text-secondary)" + > + Settings + </span> + </button> + <button + id="helpBtn" + class="p-1.5 rounded-full cursor-pointer group flex items-center" + style="background: color-mix(in srgb, var(--ui-bg) 85%, transparent)" + onmouseover="this.style.background='color-mix(in srgb, var(--ui-bg) 100%, transparent)'" + onmouseout="this.style.background='color-mix(in srgb, var(--ui-bg) 85%, transparent)'" > - Help - </span> - </button> + <img class="size-3" src="../icons/question_mark.svg" style="filter: var(--icon-filter)" /> + <span + class="absolute right-full pr-1.5 hidden group-hover:inline whitespace-nowrap" + style="color: var(--ui-text-secondary)" + > + Help + </span> + </button> + </div> <!-- Popup backdrop --> <div @@ -213,39 +231,94 @@ </div> </div> + <!-- Settings Popup --> + <div + id="settingsPopup" + class="hidden! absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 w-2/3 max-h-2/3 rounded shadow-lg backdrop-blur-lg p-8 flex flex-col" + style="background: var(--ui-popup-bg); color: var(--ui-fg); border: 1px solid var(--ui-border)" + > + <span class="font-bold text-base"> Settings </span> + + <div class="flex flex-col space-y-4 mt-4 pr-2 overflow-y-auto grow"> + <!-- Hidden object opacity --> + <div class="flex flex-col space-y-1.5"> + <div class="flex items-center justify-between"> + <label for="hiddenOpacitySlider" class="text-sm font-semibold">Hidden objects opacity</label> + <span id="hiddenOpacityValue" class="text-xs" style="color: var(--ui-text-secondary)">0%</span> + </div> + <input + id="hiddenOpacitySlider" + type="range" + min="0" + max="100" + step="1" + value="0" + class="w-full cursor-pointer accent-current focus:outline-none" + /> + <span class="text-xs" style="color: var(--ui-text-secondary)"> + When hiding an object with the eye button, it can remain slightly visible as a ghost. + </span> + </div> + </div> + + <div class="mt-4 flex justify-between items-center"> + <button + id="resetSettingsBtn" + class="px-3 py-1 rounded-sm cursor-pointer text-sm" + style="background: var(--ui-element-bg); color: var(--ui-fg); border: 1px solid var(--ui-border)" + onmouseover="this.style.background='color-mix(in srgb, var(--ui-fg) 15%, transparent)'" + onmouseout="this.style.background='var(--ui-element-bg)'" + > + Reset defaults + </button> + <button + id="closeSettingsBtn" + class="font-bold px-3 py-1 rounded-sm cursor-pointer" + style="background: var(--ui-btn-bg); color: var(--ui-btn-fg)" + onmouseover="this.style.background='var(--ui-btn-hover-bg)'" + onmouseout="this.style.background='var(--ui-btn-bg)'" + > + Close + </button> + </div> + </div> + <!-- Popup to select group buttons to show --> <div id="groupButtonsPopup" class="hidden! absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 w-2/3 max-h-2/3 rounded shadow-lg backdrop-blur-lg p-8 flex flex-col" style="background: var(--ui-popup-bg); color: var(--ui-fg); border: 1px solid var(--ui-border)" > - <span class="font-bold text-base"> - Select the groups that should be shown in the sidebar - </span> + <div class="flex flex-col mb-4"> + <span class="font-bold text-base">Sidebar groups</span> + <span class="text-xs mt-1" style="color: var(--ui-text-secondary)"> + Choose which groups are shown in the sidebar. Hidden groups remain visible in the 3D view. + </span> + </div> <div id="groupList" - class="flex flex-wrap mt-4 space-x-6 overflow-y-auto grow" + class="columns-2 gap-6 overflow-y-auto grow" ></div> - <div class="flex self-end space-x-3"> + <div class="mt-4 flex justify-between items-center"> <button - id="cancelBtn" - class="px-3 py-1 rounded-sm cursor-pointer" + id="resetGroupsBtn" + class="px-3 py-1 rounded-sm cursor-pointer text-sm" style="background: var(--ui-element-bg); color: var(--ui-fg); border: 1px solid var(--ui-border)" onmouseover="this.style.background='color-mix(in srgb, var(--ui-fg) 15%, transparent)'" - onmouseout="this.style.background='transparent'" + onmouseout="this.style.background='var(--ui-element-bg)'" > - Cancel + Reset </button> <button - id="saveBtn" + id="closeGroupsBtn" class="font-bold px-3 py-1 rounded-sm cursor-pointer" style="background: var(--ui-btn-bg); color: var(--ui-btn-fg)" onmouseover="this.style.background='var(--ui-btn-hover-bg)'" onmouseout="this.style.background='var(--ui-btn-bg)'" > - Save + Close </button> </div> </div> diff --git a/resources/visu_vtk/index.js b/resources/visu_vtk/index.js index 254703a..51c6a97 100644 --- a/resources/visu_vtk/index.js +++ b/resources/visu_vtk/index.js @@ -11,6 +11,7 @@ window.addEventListener("message", async (e) => { // Initialize the visualization with loaded OBJ files case "init": Controller.Instance.loadFiles(body.fileContexts, body.objFilenames); + UIManager.Instance.applySettings(body.settings); break; // Toggle visibility for a specific group and update the UI label diff --git a/resources/visu_vtk/js/commands/VisibilityManager.js b/resources/visu_vtk/js/commands/VisibilityManager.js index 2bfbbaa..9fa9e04 100644 --- a/resources/visu_vtk/js/commands/VisibilityManager.js +++ b/resources/visu_vtk/js/commands/VisibilityManager.js @@ -127,11 +127,20 @@ class VisibilityManager { // Show/hide the file group actor (the full mesh) const fileGroup = this.groups[object]; if (fileGroup) { - fileGroup.actor.setVisibility(nowVisible); if (nowVisible) { - // Restore the correct opacity based on whether any groups are highlighted + // Showing: restore visibility and the correct opacity + fileGroup.actor.setVisibility(true); const opacity = this.visibleGroupsByObject[object] > 0 ? 0.2 : 1.0; fileGroup.setOpacity(opacity); + } else { + // Hiding: use ghost opacity (may be 0 for fully invisible) + const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; + if (hiddenOpacity === 0) { + fileGroup.actor.setVisibility(false); + } else { + fileGroup.actor.setVisibility(true); + fileGroup.setOpacity(hiddenOpacity); + } } } @@ -162,6 +171,26 @@ class VisibilityManager { group.setOpacity(meshOpacity); } + /** + * Re-applies the current hiddenObjectOpacity to all hidden objects. + * Called when the opacity slider value changes. + */ + applyHiddenObjectOpacity() { + const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; + for (const object in this.hiddenObjects) { + if (!this.hiddenObjects[object]) continue; + const fileGroup = this.groups[object]; + if (!fileGroup) continue; + if (hiddenOpacity === 0) { + fileGroup.actor.setVisibility(false); + } else { + fileGroup.actor.setVisibility(true); + fileGroup.setOpacity(hiddenOpacity); + } + } + VtkApp.Instance.getRenderWindow().render(); + } + /** * Resets visibility and transparency for all groups. */ diff --git a/resources/visu_vtk/js/settings/GlobalSettings.js b/resources/visu_vtk/js/settings/GlobalSettings.js index c544404..b5e3561 100644 --- a/resources/visu_vtk/js/settings/GlobalSettings.js +++ b/resources/visu_vtk/js/settings/GlobalSettings.js @@ -35,6 +35,8 @@ class GlobalSettings { selectHelperColor = [1, 1, 1]; // #ffffff selectionPointColor = [1, 0, 0]; // #ff0000 + hiddenObjectOpacity = 0; + get isDark() { return document.body.classList.contains('vscode-dark') || document.body.classList.contains('vscode-high-contrast'); diff --git a/resources/visu_vtk/js/ui/UIManager.js b/resources/visu_vtk/js/ui/UIManager.js index a5a6bfd..a69b598 100644 --- a/resources/visu_vtk/js/ui/UIManager.js +++ b/resources/visu_vtk/js/ui/UIManager.js @@ -37,10 +37,14 @@ class UIManager { selectGroupsBtn.addEventListener("click", () => { this.openGroupButtonsPopup(); }); - const saveBtn = document.getElementById("saveBtn"); - saveBtn.addEventListener("click", this.saveGroupButtonsPopup); - const cancelBtn = document.getElementById("cancelBtn"); - cancelBtn.addEventListener("click", this.cancelGroupButtonsPopup); + const closeGroupsBtn = document.getElementById("closeGroupsBtn"); + closeGroupsBtn.addEventListener("click", () => { + this.closeGroupButtonsPopup(); + }); + const resetGroupsBtn = document.getElementById("resetGroupsBtn"); + resetGroupsBtn.addEventListener("click", () => { + this.resetGroupButtonsPopup(); + }); // Camera axis buttons, to allow quick camera control const xBtn = document.getElementById("xBtn"); @@ -56,6 +60,36 @@ class UIManager { CameraManager.Instance.setCameraAxis("z"); }); + // Settings popup + const settingsBtn = document.getElementById("settingsBtn"); + settingsBtn.addEventListener("click", () => { + this.openSettingsPopup(); + }); + const closeSettingsBtn = document.getElementById("closeSettingsBtn"); + closeSettingsBtn.addEventListener("click", () => { + this.closeSettingsPopup(); + }); + const resetSettingsBtn = document.getElementById("resetSettingsBtn"); + resetSettingsBtn.addEventListener("click", () => { + this.resetSettings(); + }); + + // Hidden object opacity slider + const hiddenOpacitySlider = document.getElementById("hiddenOpacitySlider"); + const hiddenOpacityValue = document.getElementById("hiddenOpacityValue"); + hiddenOpacitySlider.addEventListener("input", () => { + const raw = parseInt(hiddenOpacitySlider.value, 10); + const pct = Math.min(raw, 50); + hiddenOpacitySlider.value = pct; + hiddenOpacityValue.textContent = `${pct}%`; + GlobalSettings.Instance.hiddenObjectOpacity = pct / 100; + VisibilityManager.Instance.applyHiddenObjectOpacity(); + Controller.Instance.getVSCodeAPI().postMessage({ + type: "saveSettings", + settings: { hiddenObjectOpacity: GlobalSettings.Instance.hiddenObjectOpacity }, + }); + }); + // Help popup const helpBtn = document.getElementById("helpBtn"); helpBtn.addEventListener("click", () => { @@ -112,7 +146,7 @@ class UIManager { const colorCss = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; const objSvgPath = "M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"; const icon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" class="size-4.5 shrink-0 mt-0.5" fill="${colorCss}"><path d="${objSvgPath}"/></svg>`; - const text = `<span id="objName_${object}" class="flex-1 truncate text-center px-2 cursor-pointer">${objectName}</span>`; + const text = `<span id="objName_${object}" class="flex-1 truncate text-center px-2 cursor-pointer select-none">${objectName}</span>`; const eyeBtn = `<button id="eyeBtn_${object}" title="Hide/show mesh" class="size-4.5 shrink-0 flex items-center justify-center cursor-pointer opacity-40 hover:opacity-90"><img id="eyeIcon_${object}" src="${eyeIconUrl}" class="size-4 block mt-0.5" style="filter: var(--icon-filter)"></button>`; objectLabel.innerHTML = icon + text + eyeBtn; @@ -136,15 +170,19 @@ class UIManager { groupCountEl.style.color = "var(--ui-text-muted)"; groupCountEl.textContent = `${groupCount} groups`; - // Name span toggles group container visibility + // Name span toggles group container visibility (disabled when all groups are hidden) document.getElementById(`objName_${object}`).addEventListener("click", () => { + const grpHidden = document.getElementById(`grpHidden_${object}`); + const allHidden = grpHidden && !grpHidden.classList.contains("hidden!") && + [...groupContainer.querySelectorAll(`[id^="btn_${object}::"]`)].every(b => b.classList.contains("hidden!")); + if (allHidden) { return; } const collapsed = groupContainer.classList.toggle("hidden!"); groupCountEl.classList.toggle("hidden!", !collapsed); }); // Create group buttons for the current object - const groups = faces.concat(nodes); - groups.forEach((groupName) => { + const groupNames = faces.concat(nodes); + groupNames.forEach((groupName) => { const btn = document.createElement("button"); btn.id = `btn_${object}::${groupName}`; btn.classList.add( @@ -184,6 +222,13 @@ class UIManager { groupContainer.appendChild(btn); }); + // Small label showing how many groups are hidden from the sidebar + const grpHiddenEl = document.createElement("div"); + grpHiddenEl.id = `grpHidden_${object}`; + grpHiddenEl.classList.add("hidden!", "w-full", "text-center", "text-[0.7rem]", "pb-1"); + grpHiddenEl.style.color = "var(--ui-text-muted)"; + groupContainer.appendChild(grpHiddenEl); + groupButtonsDiv.appendChild(groupContainer); groupButtonsDiv.appendChild(groupCountEl); } @@ -199,13 +244,11 @@ class UIManager { const btn = document.getElementById(`btn_${groupName}`); if (color) { - // If the button was not highlighted, highlight it btn.classList.add("font-semibold"); btn.dataset.highlighted = "1"; btn.style.background = `rgb(${color[0] * 255}, ${color[1] * 255}, ${color[2] * 255}, 0.8)`; btn.style.color = "var(--ui-highlight-text)"; } else { - // Else unapply the highlight btn.classList.remove("font-semibold"); delete btn.dataset.highlighted; btn.style.background = "var(--ui-element-bg)"; @@ -218,32 +261,140 @@ class UIManager { * @param {Map <string, { faces: [], nodes: [] }>} objects A map of objects with their corresponding face and node groups. */ initGroupButtonsPopup(objects) { - // Get group list inside the popup const groupList = document.getElementById("groupList"); - // Add buttons for each object and its groups + + const faceSvgPath = "M161-366q-16-12-15.5-31.5T162-429q11-8 24-8t24 8l270 209 270-209q11-8 24-8t24 8q16 12 16.5 31.5T799-366L529-156q-22 17-49 17t-49-17L161-366Zm270 8L201-537q-31-24-31-63t31-63l230-179q22-17 49-17t49 17l230 179q31 24 31 63t-31 63L529-358q-22 17-49 17t-49-17Zm49-64 230-178-230-178-230 178 230 178Zm0-178Z"; + const nodeSvgPath = "M580-120q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Zm0-80q17 0 28.5-11.5T620-240q0-17-11.5-28.5T580-280q-17 0-28.5 11.5T540-240q0 17 11.5 28.5T580-200Zm80-200q-92 0-156-64t-64-156q0-92 64-156t156-64q92 0 156 64t64 156q0 92-64 156t-156 64Zm0-80q59 0 99.5-40.5T800-620q0-59-40.5-99.5T660-760q-59 0-99.5 40.5T520-620q0 59 40.5 99.5T660-480ZM280-240q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T360-400q0-33-23.5-56.5T280-480q-33 0-56.5 23.5T200-400q0 33 23.5 56.5T280-320Zm300 80Zm80-380ZM280-400Z"; + const objSvgPath = "M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"; + const makeSvg = (path, fill, cls) => { + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("viewBox", "0 -960 960 960"); + svg.setAttribute("fill", fill); + svg.classList.add(...cls.split(" ")); + const p = document.createElementNS("http://www.w3.org/2000/svg", "path"); + p.setAttribute("d", path); + svg.appendChild(p); + return svg; + }; + for (const object in objects) { const { faces, nodes } = objects[object]; const objectName = object.replace("all_", "").replace(".obj", ""); - // Create object div + const [r, g, b] = objects[object].color ?? [0.537, 0.529, 0.529]; + const colorCss = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; + const objectDiv = document.createElement("div"); - objectDiv.classList.add("flex", "flex-col", "space-y-1", "mb-4"); + objectDiv.classList.add("break-inside-avoid", "flex", "flex-col", "space-y-1.5", "mb-5"); objectDiv.dataset.object = object; - // Create object label - const objectLabel = `<span class="font-semibold text-sm">${objectName}</span>`; - objectDiv.innerHTML += objectLabel; + // Object header with select-all toggle + const header = document.createElement("div"); + header.classList.add("flex", "items-center", "justify-between", "pb-1"); + header.style.borderBottom = "1px solid var(--ui-border)"; + + const nameGroup = document.createElement("div"); + nameGroup.classList.add("flex", "items-center", "gap-1.5"); + nameGroup.appendChild(makeSvg(objSvgPath, colorCss, "size-4 shrink-0")); + + const nameSpan = document.createElement("span"); + nameSpan.classList.add("font-semibold", "text-sm"); + nameSpan.textContent = objectName; + nameGroup.appendChild(nameSpan); + + const toggleAll = document.createElement("button"); + toggleAll.classList.add("text-xs", "leading-none", "cursor-pointer", "px-1.5", "py-0.5", "rounded-sm"); + toggleAll.style.color = "var(--ui-text-secondary)"; + toggleAll.addEventListener("mouseover", () => { toggleAll.style.background = "var(--ui-element-bg)"; }); + toggleAll.addEventListener("mouseout", () => { toggleAll.style.background = ""; }); + toggleAll.textContent = "Hide all"; + + header.appendChild(nameGroup); + header.appendChild(toggleAll); + objectDiv.appendChild(header); - // Create group checkboxes for the current object + // Group checkboxes const groups = faces.concat(nodes); groups.forEach((groupName) => { - const label = `<label class="flex items-center space-x-1 cursor-pointer select-none"> - <input class="mt-0.5" type="checkbox" checked /> - <span class="text-xs"> ${groupName} </span> - </label>`; - objectDiv.innerHTML += label; + const label = document.createElement("label"); + label.classList.add("flex", "items-center", "gap-1.5", "cursor-pointer", "select-none"); + + const input = document.createElement("input"); + input.type = "checkbox"; + input.checked = true; + input.classList.add("custom-cb"); + input.addEventListener("change", () => { + this.applyGroupVisibility(object, objectDiv); + toggleAll.textContent = this.allUnchecked(objectDiv) ? "Show all" : "Hide all"; + }); + + const isFace = faces.includes(groupName); + const groupIcon = makeSvg(isFace ? faceSvgPath : nodeSvgPath, "currentColor", "size-3.5 shrink-0"); + + const span = document.createElement("span"); + span.classList.add("text-xs", "truncate", "-translate-y-px"); + span.textContent = groupName; + + label.appendChild(input); + label.appendChild(groupIcon); + label.appendChild(span); + objectDiv.appendChild(label); + }); + + toggleAll.addEventListener("click", () => { + const allOff = this.allUnchecked(objectDiv); + objectDiv.querySelectorAll("input[type=checkbox]").forEach((cb) => { cb.checked = allOff; }); + this.applyGroupVisibility(object, objectDiv); + toggleAll.textContent = allOff ? "Hide all" : "Show all"; }); - groupList.append(objectDiv); + + groupList.appendChild(objectDiv); + } + } + + /** + * Returns true if all checkboxes in the given object div are unchecked. + * @param {HTMLElement} objectDiv + */ + allUnchecked(objectDiv) { + return [...objectDiv.querySelectorAll("input[type=checkbox]")].every((cb) => !cb.checked); + } + + /** + * Apply checkbox state to sidebar button visibility for one object. + * @param {string} objectKey + * @param {string} objectName + * @param {HTMLElement} objectDiv + */ + applyGroupVisibility(objectKey, objectDiv) { + let hiddenCount = 0; + objectDiv.querySelectorAll("label").forEach((label) => { + const input = label.querySelector("input"); + const span = label.querySelector("span"); + const btn = document.getElementById(`btn_${objectKey}::${span.textContent.trim()}`); + if (input.checked) { + btn.classList.remove("hidden!"); + } else { + btn.classList.add("hidden!"); + hiddenCount++; + } + }); + + const grpHiddenEl = document.getElementById(`grpHidden_${objectKey}`); + if (grpHiddenEl) { + if (hiddenCount > 0) { + grpHiddenEl.textContent = `${hiddenCount} hidden`; + grpHiddenEl.classList.remove("hidden!"); + } else { + grpHiddenEl.classList.add("hidden!"); + } + } + + // Update name span cursor: not collapsible when all groups are hidden + const allHidden = hiddenCount === objectDiv.querySelectorAll("label").length; + const nameSpan = document.getElementById(`objName_${objectKey}`); + if (nameSpan) { + nameSpan.style.cursor = allHidden ? "default" : ""; } } @@ -258,52 +409,23 @@ class UIManager { } /** - * Save group visibility in the sidebar. All checked groups will be visible, while unchecked groups will be hidden. - * If all the groups from an object are hidden, the object is also hidden from the sidebar. - * Hidden groups are still visible on the 3D view, they are just hidden from the sidebar. + * Reset all group checkboxes to checked (show all groups in sidebar). */ - saveGroupButtonsPopup() { + resetGroupButtonsPopup() { const groupList = document.getElementById("groupList"); - - // Parse all objects - for (let i = 0; i < groupList.children.length; ++i) { - const objectDiv = groupList.children.item(i); - - // Retrieve current object name and key - const objectNameSpan = objectDiv.querySelector("span.font-semibold"); - const objectName = objectNameSpan.textContent.trim(); + for (const objectDiv of groupList.children) { const objectKey = objectDiv.dataset.object; - let allGroupsHidden = true; - - // Parse all labels for the current object - const labels = objectDiv.querySelectorAll("label"); - labels.forEach((label) => { - const input = label.querySelector("input"); - const span = label.querySelector("span"); - - // Retrieve group name - const groupName = span.textContent.trim(); - - // Hide or show group in the sidebar - const btn = document.getElementById(`btn_${objectKey}::${groupName}`); - if (input.checked) { - btn.classList.remove("hidden!"); - allGroupsHidden = false; - } else { - btn.classList.add("hidden!"); - } - }); - - // Retrieve object label from the sidebar - const objectLabel = document.getElementById(`obj_${objectName}`); - if (allGroupsHidden) { - objectLabel.classList.add("hidden!"); - } else { - objectLabel.classList.remove("hidden!"); - } + objectDiv.querySelectorAll("input[type=checkbox]").forEach((cb) => { cb.checked = true; }); + this.applyGroupVisibility(objectKey, objectDiv); + const toggleAll = objectDiv.querySelector("button"); + if (toggleAll) { toggleAll.textContent = "Hide all"; } } + } - // Close popup + /** + * Close the group buttons popup + */ + closeGroupButtonsPopup() { const popup = document.getElementById("popup"); const groupButtonsPopup = document.getElementById("groupButtonsPopup"); popup.classList.add("hidden!"); @@ -311,36 +433,52 @@ class UIManager { } /** - * Cancel the popup actions. - * Checked status will be reset to what they were before opening, and no additional buttons will be shown or hidden. + * Reset all settings to their default values, apply them, and save them. */ - cancelGroupButtonsPopup() { - const groupList = document.getElementById("groupList"); - - // Reset checked status for each group to what they were before opening the popup - for (let i = 0; i < groupList.children.length; ++i) { - const objectDiv = groupList.children.item(i); - const labels = objectDiv.querySelectorAll("label"); - - const objectKey = objectDiv.dataset.object; - labels.forEach((label) => { - const input = label.querySelector("input"); - const span = label.querySelector("span"); - - // Retrieve group name - const groupName = span.textContent.trim(); + resetSettings() { + this.applySettings({ hiddenObjectOpacity: 0 }); + VisibilityManager.Instance.applyHiddenObjectOpacity(); + Controller.Instance.getVSCodeAPI().postMessage({ + type: "saveSettings", + settings: { hiddenObjectOpacity: 0 }, + }); + } - // Set the checkbox state based on the button's visibility, since it did not change - const btn = document.getElementById(`btn_${objectKey}::${groupName}`); - input.checked = !btn.classList.contains("hidden!"); - }); + /** + * Apply settings received from the extension to the UI and runtime state. + * @param {Object} settings + */ + applySettings(settings) { + if (!settings) { return; } + + if (settings.hiddenObjectOpacity !== undefined) { + const pct = Math.round(settings.hiddenObjectOpacity * 100); + const slider = document.getElementById("hiddenOpacitySlider"); + const label = document.getElementById("hiddenOpacityValue"); + slider.value = pct; + label.textContent = `${pct}%`; + GlobalSettings.Instance.hiddenObjectOpacity = settings.hiddenObjectOpacity; } + } - // Close popup + /** + * Open the settings popup + */ + openSettingsPopup() { const popup = document.getElementById("popup"); - const groupButtonsPopup = document.getElementById("groupButtonsPopup"); + const settingsPopup = document.getElementById("settingsPopup"); + popup.classList.remove("hidden!"); + settingsPopup.classList.remove("hidden!"); + } + + /** + * Close the settings popup + */ + closeSettingsPopup() { + const popup = document.getElementById("popup"); + const settingsPopup = document.getElementById("settingsPopup"); popup.classList.add("hidden!"); - groupButtonsPopup.classList.add("hidden!"); + settingsPopup.classList.add("hidden!"); } /** diff --git a/resources/visu_vtk/styles.css b/resources/visu_vtk/styles.css index 1ea9b2c..69b94a7 100644 --- a/resources/visu_vtk/styles.css +++ b/resources/visu_vtk/styles.css @@ -36,12 +36,49 @@ kbd { background: color-mix(in srgb, var(--ui-bg) 70%, transparent); } +input[type="checkbox"].custom-cb:focus { + outline: none; +} + +input[type="checkbox"].custom-cb { + appearance: none; + width: 13px; + height: 13px; + flex-shrink: 0; + border-radius: 3px; + border: 1.5px solid var(--ui-text-secondary); + cursor: pointer; + position: relative; + transition: background 0.1s, border-color 0.1s; +} + +input[type="checkbox"].custom-cb:checked { + background: var(--ui-btn-bg); + border-color: var(--ui-btn-bg); +} + +input[type="checkbox"].custom-cb:checked::after { + content: ''; + position: absolute; + inset: 0; + margin: auto; + width: 4px; + height: 7px; + border-right: 1.5px solid var(--ui-btn-fg); + border-bottom: 1.5px solid var(--ui-btn-fg); + transform: translateY(-1px) rotate(45deg); +} + #groupButtons, -#helpPopup * { +#helpPopup *, +#groupList, +#settingsPopup .overflow-y-auto { scrollbar-width: none; } #groupButtons::-webkit-scrollbar, -#helpPopup ::-webkit-scrollbar { +#helpPopup ::-webkit-scrollbar, +#groupList::-webkit-scrollbar, +#settingsPopup .overflow-y-auto::-webkit-scrollbar { display: none; } diff --git a/resources/visu_vtk/tailwind.css b/resources/visu_vtk/tailwind.css index 9e81726..4c0f6b3 100644 --- a/resources/visu_vtk/tailwind.css +++ b/resources/visu_vtk/tailwind.css @@ -282,6 +282,9 @@ .mt-0\.5 { margin-top: calc(var(--spacing) * 0.5); } + .mt-1 { + margin-top: calc(var(--spacing) * 1); + } .mt-4 { margin-top: calc(var(--spacing) * 4); } @@ -291,6 +294,9 @@ .mb-4 { margin-bottom: calc(var(--spacing) * 4); } + .mb-5 { + margin-bottom: calc(var(--spacing) * 5); + } .block { display: block; } @@ -323,6 +329,10 @@ width: calc(var(--spacing) * 3); height: calc(var(--spacing) * 3); } + .size-3\.5 { + width: calc(var(--spacing) * 3.5); + height: calc(var(--spacing) * 3.5); + } .size-4 { width: calc(var(--spacing) * 4); height: calc(var(--spacing) * 4); @@ -383,6 +393,10 @@ --tw-translate-y: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } + .-translate-y-px { + --tw-translate-y: -1px; + translate: var(--tw-translate-x) var(--tw-translate-y); + } .transform { transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); } @@ -398,21 +412,33 @@ .list-disc { list-style-type: disc; } + .columns-2 { + columns: 2; + } + .break-inside-avoid { + break-inside: avoid; + } .flex-col { flex-direction: column; } - .flex-wrap { - flex-wrap: wrap; - } .items-center { align-items: center; } + .justify-between { + justify-content: space-between; + } .justify-center { justify-content: center; } .gap-1 { gap: calc(var(--spacing) * 1); } + .gap-1\.5 { + gap: calc(var(--spacing) * 1.5); + } + .gap-6 { + gap: calc(var(--spacing) * 6); + } .space-y-1 { :where(& > :not(:last-child)) { --tw-space-y-reverse: 0; @@ -420,18 +446,18 @@ margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse))); } } - .space-y-4 { + .space-y-1\.5 { :where(& > :not(:last-child)) { --tw-space-y-reverse: 0; - margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); - margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + margin-block-start: calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse))); } } - .space-x-1 { + .space-y-4 { :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); } } .space-x-1\.5 { @@ -448,13 +474,6 @@ margin-inline-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse))); } } - .space-x-6 { - :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 6) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse))); - } - } .self-end { align-self: flex-end; } @@ -521,12 +540,18 @@ .p-8 { padding: calc(var(--spacing) * 8); } + .px-1\.5 { + padding-inline: calc(var(--spacing) * 1.5); + } .px-2 { padding-inline: calc(var(--spacing) * 2); } .px-3 { padding-inline: calc(var(--spacing) * 3); } + .py-0\.5 { + padding-block: calc(var(--spacing) * 0.5); + } .py-1 { padding-block: calc(var(--spacing) * 1); } @@ -542,6 +567,9 @@ .pr-2 { padding-right: calc(var(--spacing) * 2); } + .pb-1 { + padding-bottom: calc(var(--spacing) * 1); + } .pb-1\.25 { padding-bottom: calc(var(--spacing) * 1.25); } @@ -578,6 +606,10 @@ .text-\[0\.65rem\] { font-size: 0.65rem; } + .leading-none { + --tw-leading: 1; + line-height: 1; + } .font-bold { --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); @@ -617,6 +649,9 @@ .uppercase { text-transform: uppercase; } + .accent-current { + accent-color: currentcolor; + } .opacity-40 { opacity: 40%; } @@ -653,6 +688,10 @@ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } + .select-all { + -webkit-user-select: all; + user-select: all; + } .select-none { -webkit-user-select: none; user-select: none; @@ -683,6 +722,12 @@ } } } + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; + } + } } :root { --ui-bg: var(--vscode-sideBar-background, var(--vscode-editor-background, #e8eaf0)); @@ -729,10 +774,39 @@ kbd { background: color-mix(in srgb, var(--ui-bg) 70%, transparent); } } -#groupButtons, #helpPopup * { +input[type="checkbox"].custom-cb:focus { + outline: none; +} +input[type="checkbox"].custom-cb { + appearance: none; + width: 13px; + height: 13px; + flex-shrink: 0; + border-radius: 3px; + border: 1.5px solid var(--ui-text-secondary); + cursor: pointer; + position: relative; + transition: background 0.1s, border-color 0.1s; +} +input[type="checkbox"].custom-cb:checked { + background: var(--ui-btn-bg); + border-color: var(--ui-btn-bg); +} +input[type="checkbox"].custom-cb:checked::after { + content: ''; + position: absolute; + inset: 0; + margin: auto; + width: 4px; + height: 7px; + border-right: 1.5px solid var(--ui-btn-fg); + border-bottom: 1.5px solid var(--ui-btn-fg); + transform: translateY(-1px) rotate(45deg); +} +#groupButtons, #helpPopup *, #groupList, #settingsPopup .overflow-y-auto { scrollbar-width: none; } -#groupButtons::-webkit-scrollbar, #helpPopup ::-webkit-scrollbar { +#groupButtons::-webkit-scrollbar, #helpPopup ::-webkit-scrollbar, #groupList::-webkit-scrollbar, #settingsPopup .overflow-y-auto::-webkit-scrollbar { display: none; } @property --tw-translate-x { @@ -785,6 +859,10 @@ kbd { inherits: false; initial-value: solid; } +@property --tw-leading { + syntax: "*"; + inherits: false; +} @property --tw-font-weight { syntax: "*"; inherits: false; @@ -962,6 +1040,7 @@ kbd { --tw-space-y-reverse: 0; --tw-space-x-reverse: 0; --tw-border-style: solid; + --tw-leading: initial; --tw-font-weight: initial; --tw-shadow: 0 0 #0000; --tw-shadow-color: initial; diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index 374aaa3..6bde615 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -88,12 +88,24 @@ export class WebviewVisu implements vscode.Disposable { console.log("[WebviewVisu] Webview ready signal received"); if (objFilenames) { console.log("[WebviewVisu] Sending init with files:", objFilenames); + const config = vscode.workspace.getConfiguration("vs-code-aster"); + const settings = { + hiddenObjectOpacity: config.get<number>("viewer.hiddenObjectOpacity", 0), + }; this.panel.webview.postMessage({ type: "init", - body: { fileContexts, objFilenames }, + body: { fileContexts, objFilenames, settings }, }); } break; + case "saveSettings": + // Persist viewer settings back to VS Code configuration + vscode.workspace.getConfiguration("vs-code-aster").update( + "viewer.hiddenObjectOpacity", + e.settings.hiddenObjectOpacity, + vscode.ConfigurationTarget.Global + ); + break; case "debugPanel": // Log debug messages from the webview console.log("[WebviewVisu] Message received from webview:", e.text); From e1c36ffb1de83911f1b5d43568f355186d2e71dc Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet <ulysse.bouchet@simvia.tech> Date: Fri, 6 Mar 2026 18:26:25 +0100 Subject: [PATCH 03/20] Improve zoom and rendering options --- package.json | 13 ++ resources/visu_vtk/index.html | 59 ++++++++ resources/visu_vtk/js/core/VtkApp.js | 6 + resources/visu_vtk/js/data/CreateGroups.js | 8 +- resources/visu_vtk/js/data/Group.js | 44 +++++- .../js/data/create/FaceActorCreator.js | 17 ++- .../visu_vtk/js/interaction/CameraManager.js | 65 ++++++++- .../visu_vtk/js/settings/GlobalSettings.js | 2 + resources/visu_vtk/js/ui/CustomDropdown.js | 118 ++++++++++++++++ resources/visu_vtk/js/ui/UIManager.js | 100 +++++++++++++- resources/visu_vtk/tailwind.css | 127 ++++++++++++++++++ src/WebviewVisu.ts | 20 ++- 12 files changed, 557 insertions(+), 22 deletions(-) create mode 100644 resources/visu_vtk/js/ui/CustomDropdown.js diff --git a/package.json b/package.json index 6734737..ef73c32 100644 --- a/package.json +++ b/package.json @@ -156,6 +156,19 @@ "maximum": 0.5, "markdownDescription": "Opacity of objects hidden via the eye button in the mesh viewer (0 = fully invisible, 0.5 = 50% visible as a ghost)." }, + "vs-code-aster.viewer.edgeMode": { + "order": 11, + "type": "string", + "default": "threshold", + "enum": ["gradual", "threshold", "show", "hide"], + "enumDescriptions": [ + "Edges fade in as you zoom in, scaled by mesh density. When zoomed out, large meshes may appear very flat as outer edges are mostly hidden. Performance is impacted.", + "Edges appear abruptly at a zoom level based on mesh density. When zoomed out, large meshes may appear slightly flat as outer edges are hidden. Performance is not impacted.", + "Edges are always visible. Large meshes will appear almost entirely black when zoomed out. Performance is impacted.", + "Edges are always hidden. All shapes will look slightly flat regardless of zoom level or mesh size." + ], + "markdownDescription": "Controls how mesh edges are displayed in the viewer." + }, "vs-code-aster.enableTelemetry": { "order": 100, "type": "boolean", diff --git a/resources/visu_vtk/index.html b/resources/visu_vtk/index.html index 9140fed..b5c2eed 100644 --- a/resources/visu_vtk/index.html +++ b/resources/visu_vtk/index.html @@ -133,6 +133,32 @@ </button> </div> + <!-- Zoom indicator --> + <div + id="zoomWidget" + class="absolute bottom-2 z-10 -translate-x-1/2 flex items-center gap-1.5 px-2.5 py-1 rounded-full" + style="left: 50%; background: color-mix(in srgb, var(--ui-bg) 85%, transparent); border: 1px solid var(--ui-border)" + > + <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: var(--ui-text-secondary)"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="11" x2="11" y1="8" y2="14"/><line x1="8" x2="14" y1="11" y2="11"/></svg> + <div + id="zoomTrigger" + class="cursor-pointer select-none px-1 py-0.5 rounded" + style="color: var(--ui-text-secondary)" + onmouseover="this.style.background='color-mix(in srgb, var(--ui-fg) 7%, transparent)'" + onmouseout="this.style.background=''" + > + <span id="zoomIndicator" class="text-xs font-mono">1.0×</span> + </div> + <button + id="resetZoomBtn" + title="Reset zoom" + class="hidden! size-3.5 cursor-pointer flex items-center justify-center opacity-50 hover:opacity-100" + style="color: var(--ui-fg)" + > + <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg> + </button> + </div> + <!-- Popup backdrop --> <div id="popup" @@ -240,6 +266,38 @@ <span class="font-bold text-base"> Settings </span> <div class="flex flex-col space-y-4 mt-4 pr-2 overflow-y-auto grow"> + <!-- Edge display mode --> + <div class="flex flex-col space-y-1.5"> + <label for="edgeModeSelect" class="text-sm font-semibold">Edge display</label> + <div + id="edgeModeSelect" + class="w-full text-xs px-2 py-1.5 rounded-sm cursor-pointer flex items-center justify-between gap-2 select-none" + style="background: var(--ui-element-bg); color: var(--ui-fg); border: 1px solid var(--ui-border)" + onmouseover="this.style.background='var(--ui-element-bg-hover)'" + onmouseout="this.style.background='var(--ui-element-bg)'" + > + <span id="edgeModeSelectLabel" class="truncate">Show edges when zooming (threshold)</span> + <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 opacity-60"><polyline points="6 9 12 15 18 9"/></svg> + </div> + <span id="edgeModeDesc" class="text-xs" style="color: var(--ui-text-secondary)"></span> + <div id="edgeThresholdSection" class="hidden! flex flex-col space-y-1.5 pt-0.5"> + <div class="flex items-center justify-between"> + <label for="edgeThresholdSlider" class="text-xs font-medium">Threshold sensitivity</label> + <span id="edgeThresholdValue" class="text-xs" style="color: var(--ui-text-secondary)">1×</span> + </div> + <input + id="edgeThresholdSlider" + type="range" + min="25" + max="500" + step="5" + value="100" + class="w-full cursor-pointer accent-current focus:outline-none" + /> + <span class="text-xs" style="color: var(--ui-text-secondary)">Higher values show edges from farther away.</span> + </div> + </div> + <!-- Hidden object opacity --> <div class="flex flex-col space-y-1.5"> <div class="flex items-center justify-between"> @@ -347,6 +405,7 @@ <script src="./js/interaction/CameraManager.js"></script> <script src="./js/interaction/AxesCreator.js"></script> <script src="./js/commands/VisibilityManager.js"></script> + <script src="./js/ui/CustomDropdown.js"></script> <script src="./js/ui/UIManager.js"></script> <script src="./js/Controller.js"></script> diff --git a/resources/visu_vtk/js/core/VtkApp.js b/resources/visu_vtk/js/core/VtkApp.js index 422e241..8b75979 100644 --- a/resources/visu_vtk/js/core/VtkApp.js +++ b/resources/visu_vtk/js/core/VtkApp.js @@ -61,12 +61,18 @@ class VtkApp { /** * Offsets the camera so the scene appears centered in the area to the right of the sidebar. + * Also repositions the zoom widget to the center of that same area. */ updateCameraOffset() { const sidebarWidth = document.getElementById("controls").offsetWidth; const offset = sidebarWidth / window.innerWidth; this.renderer.getActiveCamera().setWindowCenter(-offset, 0); this.renderWindow.render(); + + const zoomWidget = document.getElementById("zoomWidget"); + if (zoomWidget) { + zoomWidget.style.left = `${sidebarWidth + (window.innerWidth - sidebarWidth) / 2}px`; + } } /** @returns {vtkRenderer} The VTK renderer */ diff --git a/resources/visu_vtk/js/data/CreateGroups.js b/resources/visu_vtk/js/data/CreateGroups.js index 2ac7a10..f28f31a 100644 --- a/resources/visu_vtk/js/data/CreateGroups.js +++ b/resources/visu_vtk/js/data/CreateGroups.js @@ -50,9 +50,9 @@ class CreateGroups { const objColor = _oc[GlobalSettings.Instance.objIndex % _oc.length]; groupHierarchy[fileGroup].color = objColor; - const { actor, colorIndex: fileColorIndex, isObjectActor: fileIsObj } = FaceActorCreato.create(fileGroup, groupId); + const { actor, colorIndex: fileColorIndex, isObjectActor: fileIsObj, cellCount: fileCellCount } = FaceActorCreato.create(fileGroup, groupId); - const groupInstance = new Group(actor, fileGroup, true, null, null, fileColorIndex, fileIsObj); + const groupInstance = new Group(actor, fileGroup, true, null, null, fileColorIndex, fileIsObj, fileCellCount); this.groups[fileGroup] = groupInstance; @@ -61,9 +61,9 @@ class CreateGroups { for (const faceGroup of groupHierarchy[fileGroup].faces) { const groupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}`); - const { actor: faceActor, colorIndex: faceColorIndex, isObjectActor: faceIsObj } = FaceActorCreato.create(faceGroup, groupId); + const { actor: faceActor, colorIndex: faceColorIndex, isObjectActor: faceIsObj, cellCount: faceCellCount } = FaceActorCreato.create(faceGroup, groupId); - const subGroup = new Group(faceActor, faceGroup, true, fileGroup, size, faceColorIndex, faceIsObj); + const subGroup = new Group(faceActor, faceGroup, true, fileGroup, size, faceColorIndex, faceIsObj, faceCellCount); this.groups[`${fileGroup}::${faceGroup}`] = subGroup; } diff --git a/resources/visu_vtk/js/data/Group.js b/resources/visu_vtk/js/data/Group.js index 03a8f7c..780583e 100644 --- a/resources/visu_vtk/js/data/Group.js +++ b/resources/visu_vtk/js/data/Group.js @@ -10,7 +10,7 @@ class Group { * @param {string|null} fileGroup - Parent fileGroup name (null if this is a fileGroup) * @param {number|null} parentSize - Size of the parent fileGroup (null if this is a fileGroup) */ - constructor(actor, name, isFaceGroup, fileGroup = null, parentSize = null, colorIndex = null, isObjectActor = false) { + constructor(actor, name, isFaceGroup, fileGroup = null, parentSize = null, colorIndex = null, isObjectActor = false, cellCount = null) { this.actor = actor; this.name = name; this.isFaceGroup = isFaceGroup; @@ -18,6 +18,7 @@ class Group { this.size = parentSize; this.colorIndex = colorIndex; this.isObjectActor = isObjectActor; + this.cellCount = cellCount; } applyThemeColor() { @@ -27,6 +28,47 @@ class Group { : GlobalSettings.Instance.meshGroupColors; const color = colors[this.colorIndex % colors.length]; this.actor.getProperty().setColor(color); + this._applyEdgeColor(); + } + + /** + * Updates edge rendering based on the current edge mode and zoom level. + * @param {number} currentDistance + * @param {number} initialDistance + */ + updateEdgeVisibility(currentDistance, initialDistance) { + if (this.cellCount === null) return; + const prop = this.actor.getProperty(); + const mode = GlobalSettings.Instance.edgeMode; + + if (mode === 'hide') { + prop.setEdgeVisibility(false); + return; + } + if (mode === 'show') { + prop.setEdgeVisibility(true); + prop.setEdgeColor(0, 0, 0); + return; + } + + const threshold = initialDistance * Math.sqrt(15000 / this.cellCount) * GlobalSettings.Instance.edgeThresholdMultiplier; + + if (mode === 'threshold') { + prop.setEdgeVisibility(currentDistance < threshold); + prop.setEdgeColor(0, 0, 0); + return; + } + + // 'gradual': blend edge color from surface color (invisible) to black (fully visible) + prop.setEdgeVisibility(true); + this._edgeT = Math.min(1, Math.max(0, threshold / currentDistance)); + this._applyEdgeColor(); + } + + _applyEdgeColor() { + const t = this._edgeT ?? 0; + const [r, g, b] = this.actor.getProperty().getColor(); + this.actor.getProperty().setEdgeColor(r * (1 - t), g * (1 - t), b * (1 - t)); } /** diff --git a/resources/visu_vtk/js/data/create/FaceActorCreator.js b/resources/visu_vtk/js/data/create/FaceActorCreator.js index 5a7e2d8..7e2eb59 100644 --- a/resources/visu_vtk/js/data/create/FaceActorCreator.js +++ b/resources/visu_vtk/js/data/create/FaceActorCreator.js @@ -18,7 +18,7 @@ class FaceActorCreator { * @returns {vtkActor} */ create(groupName, groupId) { - const polyData = this.prepare(groupId); + const { polyData, cellCount } = this.prepare(groupId); const actor = vtk.Rendering.Core.vtkActor.newInstance(); const mapper = vtk.Rendering.Core.vtkMapper.newInstance(); @@ -26,10 +26,10 @@ class FaceActorCreator { mapper.setInputData(polyData); actor.setMapper(mapper); - const { colorIndex, isObjectActor } = this.setProperty(actor, groupName); + const { colorIndex, isObjectActor } = this.setProperty(actor, groupName, cellCount); VtkApp.Instance.getRenderer().addActor(actor); - return { actor, colorIndex, isObjectActor }; + return { actor, colorIndex, isObjectActor, cellCount }; } @@ -55,7 +55,8 @@ class FaceActorCreator { .map((g, idx) => (g === groupId ? idx : -1)) .filter(idx => idx !== -1); - if (cellIndices.length > 0) { + const cellCount = cellIndices.length; + if (cellCount > 0) { const cellArray = vtk.Common.Core.vtkCellArray.newInstance({ values: Uint32Array.from(cellIndices.flatMap(i => { const c = this.cells[i]; @@ -65,7 +66,7 @@ class FaceActorCreator { pd.setPolys(cellArray); } - return pd; + return { polyData: pd, cellCount }; } /** @@ -73,7 +74,7 @@ class FaceActorCreator { * @param {vtkActor} actor * @param {string} groupName */ - setProperty(actor, groupName) { + setProperty(actor, groupName, cellCount) { const prop = actor.getProperty(); let colorIndex, isObjectActor; @@ -89,7 +90,9 @@ class FaceActorCreator { actor.setVisibility(false); } - prop.setEdgeVisibility(true); + const [r, g, b] = prop.getColor(); + prop.setEdgeVisibility(true); // edge color is managed dynamically by CameraManager + prop.setEdgeColor(r, g, b); // start invisible (matches surface); CameraManager blends toward black prop.setLineWidth(0.3); prop.setInterpolationToPhong(); prop.setSpecular(0.3); diff --git a/resources/visu_vtk/js/interaction/CameraManager.js b/resources/visu_vtk/js/interaction/CameraManager.js index db03ea9..98aaafe 100644 --- a/resources/visu_vtk/js/interaction/CameraManager.js +++ b/resources/visu_vtk/js/interaction/CameraManager.js @@ -16,19 +16,27 @@ class CameraManager { */ init(groups) { this.nodesGroups = {}; + this.faceGroups = {}; const renderer = VtkApp.Instance.getRenderer(); this.camera = renderer.getActiveCamera(); - this.lastDistance = this.camera.getDistance(); + this.initialDistance = this.camera.getDistance(); + this.lastDistance = this.initialDistance; - // Store only node groups for (const [groupName, group] of Object.entries(groups)) { if (!group.isFaceGroup) { this.nodesGroups[groupName] = group; group.setSize(this.lastDistance); + } else if (group.cellCount !== null) { + this.faceGroups[groupName] = group; + group.updateEdgeVisibility(this.lastDistance, this.initialDistance); } } + this._zoomIndicator = document.getElementById("zoomIndicator"); + this._resetZoomBtn = document.getElementById("resetZoomBtn"); + this._updateZoomIndicator(this.initialDistance); + this.axisMarker = this.createAxisMarker(); this.activateSizeUpdate(); } @@ -39,15 +47,68 @@ class CameraManager { activateSizeUpdate() { this.camera.onModified(() => { const currentDistance = this.camera.getDistance(); + this._updateZoomIndicator(currentDistance); if (Math.abs(currentDistance - this.lastDistance) > 1e-2) { for (const nodeGroup of Object.values(this.nodesGroups)) { nodeGroup.setSize(currentDistance); } + for (const faceGroup of Object.values(this.faceGroups)) { + faceGroup.updateEdgeVisibility(currentDistance, this.initialDistance); + } this.lastDistance = currentDistance; } }); } + _updateZoomIndicator(currentDistance) { + if (!this._zoomIndicator) return; + const ratio = this.initialDistance / currentDistance; + let text; + if (ratio >= 10) text = `${Math.round(ratio)}×`; + else if (ratio >= 1) text = `${ratio.toFixed(1)}×`; + else text = `${ratio.toFixed(2)}×`; + this._zoomIndicator.textContent = text; + const atDefault = Math.abs(ratio - 1) < 0.01; + this._resetZoomBtn?.classList.toggle("hidden!", atDefault); + } + + resetZoom() { + VtkApp.Instance.getRenderer().resetCamera(); + VtkApp.Instance.updateCameraOffset(); // resets window center offset and renders + } + + /** + * Moves the camera to a specific zoom ratio relative to the initial position. + * @param {number} ratio - e.g. 2 means 2× zoomed in from initial + */ + setZoom(ratio) { + const focalPoint = this.camera.getFocalPoint(); + const position = this.camera.getPosition(); + const dx = position[0] - focalPoint[0]; + const dy = position[1] - focalPoint[1]; + const dz = position[2] - focalPoint[2]; + const currentDist = Math.sqrt(dx * dx + dy * dy + dz * dz); + const scale = (this.initialDistance / ratio) / currentDist; + this.camera.setPosition( + focalPoint[0] + dx * scale, + focalPoint[1] + dy * scale, + focalPoint[2] + dz * scale + ); + VtkApp.Instance.getRenderer().resetCameraClippingRange(); + VtkApp.Instance.updateCameraOffset(); + } + + /** + * Re-applies edge visibility for all face groups using the current camera distance. + * Call this when the edge mode setting changes. + */ + refreshEdgeVisibility() { + for (const faceGroup of Object.values(this.faceGroups)) { + faceGroup.updateEdgeVisibility(this.lastDistance, this.initialDistance); + } + VtkApp.Instance.getRenderWindow().render(); + } + /** * Positions the camera along a given axis relative to its focal point. * @param {string} axis - 'x', 'y', or 'z' diff --git a/resources/visu_vtk/js/settings/GlobalSettings.js b/resources/visu_vtk/js/settings/GlobalSettings.js index b5e3561..cb57824 100644 --- a/resources/visu_vtk/js/settings/GlobalSettings.js +++ b/resources/visu_vtk/js/settings/GlobalSettings.js @@ -36,6 +36,8 @@ class GlobalSettings { selectionPointColor = [1, 0, 0]; // #ff0000 hiddenObjectOpacity = 0; + edgeMode = 'threshold'; // 'hide' | 'show' | 'gradual' | 'threshold' + edgeThresholdMultiplier = 1; get isDark() { return document.body.classList.contains('vscode-dark') || diff --git a/resources/visu_vtk/js/ui/CustomDropdown.js b/resources/visu_vtk/js/ui/CustomDropdown.js new file mode 100644 index 0000000..9ab6070 --- /dev/null +++ b/resources/visu_vtk/js/ui/CustomDropdown.js @@ -0,0 +1,118 @@ +/** + * A reusable custom dropdown that matches the VS Code Aster UI style. + * The panel is appended to document.body to avoid overflow clipping. + */ +class CustomDropdown { + /** + * @param {HTMLElement} trigger - Element that opens/closes the panel on click + * @param {{ value: string, label: string }[]} options + * @param {(value: string) => void} onSelect - Called when the user picks an option + * @param {() => string|null} getValue - Returns the currently selected value (shown with a checkmark) + * @param {{ align?: 'left'|'right' }} [opts] + */ + constructor(trigger, options, onSelect, getValue, opts = {}) { + this._trigger = trigger; + this._options = options; + this._onSelect = onSelect; + this._getValue = getValue; + this._align = opts.align ?? 'left'; + this._panel = null; + + trigger.addEventListener('click', (e) => { + e.stopPropagation(); + this._panel ? this._close() : this._open(); + }); + document.addEventListener('click', () => this._close()); + } + + _open() { + const currentValue = this._getValue?.(); + + const panel = document.createElement('div'); + panel.style.cssText = ` + position: fixed; + z-index: 9999; + background: var(--ui-popup-bg); + border: 1px solid var(--ui-border); + border-radius: 4px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); + padding: 3px 0; + overflow: hidden; + `; + panel.addEventListener('click', (e) => e.stopPropagation()); + + const showCheckmarks = this._getValue != null; + + this._options.forEach(({ value, label }) => { + const isSelected = value === currentValue; + + const item = document.createElement('div'); + item.style.cssText = ` + display: flex; + align-items: center; + gap: 8px; + padding: 5px 10px; + font-size: 0.75rem; + cursor: pointer; + color: var(--ui-fg); + white-space: nowrap; + ${this._align === 'right' ? 'justify-content: flex-end;' : ''} + ${isSelected ? 'font-weight: 600;' : ''} + `; + + const labelEl = document.createElement('span'); + labelEl.textContent = label; + + if (showCheckmarks) { + const check = document.createElement('span'); + check.textContent = '✓'; + check.style.cssText = ` + font-size: 0.6rem; + flex-shrink: 0; + width: 10px; + opacity: ${isSelected ? 1 : 0}; + `; + item.appendChild(check); + } + + item.appendChild(labelEl); + + item.addEventListener('mouseenter', () => { + item.style.background = 'var(--ui-element-bg-hover)'; + }); + item.addEventListener('mouseleave', () => { + item.style.background = ''; + }); + item.addEventListener('click', () => { + this._onSelect(value); + this._close(); + }); + + panel.appendChild(item); + }); + + document.body.appendChild(panel); + + // Position after append so dimensions are known + const rect = this._trigger.getBoundingClientRect(); + const panelW = Math.max(panel.offsetWidth, rect.width); + const panelH = panel.offsetHeight; + panel.style.minWidth = `${panelW}px`; + + let left = rect.left + rect.width / 2 - panelW / 2; + left = Math.max(4, Math.min(left, window.innerWidth - panelW - 4)); + panel.style.left = `${left}px`; + + const openUp = window.innerHeight - rect.bottom < panelH + 8; + panel.style.top = openUp + ? `${rect.top - panelH - 4}px` + : `${rect.bottom + 4}px`; + + this._panel = panel; + } + + _close() { + this._panel?.remove(); + this._panel = null; + } +} diff --git a/resources/visu_vtk/js/ui/UIManager.js b/resources/visu_vtk/js/ui/UIManager.js index a69b598..81e6c90 100644 --- a/resources/visu_vtk/js/ui/UIManager.js +++ b/resources/visu_vtk/js/ui/UIManager.js @@ -46,6 +46,12 @@ class UIManager { this.resetGroupButtonsPopup(); }); + // Reset zoom button + const resetZoomBtn = document.getElementById("resetZoomBtn"); + resetZoomBtn.addEventListener("click", () => { + CameraManager.Instance.resetZoom(); + }); + // Camera axis buttons, to allow quick camera control const xBtn = document.getElementById("xBtn"); const yBtn = document.getElementById("yBtn"); @@ -90,6 +96,73 @@ class UIManager { }); }); + // Edge threshold slider + const edgeThresholdSlider = document.getElementById("edgeThresholdSlider"); + const edgeThresholdValue = document.getElementById("edgeThresholdValue"); + edgeThresholdSlider.addEventListener("input", () => { + const multiplier = parseInt(edgeThresholdSlider.value, 10) / 100; + edgeThresholdValue.textContent = `${parseFloat(multiplier.toFixed(2))}×`; + GlobalSettings.Instance.edgeThresholdMultiplier = multiplier; + if (CameraManager.Instance.faceGroups) { CameraManager.Instance.refreshEdgeVisibility(); } + Controller.Instance.getVSCodeAPI().postMessage({ + type: "saveSettings", + settings: { edgeThresholdMultiplier: multiplier }, + }); + }); + + // Edge mode dropdown + this._edgeModeDescriptions = { + gradual: "Edges fade in as you zoom in, scaled by mesh density. When zoomed out, large meshes may appear very flat as outer edges are mostly hidden. Performance is impacted.", + threshold: "Edges appear abruptly at a zoom level based on mesh density. When zoomed out, large meshes may appear slightly flat as outer edges are hidden. Performance is not impacted.", + show: "Edges are always visible. Large meshes will appear almost entirely black when zoomed out. Performance is impacted.", + hide: "Edges are always hidden. All shapes will look slightly flat regardless of zoom level or mesh size.", + }; + const edgeModeOptions = [ + { value: 'threshold', label: 'Show edges when zooming (threshold)' }, + { value: 'gradual', label: 'Show edges when zooming (gradual)' }, + { value: 'show', label: 'Always show edges' }, + { value: 'hide', label: 'Always hide edges' }, + ]; + this._applyEdgeMode = (value, save = true) => { + GlobalSettings.Instance.edgeMode = value; + const label = document.getElementById("edgeModeSelectLabel"); + const desc = document.getElementById("edgeModeDesc"); + const thresholdSection = document.getElementById("edgeThresholdSection"); + if (label) label.textContent = edgeModeOptions.find(o => o.value === value)?.label ?? value; + if (desc) desc.textContent = this._edgeModeDescriptions[value] ?? ''; + if (thresholdSection) thresholdSection.classList.toggle("hidden!", value !== 'threshold'); + if (CameraManager.Instance.faceGroups) { CameraManager.Instance.refreshEdgeVisibility(); } + if (save) { + Controller.Instance.getVSCodeAPI().postMessage({ + type: "saveSettings", + settings: { edgeMode: value }, + }); + } + }; + new CustomDropdown( + document.getElementById("edgeModeSelect"), + edgeModeOptions, + (value) => this._applyEdgeMode(value), + () => GlobalSettings.Instance.edgeMode + ); + this._applyEdgeMode(GlobalSettings.Instance.edgeMode, false); + + // Zoom dropdown + new CustomDropdown( + document.getElementById("zoomTrigger"), + [ + { value: '0.5', label: '0.5×' }, + { value: '1', label: '1×' }, + { value: '1.5', label: '1.5×' }, + { value: '2', label: '2×' }, + { value: '5', label: '5×' }, + { value: '10', label: '10×' }, + ], + (value) => CameraManager.Instance.setZoom(parseFloat(value)), + null, + { align: 'right' } + ); + // Help popup const helpBtn = document.getElementById("helpBtn"); helpBtn.addEventListener("click", () => { @@ -156,6 +229,13 @@ class UIManager { document.getElementById(`eyeBtn_${object}`).addEventListener("click", () => { const nowVisible = VisibilityManager.Instance.toggleObjectVisibility(object); document.getElementById(`eyeIcon_${object}`).src = nowVisible ? eyeIconUrl : eyeOffIconUrl; + if (!nowVisible) { + groupContainer.classList.add("hidden!"); + groupCountEl.classList.remove("hidden!"); + } else { + groupContainer.classList.remove("hidden!"); + groupCountEl.classList.add("hidden!"); + } }); // Create collapsible container for group buttons @@ -170,8 +250,9 @@ class UIManager { groupCountEl.style.color = "var(--ui-text-muted)"; groupCountEl.textContent = `${groupCount} groups`; - // Name span toggles group container visibility (disabled when all groups are hidden) + // Name span toggles group container visibility (disabled when all groups are hidden or mesh is hidden) document.getElementById(`objName_${object}`).addEventListener("click", () => { + if (VisibilityManager.Instance.hiddenObjects[object]) { return; } const grpHidden = document.getElementById(`grpHidden_${object}`); const allHidden = grpHidden && !grpHidden.classList.contains("hidden!") && [...groupContainer.querySelectorAll(`[id^="btn_${object}::"]`)].every(b => b.classList.contains("hidden!")); @@ -436,11 +517,11 @@ class UIManager { * Reset all settings to their default values, apply them, and save them. */ resetSettings() { - this.applySettings({ hiddenObjectOpacity: 0 }); + this.applySettings({ hiddenObjectOpacity: 0, edgeMode: 'threshold', edgeThresholdMultiplier: 1 }); VisibilityManager.Instance.applyHiddenObjectOpacity(); Controller.Instance.getVSCodeAPI().postMessage({ type: "saveSettings", - settings: { hiddenObjectOpacity: 0 }, + settings: { hiddenObjectOpacity: 0, edgeMode: 'threshold', edgeThresholdMultiplier: 1 }, }); } @@ -459,6 +540,19 @@ class UIManager { label.textContent = `${pct}%`; GlobalSettings.Instance.hiddenObjectOpacity = settings.hiddenObjectOpacity; } + + if (settings.edgeMode !== undefined) { + this._applyEdgeMode?.(settings.edgeMode, false); + } + + if (settings.edgeThresholdMultiplier !== undefined) { + const pct = Math.round(settings.edgeThresholdMultiplier * 100); + const slider = document.getElementById("edgeThresholdSlider"); + const label = document.getElementById("edgeThresholdValue"); + slider.value = pct; + label.textContent = `${parseFloat((pct / 100).toFixed(2))}×`; + GlobalSettings.Instance.edgeThresholdMultiplier = pct / 100; + } } /** diff --git a/resources/visu_vtk/tailwind.css b/resources/visu_vtk/tailwind.css index 4c0f6b3..f889194 100644 --- a/resources/visu_vtk/tailwind.css +++ b/resources/visu_vtk/tailwind.css @@ -22,11 +22,14 @@ --text-base: 1rem; --text-base--line-height: calc(1.5 / 1); --font-weight-normal: 400; + --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; --radius-sm: 0.25rem; --blur-xs: 4px; --blur-lg: 16px; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); --default-mono-font-family: var(--font-mono); } @@ -222,6 +225,12 @@ .right-full { right: 100%; } + .bottom-2 { + bottom: calc(var(--spacing) * 2); + } + .left-1 { + left: calc(var(--spacing) * 1); + } .left-1\.5 { left: calc(var(--spacing) * 1.5); } @@ -279,6 +288,9 @@ .my-2 { margin-block: calc(var(--spacing) * 2); } + .mt-0 { + margin-top: calc(var(--spacing) * 0); + } .mt-0\.5 { margin-top: calc(var(--spacing) * 0.5); } @@ -341,14 +353,25 @@ width: calc(var(--spacing) * 4.5); height: calc(var(--spacing) * 4.5); } + .size-5 { + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + } .size-5\.5 { width: calc(var(--spacing) * 5.5); height: calc(var(--spacing) * 5.5); } + .size-6 { + width: calc(var(--spacing) * 6); + height: calc(var(--spacing) * 6); + } .size-6\.5 { width: calc(var(--spacing) * 6.5); height: calc(var(--spacing) * 6.5); } + .h-4 { + height: calc(var(--spacing) * 4); + } .h-4\.5 { height: calc(var(--spacing) * 4.5); } @@ -361,12 +384,21 @@ .h-screen { height: 100vh; } + .max-h-2 { + max-height: calc(var(--spacing) * 2); + } .max-h-2\/3 { max-height: calc(2 / 3 * 100%); } + .w-2 { + width: calc(var(--spacing) * 2); + } .w-2\/3 { width: calc(2 / 3 * 100%); } + .w-3 { + width: calc(var(--spacing) * 3); + } .w-3\/4 { width: calc(3 / 4 * 100%); } @@ -379,16 +411,33 @@ .flex-1 { flex: 1; } + .flex-shrink { + flex-shrink: 1; + } .shrink-0 { flex-shrink: 0; } + .flex-grow { + flex-grow: 1; + } .grow { flex-grow: 1; } + .border-collapse { + border-collapse: collapse; + } + .-translate-x-1 { + --tw-translate-x: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-x-1\/2 { --tw-translate-x: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } + .-translate-y-1 { + --tw-translate-y: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -436,6 +485,9 @@ .gap-1\.5 { gap: calc(var(--spacing) * 1.5); } + .gap-2 { + gap: calc(var(--spacing) * 2); + } .gap-6 { gap: calc(var(--spacing) * 6); } @@ -460,6 +512,13 @@ margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); } } + .space-x-1 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); + } + } .space-x-1\.5 { :where(& > :not(:last-child)) { --tw-space-x-reverse: 0; @@ -522,6 +581,9 @@ .border-red-500 { border-color: var(--color-red-500); } + .bg-black { + background-color: var(--color-black); + } .bg-black\/20 { background-color: color-mix(in srgb, #000 20%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -540,27 +602,51 @@ .p-8 { padding: calc(var(--spacing) * 8); } + .px-1 { + padding-inline: calc(var(--spacing) * 1); + } .px-1\.5 { padding-inline: calc(var(--spacing) * 1.5); } .px-2 { padding-inline: calc(var(--spacing) * 2); } + .px-2\.5 { + padding-inline: calc(var(--spacing) * 2.5); + } .px-3 { padding-inline: calc(var(--spacing) * 3); } + .py-0 { + padding-block: calc(var(--spacing) * 0); + } .py-0\.5 { padding-block: calc(var(--spacing) * 0.5); } .py-1 { padding-block: calc(var(--spacing) * 1); } + .py-1\.5 { + padding-block: calc(var(--spacing) * 1.5); + } + .pt-0 { + padding-top: calc(var(--spacing) * 0); + } + .pt-0\.5 { + padding-top: calc(var(--spacing) * 0.5); + } .pt-0\.75 { padding-top: calc(var(--spacing) * 0.75); } + .pr-0 { + padding-right: calc(var(--spacing) * 0); + } .pr-0\.5 { padding-right: calc(var(--spacing) * 0.5); } + .pr-1 { + padding-right: calc(var(--spacing) * 1); + } .pr-1\.5 { padding-right: calc(var(--spacing) * 1.5); } @@ -573,6 +659,9 @@ .pb-1\.25 { padding-bottom: calc(var(--spacing) * 1.25); } + .pl-1 { + padding-left: calc(var(--spacing) * 1); + } .pl-1\.5 { padding-left: calc(var(--spacing) * 1.5); } @@ -588,6 +677,9 @@ .align-top { vertical-align: top; } + .font-mono { + font-family: var(--font-mono); + } .text-base { font-size: var(--text-base); line-height: var(--tw-leading, var(--text-base--line-height)); @@ -614,6 +706,10 @@ --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); } + .font-medium { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } .font-normal { --tw-font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal); @@ -634,12 +730,18 @@ .text-green-500 { color: var(--color-green-500); } + .text-green-600 { + color: var(--color-green-600); + } .text-green-600\! { color: var(--color-green-600) !important; } .text-red-500 { color: var(--color-red-500); } + .text-red-600 { + color: var(--color-red-600); + } .text-red-600\! { color: var(--color-red-600) !important; } @@ -649,12 +751,21 @@ .uppercase { text-transform: uppercase; } + .underline { + text-decoration-line: underline; + } .accent-current { accent-color: currentcolor; } .opacity-40 { opacity: 40%; } + .opacity-50 { + opacity: 50%; + } + .opacity-60 { + opacity: 60%; + } .shadow { --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); @@ -688,6 +799,15 @@ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } + .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } .select-all { -webkit-user-select: all; user-select: all; @@ -722,6 +842,13 @@ } } } + .hover\:opacity-100 { + &:hover { + @media (hover: hover) { + opacity: 100%; + } + } + } .focus\:outline-none { &:focus { --tw-outline-style: none; diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index 6bde615..13639d6 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -91,6 +91,7 @@ export class WebviewVisu implements vscode.Disposable { const config = vscode.workspace.getConfiguration("vs-code-aster"); const settings = { hiddenObjectOpacity: config.get<number>("viewer.hiddenObjectOpacity", 0), + edgeMode: config.get<string>("viewer.edgeMode", "gradual"), }; this.panel.webview.postMessage({ type: "init", @@ -100,11 +101,20 @@ export class WebviewVisu implements vscode.Disposable { break; case "saveSettings": // Persist viewer settings back to VS Code configuration - vscode.workspace.getConfiguration("vs-code-aster").update( - "viewer.hiddenObjectOpacity", - e.settings.hiddenObjectOpacity, - vscode.ConfigurationTarget.Global - ); + if (e.settings.hiddenObjectOpacity !== undefined) { + vscode.workspace.getConfiguration("vs-code-aster").update( + "viewer.hiddenObjectOpacity", + e.settings.hiddenObjectOpacity, + vscode.ConfigurationTarget.Global + ); + } + if (e.settings.edgeMode !== undefined) { + vscode.workspace.getConfiguration("vs-code-aster").update( + "viewer.edgeMode", + e.settings.edgeMode, + vscode.ConfigurationTarget.Global + ); + } break; case "debugPanel": // Log debug messages from the webview From 526f56f2a2a4aea4acbe529aabc1baa20fd5b8e6 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet <ulysse.bouchet@simvia.tech> Date: Tue, 10 Mar 2026 16:20:24 +0100 Subject: [PATCH 04/20] Switch viewer to Svelte --- .gitignore | 3 + .vscode/tasks.json | 23 +- .vscodeignore | 10 +- CHANGELOG.md | 16 + CITATION.cff | 2 +- README.md | 38 +- ROADMAP.md | 2 +- package-lock.json | 6922 ++++++++++------- package.json | 18 +- resources/icons/clear.svg | 1 - resources/icons/eye.svg | 1 - resources/icons/eye_off.svg | 1 - resources/icons/face.svg | 1 - resources/icons/filter.svg | 1 - resources/icons/node.svg | 1 - resources/icons/object.svg | 1 - resources/icons/question_mark.svg | 1 - resources/icons/settings.svg | 1 - resources/visu_vtk/index.html | 406 +- resources/visu_vtk/index.js | 25 - resources/visu_vtk/js/Controller.js | 74 - .../visu_vtk/js/commands/VisibilityManager.js | 226 - resources/visu_vtk/js/core/VtkApp.js | 87 - resources/visu_vtk/js/data/CreateGroups.js | 101 - resources/visu_vtk/js/data/Group.js | 95 - resources/visu_vtk/js/data/ObjLoader.js | 112 - .../js/data/create/NodeActorCreator.js | 91 - .../visu_vtk/js/interaction/AxesCreator.js | 183 - .../visu_vtk/js/interaction/CameraManager.js | 164 - .../visu_vtk/js/settings/GlobalSettings.js | 114 - resources/visu_vtk/js/ui/UIManager.js | 597 -- .../visu_vtk/{styles.css => src/app.css} | 6 - .../src/components/ActionButtons.svelte | 51 + resources/visu_vtk/src/components/App.svelte | 38 + .../src/components/AxisButtons.svelte | 33 + .../src/components/GroupButton.svelte | 49 + .../src/components/ObjectSection.svelte | 101 + .../visu_vtk/src/components/Sidebar.svelte | 33 + .../visu_vtk/src/components/TopActions.svelte | 45 + .../visu_vtk/src/components/ZoomWidget.svelte | 65 + .../src/components/popups/GroupsPopup.svelte | 143 + .../src/components/popups/HelpPopup.svelte | 72 + .../src/components/popups/Popup.svelte | 18 + .../components/popups/SettingsPopup.svelte | 186 + .../visu_vtk/src/icons/ChevronIcon.svelte | 7 + resources/visu_vtk/src/icons/ClearIcon.svelte | 9 + resources/visu_vtk/src/icons/EyeIcon.svelte | 8 + .../visu_vtk/src/icons/EyeOffIcon.svelte | 10 + resources/visu_vtk/src/icons/FaceIcon.svelte | 6 + .../visu_vtk/src/icons/FilterIcon.svelte | 7 + resources/visu_vtk/src/icons/NodeIcon.svelte | 6 + .../visu_vtk/src/icons/ObjectIcon.svelte | 6 + .../visu_vtk/src/icons/QuestionIcon.svelte | 9 + resources/visu_vtk/src/icons/ResetIcon.svelte | 8 + .../visu_vtk/src/icons/SettingsIcon.svelte | 8 + resources/visu_vtk/src/icons/ZoomIcon.svelte | 10 + resources/visu_vtk/src/lib/Controller.ts | 76 + .../src/lib/commands/VisibilityManager.ts | 170 + resources/visu_vtk/src/lib/core/VtkApp.ts | 82 + .../visu_vtk/src/lib/data/CreateGroups.ts | 76 + resources/visu_vtk/src/lib/data/Group.ts | 95 + resources/visu_vtk/src/lib/data/ObjLoader.ts | 101 + .../lib/data/create/FaceActorCreator.ts} | 66 +- .../src/lib/data/create/NodeActorCreator.ts | 79 + .../src/lib/interaction/AxesCreator.ts | 82 + .../src/lib/interaction/CameraManager.ts | 150 + .../src/lib/settings/GlobalSettings.ts | 109 + resources/visu_vtk/src/lib/state.ts | 27 + .../lib/ui/CustomDropdown.ts} | 74 +- resources/visu_vtk/src/lib/vtk.d.ts | 1 + resources/visu_vtk/src/main.ts | 56 + resources/visu_vtk/svelte.config.js | 5 + resources/visu_vtk/tailwind.css | 1211 --- resources/visu_vtk/tsconfig.json | 16 + resources/visu_vtk/vite.config.ts | 14 + src/VisuManager.ts | 2 +- tsconfig.json | 5 +- 77 files changed, 6367 insertions(+), 6382 deletions(-) delete mode 100644 resources/icons/clear.svg delete mode 100644 resources/icons/eye.svg delete mode 100644 resources/icons/eye_off.svg delete mode 100644 resources/icons/face.svg delete mode 100644 resources/icons/filter.svg delete mode 100644 resources/icons/node.svg delete mode 100644 resources/icons/object.svg delete mode 100644 resources/icons/question_mark.svg delete mode 100644 resources/icons/settings.svg delete mode 100644 resources/visu_vtk/index.js delete mode 100644 resources/visu_vtk/js/Controller.js delete mode 100644 resources/visu_vtk/js/commands/VisibilityManager.js delete mode 100644 resources/visu_vtk/js/core/VtkApp.js delete mode 100644 resources/visu_vtk/js/data/CreateGroups.js delete mode 100644 resources/visu_vtk/js/data/Group.js delete mode 100644 resources/visu_vtk/js/data/ObjLoader.js delete mode 100644 resources/visu_vtk/js/data/create/NodeActorCreator.js delete mode 100644 resources/visu_vtk/js/interaction/AxesCreator.js delete mode 100644 resources/visu_vtk/js/interaction/CameraManager.js delete mode 100644 resources/visu_vtk/js/settings/GlobalSettings.js delete mode 100644 resources/visu_vtk/js/ui/UIManager.js rename resources/visu_vtk/{styles.css => src/app.css} (91%) create mode 100644 resources/visu_vtk/src/components/ActionButtons.svelte create mode 100644 resources/visu_vtk/src/components/App.svelte create mode 100644 resources/visu_vtk/src/components/AxisButtons.svelte create mode 100644 resources/visu_vtk/src/components/GroupButton.svelte create mode 100644 resources/visu_vtk/src/components/ObjectSection.svelte create mode 100644 resources/visu_vtk/src/components/Sidebar.svelte create mode 100644 resources/visu_vtk/src/components/TopActions.svelte create mode 100644 resources/visu_vtk/src/components/ZoomWidget.svelte create mode 100644 resources/visu_vtk/src/components/popups/GroupsPopup.svelte create mode 100644 resources/visu_vtk/src/components/popups/HelpPopup.svelte create mode 100644 resources/visu_vtk/src/components/popups/Popup.svelte create mode 100644 resources/visu_vtk/src/components/popups/SettingsPopup.svelte create mode 100644 resources/visu_vtk/src/icons/ChevronIcon.svelte create mode 100644 resources/visu_vtk/src/icons/ClearIcon.svelte create mode 100644 resources/visu_vtk/src/icons/EyeIcon.svelte create mode 100644 resources/visu_vtk/src/icons/EyeOffIcon.svelte create mode 100644 resources/visu_vtk/src/icons/FaceIcon.svelte create mode 100644 resources/visu_vtk/src/icons/FilterIcon.svelte create mode 100644 resources/visu_vtk/src/icons/NodeIcon.svelte create mode 100644 resources/visu_vtk/src/icons/ObjectIcon.svelte create mode 100644 resources/visu_vtk/src/icons/QuestionIcon.svelte create mode 100644 resources/visu_vtk/src/icons/ResetIcon.svelte create mode 100644 resources/visu_vtk/src/icons/SettingsIcon.svelte create mode 100644 resources/visu_vtk/src/icons/ZoomIcon.svelte create mode 100644 resources/visu_vtk/src/lib/Controller.ts create mode 100644 resources/visu_vtk/src/lib/commands/VisibilityManager.ts create mode 100644 resources/visu_vtk/src/lib/core/VtkApp.ts create mode 100644 resources/visu_vtk/src/lib/data/CreateGroups.ts create mode 100644 resources/visu_vtk/src/lib/data/Group.ts create mode 100644 resources/visu_vtk/src/lib/data/ObjLoader.ts rename resources/visu_vtk/{js/data/create/FaceActorCreator.js => src/lib/data/create/FaceActorCreator.ts} (59%) create mode 100644 resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts create mode 100644 resources/visu_vtk/src/lib/interaction/AxesCreator.ts create mode 100644 resources/visu_vtk/src/lib/interaction/CameraManager.ts create mode 100644 resources/visu_vtk/src/lib/settings/GlobalSettings.ts create mode 100644 resources/visu_vtk/src/lib/state.ts rename resources/visu_vtk/{js/ui/CustomDropdown.js => src/lib/ui/CustomDropdown.ts} (62%) create mode 100644 resources/visu_vtk/src/lib/vtk.d.ts create mode 100644 resources/visu_vtk/src/main.ts create mode 100644 resources/visu_vtk/svelte.config.js delete mode 100644 resources/visu_vtk/tailwind.css create mode 100644 resources/visu_vtk/tsconfig.json create mode 100644 resources/visu_vtk/vite.config.ts diff --git a/.gitignore b/.gitignore index f72f8cf..179fc4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Node modules node_modules/ +# Webview build output +resources/visu_vtk/dist/ + # Build output dist/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3cf99c3..a1a58ed 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,8 @@ "label": "watch", "dependsOn": [ "npm: watch:tsc", - "npm: watch:esbuild" + "npm: watch:esbuild", + "npm: watch:webview" ], "presentation": { "reveal": "never" @@ -17,6 +18,26 @@ "isDefault": true } }, + { + "type": "npm", + "script": "watch:webview", + "group": "build", + "isBackground": true, + "label": "npm: watch:webview", + "presentation": { + "group": "watch", + "reveal": "never" + }, + "problemMatcher": { + "owner": "vite-watch", + "pattern": { "regexp": "^$" }, + "background": { + "activeOnStart": false, + "beginsPattern": "watching for file changes", + "endsPattern": "built in \\d" + } + } + }, { "type": "npm", "script": "watch:esbuild", diff --git a/.vscodeignore b/.vscodeignore index f5e8bde..e4f1b40 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -19,4 +19,12 @@ noxfile.py requirements.txt python/data python/lsp/.venv -python/.venv \ No newline at end of file +python/.venv +resources/visu_vtk/src/** +resources/visu_vtk/vite.config.ts +resources/visu_vtk/svelte.config.js +resources/visu_vtk/tsconfig.json +resources/visu_vtk/js/** +resources/visu_vtk/tailwind.css +resources/visu_vtk/styles.css +resources/visu_vtk/index.js \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 15ca2ba..3bb60ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to the **VS Code Aster** extension will be documented in thi The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.5.0] - 2026-03-10 + +Rewrote the mesh viewer UI with Svelte, and added new viewer features. + +### Added +- Migrated the mesh viewer frontend from vanilla JS/HTML to Svelte with TypeScript +- Show/hide toggle button per object in the sidebar +- Per-object color display in the sidebar +- Zoom widget in the mesh viewer +- Settings popup with configurable hidden object opacity, edge rendering mode, and edge threshold multiplier +- Groups popup to select which groups are shown in the sidebar +- Help popup +- Focusing a `.comm` file now focuses its corresponding mesh viewer webview +- Object file names are shown in the webview tab titles +- Mesh viewer UI now follows the VS Code user theme + ## [1.4.3] - 2026-03-03 Updated dependencies. diff --git a/CITATION.cff b/CITATION.cff index b5fcb0f..055d550 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,4 +1,4 @@ -cff-version: 1.4.3 +cff-version: 1.5.0 title: VS Code Aster message: >- If you use this software, please cite it using the diff --git a/README.md b/README.md index 4b8d9a7..bde4760 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ <p align="center"><img src="https://raw.githubusercontent.com/simvia-tech/vs-code-aster/main/resources/images/simvia.png" alt="Simvia Logo" width="50%" /></p> <p align="center"> - <a href="/"><img src="https://img.shields.io/badge/version-1.4.3-blue" alt="Version" /></a> + <a href="/"><img src="https://img.shields.io/badge/version-1.5.0-blue" alt="Version" /></a> <a href="./LICENSE"><img src="https://img.shields.io/badge/license-GPL%203.0-green" alt="License" /></a> </p> @@ -253,17 +253,41 @@ git clone https://github.com/simvia-tech/vs-code-aster.git npm install ``` -3. Compile extension : +### 3. Architecture overview + +The extension consists of two independently compiled parts : + +- **Extension host** (`src/`) — TypeScript compiled with esbuild, runs in Node.js inside VS Code +- **Webview** (`resources/visu_vtk/`) — Svelte 5 + Vite app that powers the 3D visualizer; built separately into `resources/visu_vtk/dist/` + +### 4. Running the extension locally + +Press `F5` (or go to `Run > Start Debugging`) to launch a new VS Code window running the extension. + +This starts three background watch tasks automatically (defined in `.vscode/tasks.json`) : + +| Task | What it does | +|---|---| +| `npm: watch:esbuild` | Recompiles the extension host on every save | +| `npm: watch:tsc` | Type-checks the extension host continuously | +| `npm: watch:webview` | Rebuilds the Svelte webview on every save | + +After making changes to the **extension host** (`src/`), reload the debug window with `Ctrl + R`. + +After making changes to the **webview** (`resources/visu_vtk/src/`), wait for the `watch:webview` task to finish rebuilding, then run `Developer: Reload Webviews` from the Command Palette. + +### 5. Building manually + +To build everything from scratch without starting the debug session : ```bash +# Build the webview +npm run build:webview + +# Compile and type-check the extension host npm run compile ``` -### 3. Running the extension locally - -You can press `F5` or go to `Run > Start Debugging` to launch a new VS Code window running this extension. -After making changes, you can reload the new window using `Ctrl` + `R`. - ## Telemetry **VS Code Aster** includes optional telemetry features to help improve the tool by collecting anonymous usage data. diff --git a/ROADMAP.md b/ROADMAP.md index 76d5bc1..1c55674 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,7 +4,7 @@ The extension aims to reduce friction between modeling, validation, execution, and analysis by bringing **code_aster** native workflows into the editor. -## Current Capabilities (v1.4.3) +## Current Capabilities (v1.5.0) - `.export` file generator - 3D mesh viewer diff --git a/package-lock.json b/package-lock.json index d0b048e..6bc9d69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vs-code-aster", - "version": "1.4.3", + "version": "1.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vs-code-aster", - "version": "1.4.3", + "version": "1.5.0", "license": "GPL-3.0", "dependencies": { "@tailwindcss/cli": "^4.1.17", @@ -14,6 +14,8 @@ "uuid": "^13.0.0" }, "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.2.4", + "@tailwindcss/vite": "^4.2.1", "@types/node": "^20.19.4", "@types/vscode": "^1.101.0", "@typescript-eslint/eslint-plugin": "^8.31.1", @@ -22,7 +24,10 @@ "esbuild": "^0.25.5", "eslint": "^9.25.1", "npm-run-all": "^4.1.5", + "svelte": "^5.53.9", + "svelte-check": "^4.4.5", "typescript": "^5.8.3", + "vite": "^7.3.1", "vscode-languageclient": "^9.0.0" }, "engines": { @@ -1084,149 +1089,132 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@tailwindcss/cli": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.2.1.tgz", - "integrity": "sha512-b7MGn51IA80oSG+7fuAgzfQ+7pZBgjzbqwmiv6NO7/+a1sev32cGqnwhscT7h0EcAvMa9r7gjRylqOH8Xhc4DA==", - "license": "MIT", - "dependencies": { - "@parcel/watcher": "^2.5.1", - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "enhanced-resolve": "^5.19.0", - "mri": "^1.2.0", - "picocolors": "^1.1.1", - "tailwindcss": "4.2.1" - }, - "bin": { - "tailwindcss": "dist/index.mjs" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "android" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">= 20" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" ], - "engines": { - "node": ">= 20" - } + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], + "dev": true, "libc": [ "glibc" ], @@ -1234,18 +1222,16 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], + "dev": true, "libc": [ "musl" ], @@ -1253,18 +1239,16 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", "cpu": [ - "x64" + "loong64" ], + "dev": true, "libc": [ "glibc" ], @@ -1272,18 +1256,16 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ - "x64" + "loong64" ], + "dev": true, "libc": [ "musl" ], @@ -1291,728 +1273,1924 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 20" - } + ] }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", "cpu": [ - "wasm32" + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" ], "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } + "os": [ + "linux" + ] }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ - "arm64" + "ppc64" + ], + "dev": true, + "libc": [ + "musl" ], "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } + "linux" + ] }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ - "x64" + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" ], "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } + "linux" + ] }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT" + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", - "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/vscode": { - "version": "1.109.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.109.0.tgz", - "integrity": "sha512-0Pf95rnwEIwDbmXGC08r0B4TQhAbsHQ5UyTIgVgoieDe4cOnf92usuR5dEczb6bTKEp7ziZH4TV1TRGPPCExtw==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } + "optional": true, + "os": [ + "openharmony" + ] }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", + "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "acorn": "^8.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz", + "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", + "deepmerge": "^4.3.1", + "magic-string": "^0.30.21", + "obug": "^2.1.0", + "vitefu": "^1.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^20.19 || ^22.12 || >=24" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz", + "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" + "obug": "^2.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^20.19 || ^22.12 || >=24" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", - "dev": true, + "node_modules/@tailwindcss/cli": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.2.1.tgz", + "integrity": "sha512-b7MGn51IA80oSG+7fuAgzfQ+7pZBgjzbqwmiv6NO7/+a1sev32cGqnwhscT7h0EcAvMa9r7gjRylqOH8Xhc4DA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" + "@parcel/watcher": "^2.5.1", + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "enhanced-resolve": "^5.19.0", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "tailwindcss": "4.2.1" + }, + "bin": { + "tailwindcss": "dist/index.mjs" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/vscode": { + "version": "1.109.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.109.0.tgz", + "integrity": "sha512-0Pf95rnwEIwDbmXGC08r0B4TQhAbsHQ5UyTIgVgoieDe4cOnf92usuR5dEczb6bTKEp7ziZH4TV1TRGPPCExtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vscode/test-electron": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", + "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "jszip": "^3.10.1", + "ora": "^8.1.0", + "semver": "^7.6.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", + "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">= 0.4" } }, - "node_modules/@vscode/test-electron": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", - "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "license": "MIT", "dependencies": { - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "jszip": "^3.10.1", - "ora": "^8.1.0", - "semver": "^7.6.2" + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" }, "engines": { - "node": ">=16" + "node": ">=10.13.0" } }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, "engines": { - "node": ">=0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">= 0.4" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14" + "node": ">= 0.4" } }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "es-errors": "^1.3.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">= 0.4" } }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { - "node": ">=12" + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "node_modules/eslint": { + "version": "9.39.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", + "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.3", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { - "node": "18 || 20 || >=22" + "node": ">= 4" } }, - "node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "balanced-match": "^4.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "18 || 20 || >=22" + "node": "*" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=6" + "node": ">=0.10" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/esrap": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz", + "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "restore-cursor": "^5.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT" }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" + "node": ">=16" } }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "node_modules/flatted": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -2021,59 +3199,44 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -2082,121 +3245,56 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "dev": true, "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", + "function-bind": "^1.1.2", "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2205,65 +3303,73 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-define-property": { + "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, "engines": { "node": ">= 0.4" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "es-errors": "^1.3.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">=10.13.0" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2272,380 +3378,319 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", - "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.3", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "dunder-proto": "^1.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/balanced-match": { + "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", + "has-symbols": "^1.0.3" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, "engines": { - "node": ">= 4" + "node": ">= 0.4" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true, - "license": "ISC", + "license": "ISC" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": "*" + "node": ">= 14" } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 14" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 4" } }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } + "license": "MIT" }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=4.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=0.8.19" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.0.0" + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "engines": { + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" + "has-bigints": "^1.0.2" }, "engines": { - "node": ">=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, "engines": { - "node": ">=16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", - "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -2654,29 +3699,33 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2685,57 +3734,82 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, "engines": { "node": ">= 0.4" }, @@ -2743,30 +3817,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2775,41 +3847,56 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "@types/estree": "^1.0.6" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globalthis": { + "node_modules/is-shared-array-buffer": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -2818,12 +3905,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { "node": ">= 0.4" }, @@ -2831,18 +3922,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, "engines": { "node": ">= 0.4" }, @@ -2850,49 +3940,39 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0" + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", "engines": { @@ -2902,14 +3982,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.3" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -2918,478 +3998,516 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "argparse": "^2.0.1" }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } + "license": "MIT" }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, - "license": "MIT", + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "json-buffer": "3.0.1" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, "license": "MIT", "dependencies": { - "has-bigints": "^1.0.2" + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.10.0" } }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, "license": "MIT", "engines": { @@ -3399,448 +4517,476 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, "engines": { - "node": ">= 0.4" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", "bin": { - "jiti": "lib/jiti-cli.mjs" + "semver": "bin/semver" } }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/json-parse-better-errors": { + "node_modules/npm-run-all/node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/npm-run-all/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true, "license": "MIT" }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", + "license": "MIT", "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "engines": { + "node": ">=4" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "shebang-regex": "^1.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", - "license": "MPL-2.0", + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.3" + "has-flag": "^3.0.0" }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" + "node": ">=4" } }, - "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "bin": { + "which": "bin/which" } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 0.4" } }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 12.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "p-limit": "^3.0.2" }, "engines": { "node": ">=10" @@ -3849,386 +4995,451 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true, - "license": "MIT" + "license": "(MIT AND Zlib)" }, - "node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">=18" + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true, "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, "engines": { - "node": ">= 0.4" + "node": ">=0.10" } }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.10.0" + "node": ">=4" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, - "license": "BlueOak-1.0.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^10 || ^12 || >=14" } }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, "license": "MIT" }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, "engines": { - "node": ">= 4" + "node": ">=6" } }, - "node_modules/npm-run-all/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/npm-run-all/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/npm-run-all/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/npm-run-all/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/npm-run-all/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-run-all/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { - "node": ">=4.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-run-all/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, "engines": { - "node": ">=0.8.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-run-all/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/npm-run-all/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", + "dependencies": { + "@types/estree": "1.0.8" + }, "bin": { - "semver": "bin/semver" + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/npm-run-all/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "es-errors": "^1.3.0", + "isarray": "^2.0.5" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "license": "MIT" }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, "engines": { "node": ">= 0.4" }, @@ -4236,119 +5447,104 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "license": "MIT", "dependencies": { - "mimic-function": "^5.0.0" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" } }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/ora/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, "engines": { "node": ">= 0.4" }, @@ -4356,236 +5552,228 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parent-module": { + "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } + "license": "CC0-1.0" }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/possible-typed-array-names": { + "node_modules/stop-iteration-iterator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, "engines": { "node": ">= 0.4" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", + "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4594,19 +5782,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4615,19 +5801,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4636,77 +5819,64 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-push-apply": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, "engines": { "node": ">= 0.4" }, @@ -4714,129 +5884,148 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-push-apply/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/svelte": { + "version": "5.53.9", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.9.tgz", + "integrity": "sha512-MwDfWsN8qZzeP0jlQsWF4k/4B3csb3IbzCRggF+L/QqY7T8bbKvnChEo1cPZztF51HJQhilDbevWYl2LvXbquA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", + "acorn": "^8.12.1", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.6.3", + "esm-env": "^1.2.1", + "esrap": "^2.2.2", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "node_modules/svelte-check": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.5.tgz", + "integrity": "sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, "bin": { - "semver": "bin/semver.js" + "svelte-check": "bin/svelte-check" }, "engines": { - "node": ">=10" + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, + "node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "prelude-ls": "^1.2.1" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, "engines": { "node": ">= 0.4" }, @@ -4844,18 +6033,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -4864,15 +6055,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -4881,37 +6076,31 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=14.17" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -4920,481 +6109,631 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "license": "Apache-2.0", "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/spdx-license-ids": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "CC0-1.0" + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 0.4" + "node": ">=18" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=18" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=18" } }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "node": ">=18" } }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" + "node": ">=18" } }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.8.0" + "node": ">=18" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.4" + "node": ">=18" } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=14.17" + "node": ">=18" } }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "node_modules/vite/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, - "license": "MIT" - }, - "node_modules/uuid": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "hasInstallScript": true, "license": "MIT", "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/vitefu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, "node_modules/vscode-jsonrpc": { @@ -5604,6 +6943,13 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index ef73c32..0f06c49 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vs-code-aster", "displayName": "VS Code Aster", - "version": "1.4.3", + "version": "1.5.0", "description": "VS Code extension for code_aster", "publisher": "simvia", "license": "GPL-3.0", @@ -160,7 +160,12 @@ "order": 11, "type": "string", "default": "threshold", - "enum": ["gradual", "threshold", "show", "hide"], + "enum": [ + "gradual", + "threshold", + "show", + "hide" + ], "enumDescriptions": [ "Edges fade in as you zoom in, scaled by mesh density. When zoomed out, large meshes may appear very flat as outer edges are mostly hidden. Performance is impacted.", "Edges appear abruptly at a zoom level based on mesh density. When zoomed out, large meshes may appear slightly flat as outer edges are hidden. Performance is not impacted.", @@ -179,16 +184,20 @@ } }, "scripts": { - "vscode:prepublish": "npm run package", + "vscode:prepublish": "npm run build:webview && npm run package", "compile": "npm run check-types && npm run lint && node esbuild.js", "watch": "npm-run-all -p watch:*", "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", + "watch:webview": "vite build --config resources/visu_vtk/vite.config.ts --watch", + "build:webview": "vite build --config resources/visu_vtk/vite.config.ts", "package": "npm run check-types && npm run lint && node esbuild.js --production", "check-types": "tsc --noEmit", "lint": "eslint src" }, "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.2.4", + "@tailwindcss/vite": "^4.2.1", "@types/node": "^20.19.4", "@types/vscode": "^1.101.0", "@typescript-eslint/eslint-plugin": "^8.31.1", @@ -197,7 +206,10 @@ "esbuild": "^0.25.5", "eslint": "^9.25.1", "npm-run-all": "^4.1.5", + "svelte": "^5.53.9", + "svelte-check": "^4.4.5", "typescript": "^5.8.3", + "vite": "^7.3.1", "vscode-languageclient": "^9.0.0" }, "dependencies": { diff --git a/resources/icons/clear.svg b/resources/icons/clear.svg deleted file mode 100644 index 9d38780..0000000 --- a/resources/icons/clear.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M690-240h150q17 0 28.5 11.5T880-200q0 17-11.5 28.5T840-160H610l80-80Zm-483 80q-8 0-15.5-3t-13.5-9l-73-73q-23-23-23.5-57t22.5-58l440-456q23-24 56.5-24t56.5 23l199 199q23 23 23 57t-23 57L532-172q-6 6-13.5 9t-15.5 3H207Zm279-80 314-322-198-198-442 456 64 64h262Zm-6-240Z"/></svg> \ No newline at end of file diff --git a/resources/icons/eye.svg b/resources/icons/eye.svg deleted file mode 100644 index 7f8ae5a..0000000 --- a/resources/icons/eye.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/></svg> diff --git a/resources/icons/eye_off.svg b/resources/icons/eye_off.svg deleted file mode 100644 index 90b2c3c..0000000 --- a/resources/icons/eye_off.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/><path d="m2 2 20 20"/></svg> diff --git a/resources/icons/face.svg b/resources/icons/face.svg deleted file mode 100644 index 7aa8e1e..0000000 --- a/resources/icons/face.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M161-366q-16-12-15.5-31.5T162-429q11-8 24-8t24 8l270 209 270-209q11-8 24-8t24 8q16 12 16.5 31.5T799-366L529-156q-22 17-49 17t-49-17L161-366Zm270 8L201-537q-31-24-31-63t31-63l230-179q22-17 49-17t49 17l230 179q31 24 31 63t-31 63L529-358q-22 17-49 17t-49-17Zm49-64 230-178-230-178-230 178 230 178Zm0-178Z"/></svg> \ No newline at end of file diff --git a/resources/icons/filter.svg b/resources/icons/filter.svg deleted file mode 100644 index 5e25d81..0000000 --- a/resources/icons/filter.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z"/></svg> diff --git a/resources/icons/node.svg b/resources/icons/node.svg deleted file mode 100644 index c147a75..0000000 --- a/resources/icons/node.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M580-120q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Zm0-80q17 0 28.5-11.5T620-240q0-17-11.5-28.5T580-280q-17 0-28.5 11.5T540-240q0 17 11.5 28.5T580-200Zm80-200q-92 0-156-64t-64-156q0-92 64-156t156-64q92 0 156 64t64 156q0 92-64 156t-156 64Zm0-80q59 0 99.5-40.5T800-620q0-59-40.5-99.5T660-760q-59 0-99.5 40.5T520-620q0 59 40.5 99.5T660-480ZM280-240q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T360-400q0-33-23.5-56.5T280-480q-33 0-56.5 23.5T200-400q0 33 23.5 56.5T280-320Zm300 80Zm80-380ZM280-400Z"/></svg> \ No newline at end of file diff --git a/resources/icons/object.svg b/resources/icons/object.svg deleted file mode 100644 index 24bee7e..0000000 --- a/resources/icons/object.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"/></svg> \ No newline at end of file diff --git a/resources/icons/question_mark.svg b/resources/icons/question_mark.svg deleted file mode 100644 index 02a8a6a..0000000 --- a/resources/icons/question_mark.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M584-637q0-43-28.5-69T480-732q-29 0-52.5 12.5T387-683q-16 23-43.5 26.5T296-671q-14-13-15.5-32t9.5-36q32-48 81.5-74.5T480-840q97 0 157.5 55T698-641q0 45-19 81t-70 85q-37 35-50 54.5T542-376q-4 24-20.5 40T482-320q-23 0-39.5-15.5T426-374q0-39 17-71.5t57-68.5q51-45 67.5-69.5T584-637ZM480-80q-33 0-56.5-23.5T400-160q0-33 23.5-56.5T480-240q33 0 56.5 23.5T560-160q0 33-23.5 56.5T480-80Z"/></svg> \ No newline at end of file diff --git a/resources/icons/settings.svg b/resources/icons/settings.svg deleted file mode 100644 index 3347a28..0000000 --- a/resources/icons/settings.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg> diff --git a/resources/visu_vtk/index.html b/resources/visu_vtk/index.html index b5c2eed..318a9bc 100644 --- a/resources/visu_vtk/index.html +++ b/resources/visu_vtk/index.html @@ -2,413 +2,13 @@ <html lang="en"> <head> <meta charset="UTF-8" /> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <link rel="stylesheet" href="./tailwind.css" /> - <link rel="stylesheet" href="./styles.css" /> - <title>MeshViewer + - - -
- -
- - -
-
- - -
-
-
- - -
-
- - -
- - -
- - - -
-
- - -
- - -
- - -
- -
- 1.0× -
- -
- - - - -
- - - - - - - +
+ - - - - - - - - - - - - - - - - - - - diff --git a/resources/visu_vtk/index.js b/resources/visu_vtk/index.js deleted file mode 100644 index 51c6a97..0000000 --- a/resources/visu_vtk/index.js +++ /dev/null @@ -1,25 +0,0 @@ -// Entry point for the VS Code Webview -const vscode = acquireVsCodeApi(); // VS Code API for messaging with the extension -const scene = document.getElementById("scene"); // HTML scene for rendering -Controller.Instance.init(scene, vscode); // Initialize the main Controller with scene and VS Code API - -// Listen for messages from the extension -window.addEventListener("message", async (e) => { - const { type, body } = e.data; - - switch (type) { - // Initialize the visualization with loaded OBJ files - case "init": - Controller.Instance.loadFiles(body.fileContexts, body.objFilenames); - UIManager.Instance.applySettings(body.settings); - break; - - // Toggle visibility for a specific group and update the UI label - case "displayGroup": - VisibilityManager.Instance.setVisibility(body.group, body.visible); - break; - } -}); - -// Notify the extension that the webview is ready -vscode.postMessage({ type: "ready" }); diff --git a/resources/visu_vtk/js/Controller.js b/resources/visu_vtk/js/Controller.js deleted file mode 100644 index 6841b13..0000000 --- a/resources/visu_vtk/js/Controller.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Controller for managing rendering operations and group visibility in the visualization module. - */ -class Controller { - static get Instance() { - if (!this._i) { - this._i = new Controller(); - } - return this._i; - } - - /** - * Initializes the render controller with the given scene and VS Code API entry. - * @param {HTMLElement} scene - The HTML scene for 3D rendering. - * @param {any} vsCodeApiEntry - The VS Code API entry point. - */ - init(scene, vsCodeApiEntry) { - this._scene = scene; - this._vsCodeApi = vsCodeApiEntry; - VtkApp.Instance.init(scene); - } - - getScene() { - return this._scene; - } - - getVSCodeAPI() { - return this._vsCodeApi; - } - - /** - * Loads a file and updates the group list in the VS Code webview. - * @param {string[]} fileContexts - The contexts of the files to load. - * @param {string[]} fileNames - The names of the files to load. - */ - loadFiles(fileContexts, fileNames) { - const lfr = new CreateGroups(fileContexts, fileNames); - lfr.do(); - this.initManagers(); - this.getVSCodeAPI().postMessage({ - type: "groups", - groupList: this.getGroupNames(), - }); - } - - saveGroups(groups, groupHierarchy) { - this._groups = groups; - this._groupHierarchy = groupHierarchy; - Controller.Instance.getVSCodeAPI().postMessage({ - type: "debugPanel", - text: `Actors and hierarchy saved`, - }); - } - - initManagers() { - UIManager.Instance.init(this._groupHierarchy); - VisibilityManager.Instance.init(this._groups, this._groupHierarchy); - CameraManager.Instance.init(this._groups); - } - - refreshThemeColors() { - if (!this._groups) return; - for (const group of Object.values(this._groups)) { - group.applyThemeColor(); - } - } - - getGroupNames() { - if (!this._groups) { - return []; - } - return Object.keys(this._groups).filter((key) => !key.includes("all_")); - } -} diff --git a/resources/visu_vtk/js/commands/VisibilityManager.js b/resources/visu_vtk/js/commands/VisibilityManager.js deleted file mode 100644 index 9fa9e04..0000000 --- a/resources/visu_vtk/js/commands/VisibilityManager.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Manages visibility of groups in the visualization module. - */ -class VisibilityManager { - /** - * Manage a singleton instance - */ - static get Instance() { - if (!this._i) { - this._i = new VisibilityManager(); - } - return this._i; - } - - /** - * Initializes the manager with groups and their hierarchy. - * @param {Map } groups A map of group names to group objects. - * @param {Map } objects A map of objects with their corresponding face and node groups. - */ - init(groups, objects) { - this.groups = groups; - this.visibleGroupsByObject = {}; - this.hiddenObjects = {}; - this.highlightedGroups = new Set(); - - for (const object in objects) { - this.visibleGroupsByObject[object] = 0; - this.hiddenObjects[object] = false; - } - } - - /** - * Sets visibility for a given group and updates associated object transparency. - * The highlighted state is tracked independently from actor visibility so that - * hiding/showing an entire object does not corrupt the highlight state. - * @param {string} groupName Name of the group to modify. - * @param {boolean} visible Optional visibility state; toggles if omitted. - * @returns {Object} Current visibility info: {visible, color, isFaceGroup} - */ - setVisibility(groupName, visible) { - // Helper function to send messages to the backend - const post = (text) => { - Controller.Instance.getVSCodeAPI().postMessage({ - type: "debugPanel", - text, - }); - }; - - // Handle errors - const group = this.groups[groupName]; - if (!group) { - post(`setVisibility: group "${groupName}" has no group defined`); - return; - } - const object = group.fileGroup; - if (!object) { - post(`setVisibility: group "${groupName}" has no parent object`); - return; - } - const actor = group.actor; - if (!actor) { - post(`setVisibility: no actor found for group "${groupName}"`); - return; - } - - // Get data about the group - const color = group.getColor(); - const isFaceGroup = group.isFaceGroup; - - // Determine new highlighted state from the tracking set, not from actor visibility. - // This ensures correctness even when the whole object is hidden. - const wasHighlighted = this.highlightedGroups.has(groupName); - const isHighlighted = - typeof visible === "boolean" ? visible : !wasHighlighted; - - // Update the highlighted tracking set - if (isHighlighted) { - this.highlightedGroups.add(groupName); - } else { - this.highlightedGroups.delete(groupName); - } - - // Apply to actor only if the parent object is not globally hidden - if (!this.hiddenObjects[object]) { - group.setVisibility(isHighlighted); - } - - // Update transparency counter when highlight state actually changes - if (wasHighlighted !== isHighlighted) { - const visibleGroupsCount = this.visibleGroupsByObject[object]; - if (!this.hiddenObjects[object]) { - if ( - (visibleGroupsCount === 0 && isHighlighted) || - (visibleGroupsCount === 1 && !isHighlighted) - ) { - this.setTransparence(isHighlighted, object); - } - } - this.visibleGroupsByObject[object] += isHighlighted ? 1 : -1; - } - - // Change group button highlight status - if (isHighlighted) { - UIManager.Instance.highlightButton(groupName, color); - } else { - UIManager.Instance.highlightButton(groupName); - } - - // Re-render the VTK window - VtkApp.Instance.getRenderWindow().render(); - - return { visible: isHighlighted, color, isFaceGroup }; - } - - /** - * Toggles the visibility of an entire object (mesh). - * When hidden, all actors for the object are invisible. - * When shown, the file group and any highlighted sub-groups are restored. - * @param {string} object Name of the file group (e.g. "all_mesh.obj"). - * @returns {boolean} True if the object is now visible, false if now hidden. - */ - toggleObjectVisibility(object) { - // Toggle hidden state - const nowVisible = this.hiddenObjects[object]; // was hidden → now visible - this.hiddenObjects[object] = !nowVisible; - - // Show/hide the file group actor (the full mesh) - const fileGroup = this.groups[object]; - if (fileGroup) { - if (nowVisible) { - // Showing: restore visibility and the correct opacity - fileGroup.actor.setVisibility(true); - const opacity = this.visibleGroupsByObject[object] > 0 ? 0.2 : 1.0; - fileGroup.setOpacity(opacity); - } else { - // Hiding: use ghost opacity (may be 0 for fully invisible) - const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; - if (hiddenOpacity === 0) { - fileGroup.actor.setVisibility(false); - } else { - fileGroup.actor.setVisibility(true); - fileGroup.setOpacity(hiddenOpacity); - } - } - } - - // Show/hide sub-group actors based on their highlighted state - for (const [groupName, group] of Object.entries(this.groups)) { - if (group.fileGroup === object) { - group.actor.setVisibility( - nowVisible && this.highlightedGroups.has(groupName) - ); - } - } - - VtkApp.Instance.getRenderWindow().render(); - return nowVisible; - } - - /** - * Sets the opacity of an object. - * @param {boolean} transparent Whether the object should be partially transparent or opaque. - * @param {string} object Name of the object. - */ - setTransparence(transparent, object) { - if (!this.groups || this.hiddenObjects[object]) { - return; - } - const meshOpacity = transparent ? 0.2 : 1; - const group = this.groups[object]; - group.setOpacity(meshOpacity); - } - - /** - * Re-applies the current hiddenObjectOpacity to all hidden objects. - * Called when the opacity slider value changes. - */ - applyHiddenObjectOpacity() { - const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; - for (const object in this.hiddenObjects) { - if (!this.hiddenObjects[object]) continue; - const fileGroup = this.groups[object]; - if (!fileGroup) continue; - if (hiddenOpacity === 0) { - fileGroup.actor.setVisibility(false); - } else { - fileGroup.actor.setVisibility(true); - fileGroup.setOpacity(hiddenOpacity); - } - } - VtkApp.Instance.getRenderWindow().render(); - } - - /** - * Resets visibility and transparency for all groups. - */ - clear() { - /** - * Parse all groups and set their visibility to false (meaning they are not highlighted) - */ - for (const [groupName, group] of Object.entries(this.groups)) { - if (!group.actor) { - continue; - } - if (group.fileGroup === null) { - continue; - } - group.setVisibility(false); - - // Change group button highlight status - UIManager.Instance.highlightButton(groupName); - } - - // Reset highlighted tracking - this.highlightedGroups.clear(); - - // Make all visible objects opaque - for (const object in this.visibleGroupsByObject) { - this.setTransparence(false, object); - this.visibleGroupsByObject[object] = 0; - } - - // Re-render - VtkApp.Instance.getRenderWindow().render(); - } -} diff --git a/resources/visu_vtk/js/core/VtkApp.js b/resources/visu_vtk/js/core/VtkApp.js deleted file mode 100644 index 8b75979..0000000 --- a/resources/visu_vtk/js/core/VtkApp.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Singleton managing the VTK rendering context. - * Handles the creation of renderer and render window for the visualization panel. - */ -class VtkApp { - - static get Instance() { - if (!this._i) { - this._i = new VtkApp(); - } - return this._i; - } - - /** - * Initializes the full-screen renderer in the given HTML scene - * @param {HTMLElement} scene - The HTML element to attach the renderer - */ - _readEditorBackground() { - const raw = getComputedStyle(document.body).getPropertyValue("--vscode-editor-background").trim(); - const match = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i); - if (match) { - return [parseInt(match[1], 16) / 255, parseInt(match[2], 16) / 255, parseInt(match[3], 16) / 255]; - } - return [0.4, 0.6, 1.0]; - } - - updateBackground() { - this.renderer.setBackground(this._readEditorBackground()); - } - - init(scene) { - if (!window.vtk) {return;} - - this.fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({ - rootContainer: scene, - background: this._readEditorBackground(), - }); - - this.renderer = this.fullScreenRenderer.getRenderer(); - this.renderWindow = this.fullScreenRenderer.getRenderWindow(); - - this.updateCameraOffset(); - - // Keep the offset in sync if the window or sidebar resizes - const controls = document.getElementById("controls"); - new ResizeObserver(() => this.updateCameraOffset()).observe(controls); - window.addEventListener("resize", () => this.updateCameraOffset()); - - // Refresh scene colors when VS Code theme changes - new MutationObserver(() => { - this.updateBackground(); - Controller.Instance.refreshThemeColors(); - this.renderWindow.render(); - }).observe(document.body, { attributes: true, attributeFilter: ["class"] }); - - Controller.Instance.getVSCodeAPI().postMessage({ - type: 'debugPanel', - text: 'vtkAppInitialized' - }); - } - - /** - * Offsets the camera so the scene appears centered in the area to the right of the sidebar. - * Also repositions the zoom widget to the center of that same area. - */ - updateCameraOffset() { - const sidebarWidth = document.getElementById("controls").offsetWidth; - const offset = sidebarWidth / window.innerWidth; - this.renderer.getActiveCamera().setWindowCenter(-offset, 0); - this.renderWindow.render(); - - const zoomWidget = document.getElementById("zoomWidget"); - if (zoomWidget) { - zoomWidget.style.left = `${sidebarWidth + (window.innerWidth - sidebarWidth) / 2}px`; - } - } - - /** @returns {vtkRenderer} The VTK renderer */ - getRenderer() { - return this.renderer; - } - - /** @returns {vtkRenderWindow} The VTK render window */ - getRenderWindow() { - return this.renderWindow; - } -} diff --git a/resources/visu_vtk/js/data/CreateGroups.js b/resources/visu_vtk/js/data/CreateGroups.js deleted file mode 100644 index f28f31a..0000000 --- a/resources/visu_vtk/js/data/CreateGroups.js +++ /dev/null @@ -1,101 +0,0 @@ -class CreateGroups { - /** - * Creates a CreateGroups. - * @param {string[]} fileContext The contexts of the files to load. - * @param {string[]} fileName The names of the files to load. - */ - constructor(fileContexts, fileNames) { - this.fileContexts = fileContexts; - this.fileNames = fileNames; - this.groups = {}; - } - - /** - * Loads the files, creates Actors instances - * @method - */ - do() { - - const result = ObjLoader.loadFiles(this.fileContexts, this.fileNames); - const post = (text) => { - Controller.Instance.getVSCodeAPI().postMessage({ - type: 'debugPanel', - text, - }); - }; - - if (!result) { - return; - } - - const { - vertices, - cells, - cellIndexToGroup, - nodes, - nodeIndexToGroup, - faceGroups, - nodeGroups, - groupHierarchy - } = result; - - const FaceActorCreato = new FaceActorCreator(vertices, cells, cellIndexToGroup); - const NodeActorCreato = new NodeActorCreator(vertices, nodes, nodeIndexToGroup); - - for (const fileGroup in groupHierarchy) { - const groupId = faceGroups.indexOf(fileGroup); - - // Record the color before create() increments the object index - const _oc = GlobalSettings.Instance.objectColors; - const objColor = _oc[GlobalSettings.Instance.objIndex % _oc.length]; - groupHierarchy[fileGroup].color = objColor; - - const { actor, colorIndex: fileColorIndex, isObjectActor: fileIsObj, cellCount: fileCellCount } = FaceActorCreato.create(fileGroup, groupId); - - const groupInstance = new Group(actor, fileGroup, true, null, null, fileColorIndex, fileIsObj, fileCellCount); - - this.groups[fileGroup] = groupInstance; - - const size = this.computeSize(actor); - - for (const faceGroup of groupHierarchy[fileGroup].faces) { - const groupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}`); - - const { actor: faceActor, colorIndex: faceColorIndex, isObjectActor: faceIsObj, cellCount: faceCellCount } = FaceActorCreato.create(faceGroup, groupId); - - const subGroup = new Group(faceActor, faceGroup, true, fileGroup, size, faceColorIndex, faceIsObj, faceCellCount); - this.groups[`${fileGroup}::${faceGroup}`] = subGroup; - } - - for (const nodeGroup of groupHierarchy[fileGroup].nodes) { - const groupId = nodeGroups.indexOf(`${fileGroup}::${nodeGroup}`); - - const { actor: nodeActor, colorIndex: nodeColorIndex } = NodeActorCreato.create(groupId); - - const subGroup = new Group(nodeActor, nodeGroup, false, fileGroup, size, nodeColorIndex, false); - this.groups[`${fileGroup}::${nodeGroup}`] = subGroup; - } - } - - //Reset the camera after Actors creation - VtkApp.Instance.getRenderer().resetCamera(); - VtkApp.Instance.getRenderWindow().render(); - post(`actors : ${Object.keys(this.groups).length}`); - - //Send groups to the controller - Controller.Instance.saveGroups(this.groups, groupHierarchy); - } - - computeSize(actor) { - const bounds = actor.getBounds(); - - const dx = bounds[1] - bounds[0]; - const dy = bounds[3] - bounds[2]; - const dz = bounds[5] - bounds[4]; - - const size = Math.sqrt(dx*dx + dy*dy + dz*dz); - - return Math.max(size, 1e-3); - } - -} \ No newline at end of file diff --git a/resources/visu_vtk/js/data/Group.js b/resources/visu_vtk/js/data/Group.js deleted file mode 100644 index 780583e..0000000 --- a/resources/visu_vtk/js/data/Group.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Represents a group in the visualization module. - * Can be a fileGroup or a sub-group of faces/nodes. - */ -class Group { - /** - * @param {vtkActor} actor - The VTK actor associated with the group - * @param {string} name - Name of the group (fileGroup or sub-group) - * @param {boolean} isFaceGroup - True for face group, false for nodal - * @param {string|null} fileGroup - Parent fileGroup name (null if this is a fileGroup) - * @param {number|null} parentSize - Size of the parent fileGroup (null if this is a fileGroup) - */ - constructor(actor, name, isFaceGroup, fileGroup = null, parentSize = null, colorIndex = null, isObjectActor = false, cellCount = null) { - this.actor = actor; - this.name = name; - this.isFaceGroup = isFaceGroup; - this.fileGroup = fileGroup; - this.size = parentSize; - this.colorIndex = colorIndex; - this.isObjectActor = isObjectActor; - this.cellCount = cellCount; - } - - applyThemeColor() { - if (this.colorIndex === null) return; - const colors = this.isObjectActor - ? GlobalSettings.Instance.objectColors - : GlobalSettings.Instance.meshGroupColors; - const color = colors[this.colorIndex % colors.length]; - this.actor.getProperty().setColor(color); - this._applyEdgeColor(); - } - - /** - * Updates edge rendering based on the current edge mode and zoom level. - * @param {number} currentDistance - * @param {number} initialDistance - */ - updateEdgeVisibility(currentDistance, initialDistance) { - if (this.cellCount === null) return; - const prop = this.actor.getProperty(); - const mode = GlobalSettings.Instance.edgeMode; - - if (mode === 'hide') { - prop.setEdgeVisibility(false); - return; - } - if (mode === 'show') { - prop.setEdgeVisibility(true); - prop.setEdgeColor(0, 0, 0); - return; - } - - const threshold = initialDistance * Math.sqrt(15000 / this.cellCount) * GlobalSettings.Instance.edgeThresholdMultiplier; - - if (mode === 'threshold') { - prop.setEdgeVisibility(currentDistance < threshold); - prop.setEdgeColor(0, 0, 0); - return; - } - - // 'gradual': blend edge color from surface color (invisible) to black (fully visible) - prop.setEdgeVisibility(true); - this._edgeT = Math.min(1, Math.max(0, threshold / currentDistance)); - this._applyEdgeColor(); - } - - _applyEdgeColor() { - const t = this._edgeT ?? 0; - const [r, g, b] = this.actor.getProperty().getColor(); - this.actor.getProperty().setEdgeColor(r * (1 - t), g * (1 - t), b * (1 - t)); - } - - /** - * Sets the visual point size of the actor based on distance. - * @param {number} distance - Distance used to compute scaling - */ - setSize(distance) { - const decay = this.size / 5; - const scale = Math.max(30 * (1 / Math.sqrt(1 + distance / decay)), 0); - this.actor.getProperty().setPointSize(scale); - } - - getColor() { - return this.actor.getProperty().getColor(); - } - - setVisibility(visible) { - this.actor.setVisibility(visible); - } - - setOpacity(opacity) { - this.actor.getProperty().setOpacity(opacity); - } -} diff --git a/resources/visu_vtk/js/data/ObjLoader.js b/resources/visu_vtk/js/data/ObjLoader.js deleted file mode 100644 index 34979f5..0000000 --- a/resources/visu_vtk/js/data/ObjLoader.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Loads OBJ-like file contents and constructs geometry data structures. - * Handles vertices, faces, nodes, face groups, node groups, and group hierarchy. - */ -class ObjLoader { - - /** - * Parses file contents and returns structured geometry info. - * @param {string[]} fileContexts - Array of file contents (one string per file) - * @param {string[]} fileNames - Corresponding names of the files - * @returns {Object} - Geometry data including vertices, cells, nodes, and group mappings - */ - static loadFiles(fileContexts, fileNames) { - - const vertices = [], - cells = [], - cellIndexToGroup = [], - nodes = [], - nodeIndexToGroup = [], - faceGroups = [], - nodeGroups = [], - groupHierarchy = {}; - - let nbVertices = 0; - let groupId = -1; - let nodeGroupId = -1; - - for (let i = 0; i < fileContexts.length; i++) { - try { - groupId++; - const skinName = "all_" + fileNames[i]; - - groupHierarchy[skinName] = { faces: [], nodes: [] }; - faceGroups.push(skinName); - nbVertices = vertices.length; - - // Split lines and normalize line endings - const lines = fileContexts[i].split('\n').map(l => l.replace('\r', '')); - - let vertexCount = 0; - let faceCount = 0; - - for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { - const line = lines[lineIdx]; - const ss = line.split(' ').filter(p => p.length !== 0); - if (ss.length === 0) { continue; } - - switch (ss[0]) { - case 'v': // Vertex definition - vertices.push({ - x: Number.parseFloat(ss[1]), - y: Number.parseFloat(ss[2]), - z: Number.parseFloat(ss[3]) - }); - vertexCount++; - break; - - case 'f': // Face definition - const faceIndices = ss.slice(1).map(p => Number.parseInt(p) - 1 + nbVertices); - cells.push(faceIndices); - cellIndexToGroup.push(groupId); - faceCount++; - break; - - case 'g': // New face group - groupId++; - const faceGroupName = ss[1] || `group${groupId}`; - faceGroups.push(`${skinName}::${faceGroupName}`); - groupHierarchy[skinName].faces.push(faceGroupName); - break; - - case 'ng': // New node group - nodeGroupId++; - const nodeGroupName = ss[1] || `nodeGroup${nodeGroupId}`; - nodeGroups.push(`${skinName}::${nodeGroupName}`); - groupHierarchy[skinName].nodes.push(nodeGroupName); - break; - - case 'p': // Node assignment - const nodeIndex = parseInt(ss[1]); - nodes.push(nodeIndex - 1 + nbVertices); - nodeIndexToGroup.push(nodeGroupId); - break; - } - } - - } catch (fileError) { - Controller.Instance.getVSCodeAPI().postMessage({ - type: 'debugPanel', - text: `ERROR: ${fileError.message}` - }); - throw fileError; - } - } - - Controller.Instance.getVSCodeAPI().postMessage({ - type: 'debugPanel', - text: `TOTAL: ${vertices.length} vertices, ${cells.length} cells, ${nodes.length} nodes` - }); - - return { - vertices, - cells, - cellIndexToGroup, - nodes, - nodeIndexToGroup, - faceGroups, - nodeGroups, - groupHierarchy - }; - } -} diff --git a/resources/visu_vtk/js/data/create/NodeActorCreator.js b/resources/visu_vtk/js/data/create/NodeActorCreator.js deleted file mode 100644 index d9d131f..0000000 --- a/resources/visu_vtk/js/data/create/NodeActorCreator.js +++ /dev/null @@ -1,91 +0,0 @@ -class NodeActorCreator { - /** - * @param {Vector[]} vertices - List of vertex coordinates - * @param {number[][]} nodes - - * @param {number[]} nodeIndexToGroup - Node-to-group index mapping - */ - constructor(vertices, nodes, nodeIndexToGroup) { - this.vertices = vertices; - this.nodes = nodes; - this.nodeIndexToGroup = nodeIndexToGroup; - } - - /** - * Creates and configures an actor for a face group. - * @param {number} groupId - * @returns {vtkActor} - */ - create(groupId) { - - const polyData = this.prepare(groupId); - - const mapper = vtk.Rendering.Core.vtkMapper.newInstance(); - mapper.setInputData(polyData); - - const actor = vtk.Rendering.Core.vtkActor.newInstance(); - actor.setMapper(mapper); - - const colorIndex = this.setProperty(actor); - VtkApp.Instance.getRenderer().addActor(actor); - - return { actor, colorIndex }; - } - - /** - * Prepares vtkPolyData for a given groupId using instance data. - * @param {number} groupId - * @returns {vtkPolyData} - */ -prepare(groupId) { - const pd = vtk.Common.DataModel.vtkPolyData.newInstance(); - - const nodeIndices = this.nodeIndexToGroup - .map((g, idx) => (g === groupId ? idx : -1)) - .filter(idx => idx !== -1); - - if (nodeIndices.length > 0) { - const pts = vtk.Common.Core.vtkPoints.newInstance(); - const data = []; - - for (const idx of nodeIndices) { - const v = this.vertices[this.nodes[idx]]; - if (v) { - data.push(v.x, v.y, v.z); - } - } - - pts.setData(Float32Array.from(data), 3); - pd.setPoints(pts); - - const numPoints = data.length / 3; - const verts = vtk.Common.Core.vtkCellArray.newInstance(); - const vertData = []; - - for (let i = 0; i < numPoints; i++) { - vertData.push(1, i); - } - - verts.setData(Uint32Array.from(vertData)); - pd.setVerts(verts); - - } - - return pd; -} - - /** - * Initialize rendering properties (color, opacity, visibility) - * @param {vtkActor} actor - * @param {string} groupName - */ - setProperty(actor) { - const prop = actor.getProperty(); - const colorIndex = GlobalSettings.Instance.grpIndex; - prop.setRepresentation(0); - prop.setOpacity(1); - actor.setVisibility(false); - prop.setColor(GlobalSettings.Instance.getColorForGroup()); - return colorIndex; - } - -} diff --git a/resources/visu_vtk/js/interaction/AxesCreator.js b/resources/visu_vtk/js/interaction/AxesCreator.js deleted file mode 100644 index f11c6be..0000000 --- a/resources/visu_vtk/js/interaction/AxesCreator.js +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Creates custom XYZ axes actors with colored cylinders and spheres for visualization. - * Provides utility to generate axes for VTK rendering. - */ -class CustomAxesCreator { - constructor() { - this.axisLength = 1.0; - this.axisRadius = 0.02; - this.sphereRadius = 0.08; - - this.colors = { - x: [1, 0, 0], - y: [0.251, 0.529, 0.376], - z: [0, 0, 1] - }; - } - - /** - * Creates a single actor containing X, Y, Z axes with spheres at the ends. - * @returns {vtkActor} - VTK actor containing all axes - */ - static createCustomAxesActor() { - const instance = new CustomAxesCreator(); - - const axisRadius = instance.axisRadius; - const sphereRadius = 0.1; - const sphereTheta = 12; - const spherePhi = 12; - - const addColor = (polyData, color) => { - const scalars = vtk.Common.Core.vtkDataArray.newInstance({ - numberOfComponents: 3, - values: new Uint8Array(polyData.getPoints().getNumberOfPoints() * 3), - name: 'color' - }); - - const colors = scalars.getData(); - const rgb = color.map(c => Math.round(c * 255)); - for (let i = 0; i < colors.length; i += 3) { - colors[i] = rgb[0]; - colors[i + 1] = rgb[1]; - colors[i + 2] = rgb[2]; - } - - polyData.getPointData().setScalars(scalars); - }; - - const xAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); - xAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ - radius: axisRadius, - resolution: 20, - direction: [1, 0, 0], - center: [0.5, 0, 0] - }).getOutputData()); - - xAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ - radius: sphereRadius, - center: [1, 0, 0], - thetaResolution: sphereTheta, - phiResolution: spherePhi - }).getOutputData()); - - const xAxis = xAxisSource.getOutputData(); - addColor(xAxis, instance.colors.x); - - const yAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); - yAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ - radius: axisRadius, - resolution: 20, - direction: [0, 1, 0], - center: [0, 0.5, 0] - }).getOutputData()); - - yAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ - radius: sphereRadius, - center: [0, 1, 0], - thetaResolution: sphereTheta, - phiResolution: spherePhi - }).getOutputData()); - - const yAxis = yAxisSource.getOutputData(); - addColor(yAxis, instance.colors.y); - - const zAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); - zAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ - radius: axisRadius, - resolution: 20, - direction: [0, 0, 1], - center: [0, 0, 0.5] - }).getOutputData()); - - zAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ - radius: sphereRadius, - center: [0, 0, 1], - thetaResolution: sphereTheta, - phiResolution: spherePhi - }).getOutputData()); - - const zAxis = zAxisSource.getOutputData(); - addColor(zAxis, instance.colors.z); - - // Combine all axes - const axesSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); - axesSource.setInputData(xAxis); - axesSource.addInputData(yAxis); - axesSource.addInputData(zAxis); - - const axesMapper = vtk.Rendering.Core.vtkMapper.newInstance(); - axesMapper.setInputData(axesSource.getOutputData()); - - const axesActor = vtk.Rendering.Core.vtkActor.newInstance(); - axesActor.setMapper(axesMapper); - axesActor.getProperty().setLighting(false); - - return axesActor; - } - - createAxisWithSphere(axis) { - const start = [0, 0, 0]; - const end = [0, 0, 0]; - end[['x', 'y', 'z'].indexOf(axis)] = this.axisLength; - - const cylinderSource = vtk.Filters.Sources.vtkCylinderSource.newInstance({ - height: this.axisLength, - radius: this.axisRadius, - resolution: 16 - }); - const cylinderMapper = vtk.Rendering.Core.vtkMapper.newInstance(); - cylinderMapper.setInputConnection(cylinderSource.getOutputPort()); - const cylinderActor = vtk.Rendering.Core.vtkActor.newInstance(); - cylinderActor.setMapper(cylinderMapper); - cylinderActor.getProperty().setColor(...this.colors[axis]); - this.positionCylinder(cylinderActor, start, end); - - const sphereSource = vtk.Filters.Sources.vtkSphereSource.newInstance({ - radius: this.sphereRadius, - thetaResolution: 16, - phiResolution: 16 - }); - const sphereMapper = vtk.Rendering.Core.vtkMapper.newInstance(); - sphereMapper.setInputConnection(sphereSource.getOutputPort()); - const sphereActor = vtk.Rendering.Core.vtkActor.newInstance(); - sphereActor.setMapper(sphereMapper); - sphereActor.setPosition(...end); - sphereActor.getProperty().setColor(...this.colors[axis]); - - return { cylinder: cylinderActor, sphere: sphereActor }; - } - - positionCylinder(actor, start, end) { - const center = [ - (start[0] + end[0]) / 2, - (start[1] + end[1]) / 2, - (start[2] + end[2]) / 2 - ]; - - const direction = [ - end[0] - start[0], - end[1] - start[1], - end[2] - start[2] - ]; - - const length = Math.sqrt(direction[0] ** 2 + direction[1] ** 2 + direction[2] ** 2); - const normalized = direction.map(d => d / length); - - const yAxis = [0, 1, 0]; - const rotationAxis = [ - yAxis[1] * normalized[2] - yAxis[2] * normalized[1], - yAxis[2] * normalized[0] - yAxis[0] * normalized[2], - yAxis[0] * normalized[1] - yAxis[1] * normalized[0] - ]; - - const dotProduct = yAxis[0] * normalized[0] + yAxis[1] * normalized[1] + yAxis[2] * normalized[2]; - const angle = Math.acos(dotProduct) * (180 / Math.PI); - - actor.setPosition(...center); - - const axisLength = Math.sqrt(rotationAxis[0] ** 2 + rotationAxis[1] ** 2 + rotationAxis[2] ** 2); - if (axisLength > 0.0001) { - actor.rotateWXYZ(angle, ...rotationAxis.map(a => a / axisLength)); - } - } -} diff --git a/resources/visu_vtk/js/interaction/CameraManager.js b/resources/visu_vtk/js/interaction/CameraManager.js deleted file mode 100644 index 98aaafe..0000000 --- a/resources/visu_vtk/js/interaction/CameraManager.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Manages the camera and node scaling in the VTK visualization. - */ -class CameraManager { - - static get Instance() { - if (!this._i) { - this._i = new CameraManager(); - } - return this._i; - } - - /** - * Initializes camera manager with node groups, sets up axis marker and size updates. - * @param {Object} groups - Map of groupName -> Group instances - */ - init(groups) { - this.nodesGroups = {}; - this.faceGroups = {}; - - const renderer = VtkApp.Instance.getRenderer(); - this.camera = renderer.getActiveCamera(); - this.initialDistance = this.camera.getDistance(); - this.lastDistance = this.initialDistance; - - for (const [groupName, group] of Object.entries(groups)) { - if (!group.isFaceGroup) { - this.nodesGroups[groupName] = group; - group.setSize(this.lastDistance); - } else if (group.cellCount !== null) { - this.faceGroups[groupName] = group; - group.updateEdgeVisibility(this.lastDistance, this.initialDistance); - } - } - - this._zoomIndicator = document.getElementById("zoomIndicator"); - this._resetZoomBtn = document.getElementById("resetZoomBtn"); - this._updateZoomIndicator(this.initialDistance); - - this.axisMarker = this.createAxisMarker(); - this.activateSizeUpdate(); - } - - /** - * Automatically updates node group sizes when the camera distance changes - */ - activateSizeUpdate() { - this.camera.onModified(() => { - const currentDistance = this.camera.getDistance(); - this._updateZoomIndicator(currentDistance); - if (Math.abs(currentDistance - this.lastDistance) > 1e-2) { - for (const nodeGroup of Object.values(this.nodesGroups)) { - nodeGroup.setSize(currentDistance); - } - for (const faceGroup of Object.values(this.faceGroups)) { - faceGroup.updateEdgeVisibility(currentDistance, this.initialDistance); - } - this.lastDistance = currentDistance; - } - }); - } - - _updateZoomIndicator(currentDistance) { - if (!this._zoomIndicator) return; - const ratio = this.initialDistance / currentDistance; - let text; - if (ratio >= 10) text = `${Math.round(ratio)}×`; - else if (ratio >= 1) text = `${ratio.toFixed(1)}×`; - else text = `${ratio.toFixed(2)}×`; - this._zoomIndicator.textContent = text; - const atDefault = Math.abs(ratio - 1) < 0.01; - this._resetZoomBtn?.classList.toggle("hidden!", atDefault); - } - - resetZoom() { - VtkApp.Instance.getRenderer().resetCamera(); - VtkApp.Instance.updateCameraOffset(); // resets window center offset and renders - } - - /** - * Moves the camera to a specific zoom ratio relative to the initial position. - * @param {number} ratio - e.g. 2 means 2× zoomed in from initial - */ - setZoom(ratio) { - const focalPoint = this.camera.getFocalPoint(); - const position = this.camera.getPosition(); - const dx = position[0] - focalPoint[0]; - const dy = position[1] - focalPoint[1]; - const dz = position[2] - focalPoint[2]; - const currentDist = Math.sqrt(dx * dx + dy * dy + dz * dz); - const scale = (this.initialDistance / ratio) / currentDist; - this.camera.setPosition( - focalPoint[0] + dx * scale, - focalPoint[1] + dy * scale, - focalPoint[2] + dz * scale - ); - VtkApp.Instance.getRenderer().resetCameraClippingRange(); - VtkApp.Instance.updateCameraOffset(); - } - - /** - * Re-applies edge visibility for all face groups using the current camera distance. - * Call this when the edge mode setting changes. - */ - refreshEdgeVisibility() { - for (const faceGroup of Object.values(this.faceGroups)) { - faceGroup.updateEdgeVisibility(this.lastDistance, this.initialDistance); - } - VtkApp.Instance.getRenderWindow().render(); - } - - /** - * Positions the camera along a given axis relative to its focal point. - * @param {string} axis - 'x', 'y', or 'z' - */ - setCameraAxis(axis) { - if (!this.camera) { return; } - - const focalPoint = this.camera.getFocalPoint(); - const distance = this.camera.getDistance(); - - let newPosition = [0, 0, 0]; - let viewUp = [0, 0, 1]; - - switch(axis.toLowerCase()) { - case 'x': - newPosition = [focalPoint[0] + distance, focalPoint[1], focalPoint[2]]; - break; - case 'y': - newPosition = [focalPoint[0], focalPoint[1] + distance, focalPoint[2]]; - break; - case 'z': - newPosition = [focalPoint[0], focalPoint[1], focalPoint[2] + distance]; - viewUp = [0, 1, 0]; - break; - default: - return; - } - - this.camera.setPosition(...newPosition); - this.camera.setViewUp(viewUp); - VtkApp.Instance.getRenderer().resetCameraClippingRange(); - VtkApp.Instance.getRenderWindow().render(); - } - - /** - * Creates an orientation marker widget with XYZ axes in the bottom-right corner. - * @returns {vtkOrientationMarkerWidget} - */ - createAxisMarker() { - const axes = CustomAxesCreator.createCustomAxesActor(); - - const widget = vtk.Interaction.Widgets.vtkOrientationMarkerWidget.newInstance({ - actor: axes, - interactor: VtkApp.Instance.getRenderWindow().getInteractor(), - }); - widget.setEnabled(true); - widget.setViewportCorner(vtk.Interaction.Widgets.vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT); - widget.setViewportSize(0.15); - - this.orientationWidget = widget; - this.axesActor = axes; - } -} diff --git a/resources/visu_vtk/js/settings/GlobalSettings.js b/resources/visu_vtk/js/settings/GlobalSettings.js deleted file mode 100644 index cb57824..0000000 --- a/resources/visu_vtk/js/settings/GlobalSettings.js +++ /dev/null @@ -1,114 +0,0 @@ -class GlobalSettings { - static get Instance() { - if (!this._instance) { - this._instance = new GlobalSettings(); - } - return this._instance; - } - - constructor() { - this.grpIndex = 0; - this.objIndex = 0; - } - - // scene - backgroundColor = [0.6627, 0.7960, 0.910]; // #a9cbe8 - ambientLightColor = [0.2, 0.2, 0.2]; // #333333 - lightColor = [0.6667, 0.6667, 0.6667]; // #aaaaaa - // app - surfaceInsideColor = [1, 1, 0]; // #ffff00 - - surfaceOutsideColor = [0.537, 0.529, 0.529]; // #898787 - localSelectedColor = [1, 1, 1]; // #ffffff - surfaceTransparentColor = [0.553, 0.749, 0.42]; // #8dbf6b - surfaceRenderOrder = 0; - - wireframeColor = [0, 0, 0]; // #000000 - wireframeOpacity = 0.35; - wireframeAlpha = 1; - wireframeRenderOrder = 10; - wireframeSelectedColor = [1, 1, 1]; // #ffffff - wireframeSelectedRenderOrder = 11; - - drawLineColor = [1, 0, 0]; // #ff0000 - drawLineHelperRenderOrder = 12; - selectHelperColor = [1, 1, 1]; // #ffffff - selectionPointColor = [1, 0, 0]; // #ff0000 - - hiddenObjectOpacity = 0; - edgeMode = 'threshold'; // 'hide' | 'show' | 'gradual' | 'threshold' - edgeThresholdMultiplier = 1; - - get isDark() { - return document.body.classList.contains('vscode-dark') || - document.body.classList.contains('vscode-high-contrast'); - } - - // Group colors — vivid for dark mode, toned down for light mode - _meshGroupColors = [ - [0.902, 0.098, 0.294], // #e6194b - [0.235, 0.706, 0.294], // #3cb44b - [1, 0.882, 0.098], // #ffe119 - [0.941, 0.196, 0.902], // #f032e6 - [0.961, 0.510, 0.192], // #f58231 - [0.569, 0.118, 0.706], // #911eb4 - [0.275, 0.941, 0.941], // #46f0f0 - [0.737, 0.965, 0.047], // #bcf60c - [0.980, 0.745, 0.745], // #fabebe - [0, 0.502, 0.502], // #008080 - [0.902, 0.745, 1 ], // #e6beff - [0.604, 0.388, 0.141], // #9a6324 - [0.263, 0.388, 0.847], // #4363d8 - [1, 0.980, 0.784], // #fffac8 - [0.502, 0, 0 ], // #800000 - [0.667, 1, 0.764], // #aaffc3 - [0.502, 0.502, 0 ], // #808000 - [1, 0.847, 0.694], // #ffd8b1 - [0, 0, 0.463], // #000075 - [0.502, 0.502, 0.502], // #808080 - ]; - - get meshGroupColors() { - if (this.isDark) return this._meshGroupColors; - return this._meshGroupColors.map(([r, g, b]) => [r * 0.72, g * 0.72, b * 0.72]); - } - - getColorForGroup() { - const idx = this.grpIndex % this._meshGroupColors.length; - this.grpIndex++; - return this.meshGroupColors[idx]; - } - - // Object base colors — muted for light mode, vivid for dark mode - _objectColorsLight = [ - [0.400, 0.620, 0.820], // steel blue - [0.280, 0.700, 0.580], // teal - [0.880, 0.560, 0.280], // amber - [0.600, 0.400, 0.800], // lavender - [0.380, 0.720, 0.420], // sage green - [0.820, 0.380, 0.440], // rose - [0.380, 0.680, 0.820], // sky - [0.820, 0.620, 0.380], // bronze - ]; - - _objectColorsDark = [ - [0.440, 0.720, 0.980], // bright steel blue - [0.240, 0.880, 0.700], // bright teal - [0.980, 0.660, 0.320], // bright amber - [0.720, 0.500, 0.980], // bright lavender - [0.400, 0.900, 0.500], // bright sage green - [0.980, 0.420, 0.520], // bright rose - [0.360, 0.800, 0.980], // bright sky - [0.980, 0.740, 0.440], // bright bronze - ]; - - get objectColors() { - return this.isDark ? this._objectColorsDark : this._objectColorsLight; - } - - getColorForObject() { - const idx = this.objIndex % this.objectColors.length; - this.objIndex++; - return this.objectColors[idx]; - } -} diff --git a/resources/visu_vtk/js/ui/UIManager.js b/resources/visu_vtk/js/ui/UIManager.js deleted file mode 100644 index 81e6c90..0000000 --- a/resources/visu_vtk/js/ui/UIManager.js +++ /dev/null @@ -1,597 +0,0 @@ -/** - * Manages the creation and interaction of UI elements in the visualization panel. - */ -class UIManager { - /** - * Manage a singleton instance - */ - static get Instance() { - if (!this._i) { - this._i = new UIManager(); - } - return this._i; - } - - /** - * Initializes the manager by adding onclick events, buttons and setting up the popup. - * @param {Map { - VisibilityManager.Instance.clear(); - }); - - // Group buttons popup - const selectGroupsBtn = document.getElementById("selectGroupsBtn"); - selectGroupsBtn.addEventListener("click", () => { - this.openGroupButtonsPopup(); - }); - const closeGroupsBtn = document.getElementById("closeGroupsBtn"); - closeGroupsBtn.addEventListener("click", () => { - this.closeGroupButtonsPopup(); - }); - const resetGroupsBtn = document.getElementById("resetGroupsBtn"); - resetGroupsBtn.addEventListener("click", () => { - this.resetGroupButtonsPopup(); - }); - - // Reset zoom button - const resetZoomBtn = document.getElementById("resetZoomBtn"); - resetZoomBtn.addEventListener("click", () => { - CameraManager.Instance.resetZoom(); - }); - - // Camera axis buttons, to allow quick camera control - const xBtn = document.getElementById("xBtn"); - const yBtn = document.getElementById("yBtn"); - const zBtn = document.getElementById("zBtn"); - xBtn.addEventListener("click", () => { - CameraManager.Instance.setCameraAxis("x"); - }); - yBtn.addEventListener("click", () => { - CameraManager.Instance.setCameraAxis("y"); - }); - zBtn.addEventListener("click", () => { - CameraManager.Instance.setCameraAxis("z"); - }); - - // Settings popup - const settingsBtn = document.getElementById("settingsBtn"); - settingsBtn.addEventListener("click", () => { - this.openSettingsPopup(); - }); - const closeSettingsBtn = document.getElementById("closeSettingsBtn"); - closeSettingsBtn.addEventListener("click", () => { - this.closeSettingsPopup(); - }); - const resetSettingsBtn = document.getElementById("resetSettingsBtn"); - resetSettingsBtn.addEventListener("click", () => { - this.resetSettings(); - }); - - // Hidden object opacity slider - const hiddenOpacitySlider = document.getElementById("hiddenOpacitySlider"); - const hiddenOpacityValue = document.getElementById("hiddenOpacityValue"); - hiddenOpacitySlider.addEventListener("input", () => { - const raw = parseInt(hiddenOpacitySlider.value, 10); - const pct = Math.min(raw, 50); - hiddenOpacitySlider.value = pct; - hiddenOpacityValue.textContent = `${pct}%`; - GlobalSettings.Instance.hiddenObjectOpacity = pct / 100; - VisibilityManager.Instance.applyHiddenObjectOpacity(); - Controller.Instance.getVSCodeAPI().postMessage({ - type: "saveSettings", - settings: { hiddenObjectOpacity: GlobalSettings.Instance.hiddenObjectOpacity }, - }); - }); - - // Edge threshold slider - const edgeThresholdSlider = document.getElementById("edgeThresholdSlider"); - const edgeThresholdValue = document.getElementById("edgeThresholdValue"); - edgeThresholdSlider.addEventListener("input", () => { - const multiplier = parseInt(edgeThresholdSlider.value, 10) / 100; - edgeThresholdValue.textContent = `${parseFloat(multiplier.toFixed(2))}×`; - GlobalSettings.Instance.edgeThresholdMultiplier = multiplier; - if (CameraManager.Instance.faceGroups) { CameraManager.Instance.refreshEdgeVisibility(); } - Controller.Instance.getVSCodeAPI().postMessage({ - type: "saveSettings", - settings: { edgeThresholdMultiplier: multiplier }, - }); - }); - - // Edge mode dropdown - this._edgeModeDescriptions = { - gradual: "Edges fade in as you zoom in, scaled by mesh density. When zoomed out, large meshes may appear very flat as outer edges are mostly hidden. Performance is impacted.", - threshold: "Edges appear abruptly at a zoom level based on mesh density. When zoomed out, large meshes may appear slightly flat as outer edges are hidden. Performance is not impacted.", - show: "Edges are always visible. Large meshes will appear almost entirely black when zoomed out. Performance is impacted.", - hide: "Edges are always hidden. All shapes will look slightly flat regardless of zoom level or mesh size.", - }; - const edgeModeOptions = [ - { value: 'threshold', label: 'Show edges when zooming (threshold)' }, - { value: 'gradual', label: 'Show edges when zooming (gradual)' }, - { value: 'show', label: 'Always show edges' }, - { value: 'hide', label: 'Always hide edges' }, - ]; - this._applyEdgeMode = (value, save = true) => { - GlobalSettings.Instance.edgeMode = value; - const label = document.getElementById("edgeModeSelectLabel"); - const desc = document.getElementById("edgeModeDesc"); - const thresholdSection = document.getElementById("edgeThresholdSection"); - if (label) label.textContent = edgeModeOptions.find(o => o.value === value)?.label ?? value; - if (desc) desc.textContent = this._edgeModeDescriptions[value] ?? ''; - if (thresholdSection) thresholdSection.classList.toggle("hidden!", value !== 'threshold'); - if (CameraManager.Instance.faceGroups) { CameraManager.Instance.refreshEdgeVisibility(); } - if (save) { - Controller.Instance.getVSCodeAPI().postMessage({ - type: "saveSettings", - settings: { edgeMode: value }, - }); - } - }; - new CustomDropdown( - document.getElementById("edgeModeSelect"), - edgeModeOptions, - (value) => this._applyEdgeMode(value), - () => GlobalSettings.Instance.edgeMode - ); - this._applyEdgeMode(GlobalSettings.Instance.edgeMode, false); - - // Zoom dropdown - new CustomDropdown( - document.getElementById("zoomTrigger"), - [ - { value: '0.5', label: '0.5×' }, - { value: '1', label: '1×' }, - { value: '1.5', label: '1.5×' }, - { value: '2', label: '2×' }, - { value: '5', label: '5×' }, - { value: '10', label: '10×' }, - ], - (value) => CameraManager.Instance.setZoom(parseFloat(value)), - null, - { align: 'right' } - ); - - // Help popup - const helpBtn = document.getElementById("helpBtn"); - helpBtn.addEventListener("click", () => { - this.openHelpPopup(); - }); - const closeHelpBtn = document.getElementById("closeHelpBtn"); - closeHelpBtn.addEventListener("click", () => { - this.closeHelpPopup(); - }); - } - - /** - * Add the list of group buttons to the sidebar. - * @param {Map } objects A map of objects with their corresponding face and node groups. - */ - addGroupButtons(objects) { - // Hack to retrieve necessary icons - const eyeIconUrl = document.getElementById("eye").src; - // Inline SVG paths for face/node icons (fill="currentColor" inherits button text color) - const faceSvgPath = "M161-366q-16-12-15.5-31.5T162-429q11-8 24-8t24 8l270 209 270-209q11-8 24-8t24 8q16 12 16.5 31.5T799-366L529-156q-22 17-49 17t-49-17L161-366Zm270 8L201-537q-31-24-31-63t31-63l230-179q22-17 49-17t49 17l230 179q31 24 31 63t-31 63L529-358q-22 17-49 17t-49-17Zm49-64 230-178-230-178-230 178 230 178Zm0-178Z"; - const nodeSvgPath = "M580-120q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Zm0-80q17 0 28.5-11.5T620-240q0-17-11.5-28.5T580-280q-17 0-28.5 11.5T540-240q0 17 11.5 28.5T580-200Zm80-200q-92 0-156-64t-64-156q0-92 64-156t156-64q92 0 156 64t64 156q0 92-64 156t-156 64Zm0-80q59 0 99.5-40.5T800-620q0-59-40.5-99.5T660-760q-59 0-99.5 40.5T520-620q0 59 40.5 99.5T660-480ZM280-240q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T360-400q0-33-23.5-56.5T280-480q-33 0-56.5 23.5T200-400q0 33 23.5 56.5T280-320Zm300 80Zm80-380ZM280-400Z"; - const eyeOffIconUrl = document.getElementById("eye_off").src; - - // Get group buttons div - const groupButtonsDiv = document.getElementById("groupButtons"); - - // Add buttons for each object and its groups - for (const object in objects) { - const { faces, nodes } = objects[object]; - const objectName = object.replace("all_", "").replace(".obj", ""); - - // Create object label - const objectLabel = document.createElement("span"); - objectLabel.id = `obj_${objectName}`; - objectLabel.classList.add( - "h-4.5", - "w-full", - "self-stretch", - "flex", - "items-center", - "gap-1", - "pl-1.25", - "pr-0.5", - "mb-2", - "not-nth-of-type-[1]:mt-1", - "text-xs", - "font-bold" - ); - objectLabel.style.color = "var(--ui-text-primary)"; - - const groupCount = faces.length + nodes.length; - - const [r, g, b] = objects[object].color ?? [0.537, 0.529, 0.529]; - const colorCss = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; - const objSvgPath = "M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"; - const icon = ``; - const text = `${objectName}`; - const eyeBtn = ``; - objectLabel.innerHTML = icon + text + eyeBtn; - - groupButtonsDiv.appendChild(objectLabel); - - // Eye button toggles full mesh visibility - document.getElementById(`eyeBtn_${object}`).addEventListener("click", () => { - const nowVisible = VisibilityManager.Instance.toggleObjectVisibility(object); - document.getElementById(`eyeIcon_${object}`).src = nowVisible ? eyeIconUrl : eyeOffIconUrl; - if (!nowVisible) { - groupContainer.classList.add("hidden!"); - groupCountEl.classList.remove("hidden!"); - } else { - groupContainer.classList.remove("hidden!"); - groupCountEl.classList.add("hidden!"); - } - }); - - // Create collapsible container for group buttons - const groupContainer = document.createElement("div"); - groupContainer.id = `grpContainer_${object}`; - groupContainer.classList.add("w-full", "flex", "flex-col", "items-center", "space-y-1"); - - // Create collapsed summary shown in place of the buttons - const groupCountEl = document.createElement("div"); - groupCountEl.id = `grpCount_${object}`; - groupCountEl.classList.add("hidden!", "w-full", "text-center", "text-[0.7rem]", "font-normal", "mb-2"); - groupCountEl.style.color = "var(--ui-text-muted)"; - groupCountEl.textContent = `${groupCount} groups`; - - // Name span toggles group container visibility (disabled when all groups are hidden or mesh is hidden) - document.getElementById(`objName_${object}`).addEventListener("click", () => { - if (VisibilityManager.Instance.hiddenObjects[object]) { return; } - const grpHidden = document.getElementById(`grpHidden_${object}`); - const allHidden = grpHidden && !grpHidden.classList.contains("hidden!") && - [...groupContainer.querySelectorAll(`[id^="btn_${object}::"]`)].every(b => b.classList.contains("hidden!")); - if (allHidden) { return; } - const collapsed = groupContainer.classList.toggle("hidden!"); - groupCountEl.classList.toggle("hidden!", !collapsed); - }); - - // Create group buttons for the current object - const groupNames = faces.concat(nodes); - groupNames.forEach((groupName) => { - const btn = document.createElement("button"); - btn.id = `btn_${object}::${groupName}`; - btn.classList.add( - "relative", - "flex", - "items-center", - "justify-center", - "rounded-sm", - "text-xs", - "px-2", - "pt-0.75", - "pb-1.25", - "w-full", - "cursor-pointer" - ); - btn.style.background = "var(--ui-element-bg)"; - btn.style.color = "var(--ui-text-primary)"; - btn.addEventListener("mouseover", () => { - if (!btn.dataset.highlighted) { - btn.style.background = "var(--ui-element-bg-hover)"; - } - }); - btn.addEventListener("mouseout", () => { - if (!btn.dataset.highlighted) { - btn.style.background = "var(--ui-element-bg)"; - } - }); - - const icon = ``; - const text = `${groupName}`; - btn.innerHTML = icon + text; - - btn.addEventListener("click", () => { - VisibilityManager.Instance.setVisibility(`${object}::${groupName}`); - }); - - groupContainer.appendChild(btn); - }); - - // Small label showing how many groups are hidden from the sidebar - const grpHiddenEl = document.createElement("div"); - grpHiddenEl.id = `grpHidden_${object}`; - grpHiddenEl.classList.add("hidden!", "w-full", "text-center", "text-[0.7rem]", "pb-1"); - grpHiddenEl.style.color = "var(--ui-text-muted)"; - groupContainer.appendChild(grpHiddenEl); - - groupButtonsDiv.appendChild(groupContainer); - groupButtonsDiv.appendChild(groupCountEl); - } - } - - /** - * Set a group button's status between highlighted or not. - * A highlighted button will be colorful with bold text, while a non highlighted button will be grey. - * @param {HTMLButtonElement} groupName The group button that will be highlighted or not. - * @param {number[]} color An RGB color array corresponding to the group. The highlight will be removed if not set. - */ - highlightButton(groupName, color) { - const btn = document.getElementById(`btn_${groupName}`); - - if (color) { - btn.classList.add("font-semibold"); - btn.dataset.highlighted = "1"; - btn.style.background = `rgb(${color[0] * 255}, ${color[1] * 255}, ${color[2] * 255}, 0.8)`; - btn.style.color = "var(--ui-highlight-text)"; - } else { - btn.classList.remove("font-semibold"); - delete btn.dataset.highlighted; - btn.style.background = "var(--ui-element-bg)"; - btn.style.color = "var(--ui-text-primary)"; - } - } - - /** - * Add the list of group buttons to the sidebar. - * @param {Map } objects A map of objects with their corresponding face and node groups. - */ - initGroupButtonsPopup(objects) { - const groupList = document.getElementById("groupList"); - - const faceSvgPath = "M161-366q-16-12-15.5-31.5T162-429q11-8 24-8t24 8l270 209 270-209q11-8 24-8t24 8q16 12 16.5 31.5T799-366L529-156q-22 17-49 17t-49-17L161-366Zm270 8L201-537q-31-24-31-63t31-63l230-179q22-17 49-17t49 17l230 179q31 24 31 63t-31 63L529-358q-22 17-49 17t-49-17Zm49-64 230-178-230-178-230 178 230 178Zm0-178Z"; - const nodeSvgPath = "M580-120q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35Zm0-80q17 0 28.5-11.5T620-240q0-17-11.5-28.5T580-280q-17 0-28.5 11.5T540-240q0 17 11.5 28.5T580-200Zm80-200q-92 0-156-64t-64-156q0-92 64-156t156-64q92 0 156 64t64 156q0 92-64 156t-156 64Zm0-80q59 0 99.5-40.5T800-620q0-59-40.5-99.5T660-760q-59 0-99.5 40.5T520-620q0 59 40.5 99.5T660-480ZM280-240q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T360-400q0-33-23.5-56.5T280-480q-33 0-56.5 23.5T200-400q0 33 23.5 56.5T280-320Zm300 80Zm80-380ZM280-400Z"; - const objSvgPath = "M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-40-343 237-137-237-137-237 137 237 137ZM160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11L160-252Zm320-228Z"; - const makeSvg = (path, fill, cls) => { - const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - svg.setAttribute("viewBox", "0 -960 960 960"); - svg.setAttribute("fill", fill); - svg.classList.add(...cls.split(" ")); - const p = document.createElementNS("http://www.w3.org/2000/svg", "path"); - p.setAttribute("d", path); - svg.appendChild(p); - return svg; - }; - - for (const object in objects) { - const { faces, nodes } = objects[object]; - const objectName = object.replace("all_", "").replace(".obj", ""); - - const [r, g, b] = objects[object].color ?? [0.537, 0.529, 0.529]; - const colorCss = `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; - - const objectDiv = document.createElement("div"); - objectDiv.classList.add("break-inside-avoid", "flex", "flex-col", "space-y-1.5", "mb-5"); - objectDiv.dataset.object = object; - - // Object header with select-all toggle - const header = document.createElement("div"); - header.classList.add("flex", "items-center", "justify-between", "pb-1"); - header.style.borderBottom = "1px solid var(--ui-border)"; - - const nameGroup = document.createElement("div"); - nameGroup.classList.add("flex", "items-center", "gap-1.5"); - nameGroup.appendChild(makeSvg(objSvgPath, colorCss, "size-4 shrink-0")); - - const nameSpan = document.createElement("span"); - nameSpan.classList.add("font-semibold", "text-sm"); - nameSpan.textContent = objectName; - nameGroup.appendChild(nameSpan); - - const toggleAll = document.createElement("button"); - toggleAll.classList.add("text-xs", "leading-none", "cursor-pointer", "px-1.5", "py-0.5", "rounded-sm"); - toggleAll.style.color = "var(--ui-text-secondary)"; - toggleAll.addEventListener("mouseover", () => { toggleAll.style.background = "var(--ui-element-bg)"; }); - toggleAll.addEventListener("mouseout", () => { toggleAll.style.background = ""; }); - toggleAll.textContent = "Hide all"; - - header.appendChild(nameGroup); - header.appendChild(toggleAll); - objectDiv.appendChild(header); - - // Group checkboxes - const groups = faces.concat(nodes); - groups.forEach((groupName) => { - const label = document.createElement("label"); - label.classList.add("flex", "items-center", "gap-1.5", "cursor-pointer", "select-none"); - - const input = document.createElement("input"); - input.type = "checkbox"; - input.checked = true; - input.classList.add("custom-cb"); - input.addEventListener("change", () => { - this.applyGroupVisibility(object, objectDiv); - toggleAll.textContent = this.allUnchecked(objectDiv) ? "Show all" : "Hide all"; - }); - - const isFace = faces.includes(groupName); - const groupIcon = makeSvg(isFace ? faceSvgPath : nodeSvgPath, "currentColor", "size-3.5 shrink-0"); - - const span = document.createElement("span"); - span.classList.add("text-xs", "truncate", "-translate-y-px"); - span.textContent = groupName; - - label.appendChild(input); - label.appendChild(groupIcon); - label.appendChild(span); - objectDiv.appendChild(label); - }); - - toggleAll.addEventListener("click", () => { - const allOff = this.allUnchecked(objectDiv); - objectDiv.querySelectorAll("input[type=checkbox]").forEach((cb) => { cb.checked = allOff; }); - this.applyGroupVisibility(object, objectDiv); - toggleAll.textContent = allOff ? "Hide all" : "Show all"; - }); - - groupList.appendChild(objectDiv); - } - } - - /** - * Returns true if all checkboxes in the given object div are unchecked. - * @param {HTMLElement} objectDiv - */ - allUnchecked(objectDiv) { - return [...objectDiv.querySelectorAll("input[type=checkbox]")].every((cb) => !cb.checked); - } - - /** - * Apply checkbox state to sidebar button visibility for one object. - * @param {string} objectKey - * @param {string} objectName - * @param {HTMLElement} objectDiv - */ - applyGroupVisibility(objectKey, objectDiv) { - let hiddenCount = 0; - objectDiv.querySelectorAll("label").forEach((label) => { - const input = label.querySelector("input"); - const span = label.querySelector("span"); - const btn = document.getElementById(`btn_${objectKey}::${span.textContent.trim()}`); - if (input.checked) { - btn.classList.remove("hidden!"); - } else { - btn.classList.add("hidden!"); - hiddenCount++; - } - }); - - const grpHiddenEl = document.getElementById(`grpHidden_${objectKey}`); - if (grpHiddenEl) { - if (hiddenCount > 0) { - grpHiddenEl.textContent = `${hiddenCount} hidden`; - grpHiddenEl.classList.remove("hidden!"); - } else { - grpHiddenEl.classList.add("hidden!"); - } - } - - // Update name span cursor: not collapsible when all groups are hidden - const allHidden = hiddenCount === objectDiv.querySelectorAll("label").length; - const nameSpan = document.getElementById(`objName_${objectKey}`); - if (nameSpan) { - nameSpan.style.cursor = allHidden ? "default" : ""; - } - } - - /** - * Open the group buttons popup - */ - openGroupButtonsPopup() { - const popup = document.getElementById("popup"); - const groupButtonsPopup = document.getElementById("groupButtonsPopup"); - popup.classList.remove("hidden!"); - groupButtonsPopup.classList.remove("hidden!"); - } - - /** - * Reset all group checkboxes to checked (show all groups in sidebar). - */ - resetGroupButtonsPopup() { - const groupList = document.getElementById("groupList"); - for (const objectDiv of groupList.children) { - const objectKey = objectDiv.dataset.object; - objectDiv.querySelectorAll("input[type=checkbox]").forEach((cb) => { cb.checked = true; }); - this.applyGroupVisibility(objectKey, objectDiv); - const toggleAll = objectDiv.querySelector("button"); - if (toggleAll) { toggleAll.textContent = "Hide all"; } - } - } - - /** - * Close the group buttons popup - */ - closeGroupButtonsPopup() { - const popup = document.getElementById("popup"); - const groupButtonsPopup = document.getElementById("groupButtonsPopup"); - popup.classList.add("hidden!"); - groupButtonsPopup.classList.add("hidden!"); - } - - /** - * Reset all settings to their default values, apply them, and save them. - */ - resetSettings() { - this.applySettings({ hiddenObjectOpacity: 0, edgeMode: 'threshold', edgeThresholdMultiplier: 1 }); - VisibilityManager.Instance.applyHiddenObjectOpacity(); - Controller.Instance.getVSCodeAPI().postMessage({ - type: "saveSettings", - settings: { hiddenObjectOpacity: 0, edgeMode: 'threshold', edgeThresholdMultiplier: 1 }, - }); - } - - /** - * Apply settings received from the extension to the UI and runtime state. - * @param {Object} settings - */ - applySettings(settings) { - if (!settings) { return; } - - if (settings.hiddenObjectOpacity !== undefined) { - const pct = Math.round(settings.hiddenObjectOpacity * 100); - const slider = document.getElementById("hiddenOpacitySlider"); - const label = document.getElementById("hiddenOpacityValue"); - slider.value = pct; - label.textContent = `${pct}%`; - GlobalSettings.Instance.hiddenObjectOpacity = settings.hiddenObjectOpacity; - } - - if (settings.edgeMode !== undefined) { - this._applyEdgeMode?.(settings.edgeMode, false); - } - - if (settings.edgeThresholdMultiplier !== undefined) { - const pct = Math.round(settings.edgeThresholdMultiplier * 100); - const slider = document.getElementById("edgeThresholdSlider"); - const label = document.getElementById("edgeThresholdValue"); - slider.value = pct; - label.textContent = `${parseFloat((pct / 100).toFixed(2))}×`; - GlobalSettings.Instance.edgeThresholdMultiplier = pct / 100; - } - } - - /** - * Open the settings popup - */ - openSettingsPopup() { - const popup = document.getElementById("popup"); - const settingsPopup = document.getElementById("settingsPopup"); - popup.classList.remove("hidden!"); - settingsPopup.classList.remove("hidden!"); - } - - /** - * Close the settings popup - */ - closeSettingsPopup() { - const popup = document.getElementById("popup"); - const settingsPopup = document.getElementById("settingsPopup"); - popup.classList.add("hidden!"); - settingsPopup.classList.add("hidden!"); - } - - /** - * Open the help popup - */ - openHelpPopup() { - const popup = document.getElementById("popup"); - const helpPopup = document.getElementById("helpPopup"); - popup.classList.remove("hidden!"); - helpPopup.classList.remove("hidden!"); - } - - /** - * Close the help popup - */ - closeHelpPopup() { - const popup = document.getElementById("popup"); - const helpPopup = document.getElementById("helpPopup"); - popup.classList.add("hidden!"); - helpPopup.classList.add("hidden!"); - } -} diff --git a/resources/visu_vtk/styles.css b/resources/visu_vtk/src/app.css similarity index 91% rename from resources/visu_vtk/styles.css rename to resources/visu_vtk/src/app.css index 69b94a7..2e20f83 100644 --- a/resources/visu_vtk/styles.css +++ b/resources/visu_vtk/src/app.css @@ -10,23 +10,17 @@ --ui-border: var(--vscode-widget-border, var(--vscode-editorWidget-border, rgba(0,0,0,0.1))); --icon-filter: none; - /* Text contrast levels */ --ui-text-primary: color-mix(in srgb, var(--ui-fg) 90%, transparent); --ui-text-secondary: color-mix(in srgb, var(--ui-fg) 70%, transparent); --ui-text-muted: color-mix(in srgb, var(--ui-fg) 55%, transparent); - - /* Element backgrounds */ --ui-element-bg: color-mix(in srgb, var(--ui-fg) 10%, transparent); --ui-element-bg-hover: color-mix(in srgb, var(--ui-fg) 18%, transparent); - - /* Text on highlighted group buttons — light mode: dark 0.72× colors → white text */ --ui-highlight-text: rgba(255, 255, 255, 0.9); } body.vscode-dark, body.vscode-high-contrast { --icon-filter: invert(1); - /* Dark mode: bright vivid colors → dark text for contrast */ --ui-highlight-text: rgba(0, 0, 0, 0.8); } diff --git a/resources/visu_vtk/src/components/ActionButtons.svelte b/resources/visu_vtk/src/components/ActionButtons.svelte new file mode 100644 index 0000000..980f626 --- /dev/null +++ b/resources/visu_vtk/src/components/ActionButtons.svelte @@ -0,0 +1,51 @@ + + +
+
+ + +
+
+
+ + +
+
diff --git a/resources/visu_vtk/src/components/App.svelte b/resources/visu_vtk/src/components/App.svelte new file mode 100644 index 0000000..a34aad7 --- /dev/null +++ b/resources/visu_vtk/src/components/App.svelte @@ -0,0 +1,38 @@ + + +{#if hasData} + { openPopup = 'groups'; }} /> +{/if} + + { openPopup = 'settings'; }} + onOpenHelp={() => { openPopup = 'help'; }} +/> + + + +{#if openPopup} + { openPopup = null; }}> + {#if openPopup === 'help'} + { openPopup = null; }} /> + {:else if openPopup === 'settings'} + { openPopup = null; }} /> + {:else if openPopup === 'groups'} + { openPopup = null; }} /> + {/if} + +{/if} diff --git a/resources/visu_vtk/src/components/AxisButtons.svelte b/resources/visu_vtk/src/components/AxisButtons.svelte new file mode 100644 index 0000000..4b0cbe1 --- /dev/null +++ b/resources/visu_vtk/src/components/AxisButtons.svelte @@ -0,0 +1,33 @@ + + +
+ + + +
diff --git a/resources/visu_vtk/src/components/GroupButton.svelte b/resources/visu_vtk/src/components/GroupButton.svelte new file mode 100644 index 0000000..eae2b92 --- /dev/null +++ b/resources/visu_vtk/src/components/GroupButton.svelte @@ -0,0 +1,49 @@ + + +{#if !isHidden} + +{/if} diff --git a/resources/visu_vtk/src/components/ObjectSection.svelte b/resources/visu_vtk/src/components/ObjectSection.svelte new file mode 100644 index 0000000..6352a93 --- /dev/null +++ b/resources/visu_vtk/src/components/ObjectSection.svelte @@ -0,0 +1,101 @@ + + + + + + {objectName} + + + + +{#if isHidden} +
+ {groupCount} groups +
+{:else} + {#if !collapsed} +
+ {#each faces as groupName} + + {/each} + {#each nodes as groupName} + + {/each} + {#if hiddenGroupCount > 0} +
+ {hiddenGroupCount} hidden +
+ {/if} +
+ {:else} +
+ {groupCount} groups +
+ {/if} +{/if} diff --git a/resources/visu_vtk/src/components/Sidebar.svelte b/resources/visu_vtk/src/components/Sidebar.svelte new file mode 100644 index 0000000..d7b483b --- /dev/null +++ b/resources/visu_vtk/src/components/Sidebar.svelte @@ -0,0 +1,33 @@ + + +
+
+ {#each Object.entries($groupHierarchy) as [key, data]} + + {/each} +
+ + + +
+ + +
diff --git a/resources/visu_vtk/src/components/TopActions.svelte b/resources/visu_vtk/src/components/TopActions.svelte new file mode 100644 index 0000000..53da7ee --- /dev/null +++ b/resources/visu_vtk/src/components/TopActions.svelte @@ -0,0 +1,45 @@ + + +
+ + +
diff --git a/resources/visu_vtk/src/components/ZoomWidget.svelte b/resources/visu_vtk/src/components/ZoomWidget.svelte new file mode 100644 index 0000000..dce26a8 --- /dev/null +++ b/resources/visu_vtk/src/components/ZoomWidget.svelte @@ -0,0 +1,65 @@ + + +
+ +
{ (e.currentTarget as HTMLElement).style.background = 'color-mix(in srgb, var(--ui-fg) 7%, transparent)'; }} + onmouseout={(e) => { (e.currentTarget as HTMLElement).style.background = ''; }} + role="button" + tabindex="0" + > + {zoomText} +
+ {#if !$isAtDefaultZoom} + + {/if} +
diff --git a/resources/visu_vtk/src/components/popups/GroupsPopup.svelte b/resources/visu_vtk/src/components/popups/GroupsPopup.svelte new file mode 100644 index 0000000..7227b17 --- /dev/null +++ b/resources/visu_vtk/src/components/popups/GroupsPopup.svelte @@ -0,0 +1,143 @@ + + +
e.stopPropagation()} + role="document" +> +
+ Sidebar groups + + Choose which groups are shown in the sidebar. Hidden groups remain visible in the 3D view. + +
+ +
+ {#each objects as obj (obj.key)} + {@const allOff = allUnchecked(obj.key, obj.allGroups)} +
+
+
+ + {obj.name} +
+ +
+ + {#each obj.allGroups as group} + + {/each} +
+ {/each} +
+ +
+ + +
+
diff --git a/resources/visu_vtk/src/components/popups/HelpPopup.svelte b/resources/visu_vtk/src/components/popups/HelpPopup.svelte new file mode 100644 index 0000000..5c56a9c --- /dev/null +++ b/resources/visu_vtk/src/components/popups/HelpPopup.svelte @@ -0,0 +1,72 @@ + + +
e.stopPropagation()} + role="document" +> + Help + +
+
+ Group highlighting +
    +
  • Click on a group name in the sidebar to highlight or unhighlight it
  • +
  • + Click on the + + button in the sidebar to reset highlight status for all groups +
  • +
  • + Click on the + + button in the sidebar to choose which groups are easily accessible in the sidebar +
  • +
  • Objects becomes transparent when you highlight their groups, helping visualize details more clearly
  • +
+
+ +
+ Camera control +
    +
  • Hold Left click and move your mouse to rotate the camera
  • +
  • Hold Ctrl + Left click and move your mouse to rotate the camera around an axis
  • +
  • Hold Shift + Left click and move your mouse to pan the camera
  • +
  • Use the Mouse wheel to zoom in and out
  • +
  • + Click on the X, + Y and + Z buttons at the bottom of the sidebar to quickly align the camera along an axis +
  • +
+
+ +
+ File management +
    +
  • + Mesh files (.*med files) are converted to .obj files, + which are stored in a hidden folder called .visu_data/ in your workspace +
  • +
+
+
+ +
+ +
+
diff --git a/resources/visu_vtk/src/components/popups/Popup.svelte b/resources/visu_vtk/src/components/popups/Popup.svelte new file mode 100644 index 0000000..9d8fe7a --- /dev/null +++ b/resources/visu_vtk/src/components/popups/Popup.svelte @@ -0,0 +1,18 @@ + + + diff --git a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte new file mode 100644 index 0000000..0074015 --- /dev/null +++ b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte @@ -0,0 +1,186 @@ + + +
e.stopPropagation()} + role="document" +> + Settings + +
+
+ +
{ (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg-hover)'; }} + onmouseout={(e) => { (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg)'; }} + role="button" + tabindex="0" + > + {edgeModeLabel} + +
+ {edgeModeDesc} + {#if showThresholdSection} +
+
+ + {edgeThresholdDisplay}× +
+ + Higher values show edges from farther away. +
+ {/if} +
+ +
+
+ + {hiddenOpacityPct}% +
+ + + When hiding an object with the eye button, it can remain slightly visible as a ghost. + +
+
+ +
+ + +
+
diff --git a/resources/visu_vtk/src/icons/ChevronIcon.svelte b/resources/visu_vtk/src/icons/ChevronIcon.svelte new file mode 100644 index 0000000..e084886 --- /dev/null +++ b/resources/visu_vtk/src/icons/ChevronIcon.svelte @@ -0,0 +1,7 @@ + + + + diff --git a/resources/visu_vtk/src/icons/ClearIcon.svelte b/resources/visu_vtk/src/icons/ClearIcon.svelte new file mode 100644 index 0000000..de72505 --- /dev/null +++ b/resources/visu_vtk/src/icons/ClearIcon.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/resources/visu_vtk/src/icons/EyeIcon.svelte b/resources/visu_vtk/src/icons/EyeIcon.svelte new file mode 100644 index 0000000..b1ef35a --- /dev/null +++ b/resources/visu_vtk/src/icons/EyeIcon.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/resources/visu_vtk/src/icons/EyeOffIcon.svelte b/resources/visu_vtk/src/icons/EyeOffIcon.svelte new file mode 100644 index 0000000..130ad8f --- /dev/null +++ b/resources/visu_vtk/src/icons/EyeOffIcon.svelte @@ -0,0 +1,10 @@ + + + + + + + diff --git a/resources/visu_vtk/src/icons/FaceIcon.svelte b/resources/visu_vtk/src/icons/FaceIcon.svelte new file mode 100644 index 0000000..b2ebf6c --- /dev/null +++ b/resources/visu_vtk/src/icons/FaceIcon.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/resources/visu_vtk/src/icons/FilterIcon.svelte b/resources/visu_vtk/src/icons/FilterIcon.svelte new file mode 100644 index 0000000..f5c9864 --- /dev/null +++ b/resources/visu_vtk/src/icons/FilterIcon.svelte @@ -0,0 +1,7 @@ + + + + diff --git a/resources/visu_vtk/src/icons/NodeIcon.svelte b/resources/visu_vtk/src/icons/NodeIcon.svelte new file mode 100644 index 0000000..effefe5 --- /dev/null +++ b/resources/visu_vtk/src/icons/NodeIcon.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/resources/visu_vtk/src/icons/ObjectIcon.svelte b/resources/visu_vtk/src/icons/ObjectIcon.svelte new file mode 100644 index 0000000..fc0d680 --- /dev/null +++ b/resources/visu_vtk/src/icons/ObjectIcon.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/resources/visu_vtk/src/icons/QuestionIcon.svelte b/resources/visu_vtk/src/icons/QuestionIcon.svelte new file mode 100644 index 0000000..d87029c --- /dev/null +++ b/resources/visu_vtk/src/icons/QuestionIcon.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/resources/visu_vtk/src/icons/ResetIcon.svelte b/resources/visu_vtk/src/icons/ResetIcon.svelte new file mode 100644 index 0000000..4435773 --- /dev/null +++ b/resources/visu_vtk/src/icons/ResetIcon.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/resources/visu_vtk/src/icons/SettingsIcon.svelte b/resources/visu_vtk/src/icons/SettingsIcon.svelte new file mode 100644 index 0000000..1885533 --- /dev/null +++ b/resources/visu_vtk/src/icons/SettingsIcon.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/resources/visu_vtk/src/icons/ZoomIcon.svelte b/resources/visu_vtk/src/icons/ZoomIcon.svelte new file mode 100644 index 0000000..7fd3230 --- /dev/null +++ b/resources/visu_vtk/src/icons/ZoomIcon.svelte @@ -0,0 +1,10 @@ + + + + + + + diff --git a/resources/visu_vtk/src/lib/Controller.ts b/resources/visu_vtk/src/lib/Controller.ts new file mode 100644 index 0000000..4c16924 --- /dev/null +++ b/resources/visu_vtk/src/lib/Controller.ts @@ -0,0 +1,76 @@ +import { VtkApp } from './core/VtkApp'; +import { CreateGroups } from './data/CreateGroups'; +import { VisibilityManager } from './commands/VisibilityManager'; +import { CameraManager } from './interaction/CameraManager'; +import { groupHierarchy as groupHierarchyStore } from './state'; +import type { Group } from './data/Group'; + +export class Controller { + private static _i: Controller; + private _scene: HTMLElement | null = null; + private _vsCodeApi: any = null; + private _groups: Record | null = null; + private _groupHierarchy: Record | null = null; + + static get Instance(): Controller { + if (!this._i) { + this._i = new Controller(); + } + return this._i; + } + + init(scene: HTMLElement, vsCodeApiEntry: any): void { + this._scene = scene; + this._vsCodeApi = vsCodeApiEntry; + VtkApp.Instance.init(scene); + } + + getScene(): HTMLElement | null { + return this._scene; + } + + getVSCodeAPI(): any { + return this._vsCodeApi; + } + + loadFiles(fileContexts: string[], fileNames: string[]): void { + const lfr = new CreateGroups(fileContexts, fileNames); + lfr.do(); + this._vsCodeApi.postMessage({ + type: 'groups', + groupList: this.getGroupNames(), + }); + } + + saveGroups(groups: Record, groupHierarchy: Record): void { + this._groups = groups; + this._groupHierarchy = groupHierarchy; + + groupHierarchyStore.set(groupHierarchy); + + this.initManagers(); + + this._vsCodeApi.postMessage({ + type: 'debugPanel', + text: 'Actors and hierarchy saved', + }); + } + + private initManagers(): void { + if (!this._groups || !this._groupHierarchy) return; + VisibilityManager.Instance.init(this._groups, this._groupHierarchy); + CameraManager.Instance.init(this._groups); + } + + refreshThemeColors(): void { + if (!this._groups) return; + for (const group of Object.values(this._groups)) { + group.applyThemeColor(); + } + } + + getGroupNames(): string[] { + if (!this._groups) { return []; } + return Object.keys(this._groups).filter((key) => !key.includes('all_')); + } +} diff --git a/resources/visu_vtk/src/lib/commands/VisibilityManager.ts b/resources/visu_vtk/src/lib/commands/VisibilityManager.ts new file mode 100644 index 0000000..81dc2f0 --- /dev/null +++ b/resources/visu_vtk/src/lib/commands/VisibilityManager.ts @@ -0,0 +1,170 @@ +import { Controller } from '../Controller'; +import { VtkApp } from '../core/VtkApp'; +import { GlobalSettings } from '../settings/GlobalSettings'; +import { highlightedGroups, hiddenObjects } from '../state'; +import type { Group } from '../data/Group'; + +export class VisibilityManager { + private static _i: VisibilityManager; + groups: Record = {}; + private visibleGroupsByObject: Record = {}; + hiddenObjects: Record = {}; + private highlightedGroupsSet: Set = new Set(); + + static get Instance(): VisibilityManager { + if (!this._i) { + this._i = new VisibilityManager(); + } + return this._i; + } + + init(groups: Record, objects: Record): void { + this.groups = groups; + this.visibleGroupsByObject = {}; + this.hiddenObjects = {}; + this.highlightedGroupsSet = new Set(); + + for (const object in objects) { + this.visibleGroupsByObject[object] = 0; + this.hiddenObjects[object] = false; + } + + hiddenObjects.set(new Set()); + highlightedGroups.set(new Map()); + } + + setVisibility(groupName: string, visible?: boolean): { visible: boolean; color: number[]; isFaceGroup: boolean } | undefined { + const post = (text: string) => { + Controller.Instance.getVSCodeAPI().postMessage({ type: 'debugPanel', text }); + }; + + const group = this.groups[groupName]; + if (!group) { + post(`setVisibility: group "${groupName}" has no group defined`); + return; + } + const object = group.fileGroup; + if (!object) { + post(`setVisibility: group "${groupName}" has no parent object`); + return; + } + const actor = group.actor; + if (!actor) { + post(`setVisibility: no actor found for group "${groupName}"`); + return; + } + + const color = group.getColor(); + const isFaceGroup = group.isFaceGroup; + + const wasHighlighted = this.highlightedGroupsSet.has(groupName); + const isHighlighted = typeof visible === 'boolean' ? visible : !wasHighlighted; + + if (isHighlighted) { + this.highlightedGroupsSet.add(groupName); + highlightedGroups.update((map) => { map.set(groupName, color); return map; }); + } else { + this.highlightedGroupsSet.delete(groupName); + highlightedGroups.update((map) => { map.delete(groupName); return map; }); + } + + if (!this.hiddenObjects[object]) { + group.setVisibility(isHighlighted); + } + + if (wasHighlighted !== isHighlighted) { + const visibleGroupsCount = this.visibleGroupsByObject[object]; + if (!this.hiddenObjects[object]) { + if ( + (visibleGroupsCount === 0 && isHighlighted) || + (visibleGroupsCount === 1 && !isHighlighted) + ) { + this.setTransparence(isHighlighted, object); + } + } + this.visibleGroupsByObject[object] += isHighlighted ? 1 : -1; + } + + VtkApp.Instance.getRenderWindow().render(); + + return { visible: isHighlighted, color, isFaceGroup }; + } + + toggleObjectVisibility(object: string): boolean { + const nowVisible = this.hiddenObjects[object]; + this.hiddenObjects[object] = !nowVisible; + + hiddenObjects.update((s) => { + if (nowVisible) s.delete(object); + else s.add(object); + return s; + }); + + const fileGroup = this.groups[object]; + if (fileGroup) { + if (nowVisible) { + fileGroup.actor.setVisibility(true); + const opacity = this.visibleGroupsByObject[object] > 0 ? 0.2 : 1.0; + fileGroup.setOpacity(opacity); + } else { + const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; + if (hiddenOpacity === 0) { + fileGroup.actor.setVisibility(false); + } else { + fileGroup.actor.setVisibility(true); + fileGroup.setOpacity(hiddenOpacity); + } + } + } + + for (const [groupName, group] of Object.entries(this.groups)) { + if (group.fileGroup === object) { + group.actor.setVisibility(nowVisible && this.highlightedGroupsSet.has(groupName)); + } + } + + VtkApp.Instance.getRenderWindow().render(); + return nowVisible; + } + + setTransparence(transparent: boolean, object: string): void { + if (!this.groups || this.hiddenObjects[object]) { return; } + const meshOpacity = transparent ? 0.2 : 1; + const group = this.groups[object]; + group.setOpacity(meshOpacity); + } + + applyHiddenObjectOpacity(): void { + const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; + for (const object in this.hiddenObjects) { + if (!this.hiddenObjects[object]) continue; + const fileGroup = this.groups[object]; + if (!fileGroup) continue; + if (hiddenOpacity === 0) { + fileGroup.actor.setVisibility(false); + } else { + fileGroup.actor.setVisibility(true); + fileGroup.setOpacity(hiddenOpacity); + } + } + VtkApp.Instance.getRenderWindow().render(); + } + + clear(): void { + for (const [groupName, group] of Object.entries(this.groups)) { + if (!group.actor) { continue; } + if (group.fileGroup === null) { continue; } + group.setVisibility(false); + } + + this.highlightedGroupsSet.clear(); + highlightedGroups.set(new Map()); + + for (const object in this.visibleGroupsByObject) { + this.setTransparence(false, object); + this.visibleGroupsByObject[object] = 0; + } + + VtkApp.Instance.getRenderWindow().render(); + } +} diff --git a/resources/visu_vtk/src/lib/core/VtkApp.ts b/resources/visu_vtk/src/lib/core/VtkApp.ts new file mode 100644 index 0000000..ae2eda2 --- /dev/null +++ b/resources/visu_vtk/src/lib/core/VtkApp.ts @@ -0,0 +1,82 @@ +import { Controller } from '../Controller'; + +export class VtkApp { + private static _i: VtkApp; + private fullScreenRenderer: any; + renderer: any; + renderWindow: any; + + static get Instance(): VtkApp { + if (!this._i) { + this._i = new VtkApp(); + } + return this._i; + } + + private _readEditorBackground(): number[] { + const raw = getComputedStyle(document.body).getPropertyValue('--vscode-editor-background').trim(); + const match = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i); + if (match) { + return [parseInt(match[1], 16) / 255, parseInt(match[2], 16) / 255, parseInt(match[3], 16) / 255]; + } + return [0.4, 0.6, 1.0]; + } + + updateBackground(): void { + this.renderer.setBackground(this._readEditorBackground()); + } + + init(scene: HTMLElement): void { + if (!window.vtk) { return; } + + this.fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({ + rootContainer: scene, + background: this._readEditorBackground(), + }); + + this.renderer = this.fullScreenRenderer.getRenderer(); + this.renderWindow = this.fullScreenRenderer.getRenderWindow(); + + this.updateCameraOffset(); + + const controls = document.getElementById('controls'); + if (controls) { + new ResizeObserver(() => this.updateCameraOffset()).observe(controls); + } + window.addEventListener('resize', () => this.updateCameraOffset()); + + new MutationObserver(() => { + this.updateBackground(); + Controller.Instance.refreshThemeColors(); + this.renderWindow.render(); + }).observe(document.body, { attributes: true, attributeFilter: ['class'] }); + + Controller.Instance.getVSCodeAPI().postMessage({ + type: 'debugPanel', + text: 'vtkAppInitialized', + }); + } + + updateCameraOffset(): void { + const controls = document.getElementById('controls'); + const sidebarActions = document.getElementById('sidebarActions'); + if (!controls) return; + const sidebarWidth = controls.offsetWidth - (sidebarActions?.offsetWidth ?? 0); + const offset = sidebarWidth / window.innerWidth; + this.renderer.getActiveCamera().setWindowCenter(-offset, 0); + this.renderWindow.render(); + + const zoomWidget = document.getElementById('zoomWidget'); + if (zoomWidget) { + zoomWidget.style.left = `${sidebarWidth + (window.innerWidth - sidebarWidth) / 2}px`; + } + } + + getRenderer(): any { + return this.renderer; + } + + getRenderWindow(): any { + return this.renderWindow; + } +} diff --git a/resources/visu_vtk/src/lib/data/CreateGroups.ts b/resources/visu_vtk/src/lib/data/CreateGroups.ts new file mode 100644 index 0000000..7bb3958 --- /dev/null +++ b/resources/visu_vtk/src/lib/data/CreateGroups.ts @@ -0,0 +1,76 @@ +import { GlobalSettings } from '../settings/GlobalSettings'; +import { ObjLoader } from './ObjLoader'; +import { FaceActorCreator } from './create/FaceActorCreator'; +import { NodeActorCreator } from './create/NodeActorCreator'; +import { Group } from './Group'; +import { Controller } from '../Controller'; +import { VtkApp } from '../core/VtkApp'; + +export class CreateGroups { + private fileContexts: string[]; + private fileNames: string[]; + groups: Record = {}; + + constructor(fileContexts: string[], fileNames: string[]) { + this.fileContexts = fileContexts; + this.fileNames = fileNames; + } + + do(): void { + const result = ObjLoader.loadFiles(this.fileContexts, this.fileNames); + const post = (text: string) => { + Controller.Instance.getVSCodeAPI().postMessage({ type: 'debugPanel', text }); + }; + + if (!result) { return; } + + const { vertices, cells, cellIndexToGroup, nodes, nodeIndexToGroup, faceGroups, nodeGroups, groupHierarchy } = result; + + const faceActorCreator = new FaceActorCreator(vertices, cells, cellIndexToGroup); + const nodeActorCreator = new NodeActorCreator(vertices, nodes, nodeIndexToGroup); + + for (const fileGroup in groupHierarchy) { + const groupId = faceGroups.indexOf(fileGroup); + + const _oc = GlobalSettings.Instance.objectColors; + const objColor = _oc[GlobalSettings.Instance.objIndex % _oc.length]; + (groupHierarchy[fileGroup] as any).color = objColor; + + const { actor, colorIndex: fileColorIndex, isObjectActor: fileIsObj, cellCount: fileCellCount } = faceActorCreator.create(fileGroup, groupId); + + const groupInstance = new Group(actor, fileGroup, true, null, null, fileColorIndex, fileIsObj, fileCellCount); + this.groups[fileGroup] = groupInstance; + + const size = this.computeSize(actor); + + for (const faceGroup of groupHierarchy[fileGroup].faces) { + const faceGroupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}`); + const { actor: faceActor, colorIndex: faceColorIndex, isObjectActor: faceIsObj, cellCount: faceCellCount } = faceActorCreator.create(faceGroup, faceGroupId); + const subGroup = new Group(faceActor, faceGroup, true, fileGroup, size, faceColorIndex, faceIsObj, faceCellCount); + this.groups[`${fileGroup}::${faceGroup}`] = subGroup; + } + + for (const nodeGroup of groupHierarchy[fileGroup].nodes) { + const nodeGroupId = nodeGroups.indexOf(`${fileGroup}::${nodeGroup}`); + const { actor: nodeActor, colorIndex: nodeColorIndex } = nodeActorCreator.create(nodeGroupId); + const subGroup = new Group(nodeActor, nodeGroup, false, fileGroup, size, nodeColorIndex, false); + this.groups[`${fileGroup}::${nodeGroup}`] = subGroup; + } + } + + VtkApp.Instance.getRenderer().resetCamera(); + VtkApp.Instance.getRenderWindow().render(); + post(`actors : ${Object.keys(this.groups).length}`); + + Controller.Instance.saveGroups(this.groups, groupHierarchy); + } + + private computeSize(actor: any): number { + const bounds = actor.getBounds(); + const dx = bounds[1] - bounds[0]; + const dy = bounds[3] - bounds[2]; + const dz = bounds[5] - bounds[4]; + const size = Math.sqrt(dx * dx + dy * dy + dz * dz); + return Math.max(size, 1e-3); + } +} diff --git a/resources/visu_vtk/src/lib/data/Group.ts b/resources/visu_vtk/src/lib/data/Group.ts new file mode 100644 index 0000000..0248a9d --- /dev/null +++ b/resources/visu_vtk/src/lib/data/Group.ts @@ -0,0 +1,95 @@ +import { GlobalSettings } from '../settings/GlobalSettings'; + +export class Group { + actor: any; + name: string; + isFaceGroup: boolean; + fileGroup: string | null; + size: number | null; + colorIndex: number | null; + isObjectActor: boolean; + cellCount: number | null; + private _edgeT?: number; + + constructor( + actor: any, + name: string, + isFaceGroup: boolean, + fileGroup: string | null = null, + parentSize: number | null = null, + colorIndex: number | null = null, + isObjectActor = false, + cellCount: number | null = null, + ) { + this.actor = actor; + this.name = name; + this.isFaceGroup = isFaceGroup; + this.fileGroup = fileGroup; + this.size = parentSize; + this.colorIndex = colorIndex; + this.isObjectActor = isObjectActor; + this.cellCount = cellCount; + } + + applyThemeColor(): void { + if (this.colorIndex === null) return; + const colors = this.isObjectActor + ? GlobalSettings.Instance.objectColors + : GlobalSettings.Instance.meshGroupColors; + const color = colors[this.colorIndex % colors.length]; + this.actor.getProperty().setColor(color); + this._applyEdgeColor(); + } + + updateEdgeVisibility(currentDistance: number, initialDistance: number): void { + if (this.cellCount === null) return; + const prop = this.actor.getProperty(); + const mode = GlobalSettings.Instance.edgeMode; + + if (mode === 'hide') { + prop.setEdgeVisibility(false); + return; + } + if (mode === 'show') { + prop.setEdgeVisibility(true); + prop.setEdgeColor(0, 0, 0); + return; + } + + const threshold = initialDistance * Math.sqrt(15000 / this.cellCount) * GlobalSettings.Instance.edgeThresholdMultiplier; + + if (mode === 'threshold') { + prop.setEdgeVisibility(currentDistance < threshold); + prop.setEdgeColor(0, 0, 0); + return; + } + + prop.setEdgeVisibility(true); + this._edgeT = Math.min(1, Math.max(0, threshold / currentDistance)); + this._applyEdgeColor(); + } + + private _applyEdgeColor(): void { + const t = this._edgeT ?? 0; + const [r, g, b] = this.actor.getProperty().getColor(); + this.actor.getProperty().setEdgeColor(r * (1 - t), g * (1 - t), b * (1 - t)); + } + + setSize(distance: number): void { + const decay = (this.size ?? 1) / 5; + const scale = Math.max(30 * (1 / Math.sqrt(1 + distance / decay)), 0); + this.actor.getProperty().setPointSize(scale); + } + + getColor(): number[] { + return this.actor.getProperty().getColor(); + } + + setVisibility(visible: boolean): void { + this.actor.setVisibility(visible); + } + + setOpacity(opacity: number): void { + this.actor.getProperty().setOpacity(opacity); + } +} diff --git a/resources/visu_vtk/src/lib/data/ObjLoader.ts b/resources/visu_vtk/src/lib/data/ObjLoader.ts new file mode 100644 index 0000000..dcb7fa8 --- /dev/null +++ b/resources/visu_vtk/src/lib/data/ObjLoader.ts @@ -0,0 +1,101 @@ +import { Controller } from '../Controller'; + +export interface ObjLoaderResult { + vertices: { x: number; y: number; z: number }[]; + cells: number[][]; + cellIndexToGroup: number[]; + nodes: number[]; + nodeIndexToGroup: number[]; + faceGroups: string[]; + nodeGroups: string[]; + groupHierarchy: Record; +} + +export class ObjLoader { + static loadFiles(fileContexts: string[], fileNames: string[]): ObjLoaderResult { + const vertices: { x: number; y: number; z: number }[] = []; + const cells: number[][] = []; + const cellIndexToGroup: number[] = []; + const nodes: number[] = []; + const nodeIndexToGroup: number[] = []; + const faceGroups: string[] = []; + const nodeGroups: string[] = []; + const groupHierarchy: Record = {}; + + let nbVertices = 0; + let groupId = -1; + let nodeGroupId = -1; + + for (let i = 0; i < fileContexts.length; i++) { + try { + groupId++; + const skinName = 'all_' + fileNames[i]; + + groupHierarchy[skinName] = { faces: [], nodes: [] }; + faceGroups.push(skinName); + nbVertices = vertices.length; + + const lines = fileContexts[i].split('\n').map((l) => l.replace('\r', '')); + + for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { + const line = lines[lineIdx]; + const ss = line.split(' ').filter((p) => p.length !== 0); + if (ss.length === 0) { continue; } + + switch (ss[0]) { + case 'v': + vertices.push({ + x: Number.parseFloat(ss[1]), + y: Number.parseFloat(ss[2]), + z: Number.parseFloat(ss[3]), + }); + break; + + case 'f': { + const faceIndices = ss.slice(1).map((p) => Number.parseInt(p) - 1 + nbVertices); + cells.push(faceIndices); + cellIndexToGroup.push(groupId); + break; + } + + case 'g': { + groupId++; + const faceGroupName = ss[1] || `group${groupId}`; + faceGroups.push(`${skinName}::${faceGroupName}`); + groupHierarchy[skinName].faces.push(faceGroupName); + break; + } + + case 'ng': { + nodeGroupId++; + const nodeGroupName = ss[1] || `nodeGroup${nodeGroupId}`; + nodeGroups.push(`${skinName}::${nodeGroupName}`); + groupHierarchy[skinName].nodes.push(nodeGroupName); + break; + } + + case 'p': { + const nodeIndex = parseInt(ss[1]); + nodes.push(nodeIndex - 1 + nbVertices); + nodeIndexToGroup.push(nodeGroupId); + break; + } + } + } + } catch (fileError: any) { + Controller.Instance.getVSCodeAPI().postMessage({ + type: 'debugPanel', + text: `ERROR: ${fileError.message}`, + }); + throw fileError; + } + } + + Controller.Instance.getVSCodeAPI().postMessage({ + type: 'debugPanel', + text: `TOTAL: ${vertices.length} vertices, ${cells.length} cells, ${nodes.length} nodes`, + }); + + return { vertices, cells, cellIndexToGroup, nodes, nodeIndexToGroup, faceGroups, nodeGroups, groupHierarchy }; + } +} diff --git a/resources/visu_vtk/js/data/create/FaceActorCreator.js b/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts similarity index 59% rename from resources/visu_vtk/js/data/create/FaceActorCreator.js rename to resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts index 7e2eb59..ca8b175 100644 --- a/resources/visu_vtk/js/data/create/FaceActorCreator.js +++ b/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts @@ -1,23 +1,22 @@ -class FaceActorCreator { - /** - * Create a FaceActorCreator. - * @param {Vector[]} vertices - List of vertex coordinates - * @param {number[][]} cells - Connectivity list - * @param {number[]} cellIndexToGroup - Cell-to-group index mapping - */ - constructor(vertices, cells, cellIndexToGroup) { +import { GlobalSettings } from '../../settings/GlobalSettings'; +import { VtkApp } from '../../core/VtkApp'; + +export class FaceActorCreator { + private vertices: { x: number; y: number; z: number }[]; + private cells: number[][]; + private cellIndexToGroup: number[]; + + constructor( + vertices: { x: number; y: number; z: number }[], + cells: number[][], + cellIndexToGroup: number[], + ) { this.vertices = vertices; this.cells = cells; this.cellIndexToGroup = cellIndexToGroup; } - /** - * Creates and configures an actor for a face group. - * @param {string} groupName - * @param {number} groupId - * @returns {vtkActor} - */ - create(groupName, groupId) { + create(groupName: string, groupId: number): { actor: any; colorIndex: number; isObjectActor: boolean; cellCount: number } { const { polyData, cellCount } = this.prepare(groupId); const actor = vtk.Rendering.Core.vtkActor.newInstance(); @@ -32,13 +31,7 @@ class FaceActorCreator { return { actor, colorIndex, isObjectActor, cellCount }; } - - /** - * Prepares vtkPolyData for a given groupId using instance data. - * @param {number} groupId - * @returns {vtkPolyData} - */ - prepare(groupId) { + private prepare(groupId: number): { polyData: any; cellCount: number } { const pd = vtk.Common.DataModel.vtkPolyData.newInstance(); const pts = vtk.Common.Core.vtkPoints.newInstance(); @@ -53,15 +46,17 @@ class FaceActorCreator { const cellIndices = this.cellIndexToGroup .map((g, idx) => (g === groupId ? idx : -1)) - .filter(idx => idx !== -1); + .filter((idx) => idx !== -1); const cellCount = cellIndices.length; if (cellCount > 0) { const cellArray = vtk.Common.Core.vtkCellArray.newInstance({ - values: Uint32Array.from(cellIndices.flatMap(i => { - const c = this.cells[i]; - return [c.length, ...c]; - })) + values: Uint32Array.from( + cellIndices.flatMap((i) => { + const c = this.cells[i]; + return [c.length, ...c]; + }), + ), }); pd.setPolys(cellArray); } @@ -69,16 +64,12 @@ class FaceActorCreator { return { polyData: pd, cellCount }; } - /** - * Configures rendering properties (color, opacity, visibility) - * @param {vtkActor} actor - * @param {string} groupName - */ - setProperty(actor, groupName, cellCount) { + private setProperty(actor: any, groupName: string, _cellCount: number): { colorIndex: number; isObjectActor: boolean } { const prop = actor.getProperty(); - let colorIndex, isObjectActor; - if (groupName.includes("all_")) { + let colorIndex: number; + let isObjectActor: boolean; + if (groupName.includes('all_')) { isObjectActor = true; colorIndex = GlobalSettings.Instance.objIndex; prop.setColor(GlobalSettings.Instance.getColorForObject()); @@ -91,8 +82,8 @@ class FaceActorCreator { } const [r, g, b] = prop.getColor(); - prop.setEdgeVisibility(true); // edge color is managed dynamically by CameraManager - prop.setEdgeColor(r, g, b); // start invisible (matches surface); CameraManager blends toward black + prop.setEdgeVisibility(true); + prop.setEdgeColor(r, g, b); prop.setLineWidth(0.3); prop.setInterpolationToPhong(); prop.setSpecular(0.3); @@ -100,5 +91,4 @@ class FaceActorCreator { return { colorIndex, isObjectActor }; } - } diff --git a/resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts b/resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts new file mode 100644 index 0000000..67f958f --- /dev/null +++ b/resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts @@ -0,0 +1,79 @@ +import { GlobalSettings } from '../../settings/GlobalSettings'; +import { VtkApp } from '../../core/VtkApp'; + +export class NodeActorCreator { + private vertices: { x: number; y: number; z: number }[]; + private nodes: number[]; + private nodeIndexToGroup: number[]; + + constructor( + vertices: { x: number; y: number; z: number }[], + nodes: number[], + nodeIndexToGroup: number[], + ) { + this.vertices = vertices; + this.nodes = nodes; + this.nodeIndexToGroup = nodeIndexToGroup; + } + + create(groupId: number): { actor: any; colorIndex: number } { + const polyData = this.prepare(groupId); + + const mapper = vtk.Rendering.Core.vtkMapper.newInstance(); + mapper.setInputData(polyData); + + const actor = vtk.Rendering.Core.vtkActor.newInstance(); + actor.setMapper(mapper); + + const colorIndex = this.setProperty(actor); + VtkApp.Instance.getRenderer().addActor(actor); + + return { actor, colorIndex }; + } + + private prepare(groupId: number): any { + const pd = vtk.Common.DataModel.vtkPolyData.newInstance(); + + const nodeIndices = this.nodeIndexToGroup + .map((g, idx) => (g === groupId ? idx : -1)) + .filter((idx) => idx !== -1); + + if (nodeIndices.length > 0) { + const pts = vtk.Common.Core.vtkPoints.newInstance(); + const data: number[] = []; + + for (const idx of nodeIndices) { + const v = this.vertices[this.nodes[idx]]; + if (v) { + data.push(v.x, v.y, v.z); + } + } + + pts.setData(Float32Array.from(data), 3); + pd.setPoints(pts); + + const numPoints = data.length / 3; + const verts = vtk.Common.Core.vtkCellArray.newInstance(); + const vertData: number[] = []; + + for (let i = 0; i < numPoints; i++) { + vertData.push(1, i); + } + + verts.setData(Uint32Array.from(vertData)); + pd.setVerts(verts); + } + + return pd; + } + + private setProperty(actor: any): number { + const prop = actor.getProperty(); + const colorIndex = GlobalSettings.Instance.grpIndex; + prop.setRepresentation(0); + prop.setOpacity(1); + actor.setVisibility(false); + prop.setColor(GlobalSettings.Instance.getColorForGroup()); + return colorIndex; + } +} diff --git a/resources/visu_vtk/src/lib/interaction/AxesCreator.ts b/resources/visu_vtk/src/lib/interaction/AxesCreator.ts new file mode 100644 index 0000000..92e0a19 --- /dev/null +++ b/resources/visu_vtk/src/lib/interaction/AxesCreator.ts @@ -0,0 +1,82 @@ +export class AxesCreator { + private axisLength = 1.0; + private axisRadius = 0.02; + private sphereRadius = 0.08; + + private colors = { + x: [1, 0, 0], + y: [0.251, 0.529, 0.376], + z: [0, 0, 1], + }; + + static createCustomAxesActor(): any { + const instance = new AxesCreator(); + + const axisRadius = instance.axisRadius; + const sphereRadius = 0.1; + const sphereTheta = 12; + const spherePhi = 12; + + const addColor = (polyData: any, color: number[]) => { + const scalars = vtk.Common.Core.vtkDataArray.newInstance({ + numberOfComponents: 3, + values: new Uint8Array(polyData.getPoints().getNumberOfPoints() * 3), + name: 'color', + }); + + const colors = scalars.getData(); + const rgb = color.map((c) => Math.round(c * 255)); + for (let i = 0; i < colors.length; i += 3) { + colors[i] = rgb[0]; + colors[i + 1] = rgb[1]; + colors[i + 2] = rgb[2]; + } + + polyData.getPointData().setScalars(scalars); + }; + + const xAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); + xAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ + radius: axisRadius, resolution: 20, direction: [1, 0, 0], center: [0.5, 0, 0], + }).getOutputData()); + xAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ + radius: sphereRadius, center: [1, 0, 0], thetaResolution: sphereTheta, phiResolution: spherePhi, + }).getOutputData()); + const xAxis = xAxisSource.getOutputData(); + addColor(xAxis, instance.colors.x); + + const yAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); + yAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ + radius: axisRadius, resolution: 20, direction: [0, 1, 0], center: [0, 0.5, 0], + }).getOutputData()); + yAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ + radius: sphereRadius, center: [0, 1, 0], thetaResolution: sphereTheta, phiResolution: spherePhi, + }).getOutputData()); + const yAxis = yAxisSource.getOutputData(); + addColor(yAxis, instance.colors.y); + + const zAxisSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); + zAxisSource.setInputData(vtk.Filters.Sources.vtkCylinderSource.newInstance({ + radius: axisRadius, resolution: 20, direction: [0, 0, 1], center: [0, 0, 0.5], + }).getOutputData()); + zAxisSource.addInputData(vtk.Filters.Sources.vtkSphereSource.newInstance({ + radius: sphereRadius, center: [0, 0, 1], thetaResolution: sphereTheta, phiResolution: spherePhi, + }).getOutputData()); + const zAxis = zAxisSource.getOutputData(); + addColor(zAxis, instance.colors.z); + + const axesSource = vtk.Filters.General.vtkAppendPolyData.newInstance(); + axesSource.setInputData(xAxis); + axesSource.addInputData(yAxis); + axesSource.addInputData(zAxis); + + const axesMapper = vtk.Rendering.Core.vtkMapper.newInstance(); + axesMapper.setInputData(axesSource.getOutputData()); + + const axesActor = vtk.Rendering.Core.vtkActor.newInstance(); + axesActor.setMapper(axesMapper); + axesActor.getProperty().setLighting(false); + + return axesActor; + } +} diff --git a/resources/visu_vtk/src/lib/interaction/CameraManager.ts b/resources/visu_vtk/src/lib/interaction/CameraManager.ts new file mode 100644 index 0000000..498d48f --- /dev/null +++ b/resources/visu_vtk/src/lib/interaction/CameraManager.ts @@ -0,0 +1,150 @@ +import { VtkApp } from '../core/VtkApp'; +import { AxesCreator } from './AxesCreator'; +import { zoomRatio, isAtDefaultZoom } from '../state'; +import type { Group } from '../data/Group'; + +export class CameraManager { + private static _i: CameraManager; + private camera: any; + private initialDistance = 0; + private lastDistance = 0; + nodesGroups: Record = {}; + faceGroups: Record = {}; + private orientationWidget: any; + private axesActor: any; + + static get Instance(): CameraManager { + if (!this._i) { + this._i = new CameraManager(); + } + return this._i; + } + + init(groups: Record): void { + this.nodesGroups = {}; + this.faceGroups = {}; + + const renderer = VtkApp.Instance.getRenderer(); + this.camera = renderer.getActiveCamera(); + this.initialDistance = this.camera.getDistance(); + this.lastDistance = this.initialDistance; + + for (const [groupName, group] of Object.entries(groups)) { + if (!group.isFaceGroup) { + this.nodesGroups[groupName] = group; + group.setSize(this.lastDistance); + } else if (group.cellCount !== null) { + this.faceGroups[groupName] = group; + group.updateEdgeVisibility(this.lastDistance, this.initialDistance); + } + } + + this._updateZoomIndicator(this.initialDistance); + this.axesActor = this.createAxisMarker(); + this.activateSizeUpdate(); + } + + private activateSizeUpdate(): void { + this.camera.onModified(() => { + const currentDistance = this.camera.getDistance(); + this._updateZoomIndicator(currentDistance); + if (Math.abs(currentDistance - this.lastDistance) > 1e-2) { + for (const nodeGroup of Object.values(this.nodesGroups)) { + nodeGroup.setSize(currentDistance); + } + for (const faceGroup of Object.values(this.faceGroups)) { + faceGroup.updateEdgeVisibility(currentDistance, this.initialDistance); + } + this.lastDistance = currentDistance; + } + }); + } + + private _updateZoomIndicator(currentDistance: number): void { + const ratio = this.initialDistance / currentDistance; + let text: string; + if (ratio >= 10) text = `${Math.round(ratio)}×`; + else if (ratio >= 1) text = `${ratio.toFixed(1)}×`; + else text = `${ratio.toFixed(2)}×`; + + zoomRatio.set(ratio); + isAtDefaultZoom.set(Math.abs(ratio - 1) < 0.01); + + const zoomIndicator = document.getElementById('zoomIndicator'); + if (zoomIndicator) zoomIndicator.textContent = text; + } + + resetZoom(): void { + VtkApp.Instance.getRenderer().resetCamera(); + VtkApp.Instance.updateCameraOffset(); + } + + setZoom(ratio: number): void { + const focalPoint = this.camera.getFocalPoint(); + const position = this.camera.getPosition(); + const dx = position[0] - focalPoint[0]; + const dy = position[1] - focalPoint[1]; + const dz = position[2] - focalPoint[2]; + const currentDist = Math.sqrt(dx * dx + dy * dy + dz * dz); + const scale = (this.initialDistance / ratio) / currentDist; + this.camera.setPosition( + focalPoint[0] + dx * scale, + focalPoint[1] + dy * scale, + focalPoint[2] + dz * scale, + ); + VtkApp.Instance.getRenderer().resetCameraClippingRange(); + VtkApp.Instance.updateCameraOffset(); + } + + refreshEdgeVisibility(): void { + for (const faceGroup of Object.values(this.faceGroups)) { + faceGroup.updateEdgeVisibility(this.lastDistance, this.initialDistance); + } + VtkApp.Instance.getRenderWindow().render(); + } + + setCameraAxis(axis: string): void { + if (!this.camera) { return; } + + const focalPoint = this.camera.getFocalPoint(); + const distance = this.camera.getDistance(); + + let newPosition = [0, 0, 0]; + let viewUp = [0, 0, 1]; + + switch (axis.toLowerCase()) { + case 'x': + newPosition = [focalPoint[0] + distance, focalPoint[1], focalPoint[2]]; + break; + case 'y': + newPosition = [focalPoint[0], focalPoint[1] + distance, focalPoint[2]]; + break; + case 'z': + newPosition = [focalPoint[0], focalPoint[1], focalPoint[2] + distance]; + viewUp = [0, 1, 0]; + break; + default: + return; + } + + this.camera.setPosition(...newPosition); + this.camera.setViewUp(viewUp); + VtkApp.Instance.getRenderer().resetCameraClippingRange(); + VtkApp.Instance.getRenderWindow().render(); + } + + private createAxisMarker(): any { + const axes = AxesCreator.createCustomAxesActor(); + + const widget = vtk.Interaction.Widgets.vtkOrientationMarkerWidget.newInstance({ + actor: axes, + interactor: VtkApp.Instance.getRenderWindow().getInteractor(), + }); + widget.setEnabled(true); + widget.setViewportCorner(vtk.Interaction.Widgets.vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT); + widget.setViewportSize(0.15); + + this.orientationWidget = widget; + return axes; + } +} diff --git a/resources/visu_vtk/src/lib/settings/GlobalSettings.ts b/resources/visu_vtk/src/lib/settings/GlobalSettings.ts new file mode 100644 index 0000000..0976ef6 --- /dev/null +++ b/resources/visu_vtk/src/lib/settings/GlobalSettings.ts @@ -0,0 +1,109 @@ +import type { EdgeMode } from '../state'; + +export class GlobalSettings { + private static _instance: GlobalSettings; + + static get Instance(): GlobalSettings { + if (!this._instance) { + this._instance = new GlobalSettings(); + } + return this._instance; + } + + grpIndex = 0; + objIndex = 0; + + backgroundColor = [0.6627, 0.7960, 0.910]; + ambientLightColor = [0.2, 0.2, 0.2]; + lightColor = [0.6667, 0.6667, 0.6667]; + surfaceInsideColor = [1, 1, 0]; + surfaceOutsideColor = [0.537, 0.529, 0.529]; + localSelectedColor = [1, 1, 1]; + surfaceTransparentColor = [0.553, 0.749, 0.42]; + surfaceRenderOrder = 0; + wireframeColor = [0, 0, 0]; + wireframeOpacity = 0.35; + wireframeAlpha = 1; + wireframeRenderOrder = 10; + wireframeSelectedColor = [1, 1, 1]; + wireframeSelectedRenderOrder = 11; + drawLineColor = [1, 0, 0]; + drawLineHelperRenderOrder = 12; + selectHelperColor = [1, 1, 1]; + selectionPointColor = [1, 0, 0]; + + hiddenObjectOpacity = 0; + edgeMode: EdgeMode = 'threshold'; + edgeThresholdMultiplier = 1; + + get isDark(): boolean { + return document.body.classList.contains('vscode-dark') || + document.body.classList.contains('vscode-high-contrast'); + } + + private _meshGroupColors = [ + [0.902, 0.098, 0.294], + [0.235, 0.706, 0.294], + [1, 0.882, 0.098], + [0.941, 0.196, 0.902], + [0.961, 0.510, 0.192], + [0.569, 0.118, 0.706], + [0.275, 0.941, 0.941], + [0.737, 0.965, 0.047], + [0.980, 0.745, 0.745], + [0, 0.502, 0.502], + [0.902, 0.745, 1 ], + [0.604, 0.388, 0.141], + [0.263, 0.388, 0.847], + [1, 0.980, 0.784], + [0.502, 0, 0 ], + [0.667, 1, 0.764], + [0.502, 0.502, 0 ], + [1, 0.847, 0.694], + [0, 0, 0.463], + [0.502, 0.502, 0.502], + ]; + + get meshGroupColors(): number[][] { + if (this.isDark) return this._meshGroupColors; + return this._meshGroupColors.map(([r, g, b]) => [r * 0.72, g * 0.72, b * 0.72]); + } + + getColorForGroup(): number[] { + const idx = this.grpIndex % this._meshGroupColors.length; + this.grpIndex++; + return this.meshGroupColors[idx]; + } + + private _objectColorsLight = [ + [0.400, 0.620, 0.820], + [0.280, 0.700, 0.580], + [0.880, 0.560, 0.280], + [0.600, 0.400, 0.800], + [0.380, 0.720, 0.420], + [0.820, 0.380, 0.440], + [0.380, 0.680, 0.820], + [0.820, 0.620, 0.380], + ]; + + private _objectColorsDark = [ + [0.440, 0.720, 0.980], + [0.240, 0.880, 0.700], + [0.980, 0.660, 0.320], + [0.720, 0.500, 0.980], + [0.400, 0.900, 0.500], + [0.980, 0.420, 0.520], + [0.360, 0.800, 0.980], + [0.980, 0.740, 0.440], + ]; + + get objectColors(): number[][] { + return this.isDark ? this._objectColorsDark : this._objectColorsLight; + } + + getColorForObject(): number[] { + const idx = this.objIndex % this.objectColors.length; + this.objIndex++; + return this.objectColors[idx]; + } +} diff --git a/resources/visu_vtk/src/lib/state.ts b/resources/visu_vtk/src/lib/state.ts new file mode 100644 index 0000000..87d4c4f --- /dev/null +++ b/resources/visu_vtk/src/lib/state.ts @@ -0,0 +1,27 @@ +import { writable } from 'svelte/store'; + +export type GroupHierarchy = Record; +export type HighlightedGroups = Map; +export type HiddenObjects = Set; + +export type EdgeMode = 'gradual' | 'threshold' | 'show' | 'hide'; + +export interface Settings { + hiddenObjectOpacity: number; + edgeMode: EdgeMode; + edgeThresholdMultiplier: number; +} + +export const groupHierarchy = writable({}); +export const highlightedGroups = writable(new Map()); +export const hiddenObjects = writable(new Set()); +export const zoomRatio = writable(1); +export const isAtDefaultZoom = writable(true); +export const settings = writable({ + hiddenObjectOpacity: 0, + edgeMode: 'threshold', + edgeThresholdMultiplier: 1, +}); + +// Map> — groups NOT shown in sidebar (hidden) +export const sidebarHiddenGroups = writable>>(new Map()); diff --git a/resources/visu_vtk/js/ui/CustomDropdown.js b/resources/visu_vtk/src/lib/ui/CustomDropdown.ts similarity index 62% rename from resources/visu_vtk/js/ui/CustomDropdown.js rename to resources/visu_vtk/src/lib/ui/CustomDropdown.ts index 9ab6070..2b2db30 100644 --- a/resources/visu_vtk/js/ui/CustomDropdown.js +++ b/resources/visu_vtk/src/lib/ui/CustomDropdown.ts @@ -1,22 +1,28 @@ -/** - * A reusable custom dropdown that matches the VS Code Aster UI style. - * The panel is appended to document.body to avoid overflow clipping. - */ -class CustomDropdown { - /** - * @param {HTMLElement} trigger - Element that opens/closes the panel on click - * @param {{ value: string, label: string }[]} options - * @param {(value: string) => void} onSelect - Called when the user picks an option - * @param {() => string|null} getValue - Returns the currently selected value (shown with a checkmark) - * @param {{ align?: 'left'|'right' }} [opts] - */ - constructor(trigger, options, onSelect, getValue, opts = {}) { +export interface DropdownOption { + value: string; + label: string; +} + +export class CustomDropdown { + private _trigger: HTMLElement; + private _options: DropdownOption[]; + private _onSelect: (value: string) => void; + private _getValue: (() => string | null) | null; + private _align: 'left' | 'right'; + private _panel: HTMLElement | null = null; + + constructor( + trigger: HTMLElement, + options: DropdownOption[], + onSelect: (value: string) => void, + getValue: (() => string | null) | null = null, + opts: { align?: 'left' | 'right' } = {}, + ) { this._trigger = trigger; this._options = options; this._onSelect = onSelect; this._getValue = getValue; this._align = opts.align ?? 'left'; - this._panel = null; trigger.addEventListener('click', (e) => { e.stopPropagation(); @@ -25,8 +31,9 @@ class CustomDropdown { document.addEventListener('click', () => this._close()); } - _open() { + private _open(): void { const currentValue = this._getValue?.(); + const showCheckmarks = this._getValue != null; const panel = document.createElement('div'); panel.style.cssText = ` @@ -35,17 +42,14 @@ class CustomDropdown { background: var(--ui-popup-bg); border: 1px solid var(--ui-border); border-radius: 4px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); + box-shadow: 0 4px 16px rgba(0,0,0,0.25); padding: 3px 0; overflow: hidden; `; panel.addEventListener('click', (e) => e.stopPropagation()); - const showCheckmarks = this._getValue != null; - - this._options.forEach(({ value, label }) => { + for (const { value, label } of this._options) { const isSelected = value === currentValue; - const item = document.createElement('div'); item.style.cssText = ` display: flex; @@ -60,40 +64,26 @@ class CustomDropdown { ${isSelected ? 'font-weight: 600;' : ''} `; - const labelEl = document.createElement('span'); - labelEl.textContent = label; - if (showCheckmarks) { const check = document.createElement('span'); check.textContent = '✓'; - check.style.cssText = ` - font-size: 0.6rem; - flex-shrink: 0; - width: 10px; - opacity: ${isSelected ? 1 : 0}; - `; + check.style.cssText = `font-size: 0.6rem; flex-shrink: 0; width: 10px; opacity: ${isSelected ? 1 : 0};`; item.appendChild(check); } + const labelEl = document.createElement('span'); + labelEl.textContent = label; item.appendChild(labelEl); - item.addEventListener('mouseenter', () => { - item.style.background = 'var(--ui-element-bg-hover)'; - }); - item.addEventListener('mouseleave', () => { - item.style.background = ''; - }); - item.addEventListener('click', () => { - this._onSelect(value); - this._close(); - }); + item.addEventListener('mouseenter', () => { item.style.background = 'var(--ui-element-bg-hover)'; }); + item.addEventListener('mouseleave', () => { item.style.background = ''; }); + item.addEventListener('click', () => { this._onSelect(value); this._close(); }); panel.appendChild(item); - }); + } document.body.appendChild(panel); - // Position after append so dimensions are known const rect = this._trigger.getBoundingClientRect(); const panelW = Math.max(panel.offsetWidth, rect.width); const panelH = panel.offsetHeight; @@ -111,7 +101,7 @@ class CustomDropdown { this._panel = panel; } - _close() { + private _close(): void { this._panel?.remove(); this._panel = null; } diff --git a/resources/visu_vtk/src/lib/vtk.d.ts b/resources/visu_vtk/src/lib/vtk.d.ts new file mode 100644 index 0000000..07b18ba --- /dev/null +++ b/resources/visu_vtk/src/lib/vtk.d.ts @@ -0,0 +1 @@ +declare const vtk: any; diff --git a/resources/visu_vtk/src/main.ts b/resources/visu_vtk/src/main.ts new file mode 100644 index 0000000..dfd514c --- /dev/null +++ b/resources/visu_vtk/src/main.ts @@ -0,0 +1,56 @@ +import { mount } from 'svelte'; +import App from './components/App.svelte'; +import { Controller } from './lib/Controller'; +import { VisibilityManager } from './lib/commands/VisibilityManager'; +import { GlobalSettings } from './lib/settings/GlobalSettings'; +import { settings } from './lib/state'; +import type { EdgeMode } from './lib/state'; +import './app.css'; + +declare function acquireVsCodeApi(): { + postMessage(msg: unknown): void; + getState(): unknown; + setState(state: unknown): void; +}; + +const vscode = acquireVsCodeApi(); +const scene = document.getElementById('scene')!; + +mount(App, { target: document.getElementById('app')! }); + +Controller.Instance.init(scene, vscode); + +window.addEventListener('message', async (e) => { + const { type, body } = e.data; + + switch (type) { + case 'init': { + Controller.Instance.loadFiles(body.fileContexts, body.objFilenames); + if (body.settings) { + const s = body.settings; + if (s.hiddenObjectOpacity !== undefined) { + GlobalSettings.Instance.hiddenObjectOpacity = s.hiddenObjectOpacity; + } + if (s.edgeMode !== undefined) { + GlobalSettings.Instance.edgeMode = s.edgeMode as EdgeMode; + } + if (s.edgeThresholdMultiplier !== undefined) { + GlobalSettings.Instance.edgeThresholdMultiplier = s.edgeThresholdMultiplier; + } + settings.update((cur) => ({ + hiddenObjectOpacity: s.hiddenObjectOpacity ?? cur.hiddenObjectOpacity, + edgeMode: (s.edgeMode ?? cur.edgeMode) as EdgeMode, + edgeThresholdMultiplier: s.edgeThresholdMultiplier ?? cur.edgeThresholdMultiplier, + })); + VisibilityManager.Instance.applyHiddenObjectOpacity(); + } + break; + } + + case 'displayGroup': + VisibilityManager.Instance.setVisibility(body.group, body.visible); + break; + } +}); + +vscode.postMessage({ type: 'ready' }); diff --git a/resources/visu_vtk/svelte.config.js b/resources/visu_vtk/svelte.config.js new file mode 100644 index 0000000..4c6b24b --- /dev/null +++ b/resources/visu_vtk/svelte.config.js @@ -0,0 +1,5 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +export default { + preprocess: vitePreprocess(), +}; diff --git a/resources/visu_vtk/tailwind.css b/resources/visu_vtk/tailwind.css deleted file mode 100644 index f889194..0000000 --- a/resources/visu_vtk/tailwind.css +++ /dev/null @@ -1,1211 +0,0 @@ -/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */ -@layer properties; -@layer theme, base, components, utilities; -@layer theme { - :root, :host { - --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", - "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; - --color-red-500: oklch(63.7% 0.237 25.331); - --color-red-600: oklch(57.7% 0.245 27.325); - --color-green-500: oklch(72.3% 0.219 149.579); - --color-green-600: oklch(62.7% 0.194 149.214); - --color-blue-500: oklch(62.3% 0.214 259.815); - --color-black: #000; - --color-white: #fff; - --spacing: 0.25rem; - --text-xs: 0.75rem; - --text-xs--line-height: calc(1 / 0.75); - --text-sm: 0.875rem; - --text-sm--line-height: calc(1.25 / 0.875); - --text-base: 1rem; - --text-base--line-height: calc(1.5 / 1); - --font-weight-normal: 400; - --font-weight-medium: 500; - --font-weight-semibold: 600; - --font-weight-bold: 700; - --radius-sm: 0.25rem; - --blur-xs: 4px; - --blur-lg: 16px; - --default-transition-duration: 150ms; - --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - --default-font-family: var(--font-sans); - --default-mono-font-family: var(--font-mono); - } -} -@layer base { - *, ::after, ::before, ::backdrop, ::file-selector-button { - box-sizing: border-box; - margin: 0; - padding: 0; - border: 0 solid; - } - html, :host { - line-height: 1.5; - -webkit-text-size-adjust: 100%; - tab-size: 4; - font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); - font-feature-settings: var(--default-font-feature-settings, normal); - font-variation-settings: var(--default-font-variation-settings, normal); - -webkit-tap-highlight-color: transparent; - } - hr { - height: 0; - color: inherit; - border-top-width: 1px; - } - abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; - } - h1, h2, h3, h4, h5, h6 { - font-size: inherit; - font-weight: inherit; - } - a { - color: inherit; - -webkit-text-decoration: inherit; - text-decoration: inherit; - } - b, strong { - font-weight: bolder; - } - code, kbd, samp, pre { - font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); - font-feature-settings: var(--default-mono-font-feature-settings, normal); - font-variation-settings: var(--default-mono-font-variation-settings, normal); - font-size: 1em; - } - small { - font-size: 80%; - } - sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - } - sub { - bottom: -0.25em; - } - sup { - top: -0.5em; - } - table { - text-indent: 0; - border-color: inherit; - border-collapse: collapse; - } - :-moz-focusring { - outline: auto; - } - progress { - vertical-align: baseline; - } - summary { - display: list-item; - } - ol, ul, menu { - list-style: none; - } - img, svg, video, canvas, audio, iframe, embed, object { - display: block; - vertical-align: middle; - } - img, video { - max-width: 100%; - height: auto; - } - button, input, select, optgroup, textarea, ::file-selector-button { - font: inherit; - font-feature-settings: inherit; - font-variation-settings: inherit; - letter-spacing: inherit; - color: inherit; - border-radius: 0; - background-color: transparent; - opacity: 1; - } - :where(select:is([multiple], [size])) optgroup { - font-weight: bolder; - } - :where(select:is([multiple], [size])) optgroup option { - padding-inline-start: 20px; - } - ::file-selector-button { - margin-inline-end: 4px; - } - ::placeholder { - opacity: 1; - } - @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { - ::placeholder { - color: currentcolor; - @supports (color: color-mix(in lab, red, red)) { - color: color-mix(in oklab, currentcolor 50%, transparent); - } - } - } - textarea { - resize: vertical; - } - ::-webkit-search-decoration { - -webkit-appearance: none; - } - ::-webkit-date-and-time-value { - min-height: 1lh; - text-align: inherit; - } - ::-webkit-datetime-edit { - display: inline-flex; - } - ::-webkit-datetime-edit-fields-wrapper { - padding: 0; - } - ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { - padding-block: 0; - } - ::-webkit-calendar-picker-indicator { - line-height: 1; - } - :-moz-ui-invalid { - box-shadow: none; - } - button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button { - appearance: button; - } - ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { - height: auto; - } - [hidden]:where(:not([hidden="until-found"])) { - display: none !important; - } -} -@layer utilities { - .collapse { - visibility: collapse; - } - .invisible { - visibility: hidden; - } - .visible { - visibility: visible; - } - .absolute { - position: absolute; - } - .fixed { - position: fixed; - } - .relative { - position: relative; - } - .static { - position: static; - } - .start { - inset-inline-start: var(--spacing); - } - .end { - inset-inline-end: var(--spacing); - } - .top-1 { - top: calc(var(--spacing) * 1); - } - .top-1\/2 { - top: calc(1 / 2 * 100%); - } - .top-2 { - top: calc(var(--spacing) * 2); - } - .right-2 { - right: calc(var(--spacing) * 2); - } - .right-full { - right: 100%; - } - .bottom-2 { - bottom: calc(var(--spacing) * 2); - } - .left-1 { - left: calc(var(--spacing) * 1); - } - .left-1\.5 { - left: calc(var(--spacing) * 1.5); - } - .left-1\/2 { - left: calc(1 / 2 * 100%); - } - .left-full { - left: 100%; - } - .isolate { - isolation: isolate; - } - .z-10 { - z-index: 10; - } - .container { - width: 100%; - @media (width >= 40rem) { - max-width: 40rem; - } - @media (width >= 48rem) { - max-width: 48rem; - } - @media (width >= 64rem) { - max-width: 64rem; - } - @media (width >= 80rem) { - max-width: 80rem; - } - @media (width >= 96rem) { - max-width: 96rem; - } - } - .container\! { - width: 100% !important; - @media (width >= 40rem) { - max-width: 40rem !important; - } - @media (width >= 48rem) { - max-width: 48rem !important; - } - @media (width >= 64rem) { - max-width: 64rem !important; - } - @media (width >= 80rem) { - max-width: 80rem !important; - } - @media (width >= 96rem) { - max-width: 96rem !important; - } - } - .mx-auto { - margin-inline: auto; - } - .my-2 { - margin-block: calc(var(--spacing) * 2); - } - .mt-0 { - margin-top: calc(var(--spacing) * 0); - } - .mt-0\.5 { - margin-top: calc(var(--spacing) * 0.5); - } - .mt-1 { - margin-top: calc(var(--spacing) * 1); - } - .mt-4 { - margin-top: calc(var(--spacing) * 4); - } - .mb-2 { - margin-bottom: calc(var(--spacing) * 2); - } - .mb-4 { - margin-bottom: calc(var(--spacing) * 4); - } - .mb-5 { - margin-bottom: calc(var(--spacing) * 5); - } - .block { - display: block; - } - .contents { - display: contents; - } - .flex { - display: flex; - } - .grid { - display: grid; - } - .hidden { - display: none; - } - .hidden\! { - display: none !important; - } - .inline { - display: inline; - } - .table { - display: table; - } - .size-1 { - width: calc(var(--spacing) * 1); - height: calc(var(--spacing) * 1); - } - .size-3 { - width: calc(var(--spacing) * 3); - height: calc(var(--spacing) * 3); - } - .size-3\.5 { - width: calc(var(--spacing) * 3.5); - height: calc(var(--spacing) * 3.5); - } - .size-4 { - width: calc(var(--spacing) * 4); - height: calc(var(--spacing) * 4); - } - .size-4\.5 { - width: calc(var(--spacing) * 4.5); - height: calc(var(--spacing) * 4.5); - } - .size-5 { - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - } - .size-5\.5 { - width: calc(var(--spacing) * 5.5); - height: calc(var(--spacing) * 5.5); - } - .size-6 { - width: calc(var(--spacing) * 6); - height: calc(var(--spacing) * 6); - } - .size-6\.5 { - width: calc(var(--spacing) * 6.5); - height: calc(var(--spacing) * 6.5); - } - .h-4 { - height: calc(var(--spacing) * 4); - } - .h-4\.5 { - height: calc(var(--spacing) * 4.5); - } - .h-full { - height: 100%; - } - .h-px { - height: 1px; - } - .h-screen { - height: 100vh; - } - .max-h-2 { - max-height: calc(var(--spacing) * 2); - } - .max-h-2\/3 { - max-height: calc(2 / 3 * 100%); - } - .w-2 { - width: calc(var(--spacing) * 2); - } - .w-2\/3 { - width: calc(2 / 3 * 100%); - } - .w-3 { - width: calc(var(--spacing) * 3); - } - .w-3\/4 { - width: calc(3 / 4 * 100%); - } - .w-full { - width: 100%; - } - .w-screen { - width: 100vw; - } - .flex-1 { - flex: 1; - } - .flex-shrink { - flex-shrink: 1; - } - .shrink-0 { - flex-shrink: 0; - } - .flex-grow { - flex-grow: 1; - } - .grow { - flex-grow: 1; - } - .border-collapse { - border-collapse: collapse; - } - .-translate-x-1 { - --tw-translate-x: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .-translate-x-1\/2 { - --tw-translate-x: calc(calc(1 / 2 * 100%) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .-translate-y-1 { - --tw-translate-y: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .-translate-y-1\/2 { - --tw-translate-y: calc(calc(1 / 2 * 100%) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .-translate-y-px { - --tw-translate-y: -1px; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - .transform { - transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); - } - .cursor-pointer { - cursor: pointer; - } - .resize { - resize: both; - } - .list-inside { - list-style-position: inside; - } - .list-disc { - list-style-type: disc; - } - .columns-2 { - columns: 2; - } - .break-inside-avoid { - break-inside: avoid; - } - .flex-col { - flex-direction: column; - } - .items-center { - align-items: center; - } - .justify-between { - justify-content: space-between; - } - .justify-center { - justify-content: center; - } - .gap-1 { - gap: calc(var(--spacing) * 1); - } - .gap-1\.5 { - gap: calc(var(--spacing) * 1.5); - } - .gap-2 { - gap: calc(var(--spacing) * 2); - } - .gap-6 { - gap: calc(var(--spacing) * 6); - } - .space-y-1 { - :where(& > :not(:last-child)) { - --tw-space-y-reverse: 0; - margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse)); - margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse))); - } - } - .space-y-1\.5 { - :where(& > :not(:last-child)) { - --tw-space-y-reverse: 0; - margin-block-start: calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse)); - margin-block-end: calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse))); - } - } - .space-y-4 { - :where(& > :not(:last-child)) { - --tw-space-y-reverse: 0; - margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); - margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); - } - } - .space-x-1 { - :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); - } - } - .space-x-1\.5 { - :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 1.5) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-x-reverse))); - } - } - .space-x-3 { - :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 3) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse))); - } - } - .self-end { - align-self: flex-end; - } - .self-stretch { - align-self: stretch; - } - .truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .overflow-y-auto { - overflow-y: auto; - } - .rounded { - border-radius: 0.25rem; - } - .rounded-full { - border-radius: calc(infinity * 1px); - } - .rounded-sm { - border-radius: var(--radius-sm); - } - .rounded-r-sm { - border-top-right-radius: var(--radius-sm); - border-bottom-right-radius: var(--radius-sm); - } - .border { - border-style: var(--tw-border-style); - border-width: 1px; - } - .border-2 { - border-style: var(--tw-border-style); - border-width: 2px; - } - .border-l { - border-left-style: var(--tw-border-style); - border-left-width: 1px; - } - .border-blue-500 { - border-color: var(--color-blue-500); - } - .border-green-500 { - border-color: var(--color-green-500); - } - .border-red-500 { - border-color: var(--color-red-500); - } - .bg-black { - background-color: var(--color-black); - } - .bg-black\/20 { - background-color: color-mix(in srgb, #000 20%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-black) 20%, transparent); - } - } - .p-1 { - padding: calc(var(--spacing) * 1); - } - .p-1\.5 { - padding: calc(var(--spacing) * 1.5); - } - .p-2 { - padding: calc(var(--spacing) * 2); - } - .p-8 { - padding: calc(var(--spacing) * 8); - } - .px-1 { - padding-inline: calc(var(--spacing) * 1); - } - .px-1\.5 { - padding-inline: calc(var(--spacing) * 1.5); - } - .px-2 { - padding-inline: calc(var(--spacing) * 2); - } - .px-2\.5 { - padding-inline: calc(var(--spacing) * 2.5); - } - .px-3 { - padding-inline: calc(var(--spacing) * 3); - } - .py-0 { - padding-block: calc(var(--spacing) * 0); - } - .py-0\.5 { - padding-block: calc(var(--spacing) * 0.5); - } - .py-1 { - padding-block: calc(var(--spacing) * 1); - } - .py-1\.5 { - padding-block: calc(var(--spacing) * 1.5); - } - .pt-0 { - padding-top: calc(var(--spacing) * 0); - } - .pt-0\.5 { - padding-top: calc(var(--spacing) * 0.5); - } - .pt-0\.75 { - padding-top: calc(var(--spacing) * 0.75); - } - .pr-0 { - padding-right: calc(var(--spacing) * 0); - } - .pr-0\.5 { - padding-right: calc(var(--spacing) * 0.5); - } - .pr-1 { - padding-right: calc(var(--spacing) * 1); - } - .pr-1\.5 { - padding-right: calc(var(--spacing) * 1.5); - } - .pr-2 { - padding-right: calc(var(--spacing) * 2); - } - .pb-1 { - padding-bottom: calc(var(--spacing) * 1); - } - .pb-1\.25 { - padding-bottom: calc(var(--spacing) * 1.25); - } - .pl-1 { - padding-left: calc(var(--spacing) * 1); - } - .pl-1\.5 { - padding-left: calc(var(--spacing) * 1.5); - } - .pl-1\.25 { - padding-left: calc(var(--spacing) * 1.25); - } - .pl-5 { - padding-left: calc(var(--spacing) * 5); - } - .text-center { - text-align: center; - } - .align-top { - vertical-align: top; - } - .font-mono { - font-family: var(--font-mono); - } - .text-base { - font-size: var(--text-base); - line-height: var(--tw-leading, var(--text-base--line-height)); - } - .text-sm { - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - } - .text-xs { - font-size: var(--text-xs); - line-height: var(--tw-leading, var(--text-xs--line-height)); - } - .text-\[0\.7rem\] { - font-size: 0.7rem; - } - .text-\[0\.65rem\] { - font-size: 0.65rem; - } - .leading-none { - --tw-leading: 1; - line-height: 1; - } - .font-bold { - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - } - .font-medium { - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - } - .font-normal { - --tw-font-weight: var(--font-weight-normal); - font-weight: var(--font-weight-normal); - } - .font-semibold { - --tw-font-weight: var(--font-weight-semibold); - font-weight: var(--font-weight-semibold); - } - .whitespace-nowrap { - white-space: nowrap; - } - .text-blue-500 { - color: var(--color-blue-500); - } - .text-blue-500\! { - color: var(--color-blue-500) !important; - } - .text-green-500 { - color: var(--color-green-500); - } - .text-green-600 { - color: var(--color-green-600); - } - .text-green-600\! { - color: var(--color-green-600) !important; - } - .text-red-500 { - color: var(--color-red-500); - } - .text-red-600 { - color: var(--color-red-600); - } - .text-red-600\! { - color: var(--color-red-600) !important; - } - .lowercase { - text-transform: lowercase; - } - .uppercase { - text-transform: uppercase; - } - .underline { - text-decoration-line: underline; - } - .accent-current { - accent-color: currentcolor; - } - .opacity-40 { - opacity: 40%; - } - .opacity-50 { - opacity: 50%; - } - .opacity-60 { - opacity: 60%; - } - .shadow { - --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - .shadow-lg { - --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - .outline { - outline-style: var(--tw-outline-style); - outline-width: 1px; - } - .blur { - --tw-blur: blur(8px); - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - .invert { - --tw-invert: invert(100%); - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - .filter { - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - .backdrop-blur-lg { - --tw-backdrop-blur: blur(var(--blur-lg)); - -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - } - .backdrop-blur-xs { - --tw-backdrop-blur: blur(var(--blur-xs)); - -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - } - .backdrop-filter { - -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); - } - .transition { - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - } - .select-all { - -webkit-user-select: all; - user-select: all; - } - .select-none { - -webkit-user-select: none; - user-select: none; - } - .not-nth-of-type-\[1\]\:mt-1 { - &:not(*:nth-of-type(1)) { - margin-top: calc(var(--spacing) * 1); - } - } - .group-hover\:inline { - &:is(:where(.group):hover *) { - @media (hover: hover) { - display: inline; - } - } - } - .hover\:text-white { - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } - } - .hover\:opacity-90 { - &:hover { - @media (hover: hover) { - opacity: 90%; - } - } - } - .hover\:opacity-100 { - &:hover { - @media (hover: hover) { - opacity: 100%; - } - } - } - .focus\:outline-none { - &:focus { - --tw-outline-style: none; - outline-style: none; - } - } -} -:root { - --ui-bg: var(--vscode-sideBar-background, var(--vscode-editor-background, #e8eaf0)); - --ui-fg: var(--vscode-sideBar-foreground, var(--vscode-editor-foreground, #1f1f1f)); - --ui-btn-bg: var(--vscode-button-background, #0078d4); - --ui-btn-fg: var(--vscode-button-foreground, #ffffff); - --ui-btn-hover-bg: var(--vscode-button-hoverBackground, #005fa3); - --ui-popup-bg: var(--vscode-editorWidget-background, var(--vscode-editor-background, #f3f3f3)); - --ui-border: var(--vscode-widget-border, var(--vscode-editorWidget-border, rgba(0,0,0,0.1))); - --icon-filter: none; - --ui-text-primary: var(--ui-fg); - @supports (color: color-mix(in lab, red, red)) { - --ui-text-primary: color-mix(in srgb, var(--ui-fg) 90%, transparent); - } - --ui-text-secondary: var(--ui-fg); - @supports (color: color-mix(in lab, red, red)) { - --ui-text-secondary: color-mix(in srgb, var(--ui-fg) 70%, transparent); - } - --ui-text-muted: var(--ui-fg); - @supports (color: color-mix(in lab, red, red)) { - --ui-text-muted: color-mix(in srgb, var(--ui-fg) 55%, transparent); - } - --ui-element-bg: var(--ui-fg); - @supports (color: color-mix(in lab, red, red)) { - --ui-element-bg: color-mix(in srgb, var(--ui-fg) 10%, transparent); - } - --ui-element-bg-hover: var(--ui-fg); - @supports (color: color-mix(in lab, red, red)) { - --ui-element-bg-hover: color-mix(in srgb, var(--ui-fg) 18%, transparent); - } - --ui-highlight-text: rgba(255, 255, 255, 0.9); -} -body.vscode-dark, body.vscode-high-contrast { - --icon-filter: invert(1); - --ui-highlight-text: rgba(0, 0, 0, 0.8); -} -kbd { - border-radius: var(--radius-sm); - padding-inline: calc(var(--spacing) * 1); - padding-block: 1px; - color: var(--vscode-textLink-foreground, #0078d4); - background: var(--ui-bg); - @supports (color: color-mix(in lab, red, red)) { - background: color-mix(in srgb, var(--ui-bg) 70%, transparent); - } -} -input[type="checkbox"].custom-cb:focus { - outline: none; -} -input[type="checkbox"].custom-cb { - appearance: none; - width: 13px; - height: 13px; - flex-shrink: 0; - border-radius: 3px; - border: 1.5px solid var(--ui-text-secondary); - cursor: pointer; - position: relative; - transition: background 0.1s, border-color 0.1s; -} -input[type="checkbox"].custom-cb:checked { - background: var(--ui-btn-bg); - border-color: var(--ui-btn-bg); -} -input[type="checkbox"].custom-cb:checked::after { - content: ''; - position: absolute; - inset: 0; - margin: auto; - width: 4px; - height: 7px; - border-right: 1.5px solid var(--ui-btn-fg); - border-bottom: 1.5px solid var(--ui-btn-fg); - transform: translateY(-1px) rotate(45deg); -} -#groupButtons, #helpPopup *, #groupList, #settingsPopup .overflow-y-auto { - scrollbar-width: none; -} -#groupButtons::-webkit-scrollbar, #helpPopup ::-webkit-scrollbar, #groupList::-webkit-scrollbar, #settingsPopup .overflow-y-auto::-webkit-scrollbar { - display: none; -} -@property --tw-translate-x { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-translate-y { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-translate-z { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-rotate-x { - syntax: "*"; - inherits: false; -} -@property --tw-rotate-y { - syntax: "*"; - inherits: false; -} -@property --tw-rotate-z { - syntax: "*"; - inherits: false; -} -@property --tw-skew-x { - syntax: "*"; - inherits: false; -} -@property --tw-skew-y { - syntax: "*"; - inherits: false; -} -@property --tw-space-y-reverse { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-space-x-reverse { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-border-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} -@property --tw-leading { - syntax: "*"; - inherits: false; -} -@property --tw-font-weight { - syntax: "*"; - inherits: false; -} -@property --tw-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-shadow-color { - syntax: "*"; - inherits: false; -} -@property --tw-shadow-alpha { - syntax: ""; - inherits: false; - initial-value: 100%; -} -@property --tw-inset-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-inset-shadow-color { - syntax: "*"; - inherits: false; -} -@property --tw-inset-shadow-alpha { - syntax: ""; - inherits: false; - initial-value: 100%; -} -@property --tw-ring-color { - syntax: "*"; - inherits: false; -} -@property --tw-ring-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-inset-ring-color { - syntax: "*"; - inherits: false; -} -@property --tw-inset-ring-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-ring-inset { - syntax: "*"; - inherits: false; -} -@property --tw-ring-offset-width { - syntax: ""; - inherits: false; - initial-value: 0px; -} -@property --tw-ring-offset-color { - syntax: "*"; - inherits: false; - initial-value: #fff; -} -@property --tw-ring-offset-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} -@property --tw-blur { - syntax: "*"; - inherits: false; -} -@property --tw-brightness { - syntax: "*"; - inherits: false; -} -@property --tw-contrast { - syntax: "*"; - inherits: false; -} -@property --tw-grayscale { - syntax: "*"; - inherits: false; -} -@property --tw-hue-rotate { - syntax: "*"; - inherits: false; -} -@property --tw-invert { - syntax: "*"; - inherits: false; -} -@property --tw-opacity { - syntax: "*"; - inherits: false; -} -@property --tw-saturate { - syntax: "*"; - inherits: false; -} -@property --tw-sepia { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow-color { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow-alpha { - syntax: ""; - inherits: false; - initial-value: 100%; -} -@property --tw-drop-shadow-size { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-blur { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-brightness { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-contrast { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-grayscale { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-hue-rotate { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-invert { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-opacity { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-saturate { - syntax: "*"; - inherits: false; -} -@property --tw-backdrop-sepia { - syntax: "*"; - inherits: false; -} -@layer properties { - @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { - *, ::before, ::after, ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-translate-z: 0; - --tw-rotate-x: initial; - --tw-rotate-y: initial; - --tw-rotate-z: initial; - --tw-skew-x: initial; - --tw-skew-y: initial; - --tw-space-y-reverse: 0; - --tw-space-x-reverse: 0; - --tw-border-style: solid; - --tw-leading: initial; - --tw-font-weight: initial; - --tw-shadow: 0 0 #0000; - --tw-shadow-color: initial; - --tw-shadow-alpha: 100%; - --tw-inset-shadow: 0 0 #0000; - --tw-inset-shadow-color: initial; - --tw-inset-shadow-alpha: 100%; - --tw-ring-color: initial; - --tw-ring-shadow: 0 0 #0000; - --tw-inset-ring-color: initial; - --tw-inset-ring-shadow: 0 0 #0000; - --tw-ring-inset: initial; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-outline-style: solid; - --tw-blur: initial; - --tw-brightness: initial; - --tw-contrast: initial; - --tw-grayscale: initial; - --tw-hue-rotate: initial; - --tw-invert: initial; - --tw-opacity: initial; - --tw-saturate: initial; - --tw-sepia: initial; - --tw-drop-shadow: initial; - --tw-drop-shadow-color: initial; - --tw-drop-shadow-alpha: 100%; - --tw-drop-shadow-size: initial; - --tw-backdrop-blur: initial; - --tw-backdrop-brightness: initial; - --tw-backdrop-contrast: initial; - --tw-backdrop-grayscale: initial; - --tw-backdrop-hue-rotate: initial; - --tw-backdrop-invert: initial; - --tw-backdrop-opacity: initial; - --tw-backdrop-saturate: initial; - --tw-backdrop-sepia: initial; - } - } -} diff --git a/resources/visu_vtk/tsconfig.json b/resources/visu_vtk/tsconfig.json new file mode 100644 index 0000000..c7942f0 --- /dev/null +++ b/resources/visu_vtk/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "bundler", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "allowImportingTsExtensions": true, + "noEmit": true + }, + "include": ["src"] +} diff --git a/resources/visu_vtk/vite.config.ts b/resources/visu_vtk/vite.config.ts new file mode 100644 index 0000000..e1f4c35 --- /dev/null +++ b/resources/visu_vtk/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import tailwindcss from '@tailwindcss/vite'; +import { resolve } from 'path'; + +export default defineConfig({ + root: resolve(__dirname), + base: './', + build: { + outDir: resolve(__dirname, 'dist'), + emptyOutDir: true, + }, + plugins: [svelte(), tailwindcss()], +}); diff --git a/src/VisuManager.ts b/src/VisuManager.ts index 6627639..c56ea89 100644 --- a/src/VisuManager.ts +++ b/src/VisuManager.ts @@ -125,7 +125,7 @@ export class VisuManager { const visu = new WebviewVisu( "meshViewer", testDir, - "resources/visu_vtk/index.html", + "resources/visu_vtk/dist/index.html", fileContexts, objUris.map((uri) => path.basename(uri.fsPath)), undefined, diff --git a/tsconfig.json b/tsconfig.json index e004a91..ed0f276 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,10 @@ "sourceMap": true, "strict": true, "skipLibCheck": true - } + }, + "exclude": [ + "resources/visu_vtk" + ] } From 2690871231d830fe6403cccb04c558399348ae66 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Wed, 11 Mar 2026 16:27:55 +0100 Subject: [PATCH 05/20] Fix bugs --- resources/visu_vtk/src/app.css | 37 +++++++++++++++---- .../src/components/ActionButtons.svelte | 10 ++--- .../src/components/AxisButtons.svelte | 12 ++---- .../src/components/GroupButton.svelte | 10 ++--- .../src/components/ObjectSection.svelte | 1 + .../visu_vtk/src/components/Sidebar.svelte | 7 ++++ .../visu_vtk/src/components/TopActions.svelte | 10 +---- .../visu_vtk/src/components/ZoomWidget.svelte | 20 +++++----- .../src/components/popups/GroupsPopup.svelte | 18 +++------ .../src/components/popups/HelpPopup.svelte | 8 ++-- .../src/components/popups/Popup.svelte | 4 +- .../components/popups/SettingsPopup.svelte | 32 +++++++--------- resources/visu_vtk/src/lib/core/VtkApp.ts | 6 ++- .../visu_vtk/src/lib/ui/CustomDropdown.ts | 8 ++-- resources/visu_vtk/vite.config.ts | 7 ++++ 15 files changed, 98 insertions(+), 92 deletions(-) diff --git a/resources/visu_vtk/src/app.css b/resources/visu_vtk/src/app.css index 2e20f83..7ff9a1b 100644 --- a/resources/visu_vtk/src/app.css +++ b/resources/visu_vtk/src/app.css @@ -15,6 +15,7 @@ --ui-text-muted: color-mix(in srgb, var(--ui-fg) 55%, transparent); --ui-element-bg: color-mix(in srgb, var(--ui-fg) 10%, transparent); --ui-element-bg-hover: color-mix(in srgb, var(--ui-fg) 18%, transparent); + --ui-bg-translucent: color-mix(in srgb, var(--ui-bg) 85%, transparent); --ui-highlight-text: rgba(255, 255, 255, 0.9); } @@ -24,6 +25,26 @@ body.vscode-high-contrast { --ui-highlight-text: rgba(0, 0, 0, 0.8); } +@utility bg-ui-elem { + background: var(--ui-element-bg); +} + +@utility bg-ui-elem-hover { + background: var(--ui-element-bg-hover); +} + +@utility bg-ui-muted { + background: var(--ui-bg-translucent); +} + +@utility bg-ui-btn { + background: var(--ui-btn-bg); +} + +@utility bg-ui-btn-hover { + background: var(--ui-btn-hover-bg); +} + kbd { @apply px-1 py-px rounded-sm; color: var(--vscode-textLink-foreground, #0078d4); @@ -63,16 +84,16 @@ input[type="checkbox"].custom-cb:checked::after { transform: translateY(-1px) rotate(45deg); } -#groupButtons, -#helpPopup *, -#groupList, -#settingsPopup .overflow-y-auto { +#sidebarGroups, +#helpPopup .overflow-y-auto, +#settingsPopup .overflow-y-auto, +#groupsPopup .overflow-y-auto { scrollbar-width: none; } -#groupButtons::-webkit-scrollbar, -#helpPopup ::-webkit-scrollbar, -#groupList::-webkit-scrollbar, -#settingsPopup .overflow-y-auto::-webkit-scrollbar { +#sidebarGroups::-webkit-scrollbar, +#helpPopup .overflow-y-auto::-webkit-scrollbar, +#settingsPopup .overflow-y-auto::-webkit-scrollbar, +#groupsPopup .overflow-y-auto::-webkit-scrollbar { display: none; } diff --git a/resources/visu_vtk/src/components/ActionButtons.svelte b/resources/visu_vtk/src/components/ActionButtons.svelte index 980f626..ff9ab74 100644 --- a/resources/visu_vtk/src/components/ActionButtons.svelte +++ b/resources/visu_vtk/src/components/ActionButtons.svelte @@ -17,12 +17,10 @@ >
{/if}
diff --git a/resources/visu_vtk/src/components/popups/GroupsPopup.svelte b/resources/visu_vtk/src/components/popups/GroupsPopup.svelte index 7227b17..b8775e7 100644 --- a/resources/visu_vtk/src/components/popups/GroupsPopup.svelte +++ b/resources/visu_vtk/src/components/popups/GroupsPopup.svelte @@ -68,9 +68,9 @@
e.stopPropagation()} role="document" >
@@ -90,10 +90,8 @@ {obj.name}
diff --git a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte index 0074015..65df064 100644 --- a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte +++ b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte @@ -34,13 +34,13 @@ $effect(() => { if (!edgeModeSelectEl) return; - const dd = new CustomDropdown( + const dropdown = new CustomDropdown( edgeModeSelectEl, edgeModeOptions, (value) => applyEdgeMode(value as EdgeMode), () => GlobalSettings.Instance.edgeMode, ); - return () => {}; + return () => dropdown.close(); }); function applyEdgeMode(mode: EdgeMode) { @@ -100,22 +100,20 @@
e.stopPropagation()} role="document" > Settings
- + Edge display
{ (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg-hover)'; }} - onmouseout={(e) => { (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg)'; }} + class="w-full text-xs px-2 py-1.5 rounded-sm cursor-pointer flex items-center justify-between gap-2 select-none bg-ui-elem hover:bg-ui-elem-hover" + style="color: var(--ui-fg); border: 1px solid var(--ui-border)" role="button" tabindex="0" > @@ -126,10 +124,11 @@ {#if showThresholdSection}
- + {edgeThresholdDisplay}×
- + {hiddenOpacityPct}%
+
+{/if} + Date: Thu, 12 Mar 2026 15:29:14 +0100 Subject: [PATCH 08/20] Revamp help popup --- .../src/components/ObjectSection.svelte | 2 +- .../src/components/popups/HelpPopup.svelte | 240 ++++++++++++++---- .../visu_vtk/src/icons/MouseLeftIcon.svelte | 11 + .../visu_vtk/src/icons/MouseRightIcon.svelte | 11 + .../visu_vtk/src/icons/MouseScrollIcon.svelte | 10 + resources/visu_vtk/vite.config.ts | 7 + 6 files changed, 227 insertions(+), 54 deletions(-) create mode 100644 resources/visu_vtk/src/icons/MouseLeftIcon.svelte create mode 100644 resources/visu_vtk/src/icons/MouseRightIcon.svelte create mode 100644 resources/visu_vtk/src/icons/MouseScrollIcon.svelte diff --git a/resources/visu_vtk/src/components/ObjectSection.svelte b/resources/visu_vtk/src/components/ObjectSection.svelte index ac3ab86..5b3bdd6 100644 --- a/resources/visu_vtk/src/components/ObjectSection.svelte +++ b/resources/visu_vtk/src/components/ObjectSection.svelte @@ -79,7 +79,7 @@ onmouseleave={(e) => (e.currentTarget as HTMLElement).style.background = ''} onclick={hideAllOthers} > - Hide all others + Hide all other objects
{/if} diff --git a/resources/visu_vtk/src/components/popups/HelpPopup.svelte b/resources/visu_vtk/src/components/popups/HelpPopup.svelte index c05dd0d..188a78a 100644 --- a/resources/visu_vtk/src/components/popups/HelpPopup.svelte +++ b/resources/visu_vtk/src/components/popups/HelpPopup.svelte @@ -1,70 +1,204 @@ + +
- Help - -
-
- Group highlighting -
    -
  • Click on a group name in the sidebar to highlight or unhighlight it
  • -
  • - Click on the - - button in the sidebar to reset highlight status for all groups -
  • -
  • - Click on the - - button in the sidebar to choose which groups are easily accessible in the sidebar -
  • -
  • Objects becomes transparent when you highlight their groups, helping visualize details more clearly
  • -
-
+ -
- Camera control -
    -
  • Hold Left click and move your mouse to rotate the camera
  • -
  • Hold Ctrl + Left click and move your mouse to rotate the camera around an axis
  • -
  • Hold Shift + Left click and move your mouse to pan the camera
  • -
  • Use the Mouse wheel to zoom in and out
  • -
  • - Click on the X, - Y and - Z buttons at the bottom of the sidebar to quickly align the camera along an axis -
  • -
-
+
+
+ + {#if activeTab === 'Camera'} +
+ Drag to rotate + Ctrl+Drag to rotate around a single axis + Shift+Drag to pan + Zoom in / out + + + 2.0× + + + + + + Open the zoom level selector to choose a preset + + + + 2.0× + + + + + + Reset zoom to 1× — appears only when zoom ≠ 1× + + X + Y + Z + + Align camera along that axis — buttons at the bottom of the sidebar +
+ + {:else if activeTab === 'Objects'} +
+ + + mesh + + + Click the name to collapse or expand its groups + + + + mesh + + + Click to show or hide an entire object + + + + mesh + + + Right-click for more options — e.g. hide all other objects +
+ + {:else if activeTab === 'Groups'} +
+ + + group_A + + Click a group to highlight it — the object becomes transparent so the group stands out. Click again to unhighlight. + + + + + + + Click to choose which groups appear in the sidebar — hidden groups remain visible in the 3D view + + + + + + + Click to clear all highlights +
+ + {:else if activeTab === 'Settings'} +

+ Open settings with in the top-right corner. +

+
+ Edge display + Choose when mesh edges are visible: always, never, or only when zooming in. Threshold mode shows edges abruptly at a zoom level; gradual mode fades them in (may impact performance on dense meshes) + Hidden opacity + How transparent hidden objects appear — at 0% they are fully invisible, above 0% they remain as ghosts +
+ + {:else if activeTab === 'Files'} +
+

.med mesh files are automatically converted to .obj when opened.

+

Converted files are cached in a hidden .visu_data/ folder in your workspace and reused on subsequent opens.

+
+ + {:else if activeTab === 'About'} +
+

This extension is made by Simvia.

+

Source code and issue tracker are available on GitHub.

+
+ {/if} -
- File management -
    -
  • - Mesh files (.*med files) are converted to .obj files, - which are stored in a hidden folder called .visu_data/ in your workspace -
  • -
-
-
- +
+ +
diff --git a/resources/visu_vtk/src/icons/MouseLeftIcon.svelte b/resources/visu_vtk/src/icons/MouseLeftIcon.svelte new file mode 100644 index 0000000..30a5ec9 --- /dev/null +++ b/resources/visu_vtk/src/icons/MouseLeftIcon.svelte @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/visu_vtk/src/icons/MouseRightIcon.svelte b/resources/visu_vtk/src/icons/MouseRightIcon.svelte new file mode 100644 index 0000000..c9ba62c --- /dev/null +++ b/resources/visu_vtk/src/icons/MouseRightIcon.svelte @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/visu_vtk/src/icons/MouseScrollIcon.svelte b/resources/visu_vtk/src/icons/MouseScrollIcon.svelte new file mode 100644 index 0000000..69ee9f0 --- /dev/null +++ b/resources/visu_vtk/src/icons/MouseScrollIcon.svelte @@ -0,0 +1,10 @@ + + + + + + + diff --git a/resources/visu_vtk/vite.config.ts b/resources/visu_vtk/vite.config.ts index c3692bb..cb6d765 100644 --- a/resources/visu_vtk/vite.config.ts +++ b/resources/visu_vtk/vite.config.ts @@ -2,8 +2,15 @@ import { defineConfig } from 'vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; import tailwindcss from '@tailwindcss/vite'; import { resolve } from 'path'; +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); +const pkg = require('../../package.json'); export default defineConfig({ + define: { + __APP_VERSION__: JSON.stringify(pkg.version), + }, root: resolve(__dirname), base: './', build: { From cb750ac7157779b89aedeb38eb68b712f4abed67 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 09:37:32 +0100 Subject: [PATCH 09/20] Update settings popup --- .../src/components/popups/HelpPopup.svelte | 20 +- .../components/popups/SettingsPopup.svelte | 443 ++++++++++++++---- .../src/lib/commands/VisibilityManager.ts | 14 +- resources/visu_vtk/src/lib/data/Group.ts | 13 +- .../src/lib/data/create/FaceActorCreator.ts | 5 +- .../src/lib/interaction/CameraManager.ts | 5 + .../src/lib/settings/GlobalSettings.ts | 5 + resources/visu_vtk/src/lib/state.ts | 4 + resources/visu_vtk/src/main.ts | 21 +- src/WebviewVisu.ts | 25 +- 10 files changed, 413 insertions(+), 142 deletions(-) diff --git a/resources/visu_vtk/src/components/popups/HelpPopup.svelte b/resources/visu_vtk/src/components/popups/HelpPopup.svelte index 188a78a..05ce597 100644 --- a/resources/visu_vtk/src/components/popups/HelpPopup.svelte +++ b/resources/visu_vtk/src/components/popups/HelpPopup.svelte @@ -1,3 +1,7 @@ + + +{#snippet tip(text: string)} + + + + +{/snippet} +
- Settings - -
-
- Edge display -
+ + +
+
+ {#if activeTab === "Edges"} +
+
+ Edge rendering mode + {@render tip( + "Choose when mesh edges are visible: always, never, or only when zooming in. Threshold mode shows edges abruptly at a zoom level; gradual mode fades them in (may impact performance on dense meshes).", + )} +
+
+ {edgeModeLabel} + +
+ + {edgeModeDesc} + + {#if showThresholdSection} +
+
+
+ + {@render tip( + "Higher values show edges at a lower zoom level, from farther away.", + )} +
+ + {edgeThresholdDisplay.toPrecision( + edgeThresholdDisplay < 1 ? 2 : 3, + )}× + +
+ + Higher values show edges from farther away. +
+ {/if} +
+ {:else if activeTab === "Visibility"} +
+
+
+
+ + {@render tip( + "At 0% hidden objects are fully invisible. Above 0% they remain as faint ghosts.", + )} +
+ {hiddenOpacityPct}% +
+ + When hiding an object with the eye button, it can remain slightly + visible as a ghost. +
+
+
+
+ + {@render tip( + "When a sub-group is highlighted, the parent mesh fades to this opacity so the selected group stands out.", + )} +
+ {groupTransparencyPct}% +
+ + Opacity of the parent mesh when a sub-group is highlighted. +
+
+ {:else if activeTab === "Display"} +
+
+ +
+
+ Orientation widget + {@render tip( + "Toggle the XYZ axes indicator in the bottom-right corner of the viewport.", + )} +
+ Show the axes widget in the bottom-right corner. +
- - Higher values show edges from farther away.
{/if}
-
-
- - {hiddenOpacityPct}% -
- - - When hiding an object with the eye button, it can remain slightly visible as a ghost. - +
+ +
- -
- - -
diff --git a/resources/visu_vtk/src/lib/commands/VisibilityManager.ts b/resources/visu_vtk/src/lib/commands/VisibilityManager.ts index 3287278..ce82a5f 100644 --- a/resources/visu_vtk/src/lib/commands/VisibilityManager.ts +++ b/resources/visu_vtk/src/lib/commands/VisibilityManager.ts @@ -104,7 +104,7 @@ export class VisibilityManager { if (fileGroup) { if (nowVisible) { fileGroup.actor.setVisibility(true); - const opacity = this.visibleGroupsByObject[object] > 0 ? 0.2 : 1.0; + const opacity = this.visibleGroupsByObject[object] > 0 ? GlobalSettings.Instance.groupTransparency : 1.0; fileGroup.setOpacity(opacity); } else { const hiddenOpacity = GlobalSettings.Instance.hiddenObjectOpacity; @@ -129,11 +129,21 @@ export class VisibilityManager { setTransparence(transparent: boolean, object: string): void { if (!this.groups || this.hiddenObjects[object]) { return; } - const meshOpacity = transparent ? 0.2 : 1; + const meshOpacity = transparent ? GlobalSettings.Instance.groupTransparency : 1; const group = this.groups[object]; group.setOpacity(meshOpacity); } + applyGroupTransparency(): void { + for (const object in this.visibleGroupsByObject) { + if (this.hiddenObjects[object]) continue; + if (this.visibleGroupsByObject[object] > 0) { + this.groups[object]?.setOpacity(GlobalSettings.Instance.groupTransparency); + } + } + VtkApp.Instance.getRenderWindow().render(); + } + hideAllOthers(object: string): void { for (const key in this.hiddenObjects) { if (key === object) continue; diff --git a/resources/visu_vtk/src/lib/data/Group.ts b/resources/visu_vtk/src/lib/data/Group.ts index 0248a9d..340182a 100644 --- a/resources/visu_vtk/src/lib/data/Group.ts +++ b/resources/visu_vtk/src/lib/data/Group.ts @@ -52,7 +52,7 @@ export class Group { } if (mode === 'show') { prop.setEdgeVisibility(true); - prop.setEdgeColor(0, 0, 0); + this._applyFlatEdgeColor(prop); return; } @@ -60,7 +60,7 @@ export class Group { if (mode === 'threshold') { prop.setEdgeVisibility(currentDistance < threshold); - prop.setEdgeColor(0, 0, 0); + this._applyFlatEdgeColor(prop); return; } @@ -69,10 +69,17 @@ export class Group { this._applyEdgeColor(); } + private _applyFlatEdgeColor(prop: any): void { + const op = GlobalSettings.Instance.edgeOpacity; + const [r, g, b] = prop.getColor(); + prop.setEdgeColor(r * (1 - op), g * (1 - op), b * (1 - op)); + } + private _applyEdgeColor(): void { const t = this._edgeT ?? 0; + const op = GlobalSettings.Instance.edgeOpacity; const [r, g, b] = this.actor.getProperty().getColor(); - this.actor.getProperty().setEdgeColor(r * (1 - t), g * (1 - t), b * (1 - t)); + this.actor.getProperty().setEdgeColor(r * (1 - t * op), g * (1 - t * op), b * (1 - t * op)); } setSize(distance: number): void { diff --git a/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts b/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts index ca8b175..ea0ec28 100644 --- a/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts +++ b/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts @@ -86,8 +86,9 @@ export class FaceActorCreator { prop.setEdgeColor(r, g, b); prop.setLineWidth(0.3); prop.setInterpolationToPhong(); - prop.setSpecular(0.3); - prop.setSpecularPower(15); + prop.setAmbient(GlobalSettings.Instance.ambientIntensity); + prop.setSpecular(GlobalSettings.Instance.specular); + prop.setSpecularPower(GlobalSettings.Instance.specularPower); return { colorIndex, isObjectActor }; } diff --git a/resources/visu_vtk/src/lib/interaction/CameraManager.ts b/resources/visu_vtk/src/lib/interaction/CameraManager.ts index 498d48f..0bd12c1 100644 --- a/resources/visu_vtk/src/lib/interaction/CameraManager.ts +++ b/resources/visu_vtk/src/lib/interaction/CameraManager.ts @@ -103,6 +103,11 @@ export class CameraManager { VtkApp.Instance.getRenderWindow().render(); } + setOrientationWidgetVisible(visible: boolean): void { + this.orientationWidget.setEnabled(visible); + VtkApp.Instance.getRenderWindow().render(); + } + setCameraAxis(axis: string): void { if (!this.camera) { return; } diff --git a/resources/visu_vtk/src/lib/settings/GlobalSettings.ts b/resources/visu_vtk/src/lib/settings/GlobalSettings.ts index 0976ef6..6f6aea3 100644 --- a/resources/visu_vtk/src/lib/settings/GlobalSettings.ts +++ b/resources/visu_vtk/src/lib/settings/GlobalSettings.ts @@ -35,6 +35,11 @@ export class GlobalSettings { hiddenObjectOpacity = 0; edgeMode: EdgeMode = 'threshold'; edgeThresholdMultiplier = 1; + specular = 0.3; + specularPower = 15; + ambientIntensity = 0.1; + groupTransparency = 0.2; + showOrientationWidget = true; get isDark(): boolean { return document.body.classList.contains('vscode-dark') || diff --git a/resources/visu_vtk/src/lib/state.ts b/resources/visu_vtk/src/lib/state.ts index 87d4c4f..f1cc5f5 100644 --- a/resources/visu_vtk/src/lib/state.ts +++ b/resources/visu_vtk/src/lib/state.ts @@ -10,6 +10,8 @@ export interface Settings { hiddenObjectOpacity: number; edgeMode: EdgeMode; edgeThresholdMultiplier: number; + groupTransparency: number; + showOrientationWidget: boolean; } export const groupHierarchy = writable({}); @@ -21,6 +23,8 @@ export const settings = writable({ hiddenObjectOpacity: 0, edgeMode: 'threshold', edgeThresholdMultiplier: 1, + groupTransparency: 0.2, + showOrientationWidget: true, }); // Map> — groups NOT shown in sidebar (hidden) diff --git a/resources/visu_vtk/src/main.ts b/resources/visu_vtk/src/main.ts index dfd514c..0f61415 100644 --- a/resources/visu_vtk/src/main.ts +++ b/resources/visu_vtk/src/main.ts @@ -2,6 +2,7 @@ import { mount } from 'svelte'; import App from './components/App.svelte'; import { Controller } from './lib/Controller'; import { VisibilityManager } from './lib/commands/VisibilityManager'; +import { CameraManager } from './lib/interaction/CameraManager'; import { GlobalSettings } from './lib/settings/GlobalSettings'; import { settings } from './lib/state'; import type { EdgeMode } from './lib/state'; @@ -28,21 +29,23 @@ window.addEventListener('message', async (e) => { Controller.Instance.loadFiles(body.fileContexts, body.objFilenames); if (body.settings) { const s = body.settings; - if (s.hiddenObjectOpacity !== undefined) { - GlobalSettings.Instance.hiddenObjectOpacity = s.hiddenObjectOpacity; - } - if (s.edgeMode !== undefined) { - GlobalSettings.Instance.edgeMode = s.edgeMode as EdgeMode; - } - if (s.edgeThresholdMultiplier !== undefined) { - GlobalSettings.Instance.edgeThresholdMultiplier = s.edgeThresholdMultiplier; - } + if (s.hiddenObjectOpacity !== undefined) GlobalSettings.Instance.hiddenObjectOpacity = s.hiddenObjectOpacity; + if (s.edgeMode !== undefined) GlobalSettings.Instance.edgeMode = s.edgeMode as EdgeMode; + if (s.edgeThresholdMultiplier !== undefined) GlobalSettings.Instance.edgeThresholdMultiplier = s.edgeThresholdMultiplier; + if (s.groupTransparency !== undefined) GlobalSettings.Instance.groupTransparency = s.groupTransparency; + if (s.showOrientationWidget !== undefined) GlobalSettings.Instance.showOrientationWidget = s.showOrientationWidget; settings.update((cur) => ({ hiddenObjectOpacity: s.hiddenObjectOpacity ?? cur.hiddenObjectOpacity, edgeMode: (s.edgeMode ?? cur.edgeMode) as EdgeMode, edgeThresholdMultiplier: s.edgeThresholdMultiplier ?? cur.edgeThresholdMultiplier, + groupTransparency: s.groupTransparency ?? cur.groupTransparency, + showOrientationWidget: s.showOrientationWidget ?? cur.showOrientationWidget, })); VisibilityManager.Instance.applyHiddenObjectOpacity(); + CameraManager.Instance.refreshEdgeVisibility(); + if (s.showOrientationWidget === false) { + CameraManager.Instance.setOrientationWidgetVisible(false); + } } break; } diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index 8d78c1e..881c8a5 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -91,7 +91,9 @@ export class WebviewVisu implements vscode.Disposable { const config = vscode.workspace.getConfiguration("vs-code-aster"); const settings = { hiddenObjectOpacity: config.get("viewer.hiddenObjectOpacity", 0), - edgeMode: config.get("viewer.edgeMode", "gradual"), + edgeMode: config.get("viewer.edgeMode", "threshold"), + groupTransparency: config.get("viewer.groupTransparency", 0.2), + showOrientationWidget: config.get("viewer.showOrientationWidget", true), }; this.panel.webview.postMessage({ type: "init", @@ -101,19 +103,14 @@ export class WebviewVisu implements vscode.Disposable { break; case "saveSettings": // Persist viewer settings back to VS Code configuration - if (e.settings.hiddenObjectOpacity !== undefined) { - vscode.workspace.getConfiguration("vs-code-aster").update( - "viewer.hiddenObjectOpacity", - e.settings.hiddenObjectOpacity, - vscode.ConfigurationTarget.Global - ); - } - if (e.settings.edgeMode !== undefined) { - vscode.workspace.getConfiguration("vs-code-aster").update( - "viewer.edgeMode", - e.settings.edgeMode, - vscode.ConfigurationTarget.Global - ); + const cfg = vscode.workspace.getConfiguration("vs-code-aster"); + const settingKeys = [ + 'hiddenObjectOpacity', 'edgeMode', 'groupTransparency', 'showOrientationWidget', + ]; + for (const key of settingKeys) { + if (e.settings[key] !== undefined) { + cfg.update(`viewer.${key}`, e.settings[key], vscode.ConfigurationTarget.Global); + } } break; case "debugPanel": From 2dc8440255eb8f2bad044b1da6ac0322ab96eee4 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 10:44:50 +0100 Subject: [PATCH 10/20] Add pre-commits and CI checks for linting and formatting --- .github/workflows/ci.yml | 57 ++- .husky/pre-commit | 30 ++ .prettierignore | 5 + .prettierrc | 16 + CHANGELOG.md | 4 +- eslint.config.mjs | 2 +- package-lock.json | 445 ++++++++++-------- package.json | 20 +- pyproject.toml | 14 + python/lsp/__init__.py | 6 +- python/lsp/command_core.py | 26 +- python/lsp/command_registry.py | 344 +++++++------- python/lsp/handlers.py | 42 +- python/lsp/managers/__init__.py | 6 +- python/lsp/managers/completion_manager.py | 17 +- python/lsp/managers/hover_manager.py | 18 +- python/lsp/managers/signature_manager.py | 27 +- python/lsp/managers/status_bar_manager.py | 43 +- python/lsp/managers/update_manager.py | 5 +- python/lsp/managers_container.py | 12 +- python/lsp/server.py | 17 +- python/med2obj.py | 15 +- .../src/components/LoadingScreen.svelte | 2 + .../src/components/ObjectSection.svelte | 59 ++- .../src/components/popups/HelpPopup.svelte | 222 ++++++--- .../components/popups/SettingsPopup.svelte | 149 +++--- .../src/lib/commands/VisibilityManager.ts | 32 +- resources/visu_vtk/src/lib/data/Group.ts | 7 +- .../src/lib/data/create/FaceActorCreator.ts | 15 +- .../src/lib/interaction/AxesCreator.ts | 80 +++- .../src/lib/interaction/CameraManager.ts | 15 +- .../src/lib/settings/GlobalSettings.ts | 63 +-- resources/visu_vtk/src/lib/vtk.d.ts | 4 + resources/visu_vtk/src/main.ts | 12 +- src/WebviewVisu.ts | 102 ++-- tsconfig.json | 29 +- 36 files changed, 1154 insertions(+), 808 deletions(-) create mode 100644 .husky/pre-commit create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 pyproject.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ca6012..5c1192c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,30 +2,81 @@ name: CI on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: + checks: + name: Lint & type-check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.15 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install npm dependencies + run: npm install + + - name: Install Python tools + run: pip install ruff mypy + + - name: Prettier + run: npx prettier --check "src/**/*.ts" "resources/visu_vtk/src/**/*.{ts,svelte}" "resources/export_form/**/*.{js,css,html}" + + - name: ESLint + run: npx eslint --max-warnings=0 src/ resources/export_form/ + + - name: TypeScript + run: npx tsc --noEmit + + - name: svelte-check + run: npx svelte-check --tsconfig resources/visu_vtk/tsconfig.json --fail-on-warnings + + - name: Ruff lint + run: python3 -m ruff check python/lsp/ python/med2obj.py + + - name: Ruff format + run: python3 -m ruff format --check python/lsp/ python/med2obj.py + + - name: mypy + run: python3 -m mypy + build: + name: Package runs-on: ubuntu-latest + needs: checks steps: - uses: actions/checkout@v4 + - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: 22.15 + - name: Install Python run: sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-nox python3-venv + - name: Install npm dependencies run: npm install + - name: Install vsce run: npm install -g @vscode/vsce + - name: Build and package run: python3 -m nox -s package -v --no-error-on-missing-interpreters + - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: vsix-package path: "*.vsix" - retention-days: 30 \ No newline at end of file + retention-days: 30 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..f7b595e --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,30 @@ +#!/bin/sh +set -e + +STAGED=$(git diff --cached --name-only --diff-filter=ACM) + +STAGED_FORMATTABLE=$(echo "$STAGED" | grep -E '\.(ts|svelte|js|json|html|css)$' || true) +STAGED_TS=$(echo "$STAGED" | grep -E '^src/.*\.ts$' || true) +STAGED_EXPORT_JS=$(echo "$STAGED" | grep -E '^resources/export_form/.*\.js$' || true) +STAGED_SVELTE=$(echo "$STAGED" | grep -E '\.svelte$' || true) +STAGED_PY=$(echo "$STAGED" | grep -E '^python/(lsp/.*\.py|med2obj\.py)$' || true) + +if [ -n "$STAGED_FORMATTABLE" ]; then + echo "$STAGED_FORMATTABLE" | xargs npx prettier --write + echo "$STAGED_FORMATTABLE" | xargs git add +fi + +if [ -n "$STAGED_TS" ] || [ -n "$STAGED_EXPORT_JS" ]; then + FILES=$(printf '%s\n%s' "$STAGED_TS" "$STAGED_EXPORT_JS" | grep -v '^$' || true) + echo "$FILES" | xargs npx eslint --max-warnings=0 +fi + +if [ -n "$STAGED_SVELTE" ]; then + npx svelte-check --tsconfig resources/visu_vtk/tsconfig.json --fail-on-warnings +fi + +if [ -n "$STAGED_PY" ]; then + echo "$STAGED_PY" | xargs python3 -m ruff check + echo "$STAGED_PY" | xargs python3 -m ruff format + echo "$STAGED_PY" | xargs git add +fi diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..2e1207a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +dist/ +node_modules/ +python/ +*.min.js +*.min.css diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3a5ed67 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,16 @@ +{ + "plugins": ["prettier-plugin-svelte"], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ], + "singleQuote": true, + "semi": true, + "printWidth": 100, + "tabWidth": 2, + "trailingComma": "es5" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bb60ff..4d49368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,9 @@ Rewrote the mesh viewer UI with Svelte, and added new viewer features. - Show/hide toggle button per object in the sidebar - Per-object color display in the sidebar - Zoom widget in the mesh viewer -- Settings popup with configurable hidden object opacity, edge rendering mode, and edge threshold multiplier - Groups popup to select which groups are shown in the sidebar -- Help popup +- Revamped help popup with tabs and more tips +- Added a settings popup with configurable hidden object opacity, edge rendering mode and plenty other settings - Focusing a `.comm` file now focuses its corresponding mesh viewer webview - Object file names are shown in the webview tab titles - Mesh viewer UI now follows the VS Code user theme diff --git a/eslint.config.mjs b/eslint.config.mjs index d5c0b53..e029242 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,7 +2,7 @@ import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; export default [{ - files: ["**/*.ts"], + files: ["**/*.ts", "resources/export_form/**/*.js"], }, { plugins: { "@typescript-eslint": typescriptEslint, diff --git a/package-lock.json b/package-lock.json index 6bc9d69..e69fa47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,10 @@ "@vscode/test-electron": "^2.5.2", "esbuild": "^0.25.5", "eslint": "^9.25.1", + "husky": "^9.1.7", "npm-run-all": "^4.1.5", + "prettier": "^3.8.1", + "prettier-plugin-svelte": "^3.5.1", "svelte": "^5.53.9", "svelte-check": "^4.4.5", "typescript": "^5.8.3", @@ -506,15 +509,15 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -578,9 +581,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz", - "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { @@ -591,7 +594,7 @@ "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", - "minimatch": "^3.1.3", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -643,9 +646,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", - "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -1830,9 +1833,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", - "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", "dev": true, "license": "MIT", "dependencies": { @@ -1847,24 +1850,24 @@ "license": "MIT" }, "node_modules/@types/vscode": { - "version": "1.109.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.109.0.tgz", - "integrity": "sha512-0Pf95rnwEIwDbmXGC08r0B4TQhAbsHQ5UyTIgVgoieDe4cOnf92usuR5dEczb6bTKEp7ziZH4TV1TRGPPCExtw==", + "version": "1.110.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.110.0.tgz", + "integrity": "sha512-AGuxUEpU4F4mfuQjxPPaQVyuOMhs+VT/xRok1jiHVBubHK7lBRvCuOMZG0LKUwxncrPorJ5qq/uil3IdZBd5lA==", "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", + "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/type-utils": "8.57.0", + "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -1877,22 +1880,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", + "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "engines": { @@ -1908,14 +1911,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", + "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", + "@typescript-eslint/tsconfig-utils": "^8.57.0", + "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "engines": { @@ -1930,14 +1933,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", + "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1948,9 +1951,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", + "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", "dev": true, "license": "MIT", "engines": { @@ -1965,15 +1968,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", + "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -1990,9 +1993,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", + "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", "dev": true, "license": "MIT", "engines": { @@ -2004,16 +2007,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", + "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/project-service": "8.57.0", + "@typescript-eslint/tsconfig-utils": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2032,16 +2035,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", + "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2056,13 +2059,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", + "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2613,9 +2616,9 @@ } }, "node_modules/devalue": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", - "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", + "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", "dev": true, "license": "MIT" }, @@ -2856,25 +2859,25 @@ } }, "node_modules/eslint": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", - "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", + "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.3", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", @@ -2893,7 +2896,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3051,13 +3054,14 @@ } }, "node_modules/esrap": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz", - "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz", + "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.4.15", + "@typescript-eslint/types": "^8.2.0" } }, "node_modules/esrecurse": { @@ -3177,9 +3181,9 @@ } }, "node_modules/flatted": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", - "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", + "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", "dev": true, "license": "ISC" }, @@ -3526,6 +3530,22 @@ "node": ">= 14" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -5159,6 +5179,33 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.1.tgz", + "integrity": "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5885,9 +5932,9 @@ } }, "node_modules/svelte": { - "version": "5.53.9", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.9.tgz", - "integrity": "sha512-MwDfWsN8qZzeP0jlQsWF4k/4B3csb3IbzCRggF+L/QqY7T8bbKvnChEo1cPZztF51HJQhilDbevWYl2LvXbquA==", + "version": "5.53.11", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.11.tgz", + "integrity": "sha512-GYmqRjRhJYLQBonfdfGAt28gkfWEShrtXKGXcFGneXi502aBE+I1dJcs/YQriByvP6xqXRz/OdBGC6tfvUQHyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6233,9 +6280,9 @@ } }, "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", "cpu": [ "ppc64" ], @@ -6250,9 +6297,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", "cpu": [ "arm" ], @@ -6267,9 +6314,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", "cpu": [ "arm64" ], @@ -6284,9 +6331,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", "cpu": [ "x64" ], @@ -6301,9 +6348,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "cpu": [ "arm64" ], @@ -6318,9 +6365,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", "cpu": [ "x64" ], @@ -6335,9 +6382,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", "cpu": [ "arm64" ], @@ -6352,9 +6399,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", "cpu": [ "x64" ], @@ -6369,9 +6416,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", "cpu": [ "arm" ], @@ -6386,9 +6433,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", "cpu": [ "arm64" ], @@ -6403,9 +6450,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", "cpu": [ "ia32" ], @@ -6420,9 +6467,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", "cpu": [ "loong64" ], @@ -6437,9 +6484,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", "cpu": [ "mips64el" ], @@ -6454,9 +6501,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", "cpu": [ "ppc64" ], @@ -6471,9 +6518,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", "cpu": [ "riscv64" ], @@ -6488,9 +6535,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", "cpu": [ "s390x" ], @@ -6505,9 +6552,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", "cpu": [ "x64" ], @@ -6522,9 +6569,9 @@ } }, "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", "cpu": [ "arm64" ], @@ -6539,9 +6586,9 @@ } }, "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", "cpu": [ "x64" ], @@ -6556,9 +6603,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", "cpu": [ "arm64" ], @@ -6573,9 +6620,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", "cpu": [ "x64" ], @@ -6590,9 +6637,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", "cpu": [ "arm64" ], @@ -6607,9 +6654,9 @@ } }, "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", "cpu": [ "x64" ], @@ -6624,9 +6671,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", "cpu": [ "arm64" ], @@ -6641,9 +6688,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", "cpu": [ "ia32" ], @@ -6658,9 +6705,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "cpu": [ "x64" ], @@ -6675,9 +6722,9 @@ } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -6688,32 +6735,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" } }, "node_modules/vitefu": { diff --git a/package.json b/package.json index 0f06c49..be75b2c 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,20 @@ ], "markdownDescription": "Controls how mesh edges are displayed in the viewer." }, + "vs-code-aster.viewer.groupTransparency": { + "order": 15, + "type": "number", + "default": 0.2, + "minimum": 0, + "maximum": 0.5, + "markdownDescription": "Opacity of the parent mesh when a sub-group is highlighted (0 = invisible, 0.5 = semi-visible)." + }, + "vs-code-aster.viewer.showOrientationWidget": { + "order": 16, + "type": "boolean", + "default": true, + "markdownDescription": "Show the orientation axes widget in the bottom-right corner of the viewer." + }, "vs-code-aster.enableTelemetry": { "order": 100, "type": "boolean", @@ -193,7 +207,8 @@ "build:webview": "vite build --config resources/visu_vtk/vite.config.ts", "package": "npm run check-types && npm run lint && node esbuild.js --production", "check-types": "tsc --noEmit", - "lint": "eslint src" + "lint": "eslint src", + "prepare": "husky" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^6.2.4", @@ -205,7 +220,10 @@ "@vscode/test-electron": "^2.5.2", "esbuild": "^0.25.5", "eslint": "^9.25.1", + "husky": "^9.1.7", "npm-run-all": "^4.1.5", + "prettier": "^3.8.1", + "prettier-plugin-svelte": "^3.5.1", "svelte": "^5.53.9", "svelte-check": "^4.4.5", "typescript": "^5.8.3", diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4c3be34 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[tool.ruff] +line-length = 100 +target-version = "py311" + +[tool.ruff.lint] +select = ["E", "F", "I", "W", "UP"] +ignore = ["E501"] + +[tool.mypy] +python_version = "3.11" +ignore_missing_imports = true +warn_unused_ignores = true +warn_return_any = false +files = ["python/lsp"] diff --git a/python/lsp/__init__.py b/python/lsp/__init__.py index 2c6df74..ea13a77 100644 --- a/python/lsp/__init__.py +++ b/python/lsp/__init__.py @@ -1,7 +1,7 @@ -import sys import pathlib as pl -asterstudy_path = pl.Path(__file__).parent.parent.absolute() +import sys + +asterstudy_path = pl.Path(__file__).parent.parent.absolute() sys.path.append(str(asterstudy_path)) code_aster_path = asterstudy_path / "asterstudy" / "code_aster_version" sys.path.append(str(code_aster_path)) - diff --git a/python/lsp/command_core.py b/python/lsp/command_core.py index b2919b1..258a542 100644 --- a/python/lsp/command_core.py +++ b/python/lsp/command_core.py @@ -1,7 +1,12 @@ +import sys + try: from asterstudy.datamodel.catalogs import CATA except ImportError as exc: - raise Exception(f"Could not import CATA from asterstudy.datamodel.catalogs. Ensure the path is correct. {sys.path} ; {exc}") + raise Exception( + f"Could not import CATA from asterstudy.datamodel.catalogs. Ensure the path is correct. {sys.path} ; {exc}" + ) + class CommandCore: """ @@ -10,6 +15,7 @@ class CommandCore: - Document registries (CommandRegistry per doc) - Langage server utilities """ + _instance = None def __new__(cls): @@ -18,7 +24,7 @@ def __new__(cls): cls._instance.CATA = CATA cls._instance.document_registries = {} return cls._instance - + # ====== Langage server ====== def store_ls(self, ls): @@ -26,32 +32,32 @@ def store_ls(self, ls): self.ls = ls def log(self, debug): - self.ls.send_notification('logParser', {'text': debug}) + self.ls.send_notification("logParser", {"text": debug}) def get_ls(self): return self.ls - + def get_doc_from_uri(self, doc_uri): return self.ls.workspace.get_document(doc_uri) - + # ====== CATA ====== def get_CATA(self): """Get the CATA object""" return self.CATA - + def get_CATA_commands(self): return self.CATA.get_commands() def get_docstring(self, command_name): - return self.CATA.get_command_definition(command_name, context = None) - + return self.CATA.get_command_definition(command_name, context=None) + def get_command_def(self, command_name): cmd_obj = self.CATA.get_command_obj(command_name) if cmd_obj: cmd_def = self.CATA.parse_command(cmd_obj) return cmd_def - + # ====== Document registries ====== def get_registry(self, doc_uri): @@ -66,5 +72,3 @@ def remove_registry(self, doc_uri): """Remove a registry for a closed/removed document""" if doc_uri in self.document_registries: del self.document_registries[doc_uri] - - diff --git a/python/lsp/command_registry.py b/python/lsp/command_registry.py index 03099fc..b0c8712 100644 --- a/python/lsp/command_registry.py +++ b/python/lsp/command_registry.py @@ -4,26 +4,26 @@ """ import re -from typing import Dict, List, Optional, Tuple from dataclasses import dataclass, field @dataclass class CommandInfo: """Information about a detected command""" + name: str # Ex: "AFFE_CHAR_MECA" - var_name: Optional[str] # Ex: "CHARD" or None + var_name: str | None # Ex: "CHARD" or None start_line: int # 1-based numbering - end_line: Optional[int] # None if incomplete - end_char: Optional[int] # Position of closing parenthesis on end line + end_line: int | None # None if incomplete + end_char: int | None # Position of closing parenthesis on end line zone_end: int # End of the zone (next command or EOF) is_complete: bool - parsed_params: Dict[str, str] = field(default_factory=dict) - + parsed_params: dict[str, str] = field(default_factory=dict) + def get_key(self) -> str: """Returns the unique key of the command""" return f"{self.name}:{self.start_line}" - + def contains_line(self, line: int) -> bool: """Checks if a line belongs to this command's zone""" return self.start_line <= line <= self.zone_end @@ -33,87 +33,90 @@ class CommandRegistry: """ Command registry with incremental updates (Unique for each .comm file) """ - + def __init__(self): - self.commands: Dict[str, CommandInfo] = {} + self.commands: dict[str, CommandInfo] = {} # Sorted ranges for binary search: (start, end, cmd_key) - self.ranges: List[Tuple[int, int, Optional[str]]] = [] - - def initialize(self, ls, lines: List[str]): + self.ranges: list[tuple[int, int, str | None]] = [] + + def initialize(self, ls, lines: list[str]): """ Full registry initialization when opening the document - + Args: lines: All document lines """ self.ls = ls self.commands = {} - + # 1. Detect all commands with the existing parser raw_commands = self._parse_all_commands(lines) - + # 2. Create CommandInfo with zones for cmd_data in raw_commands: cmd_info = CommandInfo( - name=cmd_data['name'], - var_name=cmd_data['var_name'], - start_line=cmd_data['start_line'], - end_line=cmd_data['end_line'], - zone_end=cmd_data['zone_end'], - end_char=cmd_data['end_char'], - is_complete=cmd_data['is_complete'] + name=cmd_data["name"], + var_name=cmd_data["var_name"], + start_line=cmd_data["start_line"], + end_line=cmd_data["end_line"], + zone_end=cmd_data["zone_end"], + end_char=cmd_data["end_char"], + is_complete=cmd_data["is_complete"], ) - + # 3. Parse level 1 parameters cmd_info.parsed_params = self._parse_params_level1( lines, cmd_info.start_line, cmd_info.zone_end ) - + self.commands[cmd_info.get_key()] = cmd_info - + # 4. Build the range index self._rebuild_ranges() - - def on_document_change(self, lines: List[str], change_start_line: int, text_change: str) -> None: + + def on_document_change( + self, lines: list[str], change_start_line: int, text_change: str + ) -> None: """ Incremental update on a change - + Args: lines: New complete document lines change_start_line: Line where change starts (1-based) text_change: Inserted text or empty """ - + # 2. Find the affected command affected_cmd_key = self._find_command_at_line(change_start_line) - + if affected_cmd_key is None: - self.ls.send_notification('logParser', {'text': f"Change outside a command"}) + self.ls.send_notification("logParser", {"text": "Change outside a command"}) return - + # Check if we are inside the command (needs updating end_char) - self.ls.send_notification('logParser', {'text': f"Command: {affected_cmd_key}, change: {text_change}"}) + self.ls.send_notification( + "logParser", {"text": f"Command: {affected_cmd_key}, change: {text_change}"} + ) self._reparse_command(lines, affected_cmd_key) - - - def get_command_at_line(self, line: int) -> Optional[CommandInfo]: + + def get_command_at_line(self, line: int) -> CommandInfo | None: """ Returns the command that contains the given line - + Args: line: Line number (1-based) - + Returns: CommandInfo or None """ cmd_key = self._find_command_at_line(line) return self.commands.get(cmd_key) - - def get_all_commands(self) -> Dict[str, str]: + + def get_all_commands(self) -> dict[str, str]: """ Returns a simple JSON format for compatibility - + Returns: Dict {cmdName:line: "start-end" or "start"} """ @@ -124,19 +127,23 @@ def get_all_commands(self) -> Dict[str, str]: else: result[cmd_key] = str(cmd_info.start_line) return result - + def log_command(self, cmd_info): if cmd_info.is_complete: lines = [f"For the complete command: {cmd_info.name}"] - lines.append(f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}") + lines.append( + f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}" + ) lines.append(str(cmd_info.parsed_params)) return "\n".join(lines) else: lines = [f"For the incomplete command: {cmd_info.name}"] - lines.append(f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}") + lines.append( + f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}" + ) lines.append(str(cmd_info.parsed_params)) return "\n".join(lines) - + def log_all_commands(self): """ Returns all expanded commands @@ -145,330 +152,331 @@ def log_all_commands(self): for cmd_key, cmd_info in self.commands.items(): if cmd_info.is_complete: lines.append(f"For the complete command: {cmd_info.name}") - lines.append(f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}") + lines.append( + f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}" + ) lines.append(str(cmd_info.parsed_params)) lines.append("") else: lines.append(f"For the incomplete command: {cmd_info.name}") - lines.append(f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}") + lines.append( + f"start_line: {cmd_info.start_line}, end_line: {cmd_info.end_line}, zone_end: {cmd_info.zone_end}" + ) lines.append(str(cmd_info.parsed_params)) lines.append("") return "\n".join(lines) - + def text_is_outside_command(self, position, cmd_info) -> bool: """ Indicates if the position is outside the command, only when line == cmd_info.end_line - 1 (0-based). - + True => right of closing parenthesis => outside command False => left or inside the command => inside """ # Closing parenthesis is before position.character -> we are out if hasattr(cmd_info, "end_char") and cmd_info.end_char is not None: return position.character > cmd_info.end_char - + return True - + def clean_value(self, value: str) -> str: - value = value.strip().rstrip(',') - if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")): + value = value.strip().rstrip(",") + if (value.startswith('"') and value.endswith('"')) or ( + value.startswith("'") and value.endswith("'") + ): value = value[1:-1] return value - + # ============ Private methods ============ - def _parse_all_commands(self, lines: List[str]) -> List[Dict]: + def _parse_all_commands(self, lines: list[str]) -> list[dict]: """Parse all commands in the document""" commands = [] - pattern = re.compile( - r'^\s*(?:(\w+)\s*=\s*)?(?!_F\b)([A-Z_][A-Z0-9_]*)\s*\(', - re.MULTILINE - ) - + re.compile(r"^\s*(?:(\w+)\s*=\s*)?(?!_F\b)([A-Z_][A-Z0-9_]*)\s*\(", re.MULTILINE) + i = 0 while i < len(lines): line = lines[i] - + # Skip comments if self._is_comment_line(line): i += 1 continue - + match = self._find_command_start(line) if match: start_line = i + 1 # 1-based - + # Find command end - result = self._find_command_end(lines, i, match['open_paren_pos']) - + result = self._find_command_end(lines, i, match["open_paren_pos"]) + # Calculate zone_end (adjusted later) - zone_end = result['end_line'] if result['complete'] else len(lines) - - commands.append({ - 'name': match['command'], - 'var_name': match['variable'], - 'start_line': start_line, - 'end_line': result['end_line'] if result['complete'] else None, - 'end_char': result.get('end_char'), - 'zone_end': zone_end, - 'is_complete': result['complete'] - }) - - if result['complete']: - i = result['end_line'] + zone_end = result["end_line"] if result["complete"] else len(lines) + + commands.append( + { + "name": match["command"], + "var_name": match["variable"], + "start_line": start_line, + "end_line": result["end_line"] if result["complete"] else None, + "end_char": result.get("end_char"), + "zone_end": zone_end, + "is_complete": result["complete"], + } + ) + + if result["complete"]: + i = result["end_line"] else: i += 1 else: i += 1 - + # Adjust zone_end for idx, cmd in enumerate(commands): - if cmd['is_complete'] : + if cmd["is_complete"]: continue if idx < len(commands) - 1: # Zone ends before next command - cmd['zone_end'] = commands[idx + 1]['start_line'] - 1 + cmd["zone_end"] = commands[idx + 1]["start_line"] - 1 else: # Last command: zone until the end - cmd['zone_end'] = len(lines) - + cmd["zone_end"] = len(lines) + return commands - - def _parse_params_level1(self, lines: List[str], start_line: int, - zone_end: int) -> Dict[str, str]: + + def _parse_params_level1( + self, lines: list[str], start_line: int, zone_end: int + ) -> dict[str, str]: """ Parse level 1 parameters (without entering _F) - + Args: lines: All lines start_line: Start line (1-based) zone_end: Zone end line (1-based) - + Returns: Dict {param_name: value} """ params = {} - + # Extract zone content - zone_lines = lines[start_line - 1:zone_end] - content = '\n'.join(zone_lines) - + zone_lines = lines[start_line - 1 : zone_end] + content = "\n".join(zone_lines) + # Find first opening parenthesis - match = re.search(r'\(', content) + match = re.search(r"\(", content) if not match: return params - + # Parse from parenthesis - content = content[match.end():] - + content = content[match.end() :] + # Regex for param=value at level 1 # Stop at comma or closing parenthesis i = 0 paren_depth = 0 current_param = None value_start = None - + while i < len(content): char = content[i] - + # Skip strings if char in ('"', "'"): quote = char i += 1 while i < len(content) and content[i] != quote: - if content[i] == '\\': + if content[i] == "\\": i += 2 else: i += 1 i += 1 continue - + # Parenthesis management - if char == '(': + if char == "(": paren_depth += 1 - elif char == ')': + elif char == ")": paren_depth -= 1 if paren_depth < 0: # End of command - save current param before exiting if current_param and value_start is not None: - value = content[value_start:i].strip().rstrip(',') + value = content[value_start:i].strip().rstrip(",") value = self.clean_value(content[value_start:i]) params[current_param] = value break - + # Detect param= if paren_depth == 0: - param_match = re.match(r'\s*(\w+)\s*=\s*', content[i:]) + param_match = re.match(r"\s*(\w+)\s*=\s*", content[i:]) if param_match: if current_param and value_start is not None: # Save previous param - value = content[value_start:i].strip().rstrip(',') + value = content[value_start:i].strip().rstrip(",") value = self.clean_value(content[value_start:i]) params[current_param] = value - + current_param = param_match.group(1) i += param_match.end() value_start = i continue - + # Detect end of value (comma at level 0) - if char == ',' and current_param and value_start is not None: + if char == "," and current_param and value_start is not None: value = content[value_start:i].strip() value = self.clean_value(content[value_start:i]) params[current_param] = value current_param = None value_start = None - + i += 1 - + # Note: Last param is NOT saved here because either: # - It was saved during break (paren_depth < 0) # - Or the command is incomplete and we do not want partial value - - # Simplify _F(...) values + + # Simplify _F(...) values for key, value in params.items(): - if value.strip().startswith('_F('): + if value.strip().startswith("_F("): params[key] = "_F(...)" - elif value.strip().startswith('(') and '_F(' in value: + elif value.strip().startswith("(") and "_F(" in value: params[key] = "(_F(...), ...)" - + return params - - def _reparse_command(self, lines: List[str], cmd_key: str): + def _reparse_command(self, lines: list[str], cmd_key: str): """Re-parse a specific command after modification""" cmd_info = self.commands[cmd_key] - + cmd_info.parsed_params = self._parse_params_level1( lines, cmd_info.start_line, cmd_info.zone_end ) - # TODO: update last character + # TODO: update last character - - def _find_command_at_line(self, line: int) -> Optional[str]: + def _find_command_at_line(self, line: int) -> str | None: """Binary search to find the command at a line""" left, right = 0, len(self.ranges) - 1 - + while left <= right: mid = (left + right) // 2 start, end, cmd_key = self.ranges[mid] - + if start <= line <= end: return cmd_key elif line < start: right = mid - 1 else: left = mid + 1 - + return None - + def _rebuild_ranges(self): """Rebuild the range index for binary search""" self.ranges = [] - + sorted_cmds = sorted(self.commands.values(), key=lambda c: c.start_line) - + current_line = 1 for cmd_info in sorted_cmds: # Add empty zone before this command if needed if current_line < cmd_info.start_line: self.ranges.append((current_line, cmd_info.start_line - 1, None)) - + # Add the command self.ranges.append((cmd_info.start_line, cmd_info.zone_end, cmd_info.get_key())) current_line = cmd_info.zone_end + 1 - + # Add final empty zone if needed - if self.ranges and self.ranges[-1][1] < float('inf'): + if self.ranges and self.ranges[-1][1] < float("inf"): # We cannot know the exact end, leave open pass - + # ============ Parsing utilities ============ def _is_comment_line(self, line: str) -> bool: stripped = line.lstrip() - return stripped.startswith('#') or stripped == '' - - def _find_command_start(self, line: str) -> Optional[Dict]: + return stripped.startswith("#") or stripped == "" + + def _find_command_start(self, line: str) -> dict | None: line_clean = self._remove_inline_comment(line) - pattern = re.compile( - r'^\s*(?:(\w+)\s*=\s*)?(?!_F\b)([A-Z_][A-Z0-9_]*)\s*\(' - ) + pattern = re.compile(r"^\s*(?:(\w+)\s*=\s*)?(?!_F\b)([A-Z_][A-Z0-9_]*)\s*\(") match = pattern.search(line_clean) if match: return { - 'variable': match.group(1), - 'command': match.group(2), - 'open_paren_pos': match.end() - 1 + "variable": match.group(1), + "command": match.group(2), + "open_paren_pos": match.end() - 1, } return None - + def _find_open_paren_pos(self, line: str) -> int: """Find the position of the opening parenthesis""" - return line.find('(') - + return line.find("(") + def _remove_inline_comment(self, line: str) -> str: in_string = False string_char = None - + for i, char in enumerate(line): if char in ('"', "'"): if not in_string: in_string = True string_char = char - elif char == string_char and (i == 0 or line[i-1] != '\\'): + elif char == string_char and (i == 0 or line[i - 1] != "\\"): in_string = False string_char = None - - if char == '#' and not in_string: + + if char == "#" and not in_string: return line[:i] - + return line - - - def _find_command_end(self, lines: List[str], start_idx: int, - start_char_pos: int) -> Dict: + def _find_command_end(self, lines: list[str], start_idx: int, start_char_pos: int) -> dict: """Find the end of a command (parser version)""" paren_count = 1 i = start_idx char_pos = start_char_pos + 1 - + while i < len(lines) and paren_count > 0: line = lines[i] line_clean = self._remove_inline_comment(line) - + # Check for new command if i > start_idx: new_cmd = self._find_command_start(line) if new_cmd is not None: - return {'end_line': i, 'complete': False} - + return {"end_line": i, "complete": False} + in_string = False string_char = None - + while char_pos < len(line_clean): char = line_clean[char_pos] - + if char in ('"', "'"): if not in_string: in_string = True string_char = char - elif char == string_char and (char_pos == 0 or line_clean[char_pos-1] != '\\'): + elif char == string_char and ( + char_pos == 0 or line_clean[char_pos - 1] != "\\" + ): in_string = False string_char = None - + if not in_string: - if char == '(': + if char == "(": paren_count += 1 - elif char == ')': + elif char == ")": paren_count -= 1 if paren_count == 0: - return {'end_line': i + 1, 'end_char': char_pos, 'complete': True} + return {"end_line": i + 1, "end_char": char_pos, "complete": True} char_pos += 1 - + i += 1 char_pos = 0 - - return {'end_line': len(lines), 'complete': False} + + return {"end_line": len(lines), "complete": False} diff --git a/python/lsp/handlers.py b/python/lsp/handlers.py index 646f32a..4da461c 100644 --- a/python/lsp/handlers.py +++ b/python/lsp/handlers.py @@ -1,39 +1,37 @@ # python/lsp/full_parsing.py from lsprotocol.types import ( - InitializeParams, - CompletionParams, CompletionList, - HoverParams, - Hover, + CompletionParams, DidChangeTextDocumentParams, + DidChangeWatchedFilesParams, DidOpenTextDocumentParams, + Hover, + HoverParams, + InitializeParams, SignatureHelp, SignatureHelpParams, - DidChangeWatchedFilesParams ) - from pygls.server import LanguageServer from lsp.managers_container import ManagerContainer + managers = ManagerContainer() + def register_handlers(server: LanguageServer): @server.feature("initialize") - def on_initialize(ls: LanguageServer, params: InitializeParams) : + def on_initialize(ls: LanguageServer, params: InitializeParams): return { "capabilities": { - "textDocumentSync": 1, - "completionProvider": { - "resolveProvider": False, - "triggerCharacters": [" ", "."] - }, + "textDocumentSync": 1, + "completionProvider": {"resolveProvider": False, "triggerCharacters": [" ", "."]}, "hoverProvider": True, - "definitionProvider": True + "definitionProvider": True, } } - + @server.feature("textDocument/didOpen") def on_document_open(ls: LanguageServer, params: DidOpenTextDocumentParams): """Initialisation du registre à l'ouverture du document""" @@ -64,14 +62,14 @@ def signature_help(ls: LanguageServer, params: SignatureHelpParams) -> Signature position = params.position return managers.signature.help(doc_uri, position) - + @server.feature("textDocument/hover") def hover(ls: LanguageServer, params: HoverParams) -> Hover: doc_uri = params.text_document.uri position = params.position return managers.hover.display(doc_uri, position) - + @server.feature("workspace/didChangeWatchedFiles") def ignore_watched_files(ls: LanguageServer, params: DidChangeWatchedFilesParams): """Handler vide pour ignorer les notifications de fichiers surveillés.""" @@ -79,14 +77,14 @@ def ignore_watched_files(ls: LanguageServer, params: DidChangeWatchedFilesParams @server.feature("codeaster/analyzeCommandFamilies") def analyze_command_families(ls, params): - if hasattr(params, 'get'): - doc_uri = params.get('uri', 'unknown') + if hasattr(params, "get"): + doc_uri = params.get("uri", "unknown") else: - doc_uri = getattr(params, 'uri', 'unknown') + doc_uri = getattr(params, "uri", "unknown") return managers.status_bar.analyze_command_families(doc_uri) - + @server.feature("codeaster/getCompleteFamilies") def getCompleteFamilies(ls, params): - - return managers.status_bar.get_complete_families() \ No newline at end of file + + return managers.status_bar.get_complete_families() diff --git a/python/lsp/managers/__init__.py b/python/lsp/managers/__init__.py index b795d20..e63a97b 100644 --- a/python/lsp/managers/__init__.py +++ b/python/lsp/managers/__init__.py @@ -1,14 +1,14 @@ # managers/__init__.py from .completion_manager import CompletionManager -from .signature_manager import SignatureManager from .hover_manager import HoverManager -from .update_manager import UpdateManager +from .signature_manager import SignatureManager from .status_bar_manager import StatusBarManager +from .update_manager import UpdateManager __all__ = [ "CompletionManager", "SignatureManager", "HoverManager", "UpdateManager", - "StatusBarManager" + "StatusBarManager", ] diff --git a/python/lsp/managers/completion_manager.py b/python/lsp/managers/completion_manager.py index 9fa19d2..053d691 100644 --- a/python/lsp/managers/completion_manager.py +++ b/python/lsp/managers/completion_manager.py @@ -1,9 +1,9 @@ +from command_core import CommandCore from lsprotocol.types import ( - CompletionList, CompletionItem, CompletionItemKind, + CompletionList, ) -from command_core import CommandCore class CompletionManager: @@ -37,18 +37,17 @@ def _suggest_commands(self) -> CompletionList: items = [] commands = self.core.get_CATA_commands() - for cmd in commands: + for cmd in commands: items.append( CompletionItem( label=cmd["name"], kind=CompletionItemKind.Function, - documentation=cmd.get("doc", "") + documentation=cmd.get("doc", ""), ) ) return CompletionList(is_incomplete=False, items=items) - def _suggest_parameters(self, cmd_info) -> CompletionList: """ Suggest parameters of a code_aster command depending on the context. @@ -65,7 +64,6 @@ def _suggest_parameters(self, cmd_info) -> CompletionList: items = [] written = set(cmd_info.parsed_params.keys()) for param in visible_params: - if param["name"] in written: continue @@ -77,7 +75,7 @@ def _suggest_parameters(self, cmd_info) -> CompletionList: CompletionItem( label=arg["name"], kind=CompletionItemKind.Property, - insert_text=arg["name"] + "=" + insert_text=arg["name"] + "=", ) ) # Normal parameter (can be a single param or a dico (_F)) @@ -89,13 +87,12 @@ def _suggest_parameters(self, cmd_info) -> CompletionList: CompletionItem( label=param["name"], kind=CompletionItemKind.Property, - insert_text=insert_text + insert_text=insert_text, ) ) return CompletionList(is_incomplete=False, items=items) - def _expand_condition_bloc(self, params, context): """ Expand conditional blocks depending on the current context. @@ -107,6 +104,6 @@ def _expand_condition_bloc(self, params, context): if arg["bloc"].isEnabled(context): for param in arg["children"]: visible_params.append(param) - else : + else: visible_params.append(arg) return visible_params diff --git a/python/lsp/managers/hover_manager.py b/python/lsp/managers/hover_manager.py index 8b43616..56f5c9c 100644 --- a/python/lsp/managers/hover_manager.py +++ b/python/lsp/managers/hover_manager.py @@ -2,10 +2,10 @@ HoverManager: provides hover information for code_aster commands Relies on CommandCore to get the document registry and CATA metadata """ + import re -from typing import Optional -from command_core import CommandCore +from command_core import CommandCore from lsprotocol.types import ( Hover, MarkupContent, @@ -13,7 +13,6 @@ ) - class HoverManager: """ Manager for providing hover info in a code_aster document. @@ -22,7 +21,7 @@ class HoverManager: def __init__(self): self.core = CommandCore() - def display(self, doc_uri, position) -> Optional[Hover]: + def display(self, doc_uri, position) -> Hover | None: """ Return a Hover object for the given document URI and position. """ @@ -33,16 +32,11 @@ def display(self, doc_uri, position) -> Optional[Hover]: if word: docstring = self.core.get_docstring(word) if docstring: - return Hover(contents=MarkupContent( - kind=MarkupKind.PlainText, - value=docstring - )) - + return Hover(contents=MarkupContent(kind=MarkupKind.PlainText, value=docstring)) + def extract_word_at_position(self, line: str, char_pos: int) -> str: - matches = list(re.finditer(r'\b\w+\b', line)) + matches = list(re.finditer(r"\b\w+\b", line)) for match in matches: if match.start() <= char_pos <= match.end(): return match.group() return "" - - diff --git a/python/lsp/managers/signature_manager.py b/python/lsp/managers/signature_manager.py index 47655f7..52001a6 100644 --- a/python/lsp/managers/signature_manager.py +++ b/python/lsp/managers/signature_manager.py @@ -1,8 +1,8 @@ import re -from lsprotocol.types import ( - SignatureHelp, SignatureInformation -) + from command_core import CommandCore +from lsprotocol.types import SignatureHelp, SignatureInformation + class SignatureManager: """ @@ -10,7 +10,7 @@ class SignatureManager: """ def __init__(self): - self.core = CommandCore() + self.core = CommandCore() def help(self, doc_uri, position): """ @@ -18,11 +18,13 @@ def help(self, doc_uri, position): """ doc = self.core.get_doc_from_uri(doc_uri) if position.line >= len(doc.lines) or position.line < 0: - self.core.log(f"[signature_help] Position line {position.line} out of range (doc has {len(doc.lines)} lines)") + self.core.log( + f"[signature_help] Position line {position.line} out of range (doc has {len(doc.lines)} lines)" + ) return SignatureHelp(signatures=[], active_signature=0, active_parameter=0) - - line_text = doc.lines[position.line][:position.character] - + + line_text = doc.lines[position.line][: position.character] + default_signature = SignatureHelp(signatures=[], active_signature=0, active_parameter=0) # Match a command before the opening parenthesis @@ -51,12 +53,13 @@ def help(self, doc_uri, position): cmd_name = cmd_info.name cmd_def = self.core.get_command_def(cmd_name) if cmd_def: - signature = SignatureInformation(label=self.params_label(cmd_def["params"], cmd_info.parsed_params)) + signature = SignatureInformation( + label=self.params_label(cmd_def["params"], cmd_info.parsed_params) + ) self.core.log(f"Comma inside command: {cmd_name}") return SignatureHelp(signatures=[signature], active_signature=0, active_parameter=0) return default_signature - def params_label(self, command_params, current_context): """ Recursively generate a string label for the parameters of a command, @@ -72,7 +75,9 @@ def params_label(self, command_params, current_context): if param["bloc"].isEnabled(current_context): label.append(f"{self.params_label(param['children'], current_context)}") else: - label.append(f"{param['name']}: ({self.params_label(param['children'], current_context)})") + label.append( + f"{param['name']}: ({self.params_label(param['children'], current_context)})" + ) else: label.append(f"{param['name']}: {param['type']}") return ", ".join(label) diff --git a/python/lsp/managers/status_bar_manager.py b/python/lsp/managers/status_bar_manager.py index 62f1f63..f0d9014 100644 --- a/python/lsp/managers/status_bar_manager.py +++ b/python/lsp/managers/status_bar_manager.py @@ -1,9 +1,10 @@ # status_bar.py -from pathlib import Path import re -from typing import Dict, List +from pathlib import Path + from command_core import CommandCore + class StatusBarManager: """ Class that encapsulates the logic for: @@ -12,11 +13,11 @@ class StatusBarManager: """ FAMILY_MAP = { - 'Mesh': 'mesh', - 'Material': 'material', - 'BC and Load': 'bcAndLoads', - 'Analysis': 'analysis', - 'Output': 'output' + "Mesh": "mesh", + "Material": "material", + "BC and Load": "bcAndLoads", + "Analysis": "analysis", + "Output": "output", } def __init__(self): @@ -29,7 +30,7 @@ def __init__(self): self.cata = CommandCore().get_CATA() self.family_map = self.FAMILY_MAP - def analyze_command_families(self, uri: str) -> Dict[str, List[str]]: + def analyze_command_families(self, uri: str) -> dict[str, list[str]]: """ Parse a .comm file and return the commands found in each family. @@ -47,12 +48,12 @@ def analyze_command_families(self, uri: str) -> Dict[str, List[str]]: if not path.exists(): return {} - with open(path, "r", encoding="utf-8") as f: + with open(path, encoding="utf-8") as f: lines = f.readlines() content = "\n".join(lines) return self._parse_comm_file(content) - def get_complete_families(self) -> Dict[str, List[str]]: + def get_complete_families(self) -> dict[str, list[str]]: """ Return the complete list of known commands for each family. @@ -72,7 +73,7 @@ def get_complete_families(self) -> Dict[str, List[str]]: return families_result - def _parse_comm_file(self, content: str) -> Dict[str, List[str]]: + def _parse_comm_file(self, content: str) -> dict[str, list[str]]: """ Parse the content of a .comm file and extract commands by family. @@ -82,22 +83,24 @@ def _parse_comm_file(self, content: str) -> Dict[str, List[str]]: Returns: Dict[str, List[str]]: Commands grouped by family """ - lines = content.split('\n') - code_without_comments = [re.sub(r'#.*$', '', l).strip() for l in lines if l.strip()] - full_text = ' '.join(code_without_comments) + lines = content.split("\n") + code_without_comments = [ + re.sub(r"#.*$", "", line).strip() for line in lines if line.strip() + ] + full_text = " ".join(code_without_comments) - command_pattern = r'(?:^|\s)(?:[\w]+\s*=\s*)?(?!_F\b)([A-Z][A-Z0-9_]*)\s*\(' + command_pattern = r"(?:^|\s)(?:[\w]+\s*=\s*)?(?!_F\b)([A-Z][A-Z0-9_]*)\s*\(" matches = re.finditer(command_pattern, full_text, re.VERBOSE) found_commands = set() for m in matches: cmd_name = m.group(1) - if cmd_name not in ['DEBUT', 'FIN', 'POURSUITE']: + if cmd_name not in ["DEBUT", "FIN", "POURSUITE"]: found_commands.add(cmd_name) - if re.search(r'\bDEBUT\s*\(', full_text): - found_commands.add('DEBUT') - if re.search(r'\bFIN\s*\(', full_text): - found_commands.add('FIN') + if re.search(r"\bDEBUT\s*\(", full_text): + found_commands.add("DEBUT") + if re.search(r"\bFIN\s*\(", full_text): + found_commands.add("FIN") families_result = {v: [] for v in self.family_map.values()} for cmd_name in found_commands: diff --git a/python/lsp/managers/update_manager.py b/python/lsp/managers/update_manager.py index 7b5c6a8..68ba199 100644 --- a/python/lsp/managers/update_manager.py +++ b/python/lsp/managers/update_manager.py @@ -1,6 +1,7 @@ from command_core import CommandCore from command_registry import CommandRegistry + class UpdateManager: """ Manager for handling document open and change events for .comm files. @@ -36,13 +37,13 @@ def update_registry(self, doc, doc_uri, changes): self.core.set_registry(doc_uri, registry) for change in changes: - if hasattr(change, 'range') and change.range: + if hasattr(change, "range") and change.range: start_line = change.range.start.line + 1 end_line = change.range.end.line + 1 text = change.text # Handle multi-line deletions or additions - if end_line - start_line > 0 or text.count('\n') > 0 or text == '(': + if end_line - start_line > 0 or text.count("\n") > 0 or text == "(": self.core.log("on reload entierement") registry.initialize(ls, doc.lines) continue diff --git a/python/lsp/managers_container.py b/python/lsp/managers_container.py index 25e98f9..5584df7 100644 --- a/python/lsp/managers_container.py +++ b/python/lsp/managers_container.py @@ -1,13 +1,21 @@ -from managers import StatusBarManager, HoverManager, UpdateManager, SignatureManager, CompletionManager +from managers import ( + CompletionManager, + HoverManager, + SignatureManager, + StatusBarManager, + UpdateManager, +) + class ManagerContainer: """ Central container for all feature classes. Initialize all managers """ + def __init__(self): self.status_bar = StatusBarManager() self.hover = HoverManager() self.update = UpdateManager() self.signature = SignatureManager() - self.completion = CompletionManager() \ No newline at end of file + self.completion = CompletionManager() diff --git a/python/lsp/server.py b/python/lsp/server.py index fa8e9e1..925359f 100644 --- a/python/lsp/server.py +++ b/python/lsp/server.py @@ -1,26 +1,27 @@ -import pathlib as pl +# ruff: noqa: I001 — import order is intentional: lsp.handlers must precede command_core to trigger sys.path setup in lsp/__init__.py +import pathlib as pl import sys -### bundled libraries -bundled_path = pl.Path(__file__).parent.parent.absolute() / "bundled" / "libs" +### bundled libraries +bundled_path = pl.Path(__file__).parent.parent.absolute() / "bundled" / "libs" ## preprend the path to include bundled libraries #### Becareful, we prepend the path to ensure that bundled libraries are found first in place of system libraries sys.path.insert(0, str(bundled_path)) +from pygls.server import LanguageServer # noqa: E402 +from lsp.handlers import register_handlers # noqa: E402 - -from pygls.server import LanguageServer -from lsp.handlers import register_handlers - -from command_core import CommandCore +from command_core import CommandCore # noqa: E402 ls = LanguageServer(name="aster-lsp", version="0.1.0") + def main(): CommandCore().store_ls(ls) register_handlers(ls) ls.start_io() + if __name__ == "__main__": main() diff --git a/python/med2obj.py b/python/med2obj.py index 37e57f9..264d459 100644 --- a/python/med2obj.py +++ b/python/med2obj.py @@ -5,20 +5,17 @@ import argparse -import medcoupling as mc import pathlib as pl +import medcoupling as mc + def parse_args(): parser = argparse.ArgumentParser( description="Convert a .med mesh file to a .obj file with groups." ) - parser.add_argument( - "-i", "--input", type=str, required=True, help="Input .med file path." - ) - parser.add_argument( - "-o", "--output", type=str, required=True, help="Output .obj file path." - ) + parser.add_argument("-i", "--input", type=str, required=True, help="Input .med file path.") + parser.add_argument("-o", "--output", type=str, required=True, help="Output .obj file path.") return parser.parse_args() @@ -54,7 +51,7 @@ def write_obj( for elem in skin_mesh: conn = elem.getAllConn() # OBJ is 1-indexed end_connectivity = END_CONNECTIVITY[len(conn) - 1] + 1 - f.write(f'f {" ".join([str(x+1) for x in conn[1:end_connectivity]])}\n') + f.write(f"f {' '.join([str(x + 1) for x in conn[1:end_connectivity]])}\n") for group_name in skin_groups: submesh = med_file.getGroup(skin_level, group_name) @@ -62,7 +59,7 @@ def write_obj( for elem in submesh: conn = elem.getAllConn() end_connectivity = END_CONNECTIVITY[len(conn) - 1] + 1 - f.write(f'f {" ".join([str(x+1) for x in conn[1:end_connectivity]])}\n') + f.write(f"f {' '.join([str(x + 1) for x in conn[1:end_connectivity]])}\n") for group_name in node_groups: node_ids = med_file.getGroupArr(node_level, group_name).toNumPyArray() diff --git a/resources/visu_vtk/src/components/LoadingScreen.svelte b/resources/visu_vtk/src/components/LoadingScreen.svelte index 7193a44..2044fc3 100644 --- a/resources/visu_vtk/src/components/LoadingScreen.svelte +++ b/resources/visu_vtk/src/components/LoadingScreen.svelte @@ -1,3 +1,5 @@ + +
{ e.preventDefault(); closeContextMenu(); }} + oncontextmenu={(e) => { + e.preventDefault(); + closeContextMenu(); + }} role="presentation" >
@@ -64,29 +53,47 @@ style={activeTab === 'About' ? 'background: var(--ui-element-bg); color: var(--vscode-textLink-foreground, #0078d4); font-weight: 600;' : 'color: var(--ui-text-secondary);'} - onmouseenter={(e) => { if (activeTab !== 'About') (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg)'; }} - onmouseleave={(e) => { if (activeTab !== 'About') (e.currentTarget as HTMLElement).style.background = ''; }} - onclick={() => activeTab = 'About'} + onmouseenter={(e) => { + if (activeTab !== 'About') + (e.currentTarget as HTMLElement).style.background = 'var(--ui-element-bg)'; + }} + onmouseleave={(e) => { + if (activeTab !== 'About') (e.currentTarget as HTMLElement).style.background = ''; + }} + onclick={() => (activeTab = 'About')} > About - v{__APP_VERSION__} + v{__APP_VERSION__}
- {#if activeTab === 'Camera'}
Drag to rotate - Ctrl+Drag to rotate around a single axis - Shift+Drag to pan + Ctrl+Drag to rotate around a single axis + Shift+Drag to pan Zoom in / out - - + + 2.0× @@ -95,12 +102,20 @@ Open the zoom level selector to choose a preset - - + + 2.0× - + @@ -112,73 +127,134 @@ Align camera along that axis — buttons at the bottom of the sidebar
- {:else if activeTab === 'Objects'}
- + - mesh - + mesh + Click the name to collapse or expand its groups - + mesh - + Click to show or hide an entire object - + mesh - + Right-click for more options — e.g. hide all other objects
- {:else if activeTab === 'Groups'}
- + group_A - Click a group to highlight it — the object becomes transparent so the group stands out. Click again to unhighlight. + Click a group to highlight it — the object becomes transparent so the group + stands out. Click again to unhighlight. - - + + - + - Click to choose which groups appear in the sidebar — hidden groups remain visible in the 3D view + Click to choose which groups appear in the sidebar — hidden groups remain + visible in the 3D view - - + + - + Click to clear all highlights
- {:else if activeTab === 'Files'}
-

.med mesh files are automatically converted to .obj when opened.

-

Converted files are cached in a hidden .visu_data/ folder in your workspace and reused on subsequent opens.

+

+ .med mesh files are automatically converted to .obj when opened. +

+

+ Converted files are cached in a hidden .visu_data/ folder in your workspace and + reused on subsequent opens. +

- {:else if activeTab === 'About'}
-

This extension is made by Simvia.

-

Source code and issue tracker are available on GitHub.

+

+ This extension is made by Simvia. +

+

+ Source code and issue tracker are available on GitHub. +

{/if} -
@@ -192,3 +268,19 @@
+ + diff --git a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte index d27bdfc..57decad 100644 --- a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte +++ b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte @@ -1,52 +1,45 @@ {#snippet tip(text: string)} - + + {text} + {/snippet} @@ -219,29 +206,27 @@ style="width: min(36rem, 80vw); height: min(22rem, 70vh); color: var(--ui-fg); border: 1px solid var(--ui-border)" role="document" > -
+
- + {edgeThresholdDisplay.toPrecision(edgeThresholdDisplay < 1 ? 2 : 3)}×
@@ -293,7 +279,7 @@ class="w-full cursor-pointer focus:outline-none accent-(--vscode-textLink-foreground,#0078d4)" oninput={onEdgeThresholdInput} /> - Higher values show edges from farther away.
@@ -311,7 +297,7 @@ 'At 0% hidden objects are fully invisible. Above 0% they remain as faint ghosts.' )}
- {hiddenOpacityPct}%
@@ -325,7 +311,7 @@ class="w-full cursor-pointer focus:outline-none [accent-color:var(--vscode-textLink-foreground,#0078d4)]" oninput={onHiddenOpacityInput} /> - When hiding an object with the eye button, it can remain slightly visible as a ghost.
@@ -339,7 +325,7 @@ 'When a sub-group is highlighted, the parent mesh fades to this opacity so the selected group stands out.' )}
- {groupTransparencyPct}%
@@ -353,7 +339,7 @@ class="w-full cursor-pointer focus:outline-none [accent-color:var(--vscode-textLink-foreground,#0078d4)]" oninput={onGroupTransparencyInput} /> - Opacity of the parent mesh when a sub-group is highlighted.
@@ -365,10 +351,9 @@ role="switch" aria-label="Show orientation widget" aria-checked={$settings.showOrientationWidget} - class="relative inline-flex h-5 w-9 shrink-0 rounded-full transition-colors duration-150 focus:outline-none cursor-pointer" - style={$settings.showOrientationWidget - ? 'background: var(--vscode-textLink-foreground, #0078d4)' - : 'background: var(--ui-border)'} + class="relative inline-flex h-5 w-9 shrink-0 rounded-full transition-colors duration-150 focus:outline-none cursor-pointer {$settings.showOrientationWidget + ? 'bg-ui-link' + : 'bg-ui-border'}" onclick={toggleOrientationWidget} > - Show the axes widget in the bottom-right corner.
@@ -396,15 +381,13 @@
@@ -70,9 +73,7 @@ - + 2.0× @@ -84,14 +85,10 @@ - + 2.0× - + @@ -121,7 +118,8 @@ > mesh - @@ -197,8 +195,7 @@ href="https://simvia.tech" target="_blank" rel="noopener noreferrer" - class="text-ui-link underline" - >SimviaSimvia.

@@ -206,8 +203,7 @@ href="https://github.com/simvia-tech/vs-code-aster" target="_blank" rel="noopener noreferrer" - class="text-ui-link underline" - >GitHubGitHub.

diff --git a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte index 325300b..acd0288 100644 --- a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte +++ b/resources/visu_vtk/src/components/popups/SettingsPopup.svelte @@ -204,16 +204,13 @@ class="absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 w-[min(36rem,80vw)] h-[min(22rem,70vh)] rounded shadow-lg flex text-ui-fg border border-ui-border" role="document" > -
-
- {hiddenOpacityPct}% + {hiddenOpacityPct}%
- {groupTransparencyPct}% + {groupTransparencyPct}%
- + diff --git a/resources/visu_vtk/src/icons/MouseScrollIcon.svelte b/resources/visu_vtk/src/icons/MouseScrollIcon.svelte index 8839c22..b8f0827 100644 --- a/resources/visu_vtk/src/icons/MouseScrollIcon.svelte +++ b/resources/visu_vtk/src/icons/MouseScrollIcon.svelte @@ -15,13 +15,5 @@ - + From 0fd888f8eaefa811c44d2102c5174120d8ea84e5 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 13:09:34 +0100 Subject: [PATCH 16/20] Reorganise folders --- .github/workflows/ci.yml | 6 +++--- .gitignore | 10 ++-------- .husky/pre-commit | 6 +++--- .vscodeignore | 17 ++++++++--------- README.md | 4 ++-- eslint.config.mjs | 2 +- {resources => media}/icons/3d.svg | 0 {resources => media}/icons/3d_light.svg | 0 {resources => media}/images/aster.png | Bin .../images/icone-code-aster.png | Bin {resources => media}/images/simvia.png | Bin package.json | 4 ++-- src/ExportEditor.ts | 2 +- src/VisuManager.ts | 2 +- .../export_form => webviews/export}/export.css | 0 .../export}/export.html | 4 ++-- .../export_form => webviews/export}/export.js | 0 .../visu_vtk => webviews/viewer}/index.html | 0 .../visu_vtk => webviews/viewer}/js/vtk.js | 0 .../visu_vtk => webviews/viewer}/src/app.css | 0 .../src/components/ActionButtons.svelte | 0 .../viewer}/src/components/App.svelte | 0 .../viewer}/src/components/AxisButtons.svelte | 0 .../viewer}/src/components/GroupButton.svelte | 0 .../src/components/LoadingScreen.svelte | 0 .../src/components/ObjectSection.svelte | 0 .../viewer}/src/components/Sidebar.svelte | 0 .../viewer}/src/components/TopActions.svelte | 0 .../viewer}/src/components/ZoomWidget.svelte | 0 .../src/components/popups/GroupsPopup.svelte | 0 .../src/components/popups/HelpPopup.svelte | 0 .../viewer}/src/components/popups/Popup.svelte | 0 .../src/components/popups/SettingsPopup.svelte | 0 .../viewer}/src/icons/ChevronIcon.svelte | 0 .../viewer}/src/icons/ClearIcon.svelte | 0 .../viewer}/src/icons/EyeIcon.svelte | 0 .../viewer}/src/icons/EyeOffIcon.svelte | 0 .../viewer}/src/icons/FaceIcon.svelte | 0 .../viewer}/src/icons/FilterIcon.svelte | 0 .../viewer}/src/icons/MouseLeftIcon.svelte | 0 .../viewer}/src/icons/MouseRightIcon.svelte | 0 .../viewer}/src/icons/MouseScrollIcon.svelte | 0 .../viewer}/src/icons/NodeIcon.svelte | 0 .../viewer}/src/icons/ObjectIcon.svelte | 0 .../viewer}/src/icons/QuestionIcon.svelte | 0 .../viewer}/src/icons/ResetIcon.svelte | 0 .../viewer}/src/icons/SettingsIcon.svelte | 0 .../viewer}/src/icons/ZoomIcon.svelte | 0 .../viewer}/src/lib/Controller.ts | 0 .../src/lib/commands/VisibilityManager.ts | 0 .../viewer}/src/lib/core/VtkApp.ts | 0 .../viewer}/src/lib/data/CreateGroups.ts | 0 .../viewer}/src/lib/data/Group.ts | 0 .../viewer}/src/lib/data/ObjLoader.ts | 0 .../src/lib/data/create/FaceActorCreator.ts | 0 .../src/lib/data/create/NodeActorCreator.ts | 0 .../viewer}/src/lib/interaction/AxesCreator.ts | 0 .../src/lib/interaction/CameraManager.ts | 0 .../viewer}/src/lib/settings/GlobalSettings.ts | 0 .../viewer}/src/lib/state.ts | 0 .../viewer}/src/lib/ui/CustomDropdown.ts | 0 .../viewer}/src/lib/vtk.d.ts | 0 .../visu_vtk => webviews/viewer}/src/main.ts | 0 .../viewer}/svelte.config.js | 0 .../visu_vtk => webviews/viewer}/tsconfig.json | 0 .../viewer}/vite.config.ts | 0 66 files changed, 25 insertions(+), 32 deletions(-) rename {resources => media}/icons/3d.svg (100%) rename {resources => media}/icons/3d_light.svg (100%) rename {resources => media}/images/aster.png (100%) rename {resources => media}/images/icone-code-aster.png (100%) rename {resources => media}/images/simvia.png (100%) rename {resources/export_form => webviews/export}/export.css (100%) rename {resources/export_form => webviews/export}/export.html (94%) rename {resources/export_form => webviews/export}/export.js (100%) rename {resources/visu_vtk => webviews/viewer}/index.html (100%) rename {resources/visu_vtk => webviews/viewer}/js/vtk.js (100%) rename {resources/visu_vtk => webviews/viewer}/src/app.css (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/ActionButtons.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/App.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/AxisButtons.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/GroupButton.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/LoadingScreen.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/ObjectSection.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/Sidebar.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/TopActions.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/ZoomWidget.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/popups/GroupsPopup.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/popups/HelpPopup.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/popups/Popup.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/components/popups/SettingsPopup.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/ChevronIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/ClearIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/EyeIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/EyeOffIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/FaceIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/FilterIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/MouseLeftIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/MouseRightIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/MouseScrollIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/NodeIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/ObjectIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/QuestionIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/ResetIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/SettingsIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/icons/ZoomIcon.svelte (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/Controller.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/commands/VisibilityManager.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/core/VtkApp.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/data/CreateGroups.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/data/Group.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/data/ObjLoader.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/data/create/FaceActorCreator.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/data/create/NodeActorCreator.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/interaction/AxesCreator.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/interaction/CameraManager.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/settings/GlobalSettings.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/state.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/ui/CustomDropdown.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/lib/vtk.d.ts (100%) rename {resources/visu_vtk => webviews/viewer}/src/main.ts (100%) rename {resources/visu_vtk => webviews/viewer}/svelte.config.js (100%) rename {resources/visu_vtk => webviews/viewer}/tsconfig.json (100%) rename {resources/visu_vtk => webviews/viewer}/vite.config.ts (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b0382a..ca6b176 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,16 +28,16 @@ jobs: run: pip install ruff mypy - name: Prettier - run: npx prettier --check "src/**/*.ts" "resources/visu_vtk/src/**/*.{ts,svelte}" "resources/export_form/**/*.{js,css,html}" + run: npx prettier --check "src/**/*.ts" "webviews/viewer/src/**/*.{ts,svelte}" "webviews/export/**/*.{js,css,html}" - name: ESLint - run: npx eslint --max-warnings=0 src/ resources/export_form/ + run: npx eslint --max-warnings=0 src/ webviews/export/ - name: TypeScript run: npx tsc --noEmit - name: svelte-check - run: npx svelte-check --tsconfig resources/visu_vtk/tsconfig.json --fail-on-warnings + run: npx svelte-check --tsconfig webviews/viewer/tsconfig.json --fail-on-warnings - name: Ruff lint run: python3 -m ruff check python/lsp/ python/med2obj.py diff --git a/.gitignore b/.gitignore index 179fc4b..a9d2865 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ node_modules/ # Webview build output -resources/visu_vtk/dist/ +webviews/viewer/dist/ # Build output dist/ @@ -50,6 +50,7 @@ yarn.lock vsc-extension-quickstart.md **/__pycache__/ + # Fichiers temporaires ou backup *.tmp *.swp @@ -62,14 +63,7 @@ vsc-extension-quickstart.md *.js.map -node_modules/ -dist/ - -yarn.lock *.vsix - -# Exclude extension package -vs-code-aster-*.vsix .vscode-test out/ diff --git a/.husky/pre-commit b/.husky/pre-commit index dac63af..0cd5fd7 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,9 +1,9 @@ #!/bin/sh set -e -npx prettier --write "src/**/*.ts" "resources/visu_vtk/src/**/*.{ts,svelte}" "resources/export_form/**/*.{js,css,html}" +npx prettier --write "src/**/*.ts" "webviews/viewer/src/**/*.{ts,svelte}" "webviews/export/**/*.{js,css,html}" git add -u -npx eslint --max-warnings=0 src/ resources/export_form/ -npx svelte-check --tsconfig resources/visu_vtk/tsconfig.json --fail-on-warnings +npx eslint --max-warnings=0 src/ webviews/export/ +npx svelte-check --tsconfig webviews/viewer/tsconfig.json --fail-on-warnings python3 -m ruff check python/lsp/ python/med2obj.py python3 -m ruff format --check python/lsp/ python/med2obj.py diff --git a/.vscodeignore b/.vscodeignore index e4f1b40..c0171a1 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -16,15 +16,14 @@ vsc-extension-quickstart.md **/.vscode-test.* .venv noxfile.py -requirements.txt +requirements.txt python/data python/lsp/.venv python/.venv -resources/visu_vtk/src/** -resources/visu_vtk/vite.config.ts -resources/visu_vtk/svelte.config.js -resources/visu_vtk/tsconfig.json -resources/visu_vtk/js/** -resources/visu_vtk/tailwind.css -resources/visu_vtk/styles.css -resources/visu_vtk/index.js \ No newline at end of file +webviews/viewer/src/** +webviews/viewer/vite.config.ts +webviews/viewer/svelte.config.js +webviews/viewer/tsconfig.json +webviews/viewer/tailwind.css +webviews/viewer/styles.css +webviews/viewer/index.js diff --git a/README.md b/README.md index bde4760..1a5bf1d 100644 --- a/README.md +++ b/README.md @@ -258,7 +258,7 @@ npm install The extension consists of two independently compiled parts : - **Extension host** (`src/`) — TypeScript compiled with esbuild, runs in Node.js inside VS Code -- **Webview** (`resources/visu_vtk/`) — Svelte 5 + Vite app that powers the 3D visualizer; built separately into `resources/visu_vtk/dist/` +- **Webview** (`webviews/viewer/`) — Svelte 5 + Vite app that powers the 3D visualizer; built separately into `webviews/viewer/dist/` ### 4. Running the extension locally @@ -274,7 +274,7 @@ This starts three background watch tasks automatically (defined in `.vscode/task After making changes to the **extension host** (`src/`), reload the debug window with `Ctrl + R`. -After making changes to the **webview** (`resources/visu_vtk/src/`), wait for the `watch:webview` task to finish rebuilding, then run `Developer: Reload Webviews` from the Command Palette. +After making changes to the **webview** (`webviews/viewer/src/`), wait for the `watch:webview` task to finish rebuilding, then run `Developer: Reload Webviews` from the Command Palette. ### 5. Building manually diff --git a/eslint.config.mjs b/eslint.config.mjs index e029242..a1cb232 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,7 +2,7 @@ import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; export default [{ - files: ["**/*.ts", "resources/export_form/**/*.js"], + files: ["**/*.ts", "webviews/export/**/*.js"], }, { plugins: { "@typescript-eslint": typescriptEslint, diff --git a/resources/icons/3d.svg b/media/icons/3d.svg similarity index 100% rename from resources/icons/3d.svg rename to media/icons/3d.svg diff --git a/resources/icons/3d_light.svg b/media/icons/3d_light.svg similarity index 100% rename from resources/icons/3d_light.svg rename to media/icons/3d_light.svg diff --git a/resources/images/aster.png b/media/images/aster.png similarity index 100% rename from resources/images/aster.png rename to media/images/aster.png diff --git a/resources/images/icone-code-aster.png b/media/images/icone-code-aster.png similarity index 100% rename from resources/images/icone-code-aster.png rename to media/images/icone-code-aster.png diff --git a/resources/images/simvia.png b/media/images/simvia.png similarity index 100% rename from resources/images/simvia.png rename to media/images/simvia.png diff --git a/package.json b/package.json index be75b2c..7403aa7 100644 --- a/package.json +++ b/package.json @@ -203,8 +203,8 @@ "watch": "npm-run-all -p watch:*", "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", - "watch:webview": "vite build --config resources/visu_vtk/vite.config.ts --watch", - "build:webview": "vite build --config resources/visu_vtk/vite.config.ts", + "watch:webview": "vite build --config webviews/viewer/vite.config.ts --watch", + "build:webview": "vite build --config webviews/viewer/vite.config.ts", "package": "npm run check-types && npm run lint && node esbuild.js --production", "check-types": "tsc --noEmit", "lint": "eslint src", diff --git a/src/ExportEditor.ts b/src/ExportEditor.ts index fe1c8fe..e7f8bc7 100644 --- a/src/ExportEditor.ts +++ b/src/ExportEditor.ts @@ -68,7 +68,7 @@ export class ExportEditor implements vscode.Disposable { const d = new ExportEditor( 'export-editor-webview', testDir, - 'resources/export_form/export.html', + 'webviews/export/export.html', exportDescriptor, destinationFolder, undefined diff --git a/src/VisuManager.ts b/src/VisuManager.ts index efe0e65..f0dd0aa 100644 --- a/src/VisuManager.ts +++ b/src/VisuManager.ts @@ -121,7 +121,7 @@ export class VisuManager { const visu = new WebviewVisu( 'meshViewer', testDir, - 'resources/visu_vtk/dist/index.html', + 'webviews/viewer/dist/index.html', fileContexts, objUris.map((uri) => path.basename(uri.fsPath)), undefined, diff --git a/resources/export_form/export.css b/webviews/export/export.css similarity index 100% rename from resources/export_form/export.css rename to webviews/export/export.css diff --git a/resources/export_form/export.html b/webviews/export/export.html similarity index 94% rename from resources/export_form/export.html rename to webviews/export/export.html index edc8b7e..a245c34 100644 --- a/resources/export_form/export.html +++ b/webviews/export/export.html @@ -14,7 +14,7 @@ /> - + @@ -87,6 +87,6 @@

- + diff --git a/resources/export_form/export.js b/webviews/export/export.js similarity index 100% rename from resources/export_form/export.js rename to webviews/export/export.js diff --git a/resources/visu_vtk/index.html b/webviews/viewer/index.html similarity index 100% rename from resources/visu_vtk/index.html rename to webviews/viewer/index.html diff --git a/resources/visu_vtk/js/vtk.js b/webviews/viewer/js/vtk.js similarity index 100% rename from resources/visu_vtk/js/vtk.js rename to webviews/viewer/js/vtk.js diff --git a/resources/visu_vtk/src/app.css b/webviews/viewer/src/app.css similarity index 100% rename from resources/visu_vtk/src/app.css rename to webviews/viewer/src/app.css diff --git a/resources/visu_vtk/src/components/ActionButtons.svelte b/webviews/viewer/src/components/ActionButtons.svelte similarity index 100% rename from resources/visu_vtk/src/components/ActionButtons.svelte rename to webviews/viewer/src/components/ActionButtons.svelte diff --git a/resources/visu_vtk/src/components/App.svelte b/webviews/viewer/src/components/App.svelte similarity index 100% rename from resources/visu_vtk/src/components/App.svelte rename to webviews/viewer/src/components/App.svelte diff --git a/resources/visu_vtk/src/components/AxisButtons.svelte b/webviews/viewer/src/components/AxisButtons.svelte similarity index 100% rename from resources/visu_vtk/src/components/AxisButtons.svelte rename to webviews/viewer/src/components/AxisButtons.svelte diff --git a/resources/visu_vtk/src/components/GroupButton.svelte b/webviews/viewer/src/components/GroupButton.svelte similarity index 100% rename from resources/visu_vtk/src/components/GroupButton.svelte rename to webviews/viewer/src/components/GroupButton.svelte diff --git a/resources/visu_vtk/src/components/LoadingScreen.svelte b/webviews/viewer/src/components/LoadingScreen.svelte similarity index 100% rename from resources/visu_vtk/src/components/LoadingScreen.svelte rename to webviews/viewer/src/components/LoadingScreen.svelte diff --git a/resources/visu_vtk/src/components/ObjectSection.svelte b/webviews/viewer/src/components/ObjectSection.svelte similarity index 100% rename from resources/visu_vtk/src/components/ObjectSection.svelte rename to webviews/viewer/src/components/ObjectSection.svelte diff --git a/resources/visu_vtk/src/components/Sidebar.svelte b/webviews/viewer/src/components/Sidebar.svelte similarity index 100% rename from resources/visu_vtk/src/components/Sidebar.svelte rename to webviews/viewer/src/components/Sidebar.svelte diff --git a/resources/visu_vtk/src/components/TopActions.svelte b/webviews/viewer/src/components/TopActions.svelte similarity index 100% rename from resources/visu_vtk/src/components/TopActions.svelte rename to webviews/viewer/src/components/TopActions.svelte diff --git a/resources/visu_vtk/src/components/ZoomWidget.svelte b/webviews/viewer/src/components/ZoomWidget.svelte similarity index 100% rename from resources/visu_vtk/src/components/ZoomWidget.svelte rename to webviews/viewer/src/components/ZoomWidget.svelte diff --git a/resources/visu_vtk/src/components/popups/GroupsPopup.svelte b/webviews/viewer/src/components/popups/GroupsPopup.svelte similarity index 100% rename from resources/visu_vtk/src/components/popups/GroupsPopup.svelte rename to webviews/viewer/src/components/popups/GroupsPopup.svelte diff --git a/resources/visu_vtk/src/components/popups/HelpPopup.svelte b/webviews/viewer/src/components/popups/HelpPopup.svelte similarity index 100% rename from resources/visu_vtk/src/components/popups/HelpPopup.svelte rename to webviews/viewer/src/components/popups/HelpPopup.svelte diff --git a/resources/visu_vtk/src/components/popups/Popup.svelte b/webviews/viewer/src/components/popups/Popup.svelte similarity index 100% rename from resources/visu_vtk/src/components/popups/Popup.svelte rename to webviews/viewer/src/components/popups/Popup.svelte diff --git a/resources/visu_vtk/src/components/popups/SettingsPopup.svelte b/webviews/viewer/src/components/popups/SettingsPopup.svelte similarity index 100% rename from resources/visu_vtk/src/components/popups/SettingsPopup.svelte rename to webviews/viewer/src/components/popups/SettingsPopup.svelte diff --git a/resources/visu_vtk/src/icons/ChevronIcon.svelte b/webviews/viewer/src/icons/ChevronIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/ChevronIcon.svelte rename to webviews/viewer/src/icons/ChevronIcon.svelte diff --git a/resources/visu_vtk/src/icons/ClearIcon.svelte b/webviews/viewer/src/icons/ClearIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/ClearIcon.svelte rename to webviews/viewer/src/icons/ClearIcon.svelte diff --git a/resources/visu_vtk/src/icons/EyeIcon.svelte b/webviews/viewer/src/icons/EyeIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/EyeIcon.svelte rename to webviews/viewer/src/icons/EyeIcon.svelte diff --git a/resources/visu_vtk/src/icons/EyeOffIcon.svelte b/webviews/viewer/src/icons/EyeOffIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/EyeOffIcon.svelte rename to webviews/viewer/src/icons/EyeOffIcon.svelte diff --git a/resources/visu_vtk/src/icons/FaceIcon.svelte b/webviews/viewer/src/icons/FaceIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/FaceIcon.svelte rename to webviews/viewer/src/icons/FaceIcon.svelte diff --git a/resources/visu_vtk/src/icons/FilterIcon.svelte b/webviews/viewer/src/icons/FilterIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/FilterIcon.svelte rename to webviews/viewer/src/icons/FilterIcon.svelte diff --git a/resources/visu_vtk/src/icons/MouseLeftIcon.svelte b/webviews/viewer/src/icons/MouseLeftIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/MouseLeftIcon.svelte rename to webviews/viewer/src/icons/MouseLeftIcon.svelte diff --git a/resources/visu_vtk/src/icons/MouseRightIcon.svelte b/webviews/viewer/src/icons/MouseRightIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/MouseRightIcon.svelte rename to webviews/viewer/src/icons/MouseRightIcon.svelte diff --git a/resources/visu_vtk/src/icons/MouseScrollIcon.svelte b/webviews/viewer/src/icons/MouseScrollIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/MouseScrollIcon.svelte rename to webviews/viewer/src/icons/MouseScrollIcon.svelte diff --git a/resources/visu_vtk/src/icons/NodeIcon.svelte b/webviews/viewer/src/icons/NodeIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/NodeIcon.svelte rename to webviews/viewer/src/icons/NodeIcon.svelte diff --git a/resources/visu_vtk/src/icons/ObjectIcon.svelte b/webviews/viewer/src/icons/ObjectIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/ObjectIcon.svelte rename to webviews/viewer/src/icons/ObjectIcon.svelte diff --git a/resources/visu_vtk/src/icons/QuestionIcon.svelte b/webviews/viewer/src/icons/QuestionIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/QuestionIcon.svelte rename to webviews/viewer/src/icons/QuestionIcon.svelte diff --git a/resources/visu_vtk/src/icons/ResetIcon.svelte b/webviews/viewer/src/icons/ResetIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/ResetIcon.svelte rename to webviews/viewer/src/icons/ResetIcon.svelte diff --git a/resources/visu_vtk/src/icons/SettingsIcon.svelte b/webviews/viewer/src/icons/SettingsIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/SettingsIcon.svelte rename to webviews/viewer/src/icons/SettingsIcon.svelte diff --git a/resources/visu_vtk/src/icons/ZoomIcon.svelte b/webviews/viewer/src/icons/ZoomIcon.svelte similarity index 100% rename from resources/visu_vtk/src/icons/ZoomIcon.svelte rename to webviews/viewer/src/icons/ZoomIcon.svelte diff --git a/resources/visu_vtk/src/lib/Controller.ts b/webviews/viewer/src/lib/Controller.ts similarity index 100% rename from resources/visu_vtk/src/lib/Controller.ts rename to webviews/viewer/src/lib/Controller.ts diff --git a/resources/visu_vtk/src/lib/commands/VisibilityManager.ts b/webviews/viewer/src/lib/commands/VisibilityManager.ts similarity index 100% rename from resources/visu_vtk/src/lib/commands/VisibilityManager.ts rename to webviews/viewer/src/lib/commands/VisibilityManager.ts diff --git a/resources/visu_vtk/src/lib/core/VtkApp.ts b/webviews/viewer/src/lib/core/VtkApp.ts similarity index 100% rename from resources/visu_vtk/src/lib/core/VtkApp.ts rename to webviews/viewer/src/lib/core/VtkApp.ts diff --git a/resources/visu_vtk/src/lib/data/CreateGroups.ts b/webviews/viewer/src/lib/data/CreateGroups.ts similarity index 100% rename from resources/visu_vtk/src/lib/data/CreateGroups.ts rename to webviews/viewer/src/lib/data/CreateGroups.ts diff --git a/resources/visu_vtk/src/lib/data/Group.ts b/webviews/viewer/src/lib/data/Group.ts similarity index 100% rename from resources/visu_vtk/src/lib/data/Group.ts rename to webviews/viewer/src/lib/data/Group.ts diff --git a/resources/visu_vtk/src/lib/data/ObjLoader.ts b/webviews/viewer/src/lib/data/ObjLoader.ts similarity index 100% rename from resources/visu_vtk/src/lib/data/ObjLoader.ts rename to webviews/viewer/src/lib/data/ObjLoader.ts diff --git a/resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts b/webviews/viewer/src/lib/data/create/FaceActorCreator.ts similarity index 100% rename from resources/visu_vtk/src/lib/data/create/FaceActorCreator.ts rename to webviews/viewer/src/lib/data/create/FaceActorCreator.ts diff --git a/resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts b/webviews/viewer/src/lib/data/create/NodeActorCreator.ts similarity index 100% rename from resources/visu_vtk/src/lib/data/create/NodeActorCreator.ts rename to webviews/viewer/src/lib/data/create/NodeActorCreator.ts diff --git a/resources/visu_vtk/src/lib/interaction/AxesCreator.ts b/webviews/viewer/src/lib/interaction/AxesCreator.ts similarity index 100% rename from resources/visu_vtk/src/lib/interaction/AxesCreator.ts rename to webviews/viewer/src/lib/interaction/AxesCreator.ts diff --git a/resources/visu_vtk/src/lib/interaction/CameraManager.ts b/webviews/viewer/src/lib/interaction/CameraManager.ts similarity index 100% rename from resources/visu_vtk/src/lib/interaction/CameraManager.ts rename to webviews/viewer/src/lib/interaction/CameraManager.ts diff --git a/resources/visu_vtk/src/lib/settings/GlobalSettings.ts b/webviews/viewer/src/lib/settings/GlobalSettings.ts similarity index 100% rename from resources/visu_vtk/src/lib/settings/GlobalSettings.ts rename to webviews/viewer/src/lib/settings/GlobalSettings.ts diff --git a/resources/visu_vtk/src/lib/state.ts b/webviews/viewer/src/lib/state.ts similarity index 100% rename from resources/visu_vtk/src/lib/state.ts rename to webviews/viewer/src/lib/state.ts diff --git a/resources/visu_vtk/src/lib/ui/CustomDropdown.ts b/webviews/viewer/src/lib/ui/CustomDropdown.ts similarity index 100% rename from resources/visu_vtk/src/lib/ui/CustomDropdown.ts rename to webviews/viewer/src/lib/ui/CustomDropdown.ts diff --git a/resources/visu_vtk/src/lib/vtk.d.ts b/webviews/viewer/src/lib/vtk.d.ts similarity index 100% rename from resources/visu_vtk/src/lib/vtk.d.ts rename to webviews/viewer/src/lib/vtk.d.ts diff --git a/resources/visu_vtk/src/main.ts b/webviews/viewer/src/main.ts similarity index 100% rename from resources/visu_vtk/src/main.ts rename to webviews/viewer/src/main.ts diff --git a/resources/visu_vtk/svelte.config.js b/webviews/viewer/svelte.config.js similarity index 100% rename from resources/visu_vtk/svelte.config.js rename to webviews/viewer/svelte.config.js diff --git a/resources/visu_vtk/tsconfig.json b/webviews/viewer/tsconfig.json similarity index 100% rename from resources/visu_vtk/tsconfig.json rename to webviews/viewer/tsconfig.json diff --git a/resources/visu_vtk/vite.config.ts b/webviews/viewer/vite.config.ts similarity index 100% rename from resources/visu_vtk/vite.config.ts rename to webviews/viewer/vite.config.ts From dd5a6970e3798013db39aa83c36d7ed28afe22df Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 13:18:55 +0100 Subject: [PATCH 17/20] Update resources links --- README.md | 2 +- package.json | 6 +++--- webviews/export/export.html | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1a5bf1d..2f37a93 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Simvia Logo

+

Simvia Logo

Version diff --git a/package.json b/package.json index 7403aa7..c9b05a0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "engines": { "vscode": "^1.101.0" }, - "icon": "resources/images/icone-code-aster.png", + "icon": "media/images/icone-code-aster.png", "categories": [ "Other" ], @@ -78,8 +78,8 @@ ".com9" ], "icon": { - "light": "./resources/images/icone-code-aster.png", - "dark": "./resources/images/icone-code-aster.png" + "light": "./media/images/icone-code-aster.png", + "dark": "./media/images/icone-code-aster.png" }, "configuration": "./language-configuration.json" } diff --git a/webviews/export/export.html b/webviews/export/export.html index a245c34..e43ca20 100644 --- a/webviews/export/export.html +++ b/webviews/export/export.html @@ -19,8 +19,8 @@

- Logo 1 - Logo 2 + Logo 1 + Logo 2

Export File Creation

From ace640807ac1634ef981508ba5ca6f1fc8b39de1 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 14:08:32 +0100 Subject: [PATCH 18/20] Use toggle component in groups popup --- src/WebviewVisu.ts | 4 +-- .../src/components/popups/GroupsPopup.svelte | 30 ++++++++++++++----- .../components/popups/SettingsPopup.svelte | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index b1e9b12..eddd427 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -62,8 +62,8 @@ export class WebviewVisu implements vscode.Disposable { // Create webview panel with icon this.panel = vscode.window.createWebviewPanel(viewType, title, viewColumn, options); this.panel.iconPath = { - light: vscode.Uri.file(path.join(resourceRootDir, 'resources', 'icons', '3d.svg')), - dark: vscode.Uri.file(path.join(resourceRootDir, 'resources', 'icons', '3d_light.svg')), + light: vscode.Uri.file(path.join(resourceRootDir, 'media', 'icons', '3d.svg')), + dark: vscode.Uri.file(path.join(resourceRootDir, 'media', 'icons', '3d_light.svg')), }; console.log('[WebviewVisu] Webview panel created'); diff --git a/webviews/viewer/src/components/popups/GroupsPopup.svelte b/webviews/viewer/src/components/popups/GroupsPopup.svelte index 4600354..d0fe1c6 100644 --- a/webviews/viewer/src/components/popups/GroupsPopup.svelte +++ b/webviews/viewer/src/components/popups/GroupsPopup.svelte @@ -98,18 +98,34 @@ {#each obj.allGroups as group} {/each} diff --git a/webviews/viewer/src/components/popups/SettingsPopup.svelte b/webviews/viewer/src/components/popups/SettingsPopup.svelte index acd0288..2f370b1 100644 --- a/webviews/viewer/src/components/popups/SettingsPopup.svelte +++ b/webviews/viewer/src/components/popups/SettingsPopup.svelte @@ -350,7 +350,7 @@ onclick={toggleOrientationWidget} > Date: Fri, 13 Mar 2026 14:23:35 +0100 Subject: [PATCH 19/20] Fix groups with same name in same object --- src/WebviewVisu.ts | 4 ++-- webviews/viewer/src/components/GroupButton.svelte | 8 ++++++-- webviews/viewer/src/lib/data/CreateGroups.ts | 8 ++++---- webviews/viewer/src/lib/data/ObjLoader.ts | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts index eddd427..5ca0789 100644 --- a/src/WebviewVisu.ts +++ b/src/WebviewVisu.ts @@ -150,10 +150,10 @@ export class WebviewVisu implements vscode.Disposable { } // Parse the text to find group names - // Group keys are like "all_mesh.obj::SURFACE_1"; match against the short name only + // Group keys are like "all_mesh.obj::SURFACE_1::type"; match against the short name only const readGroups = this.groups?.filter((groupName) => { - const shortName = groupName.includes('::') ? groupName.split('::').pop()! : groupName; + const shortName = groupName.includes('::') ? groupName.split('::')[2]! : groupName; const regex = new RegExp(`\\b${shortName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`); return regex.test(text); }) || []; diff --git a/webviews/viewer/src/components/GroupButton.svelte b/webviews/viewer/src/components/GroupButton.svelte index 8c39dff..35d7047 100644 --- a/webviews/viewer/src/components/GroupButton.svelte +++ b/webviews/viewer/src/components/GroupButton.svelte @@ -14,7 +14,9 @@ isFace: boolean; } = $props(); - let highlight = $derived($highlightedGroups.get(`${objectKey}::${groupName}`)); + let highlight = $derived( + $highlightedGroups.get(`${objectKey}::${groupName}::${isFace ? 'face' : 'node'}`) + ); let isHidden = $derived($sidebarHiddenGroups.get(objectKey)?.has(groupName) ?? false); let bgStyle = $derived( @@ -23,7 +25,9 @@ let colorStyle = $derived(highlight ? 'var(--ui-highlight-text)' : 'var(--ui-text-primary)'); function handleClick() { - VisibilityManager.Instance.setVisibility(`${objectKey}::${groupName}`); + VisibilityManager.Instance.setVisibility( + `${objectKey}::${groupName}::${isFace ? 'face' : 'node'}` + ); } diff --git a/webviews/viewer/src/lib/data/CreateGroups.ts b/webviews/viewer/src/lib/data/CreateGroups.ts index dac43fd..9b51c7c 100644 --- a/webviews/viewer/src/lib/data/CreateGroups.ts +++ b/webviews/viewer/src/lib/data/CreateGroups.ts @@ -69,7 +69,7 @@ export class CreateGroups { const size = this.computeSize(actor); for (const faceGroup of groupHierarchy[fileGroup].faces) { - const faceGroupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}`); + const faceGroupId = faceGroups.indexOf(`${fileGroup}::${faceGroup}::face`); const { actor: faceActor, colorIndex: faceColorIndex, @@ -86,11 +86,11 @@ export class CreateGroups { faceIsObj, faceCellCount ); - this.groups[`${fileGroup}::${faceGroup}`] = subGroup; + this.groups[`${fileGroup}::${faceGroup}::face`] = subGroup; } for (const nodeGroup of groupHierarchy[fileGroup].nodes) { - const nodeGroupId = nodeGroups.indexOf(`${fileGroup}::${nodeGroup}`); + const nodeGroupId = nodeGroups.indexOf(`${fileGroup}::${nodeGroup}::node`); const { actor: nodeActor, colorIndex: nodeColorIndex } = nodeActorCreator.create(nodeGroupId); const subGroup = new Group( @@ -102,7 +102,7 @@ export class CreateGroups { nodeColorIndex, false ); - this.groups[`${fileGroup}::${nodeGroup}`] = subGroup; + this.groups[`${fileGroup}::${nodeGroup}::node`] = subGroup; } } diff --git a/webviews/viewer/src/lib/data/ObjLoader.ts b/webviews/viewer/src/lib/data/ObjLoader.ts index dc423a6..ee3d42f 100644 --- a/webviews/viewer/src/lib/data/ObjLoader.ts +++ b/webviews/viewer/src/lib/data/ObjLoader.ts @@ -63,7 +63,7 @@ export class ObjLoader { case 'g': { groupId++; const faceGroupName = ss[1] || `group${groupId}`; - faceGroups.push(`${skinName}::${faceGroupName}`); + faceGroups.push(`${skinName}::${faceGroupName}::face`); groupHierarchy[skinName].faces.push(faceGroupName); break; } @@ -71,7 +71,7 @@ export class ObjLoader { case 'ng': { nodeGroupId++; const nodeGroupName = ss[1] || `nodeGroup${nodeGroupId}`; - nodeGroups.push(`${skinName}::${nodeGroupName}`); + nodeGroups.push(`${skinName}::${nodeGroupName}::node`); groupHierarchy[skinName].nodes.push(nodeGroupName); break; } From 9e3b0f16e729d104db3ca266c76f0b92caf2ec41 Mon Sep 17 00:00:00 2001 From: Ulysse Bouchet Date: Fri, 13 Mar 2026 14:29:28 +0100 Subject: [PATCH 20/20] Update Changelog.md --- CHANGELOG.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d49368..6279e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,21 +5,24 @@ All notable changes to the **VS Code Aster** extension will be documented in thi The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.5.0] - 2026-03-10 +## [1.5.0] - 2026-03-13 Rewrote the mesh viewer UI with Svelte, and added new viewer features. ### Added - Migrated the mesh viewer frontend from vanilla JS/HTML to Svelte with TypeScript +- Mesh viewer UI now follows the VS Code user theme +- Object file names are shown in the webview tab titles +- Focusing a `.comm` file now focuses its corresponding mesh viewer webview +- Revamped help popup with tabs and more tips +- New settings popup with various settings + - Edge rendering settings + - Object visibility settings + - UI settings +- Improved various UI components in the mesh viewer - Show/hide toggle button per object in the sidebar -- Per-object color display in the sidebar +- Per-object color display - Zoom widget in the mesh viewer -- Groups popup to select which groups are shown in the sidebar -- Revamped help popup with tabs and more tips -- Added a settings popup with configurable hidden object opacity, edge rendering mode and plenty other settings -- Focusing a `.comm` file now focuses its corresponding mesh viewer webview -- Object file names are shown in the webview tab titles -- Mesh viewer UI now follows the VS Code user theme ## [1.4.3] - 2026-03-03