From c0e42c2d45966d7626db762d7b099506c2e10433 Mon Sep 17 00:00:00 2001 From: Uriel Date: Thu, 1 Jun 2023 15:42:02 -0300 Subject: [PATCH] Add more tutorials on setup (#696) Co-authored-by: Erimel --- gui/public/i18n/en/translation.ftl | 37 ++- gui/public/images/taybol.png | Bin 49700 -> 0 bytes gui/src/App.tsx | 15 ++ gui/src/components/MainLayout.tsx | 6 +- gui/src/components/TopBar.tsx | 14 +- gui/src/components/commons/TipBox.tsx | 24 +- gui/src/components/commons/icon/PauseIcon.tsx | 2 +- gui/src/components/commons/icon/PlayIcon.tsx | 2 +- .../components/commons/icon/QuestionIcon.tsx | 17 ++ .../components/commons/icon/TaybolIcon.tsx | 22 ++ gui/src/components/commons/icon/TrashIcon.tsx | 2 +- .../components/onboarding/BodyAssignment.tsx | 2 +- .../onboarding/pages/CalibrationTutorial.tsx | 10 +- .../onboarding/pages/ConnectTracker.tsx | 2 +- .../onboarding/pages/ResetTutorial.tsx | 237 +++++++++++++++--- .../components/onboarding/pages/WifiCreds.tsx | 2 +- .../AssignmentTutorial.tsx | 104 ++++++++ .../assignment-preparation/ExtensionArrow.tsx | 35 +++ .../assignment-preparation/StickerSlime.tsx | 47 ++++ .../assignment-preparation/TrackerArrow.tsx | 34 +++ .../body-proportions/ProportionsChoose.tsx | 7 + .../pages/mounting/MountingChoose.tsx | 8 + .../trackers-assign/TrackerAssignment.tsx | 11 +- gui/tailwind.config.cjs | 5 +- 24 files changed, 576 insertions(+), 69 deletions(-) delete mode 100644 gui/public/images/taybol.png create mode 100644 gui/src/components/commons/icon/QuestionIcon.tsx create mode 100644 gui/src/components/commons/icon/TaybolIcon.tsx create mode 100644 gui/src/components/onboarding/pages/assignment-preparation/AssignmentTutorial.tsx create mode 100644 gui/src/components/onboarding/pages/assignment-preparation/ExtensionArrow.tsx create mode 100644 gui/src/components/onboarding/pages/assignment-preparation/StickerSlime.tsx create mode 100644 gui/src/components/onboarding/pages/assignment-preparation/TrackerArrow.tsx diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl index a15744ebba..dd6aa64aad 100644 --- a/gui/public/i18n/en/translation.ftl +++ b/gui/public/i18n/en/translation.ftl @@ -1,4 +1,3 @@ -### SlimeVR complete GUI translations # Please developers (not translators) don't reuse a key inside another key # or concat text with a translation string in the code, use the appropriate # features like variables and selectors in each appropriate case! @@ -492,7 +491,23 @@ onboarding-wifi_creds-password = ## Mounting setup onboarding-reset_tutorial-back = Go Back to Mounting calibration onboarding-reset_tutorial = Reset tutorial -onboarding-reset_tutorial-description = This feature isn't done, just press continue +onboarding-reset_tutorial-description = While you use your trackers they might get out of alignment because of IMU yaw drift, or because you might have moved them physically. You have several ways to fix this. +onboarding-reset_tutorial-skip = Skip step +# Cares about multiline +onboarding-reset_tutorial-0 = Tap { $taps } times the highlighted tracker for triggering yaw reset. + + This will make the trackers face the same direction as your HMD. +# Cares about multiline +onboarding-reset_tutorial-1 = Tap { $taps } times the highlighted tracker for triggering full reset. + + You need to be standing for this (i-pose). There is a 3 seconds delay (configurable) before it actually happens. + This fully resets the position and rotation of all your trackers. It should fix most issues. +# Cares about multiline +onboarding-reset_tutorial-2 = Tap { $taps } times the highlighted tracker for triggering mounting reset. + + Mounting reset helps on how the trackers are actually put on you, so if you accidentally moved them and changed how they are oriented by a big amount, this will help. + + You need to be on a pose like you are skiing like it's shown on the Automatic Mounting wizard and you have a 3 second delay (configurable) before it gets triggered. ## Setup start onboarding-home = Welcome to SlimeVR @@ -546,6 +561,15 @@ onboarding-calibration_tutorial-status-calibrating = Calibrating onboarding-calibration_tutorial-status-success = Nice! onboarding-calibration_tutorial-status-error = The tracker was moved +## Tracker assignment tutorial +onboarding-assignment_tutorial = How to prepare a Slime Tracker before putting it on +onboarding-assignment_tutorial-first_step = 1. Place a body part sticker (if you have one) on the tracker according to your choosing +# This text has a character limit of around 11 characters, so please keep it short +onboarding-assignment_tutorial-sticker = Sticker +onboarding-assignment_tutorial-second_step = 2. Attach the strap to your tracker, keeping the hook and loop side of the strap face in the following orientation: +onboarding-assignment_tutorial-second_step-continuation = The hook and loop side for the extension should be in this orientation: +onboarding-assignment_tutorial-done = I put stickers and straps! + ## Tracker assignment setup onboarding-assign_trackers-back = Go Back to Wi-Fi Credentials onboarding-assign_trackers-title = Assign trackers @@ -621,6 +645,8 @@ onboarding-assign_trackers-warning-WAIST = Waist is assigned but you need { $una ## Tracker mounting method choose onboarding-choose_mounting = What mounting calibration method to use? +# Multiline text +onboarding-choose_mounting-description = Mounting orientation corrects for the placement of trackers on your body. onboarding-choose_mounting-auto_mounting = Automatic mounting # Italized text onboarding-choose_mounting-auto_mounting-subtitle = Recommended @@ -660,6 +686,9 @@ onboarding-automatic_mounting-put_trackers_on-next = I have all my trackers on ## Tracker proportions method choose onboarding-choose_proportions = What proportion calibration method to use? +# Multiline string +onboarding-choose_proportions-description = Body proportions are used to know the measurements of your body. They're required to calculate the trackers' positions. + When proportions of your body don't match the ones saved, your tracking precision will be worse and you will notice things like skating or sliding, or your body not matching your avatar well. onboarding-choose_proportions-auto_proportions = Automatic proportions # Italized text onboarding-choose_proportions-auto_proportions-subtitle = Recommended @@ -732,7 +761,7 @@ home-no_trackers = No trackers detected or assigned ## Status system status_system-StatusTrackerReset = It is recommended to perform a full reset as one or more trackers are unadjusted. status_system-StatusSteamVRDisconnected = { $type -> - *[steamvr] Unable to connect to SteamVR via the SlimeVR driver. - [steamvr_feeder] Unable to connect to the SlimeVR Feeder App. + *[steamvr] Currently not connected to SteamVR via the SlimeVR driver. + [steamvr_feeder] Currently not connected to the SlimeVR Feeder App. } status_system-StatusTrackerError = The { $trackerName } tracker has an error. diff --git a/gui/public/images/taybol.png b/gui/public/images/taybol.png deleted file mode 100644 index b45415806a34e61267a3e21691f2bfff3ca4b4a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49700 zcmYg&2{@E*)PDW6P?SL^p|Q)7eP3#frLv~%OU9mclHHJ+7<(cTMkpfNSjS!rvM1S> ziHXTNAqIo_zoYN_U!UvJH1G1f=eeKzEYCUT6=Q6u%XIF_xf3T&Fx}RJ-aB!Et{3=~ zr9T54NtSv#1$;30>RI}oIB}kp_IvWg+bqr#C%!b@hTgg#l(l-eh+J~r=5s# z1}>cs;ncnw_?hkxquPJ&Hs~@_aoYWQ;^%>n^sc9hKk0%#&@ZSRrHMY<^S2>-+1LXE zF>^p+mcS=geEo5@C|^Ck(#{CfpTSqW@Kyr2+lKky&@xXxb9CG}h=VB~C90K?l?KGn z$9FNerZQOrw=0S1VDD*eRe6pTPNxF`fdj7fRsx@Jo_N^lqj#vuv*D87vazo0z$wXR zxZ_hHYLb^@^=7*k_L)Q22E~D=WnKFBv?l_vuZ4c7UvJ~*GhP4?ROP-oo*1%7xv_LpNfRISRSXUeu*iFWlNSkV(09;O*jNnlWjeSMiPuJ->-2*XAA zOAxews}Jf{f80+SWe0LB$oPOnry%cL9W4U};Pz1df1_{{!fngQ9dD@0=YXTS{Kuex zIJIwv8%NnT=%%kAy4l3G#1^t_m1xWK-|_t0;OQ&C_=oc6{ceTuEv5ex8gzW_t}vXU zbt^mbe~>xTL0evn>rt?PI)~qr05BFxmB)v!bRJ$j?e8sfj5)?vAPoRgJVu%6v_Hc? zv|+i&)Uf!Ep@Sy(MjtR2b`*?uUEgIbOkH8;H~C8tdd!LATl+wC=%~Bs!ZU>eGZp3+|_V=vRlRY4uQFWP=~z5(#`@vd;fHLPED^qjR+uG#Lf_Tn*$~@aR)C1P z`D)g53llx&;&H$*8GOf7C4ROolkHe&XmxSGt^OV|HU;P~5PvMR>GzZNY@ar7u%(L+ z=>9`miT@wc=NOqz3zo&@x*7v=F(ff#Hii~e7OKUh8pi6 zB566Tc)3Fs;DXXW1Jww?`i52gAK8UjXtydP(~b%MyKJ29SW!MovrUPny)Y^1V>Y9$ zJ>+=6r}M8m9(S`PPxFt_RR7ZP?Z9Ny40XyTfRTj0(rjE>95~$rtl;pw6}To&mv*NG zj}GWR-p{I!>)By2W{Fbg!a6E}r5>lVq}^64EoWEB?Dz1UMaJ1*G>;M(Nu$)XB=8uRos-;; zRNxB}jZ3Jh_Lsdi%y&P3i?F2!d$S+k9w7DWu>|hbSDKB~mTUB-DIeW23|`lO#Ynpg z_^RUt#`Ryr0Dz4N=H|XbGSg^)%G9DU2+qyeas3>)*6|}v;7@!s18l>t1@DHSNZrS1 zmBrE|vboS9cpiM=gD%Z>!7m-p`9J_zC8QGi82fT43Cg^!+-3>J!KK z4?BKl{bph#;(VJOl658jhinXA8eWv$4d96|gl6gBR$%g5i7ctR8uQrQuI$v$;BO{-?KcE1&?t5`1<0C<<6q>0^`+rR8km0B%U# z4+J>*<(Ou8N48IWXFnwGJ-w0%K~es%%Hl521c51DId_L%nj?hIx|QaP=DCiK0`q*u z$^sy{_wv~8t-he~F0aGbGlvYSc76ApCt!ZE@jP)OxuEJ1uYl zv>jCs`*=$j$xO`4|AC?Vkl2508M98;JDdkEqW%xiIL0NKWkhB019H4!<^H3MxlV-u zWTJ-~%3OH_VB|=X;0;|=)H4>qvO9j1WQX+8)3{8IH!0!dP1Tv8dz1ytspkK18r4XP z!Qka?A|imk863OkHz#Rwh4Py~A4B*6-g&=1W?^6=4Px@MTni=OQggA~ySfNvwS4IMnAL93Vuuwg#U1VA6s7dI(y4X_)PsY82O+%dVC{RCO_CPcOo z$DSGI!d3 z5@^8_u7;+yz}m}3&4M5(F&fk7zjJ;#`S)ZKKcKZp<`t*d*L$xw2YlxMo#oJ?iF2Fg z=%J5~>5Rk%|8LmCLGz?=29`hah7re4XQrgkxHf-|Mi96mV+Q~xQb{6eRsw=LPm4L{ zuX57J3dRK=8$8dVE*v~B^{VNV@8pxkE5h42AYoukIfyI z24t*@%nf|SJP)N=o5YT%!te62ZQZW`d1;1|BKrRg=h@>aOCN)eD}5zO`tUCRLgmxY zxe7UE2YCItK2DZv;c$c&Wuii9@ec|i#YQItjMs8IHPEu4sdw{IFCP+1NAuyUZQp_b zQh^u0+{DOS{0b;G<}8g5UbM%+FLHipSr$pt0tX}?vr(O95n!=2_k>$>WLtS>a>`h! zlK0}r=SHj1xq)bA*m;^3Ue%Hu1JwInzQrloKXEX@FrnqrOUd!ZC|jqVt*twte#tB# z_5<)f`E|jH9xFM z^?KzE5Vh^Q$#%!+s{ap`&VE`C0`ivcJ4B+)>C}zhwcAMn2 znVFQok{uD8#rrhy=fw_|?Brb##qqbTC@zmSqu#b-`_=MW#NW&a)WIY33bnrybFa=h zmbvy(D90#Z<)dHG$Pfn*8ny5aASbRlS;T)V7B&%@M?VW?Jfze9{Fe>BB~vy$eC|=5 zzGl*v51}Do84@=!M6)yO-4S-cehO8ULO+H(du*e5kBo7vt&c3P6naaC3!K^z>tI=f zxxD)k%nhzgK)KrGV((*kGdAO!OjW!zhWz+(t0q7Yx7A@>@)}sl4FNkHkdWkkGXkl` zxD4~CSzq9kEJW^NNtbMEVi#y$m9g3J#T#|N62rndX;!N5d22PMLqjgrm4sislP%gt zj^qo+i){Z~!M3WEnRm%jjx-cjjZmT)n^$*IU5zCVA$`n%GQQ#9nW}@7IRNWPOyJxX zH9b|1S-+D#vBu(oyyW}Nzki3M-Z3*}iw#^eLS4}U0ubrDfFis(t7BoK#t;KIT`?U{ zoqLwOiA{m+AD1?H$_+~6y+9;qS(gJ(v7>r^Zb4ZBh^%anxf%_F{(fq+|Kd2fo^O$E z^ZI6cVe3*au<_LFkR=QANzaL`NonZNFB+8nn2Oq6>O%aj-Y76z8}6tsuY+hA*v4}F zjCus9flp2X`sLPoTY7vds=bmW0pB9Ioa zl67^Lf)(#LLe?W8;%6HJP7dIHygkrUP25b?FQTZe3YZ{cgsnDlcg1S0g;o#(u&~8Q z0u-y12(8!EiH|(I9XvR~&F*W@&7Kj|^0P(!7X$?YECXDV^GX2(B?u$Pfy}muXU!i>v^kFrQ2V-;NK zhxs-XeO%$i>4<1;-5_bt&JK_XyvVcz<4Ou07uz)!g=BD)PjF7)~ zd)IBwb~gMhBexdWH15c*o%nN@W#x8d=!??*E=`<_JJgI2xu#{%%z8U3EMiahLyo47 zhr_mOtMGcil%Z-~3LmQ^S$$!$HGaiu{Zo6Ju`u>u$X9opFXTtWBQFqSnn!14XUY_} zQbDZEA&?`PndR%P#v%rhdQr^fEhWORz(UHD&a8}2%F>f;G+#i$R1OROfS_NN^LLcP z-WjVQPvp-}LJ@+5Lv`6iM!Rj%3gR!J zGO^;73uL#M?@Lt-w0@LsV_J}J#eZ<|luu_!{O&`U5|l8lPhV(S|DXU)HQkJIrWTX5Y7!q% zZjbC7Z8)oY3H|Pp=&Co5SE`F#OY27W!vsO>--*ki?bhPNk#8d54Ex7R@+70TxnkxIjtPGm<=<`7UffRxy8F)SSxH-c7ak;ZvUK-A;>$YGeln&`5-irUD7dBZR@7$C~3;6QDrVwE$Ue! z)+}Sq43^)#V_a6(dV>uAP(~iAvRA7j-H7nxse1+nHmQ=dJqxkpB_);FuYiBrcW}bj zAhiLfP2zF@smtrEptBhqTKJYR^|6qAgA2~p6P>K3joV_y#6nIulLJEOqwUm4-b9@y z?)7An7eI;jIlcpSX|@4DoHh`(%&T!G8|=(Rl`%tBqg@+XppNozWy~t)nyo~ z>}6g6*SO>D61}s^2^rauhpY`V*SUd^8C8`BB=-yl&r6RMbU8DC7dy^=07n!}(&8IKNCG#ZFU^BJLS znYVzzIO`}LCgYPL|ZT-O?gSN7maTkxr!sL4_3 zoFR|+S*?^{LOoZ#ZG6Vy34eC3jBEV(p{o7l3T@j8Y;bU*Qf#UMxO;!jkOg1JRL8u! zreX5INj*4yZC~_3JBlvQZSZZ?P_fKO1Nt zkd_w<*pQZ~>T>+ZVU7|^7HRu4b}7-Tnon@6N~dC|Gkm{=rIfiR?8g41l}eCh6zQa+ zI_R})tzk8+eO#OmVe8l|>tH`E7|I*f9hSHD)feuG?3j4*MALigh5}J>O}(!BM=Noo z(I^_Osh%!4bZ!=!)kp+=4fENy2hGxjBd(Gdw_FKV?XD6Fw171^-~>YTM8atx%Y^&B z`>RC)Ah*I4>wn+}E6x|HVy|egs_UmM@b?6X#&1LKtItKL{y|*byzjfMDQ)ZpTpN0>}0yS#AZxzhBJJe1UHRz3P_@)aT}_e_+^ z_KRH*5N%)8$!kK&O3xNC!_e>HD!zD3eP_cZWmX7Cq0xf3O}Nxz9c!>sITY(ee`_HR zW*)8A-0YKXWYbBKYV&XTl;%1by&EEk#^Vl7rC?Oi!5t1-1{2uTTq|^!bNYp5CBZ0Y z6|*iFSa2W~Jjnuc=NvLVf<>6?JI;LAA@4u(SoP?h;ozUXXAZ3|v2yKjw{dTEn;BLO zU%wuHJ-#2_C>A>|A1fc+(SZ6W5tlI>$~H0)NA=oO_pw~;O{mZ-TqZjltoMfW)Q@&A zDXdZKq$e@2Su+V4b-^b%lgC#w6yO#-={eVRKg&!1NCVAZ0|LbHgxpyRaGIX3MZwPs zadHmf31^|gp1P04I^GBjV_CT!ZC2(1%_xSRwFP=W3@9nV)+wcWC6MD+T~W2Y!s2%kmlMG>`#!!+csUQ5L6?OBtWgva!}5%+$0iwRu#pQ zwzN?mgO8hTXx8RgoU5g~eJzt$clWMAQDD+IScxk9w=in6XL z?+YK5M37fNrbO@P0}o@A`&V*sCv8CGOjW2AhNm7#Q5!Y?PUj+$!@@Jr*88>_te zKna_Xe1=W=m4&GYQ+3ajC7;nQ`hx3&c(^^q>U09%Lv!oIh)13>{jMs81zCft8`Dox zJxG#2gKYxhovEYUsjfd$6y`Fl)6V9ZE+i{3O!_9X%$~`3JYa;Qny-N|K>}$V--~S5 z7GEyiqu-D{s?g|MyBQzRcrmz_Z2FQOzNLpXg3u3|^7@%xp59;HUOZcRce_@G)8t4W zTU@@|;?UxiQ+Um!$KO3N^%KcdY){!YaL@bRnf$Cq`{#XOQj@O3>4I%N8pdTY)|B)~ zp0Cy1VmW$paWA%b$0VOJo41K1JWKp8^)2ouJ%%aCUG3D==AlJA^ZUcyjrYbG_mZ-$ zfBkR{D!9~RTsBPS;D8QLxd|e-?;iS3kJYUF#Q7s-km;Y5$yA7PtI^~sU*^$KH1i#w zzG!HcqtFpQonYfO-CEU{ENS-_qC0hEQ!kY1g~e5tUcgv<0ROoqw;Cmurb`c}IPt}8 zwr~nw7%}ucNJO0v7lNhA&Rvqt`l&P}1@UEqc6xI>EGJYRWgb4kS#*^XcE$!SI@sun zOew9o+5R@FAz57ug!a|)%7Xse%wUe+R`FLRG4aoCGv97F&}_;(&}>C{{Ot>db&@jl zpSUz*ymL8VJ9^@Af*TMyC9?ZC12|2$z<^}|t7j0pN~%-DQ=2^39ouU|;x0)nVKK^%;)FwX~h_HLqK{zpHX7@n$a{Pgoz z(>$uze$0o98q1uqC{P;^&eNz-C%Z#yS1yg+eV0nV5!nCufQ>(jskfxj$W$VNSYffF zZmkJDaoH9BpSXR)fC z=qS<1FvqypO?6jo*njaLVQ7E6Jhfq11lCTUygpCJuBZ-NEpzoCui&<2B!uU$ghWF% z9!`-en0ois$*ngeU*=}@#&VuJm&oxovtl{4pgDZ36Gd)H=#ARgGGvSp00nBud_XUY zP&Xp)UHs*7Ne|@*tij@O;`0Eh@BTNK<#UrmHo9ULeMgE5WV)x%#Txd=L_>YO+HZ*d zZuX7m%nj;ZW*&~A#Ant;vL8~u(1XIeRa8uRezR{T&hxdBYSGi4yfQ0VtcR!gJ9T#s zohNY*Gk*V4I<1f~h`gra#2YhT;8PMuQp=#4BXZWew&(>$RV8IMvO+$7K38*6Qrn2J zoE#a?26F+3TK^LD27C5Ll_-$U*LVLDoJA0_6V>9+&V#?{JS-7;Hh0f^Y| z1=e0n;?d2XK=rYq_GBPwEs zj@q+NR&(DDuJYD-LhD!7R*K4rIf(8N*K4nq)J^7V&;B@rJ##r>P~4@b9Qg4_zlF+q zh>XjbE(OvkANWt%u32H3><5(w{+kBn9b5!Ug}?f{q-rB@kpO>O18j=p&rS~f$E6wJ zHWSWTdQ+ND*|H!ZVjDs6Nv}AnSEV@0U!*Ahn&~;Zsam_OaWyo&CNs!L>=k079;v76 zBv!sRAL`MR&UGP>p|1PModQH>{O(}MOQ}Xd#+rVd{!3@eX)&OF3nWT~&4(wsL#(+8 zE8K)<7U%DCJn?NoB6YHoc=x1xtF}M9+he6;NrYj1paIMjIBA$<5TyGbGDyCy{d2MZ)-Q?zhi6yuW5K-k z`PYXtOC1Yeq0PIH`at5Jr_A%KzfHHd z8x!F6ZUk#s+;iX5`U5Wtvr@;c$O@@1#FiOJ43nXYYV9JI;Ynw#$UA+`P+*gQmm6q| ztLh?h0b7Oy{LJ0?xSf_(^A+puLq#w$r*>7-yer%}Gzf|1mho!-7~}#^r^&!a+Zf}5 zGdkb6>{Lln8fKOLLbVPPy+Zh;6XE;2PL6?_l3ZhVOBylzKJ`{zs!T0aVZ?57_`&Q0 z=Otxvu5FCKXzzad8bh~2a#vAy-c8nc6v;NBH|%YF7WSiRZu9exhJDU>&&*Cz64Kd* zzcQ=Ybe{_x$cQ31dM-B?cBlXqW=&TA zWLu0HWc7u3@BC;{XyZZyKT?T9$HGuCIY!0JKCn&So%4$J)7_)cSbskyY$|>j^sGZ7 z)c^Yj;>NCh$=IhD-_z?|&feVkv9%F5TlcdH_Jx`@I{MCS9d&k#8>#IlDVrW!rtv!} zu9Lez@6z|<8VYZA?N<>z#gam8O6cP@i&VpLO`IZwSvFN2wm_mE`=F_gYqXRHNZ;RK zahQ8P^X#jH7dIuYP|cfs(;`!|)3GIia)+yKnio$zzhbubpk~%*)bSp|nnOd~E3X{U zYi3=A&@>(MuCofPmM$UU6vVku;F6a1-i&eXy2gt!Se+VqW!BMOIjdCF_&;oaTxD1X zFO(!jHYHr-Yne0=$BakobA_(YDnh2OR*J`2x4T6z#i-Mx~Xriu7R6b{H! zGW1o2U&;iKwz|VO^}2PUtKI2{Q_buk`SD=0AMED=-|#qh>-vh*&dP~9BO&43ytSp` zICdG(;A*zp;Kwy#Z=mMXQThpwy!e4y@481{l{ZVUtzategCWIG47*_{Ir-!VrtLyB){hJyp>$$h4sI7$NH^cJdHZ&pC z7i@F{%25}7_w7?g+q0JwFF4jU2G5B8O@Ewt?lnu{J7JZFK=+0Be*ix6w~?oDrA)Nq z-6JvU0@U+Jy=u8{4R6-(x=X9Kd@%*(aG|gtQ-*gkj3jc5EU+dgV2@3Ktfr-?Q%U+iRJv_V=dxCvvvAUgo4^+ z9UIf3d?oXPIOR1$0vM-3tB87|?13MAxggG6I*)9H5e4j?LrEigv>tTu;!T%-_$$wD zH*HTNj0SIGt3epZ*~oL?eHJ}<>kdw&oc_ySOE2p{fnAN#N&9B*lJg{U?@xwCxca7w zsnBlJKuS))?7rWQ{*$*(1C#;T`I%+z6Wf&rT>(b)NzEnT6v>%h}0&16ncI3ednV=9M zL|KYiU5yDks%_4fU9ho35y3+mTtFuV`eXEkL!WbSIhNk}>EjA2mPuyC5^WCc{9V40 zBElqH*YJUrC*qp;z)^4^iZcnm{Wy&IS;J8n2qI!m37qq}YKNaxTBF~n;wwqjp|A2j zSj(VnGWQ@w4$5*7`h8Bt1>UxH@Q~b9*m%x^*0J!2_*%!W5rZX;)tE)~Mp9w94^sG9 zpyaL$ct9KIRGM!S;i^^Qh=S<@CCg|pOO0=_4EgjHfrqNP>S>>r3J_C?YmXG?LPFxj zo}jOKXs>v$Nq39gnJ){SCp&4d#uUZRuy6G3b5^KNse~Eu-)A>%nc1YWZZHsk;nrO(K@70=6S5r+x>N=*GSyPaeYCz8O1-h4nwHaD) zMbdml21(+8|DJlskGxr?(J1cCn;NppEB*Id?e+}=uUiA5-dnfCe%hf{M=Pua@E*2D z-HY$-becZxcsX%_D?<%)D!jOgRMz?D?yNyh=9vmt9j(j5N<0E{?Lc!UfpP&^x*5+y zu_>P#wtIdfJdMo=MnXywL#xI$4wiY1Or9KJ@Q%d=sy`CKe^8e!;WL_R%5< zm7&5Q>8=W%DYf*5gBNRMUx1+IBf>^mc1~pwJ0qvCn`+@7Z{Bkl!nfYV3jV7e6%^9C z9I9NQ@&5j7)m4RX5(AmiK={a2NCE0{rmsW?^Fm{Q%zPGGj5GXPe9%d}UpvqTpgFC6 z>4FjTHAA3zenLuBg7vh9PjyC;$I!2h?=ds*GV)C?c_Y=)t=+D~ZHJE9{IaeG?T z|L8&QKAbm3Vaa^*aride9_3qnmaj3Sz(3SrWRLqhNDx>5HPsc9uhxYQ<+Cq^&X)nT zQ6+X#jXm5xK^u&d`NMfvDdB{i71$Ztw<51{ex{+>r>)e$zgD^&8Xv=4L|6JSe7fRD zD1LZhrlOd!bwZ5?j@Ad4eBqw6>Q}NC&gMe>ay-%x>D##JBw?k_U7h zZm5|-btC7sIwTxLk`i~pfPxyU^z>qNo4*1)e9sRXH5C0X;ZFg4YyoPqDJiN%zSKLV zqCgy-vlK3Ud@_Rp9^^JJns2b^U*z%kR@U=SoxjxtKdtz}gFqXqmrYknrE?p%|Me%} zvJSD0gSL?GH~7W3FEcp7b2wT0=kTfuL{$jQI_LOVD_UMij-#75-sgqY8hQHpePR9U{mFbOz&c#V9qFVUwc7k@H@)6Rb zT(&v_wlV`^WwkL21`Crl2eTOpurqCWDhaknw}qoXq_#-dka~dql<%j<=G=bT77@8j zC!aF+4ML;)9k&}n>*Hcp!`RH8F7PZpf3u6JaX2^G{&HM$*1971CALBr} zY=&>g@-RT6&cv~ftCo5cU9r2cv6Zf%v8_5?$p}|pCWwEKBqv78S!&$JvknE%F;5cNv1E>~(c( zq_b-bg9h~s(E8kUpIxlxf($)-QK(qraLQ zR5@g~6*M&OQ%W7v5SfCww^vpen)Wv+1%Vmmn#}VUeC4|QAL2|$C5FOt1^m)aUbE(U zYkVt3nbM$M=eG`-z7iF$2m7U2ZhHbQ&mw){11yEsQVZhyoeYCh-UBr|)!7xgmG(0; zS27g#QcQYQFf}?WiE9FU0}AGNL?~**zi71aQt!UM9}GB) zygSo;okwVEFg5CE7`vMAU7CR39^il}W^6`mBu*L$yyb|)ZEi}jr2s8L1}vp57$qN?|x6*i_X;JjOL3m5o}?WxjY|9drtF3Q`%x@sJB(M%W9y0)92f0;?s zthe`QGU=h-R5QPUl!`))gbS)LrhO~o!x?oW-HzV<&?H-#qk!gfy9-e^cYq1r)x~x< zD6KN|eo{1Ep7WIfS?}oM5CPKx>aIxt38DuJsQg^=MDVpMUM;pR%5B1+(OsZ0Iy8U` zLI&xq=jJ>2+{8WzW%M%&E<>X(2=hZX3A>HuH;}t%{U>EJjj8IAX+`vP~F zf!_8_h|`$rlvp}xJGr7zT2*#jfG8o6rEyHI_aS-FiMs6(I= ztVo*=qvjJIv~gG9JkYszY3-X5odeU>>X_K1laBWbJJ5O$GlY`+wmikz_6k=L2|i{j zQ+n54NIZvbNa}9&e8fX#$mO=@4}Z$B59v?+e&K7nb7AqxGXl_DnM!&dbmq(*{l~hQ z)90jxA5TM?Dle`l?++7&)i8D!@E=f@vs28v;1AD+e&!!7pm{IZ20?u%cfe~|-q>U(+xB*G#UH7p(57PBn6rcQ*byvo=LT<{ zflRACa4ylD*$vI}Z#=pt^PD=b5Z$FB%nc$S$~dQrUVo)G_X%`tDd_#sNa9+!98{WS zq*d~We5jww+g7~Fw4eS6Vfp5TQX=~Ix5Jy%4-;UF8n22%t3J^5nATnWA4l8keYi}H zJ5VgTHx}IWu5oz>Y4KD6tqimPhTH7-KN*oWcf36FVDNPR)~`mz+H1I6>+k78FS+?` zew$~JuQ)-jwm#@u>slCux(#y`1~yhR^|FBOEI9x1Z)SDA0(;F+w}NZ1rrwuo%nX2( zy@y<-y;e}QFb4e8^j-^(I&RJ-#|)iIid1l!aI-CvZL}>yM6@L7V_hg@^!&LsrVO-R z(35j4;8Y5{0jBw7<-d=@;zf8bSyzo>Qj+zUint!$B(KIwd&iYs4l$c#IXthk`%wKZ`K6W01KPueOl+VSmk z!%qX`!#yq3qAe^p|5AHPAKB-sP#d{}zHU5{ld3#y)etQ)C7dRGHPvL+KIU;*Caxe( zmpYlYzjhW~i6u-~CP#^Jeky_#XAesA+rPNYILJ=f76sP3j4@rpOIFz;DMy=$l?FwsC)9MF z6k$3urRHZT6tRRYx*<$*Od|49-B^WOfOSeV_Z0R;5m&nFyiF*d!UP#!oCqfggp@6U zOL{Vbj&fqCai_Li;)CqKDu`?7rFdkro3y}N5=+bi<+JhXbLP8W=)bsdg%5IwbuURx zj{oX&C`0Rry-gVIl+_ZzKRbj58Stsd%;c3csQh+g)vq53dROyt6zJGeC$Atd@VBVB z&nkKRLOvE_^mm89qa7svodgBV-Xwq}m?hFWn6|?ers_$VL<)+p!!oI#W<62F1qz9i~u;N_f zBm`F?2A6Vj_v_1v9-k^fb9BSo>G2r!X@qutKn_wVpggATk*d;wwRRszKGRB&?qFws zUT(g3I>%_25gTM$Q3q9Xu_xl-xtnqGy(`wOor84JI=)7XarcdEMMAPSZZmTEF?rrg zyCiKhOs9GGX^MOF#s(p{{f9&{FLdxQ6^$+MC$)gMLEA?mu#ZL64iUW2!WUg(cSOpQ zK-u()PWd+F_DJ8q&fDrs^{eCKnqNeSKXXpt-Uq z$1|9-VBRAiq3bB6^~2RnBJ}-_W^ZR66y{S7ia2)LjnNL|G>^C#qTqeSGR-Fm3FMjI zu(-D3qYs1V*1jqFXB;#>XkF+gM{uQ$acVPu-nS^t z*s?s6Fe*Ql6oC@ke!`nE+LJ!cJ$NAF?IB`V-%0N=#qV{mTp!o7-;jX~*I~>aF<%K7 z32C3W6V9olrn%GKK(}#qWKb_pF7+&=dPi8Cz{WqHYX2#?&eLF~V#X`{VMg|j-NlR5 zxBojkn$j#d-*9>3V02dgU62bV5tKcxxzWPndK0!6AjQ^x4VU$serVDZ>KgHR$GiKh zrw__?RJ+87@LxUqvib@$i@>mi38Sya9;)(5ojs1ULjH^o$=1)85kGH=*4Dizvx96q3 z>d<#Ozkhkk?;v8*!bkw%^TQblC3D{V8gbV=VuP@aRJ3{z#@&k7&#J}aVf98|XM?kF zRWtliwc~Qb__~{8sYh-qLvp$ZL=X930!Vo#W{ZvmYd=wV|Hx9&TeG4b$l(tsB_Kq? zCBL0JGT<}`M-kiIUJS?f=0vCG2GEg%>k>7pltJUZUmn|WMWo4Yl(dC&`^E%tVqDvv zxs5cm4?xm1go*oB`DC=TyM{f=rvgP|02aJv_q~%5kY)^#~c=2Z*y@aB!71_He7;Ys`2|-Z1 z;Rl4?kTmdHRRwFIMtC!t6#W*+(c1Y?NRp|%ChB&C(XmKQb8I0Bxqqc?(ZjWRP^el< zMsU>DT9(KP*Rfuo6pYZuZI3ZNnBWoKs{0FMn6GIGT+3>32(_t7z^4nmQ7<_$skDE; zRJLNuYt&8Fi4qQ^5nI|{x?r!f^rm+hpJ-(!CtCM^SF(jSL>cJHeJuFplV)W5G+{ex z{N_sD4C}M@H}-VnC>6!wh7S?08BgNw8Cm==^W<@Pq~u;i%7h;1ZYpsr4ZNNl*HEa9 zAh}1spR8$hERtAA8o{6y%ea3GzD(%#9(vHqf2wkj>M&Eh>OHPt88PsK%se?aAhYHh zkwMC7g=Rh-QfH%ymd~%l_Hydz^j>SJ*(Z;52hpYzRQ$#k^~4b+))@r3s+(ugWtOTl zL`7t2UZNWPZ0$TeqCTabJTSV0*sxFW-@>l8c5WYiZ&9NXv8#v!Z$b#w@c_ZuN+qR+ zEVV{b9jEc4gG+A@jDAwz+w^+dq=^y_@KDA%s>ab#gvkJ2;`S#vuUL=#K3;U}cLeVk zMN?$VoXw8jMA{flpr(9fSC7Y2h5rC*=%rh~Lsg%^1LNSS9yY{?cnUQKh~9ZWQ+4Ec z5E0Z4ceG>Ot0{}cq>VRJc^<`tVXAa^#I+;W?LuNeG#kaIXYWZWWg8Ezw-+Un&+k%C zP)YD}pvN-0EDLs2j)f~FsGTY5?P)SqNM-OSj#Fc`b^PGK`3`Y_svTT#q}Vp~dF6mw zyt8dj*r#rtCGstPi7-X0JBE{%Gj-Aywt$v^8*30Rr+U>?}6ASsH#CtpgKJbhm zq2(sW2hHa#2att0d#m!uoCEXbJ{_E8qu{sVi?~1T8usZFyV*l;>4@yUF|&of{Xh5o z_IWu=&pt#XwmZ#0gZ^v&E_6z+CE_Svq3B@}P@W0r++xaaP!>oVjLzkx1201OfDXmI zd;0>g8?ECSY{>?TvXn9DPH&)-mow;>#+AM3hn|V9Wh+aG_aew8!kc#pA$7kELz$)x zE?ruGf=euBG*$zg|CSOF7&gla>4B(HBo>bh7=RYu-^%NqA1Xe-ZEw zBZUE!Z$ST>+vkWYjCx>MV*smj3)cpR@kzaxA4tS)E=m8G;>TqLflFfBGm^G%Ta2|R zm2ZDXHS}2U5=S%gA4XL~sbp;bdKB~Z*~-dJU+=2`@fy9Tc9mE0GYsQq2jb|&299p zCrc%`@?d#=PQx#&unmSO2&5UsDe{<2lkRHKgMyy#-Ai!d_*%|3*EBDqH6IjxvjF>a zjJ-ZFSZMQh$@x6Ba8fZzedss$ILWdCPF;W7n8)oiRv6AmMaOVfM^1VE5t!`zmO)Ux zA3th!aYbvzDIoB^fA#1$yr*H?jxD6_Z3F*jTM}`XcRb2uVDHA9?VR^Gv(|_Dz#g%M z)*pT?`^Ee==tHHwXiD{?9Pe)V@KNbyid-UVzmCOvu7Tbg3tob?m%$vT%xLxtTF0#m zBu~zhb>Vd0+55n22;U(S-6P}(SG7cwD^5ThvnooQNmvPb{`W=j24otayWeDb3TW4E z;qp?OD{%cXwt)yw7%qI2t=m%*c2)BtZoKX2vdGx}Aa;$o8_Y${xuDvS0!!W6@{@%K zX!VhB`CHe8}-7SHy&?av_ z6>+;_yhhCaTug;Rp?Z?T$bMt3bk8AGYx=BxfM>H4jw;XUKYcS;CyJkZenY>NW$?RW zjgcdHE8RWEoga;N&1)~59h_cvge;GOG$~{h-djCC zpy};=q&1a`SyHkC;;JT6d~04Zg=kW#G5e-JD)KWlh-oLkmA>;`@OE`C?~fFd~Q6Mm4GQ}5C! z7QmCfU2WNzK3T+H>xhj0`q_E;53th>Q=0v02~HNrP3u9mr0i=1G=Ugo=5s*g^j7n4 z+4+Vay_-XVO;@=~ne9Mn+HR$?M-+RjIIEd&8qjM%-`)e&D#`dlC#%S_;4E-Ss5;26 zzJJ*!qMR5}HPBk@IgGG9$6sbXxG4T5gLL|y;y~lLAt6l2W=+$5!xb{x0MX^Dn=vU{ z_)&bIlgU=X-luagXy!S%X;0<2OvV^xuR33KQ$M{-EdxCpp-!da=pFDt&*=y$V=ZsO zP1O{v!lE*tg&aqM`SBZJ2*gqqUKsfM4+z>HfdIZvFs179BK|7(cNLR(?H5|Z*JKWV z+03?_1KyuVFHakUPvjDnn-yl5vPfk{R|ab|NcU|oww@WrH*P3$4NjDg6|E;l)E>?v zUQ>29M&=iSJ}oxFGt*hqx6Cxcy?F`2tq+Lq_V5UNOMSr&pqzYoVC6qjSzf-$7#21Y zsP3C+q-f`p6H!z~=`yF}Y8GOe}C?d(Sq?bS=1JFr)?43uvXeiYX(Wyrd= zw|&*;(hC@9@9vLC_s31vpWUL{pZU&l(|=0rvMDR}f5hQer$V-=J3BibrqRBuo-mBA zzy{c~P6NG*>Obx)mW@?Sy{l>4RW!dr!_oY@Vp_oWN;(+vnCtSh%W4jil3$NdXG7dXy{={&J>h0r%| zA=IjdI&1f-imZcC3B3YpwS=)Xe;G~x_MNDp!NFzT{7d~Utxd$*I`mHwP_`ePNi-$U zjj#$XTYCyK?%3emT6?H2%F>&etj7*J`oWNXrsq6i3_aBX(t5@Ts!N}cK(lI=n;!&; zDa*F=dIyqfZ?9nD5Gnm3kW&>@D_L}5Nv z--4Q}BhD_B)18%`%P1+UjT2sHqaJK=Z+V{buO@sGnr|6nuXFDU77|C-Pv*e)2TJN; zPz2ekpDP)4&JZ6ilSdHs8~2;R@C=5X4?_G%+KTx&IP5eNS?j3FXPI?QD=!#$d0(P) zjSM*l4maepIeixLb-GSRmXloTki$3<=v}(3S)olkQHEO3yYj?v5iK{`+B;@iBe5z~wS!7ZYD8*85af6Dd3}HV+w0XN=XIUOc^=2-^Zp>|ep^Z~ z>?sIX6w$$nC&UMG-Cg@SSu*MO`erGCwVmND-kvp zQzfO#pNA99-#La2DeW9I>l)w!(Zto1w#}Qq^Zsk<}C(K&u5NtSBqGfsGGe zO=VP?O4m_Mv_?-W9{x?sh_JmdQfLjgpTyEKJaB2!_Sb~ls3h_vl2HK{c|k2-C7xf zIII4o5WeftL{CpqGHc1o#P&U^!>Cdt^9{Bnyzv~XE{4(jS(! z$~9T*rphXnnaC9=c_E|TI{Uswq)o#BJj zL;c$7_?IzgU7uUv^V^GFWb&TBB2Po=oWrTFxM(onWm)dGwAOi?V&KkoVLDP<+{nXR z{c-Hn#+dFRVGY5P1au*Eit4KYqpM`&-TXdU75N#x@>=ixSIFHv&D;e~KhGlhv&-ix zY+IaVmyG3xqhnIEt9dK)v_pvpe9EP@%2Nh<6?8zE0Wm}$zBtI*3##o~M82&@<0BTD zR{puiEk&w~HU7I!^NJH97U%4&ze`jY0jN8i60WL+u_kKcfk&ce%OzTbjhO74)`DKv z2@jhzqP4xTDOZ-R*`}0o_i&GSqXSm$bFJ|Gd$i589-0C=Sj#%?DYcetr87$4beA+`wZGh25Ah zi6uCeZ!I)?IBA*#DikQ!=9Z9{1+_PXdr7u6coSp0@qU9{ffnf%#+^OvI=x z!9qA6IP8ylq5h7?f-(;KsaUznyrWCtyMDRM&1ue3`;C{|P2sqj{YOQ0EGM&As@ldh z5tC^;oYg5zQQPk7%JA7Wq%11Io0QB7MfWwR_NzbRxETmC5?Xmzt1L8rk;sz zJ@(+lhi`w{n)wljgHAjC!1{ zAL6zdqs~}IR9{^Ntq;0nPj|D;ZQBWw-v} zl1dR@lEWs%IYK`4+x5AzzacfWJZ-6SKa@`$^P3b|AC9^sC*xMTptq(4sm|YUr;bON zVff>b$hxyjq4A@m1X>ALv0AQFVhcZ9)U&J-(U*Jzu@!|jy;(3rTW!!BtuyjQSMNPV zPn|Ce=uYY%dB4r024(SFf_6)l`85SbdWWla*h8CL$aur;;w{x%>QnRuG>=yX)yh0Y0<-AxlEot4e%xS1&!Xh=2x- zA?x1+^}ZmhtsHet@buY>Lp8Q2uOj1oaKTLIpNZ!ZHa*G50x4P#m++5t9~3TsgnknY zzOT;GM(uVl@dcMw+%CZJ_?4!!oGDs0SNGprPmLs9J#?ZrN!8lhuAO_|$DvviL8v4> znbH2t7L@Y{?{8h5}E{QRfN$rl)D+v=l@x4b%RvO;-uHyQ8eL z`0=pD5xK+V8d3C=wlLP+G%#H^qO+hGe#MMyyH&CuV^ml&*>GWQxv76`4Kdb=H4iGe zL2xyXs(NCwnEcdHJ=T2iy>4nxpjyQ`^QL~RhbGxZ;0u*_($$ryCe^miF0v81;!wUyq_#`Wh#sxa0UsM-^$ZG&f`d1!UH$8 z8c(eskn|^RQ=en=VB+Z@U7ATRinq7?xVZixBtX3<1A8LTPgjYk0dJvN3M|RAz9VUY zPo@hJf`Dcq;TaZx!JBJ1Gt9vV&Q{-`2vS`(UGAMV_~XHej)o-km(;Q&YcymBW83zJ z5g#fuBPs;#uNJ`UsdV&hIa7OElDNAov|sY528#lHe($8iO3HB93fuq(8ZsAZ2btc@w}m@=E{_$S>0W)Yu)V=_ zJw4G^Eleq#OVPJso^9iw#&4v{j4_G(zsV(F)V^A9sWOYIl-&?B=c`USbcnr=n3oD? z+a7KEeQMNd2=6QhEMT|I12blRq*5RDrj9pY)9y*f+*vqJ=PmbOUON};ZNzvW)$ifG zpu6Ltu+bV+f~WN?2FOEehkteWq0%+c(KGd#`MYTduby)#`i`IE<@ge+Q-3u5iqht> zE7Q;rQ4jz((343x$)Ij;)Gw*Idv;>Ud$5UA@75<5s~(e7JtP;jKPNf$eOv#=@3^W} z+A~I`nSFEE+I~4Z+PY$l7|Cv5j#_mCjr`B*Lg~|6zR(+!y+5NE-UWQtmm(*nmk3Hp zZw`sS4nHL9k`uo0oOej`^c#qAB$>#)jGYVDicGU?GnsQvwqjS7dYONCc+f+95joR9 zvwztpFMeRS(MDEUpS!*XO4roX0W+WjhfBf8pW55u@AB#W-9&hz=r{sqCz;pB=H*}r z$LHIj9T;IMu1bRb(7cRyS?CWZQ42q@^rb5k8`TVQszQ>s1j^!+vTPjLO}bdCkax*k z@_()ide_@&uu9aUtoVmKgulCkjSPZ)zk5zH@I#MTQQZX`cNu?O;|;1c+K7lTKET}F zx;g*P6N%8~DKCFh)yWv-)WXcP5JnzFW%yk6=%Pr1xu3N8$|ypuHA`>5Yb}j7AGyh% z=FsvPe$aXkopEV>(1Q;-=o?zJ^x`yw-DR+!g;TKhsH;ZA92AEU63V{0+*==WXX%vD zTmO+M1GSkhZ0UY;hCQymp2u%=R~F#JbXqj`?M0dDefjh6_@T{`GfdDuZqH=&;lcdz8EJC2OPuHv8@VH#_0d5bI~3jgMc{AM8PFuTKAfy>2~T%~+3@A59_U zvF13>jD=cjYR39>Tj$-nW_{%LYF97onR>#aj=OvthL>--_ZW9rGrXWp*F97kKa-0b zt2Zf3`;PosaA$K`Wks@`tSTmMj35u1bdJo3J&uh0-Dr!)POT|Rp3;OIe(!qrX*&K2 zY~quRquYHVLfHu4H|kqQQjC@~*Q+vfCYBLpUq+frMbQY@qQZ0D$r#>d7i`TD+NG{6 zW4;E6B~t>mWaqm#VT9{RN7`m!^49J^NZW0%4&eeZSnDb0yqE9G(S?NNIOW z9LKHaPoyD-f!X>i&+AuDDySxw#Cu;a!5;I~+#7>PKW_)uF4{J8>^n9uUp-6x=YF3U zGl7gz`2iHg+tMVI()#Ooj)v;rcB<<`CTA0`3Lh(mK-hUqS|>}cR8@Zdo7y`oxBKKr zkDl=tjE0gEc6uu*%fwg)8tcw9c1CTGZz3KpDS|EW=@I!fw_e;DAmESeHtEih0#hP? zHXIl4-(jD8y31`##&05+_moCVe80bsrK<&R3S9hTuqj(*XTnI0s*O9GSRN37f8<<# zOf^2_^EfA3&U146y%B$K<*1s9*ulpbibO8Y&G~v-htyi$hLS{o!b6)J^VO?kH}WzD zxjJmG0O+KmRIei8?2B^t!cb8O#h86@;dMRLny`IcLd{dfH%kcl3DIEk7bDT~?Vmo? zmPr;LM6x4vT9@%|4gh6<1J?C4`u)tj{Ywssu8s4rZ%o%xeu)JL44;K%#Ehx^`!WOn z>%dNc+#}CV*a|on-1rfY2qFheA6HGSaoBB=Vh3V0BVep+r4#Qei8Qz(C4^P@E-M9w zf}h?>ck_%rvl6;LYqw6!WPZRVftcCt-|yM8qLbr=y{uvRfY%Lk@odfY(KY8bNs(-K zdamOqD`%sC{70-~Y0{>q%et!Fe&XbgiFyF<+TYcTWu_>iz{p>r(V!garTtxS`kHNz z5x->Ue8h0ld}Hj{J-w+E%)aRO^7m3^uHc5spxHIGMp(CrNaEV|fCe(sLTQPisM~v; zrBtKU`-DYG*tY3>I+zxwNCT>HHcT&L1XAxer#p<`F>)5zGdnhS9JG+?Ck~lJjf;%0 z4p-_Az8~1(9Pc~{BgF%%cKEd^{L9Zt1&3}5&n;w|NPEws?-+(H*$ZsJUAMcH%;Yjv zga7zoA}7y0%Sa5?ovI6z=DYA|D=?2^eAAJR_OA||qse)36xQzASJ3RFOsp$fuGtc* zq_#@H9{lkwA#LVDj({40z*egtm!d6Xc1&R_-K7YVRL3JnxtlruJVB|=9Vt(oGWaBp zl@tzMfTqhUj~OMhv=cP{lwalJzAafrB^-l155V(u!lwU{s`kdR=l^t)bOe-SSC^1p zIbUB4$I2R{OxBo*H03{X=gXjPM>F|zcfaa4L<`niiOdHsZOSx>Ep0e{u-@1&YQ42M zj&nMN8c@u=cf&l8g3$e9`f?dhbcm|NJMk*2nnX~4Jh|8c`Pj2=Hlzvm`UVRMKa(g} zX(nR0WAQ{d{yv&H7v7sFU@V_DiXx#B|C^VAV0?fAUJ=rLL5Y`M26hgM4OHb?#x3=) z`V|LgSaypr#i?IIWoqEB#92~t`g^yX+|gyB`goDhC(IV2bWviegHL!GOJu-dDT`qv z_h9#-Tb8F7`=@w>#r_YQFTPx3le%UPZ3P%j_eH(Rhdjb!zu3h8N-S)fWP^&ZJjBVqE!%+s(g4=o*u zS6m$Mwn+|iHKe782Qs9%nBk^v!y6R)7TQzhkr5)I0~W(sJ8Wxma9g_TS;bz^)|dHa zD|U(RN!z1%=e)`gFTP;_;kdk&WG0dlE89W`XA*MbM84G58?l8L+{y~qMZ}&sn$!o48(?3h! zcGFH&Y!W?#Rf}IDH&~YGet}62jJK})clMI8{KcXukU&ojnDRAagL|?Sl;^)>Zo3ij z%QA3bW47pr6;a8J}qE)_U+2RGmDz4_3<6Ab-NA|WI*&jym>-zTTi!#W)g zl7E82;51%ike~6dIB=hSJ3NWJp(i&-nf8ByiFH97ZdivR3{&NE{n@ESB$C zr4Imhy{>#Qn_Ec^?!Wo#>>c#gBn)>t=$t`iUB0T<`^bDz&;2`?GoJGXu{nV)D%cpk zap|8w5$7DwQVaSPo-)UNpFuAEyScu5^*K*v3f})vHGEX(s^o;< z#I2>$tMR8?++;)Xf9|2x0PLTB6IyWl{msp!87P6cYissU~A3WK!YBPfPN5WG> z`He?8vxcr{doJX<5GrQC4N6%_rdvg%0Ddv4z)>y5_Ekc%k7CHuBfR)&A1s44>ZAI= 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 /> + } /> } /> } /> }> @@ -224,6 +228,17 @@ export default function App() { }; }, []); + useEffect(() => { + function onKeyboard(ev: KeyboardEvent) { + if (ev.key === 'F1') { + return open(DOCS_SITE).catch(() => window.open(DOCS_SITE, '_blank')); + } + } + + document.addEventListener('keypress', onKeyboard); + return () => document.removeEventListener('keypress', onKeyboard); + }, []); + return ( diff --git a/gui/src/components/MainLayout.tsx b/gui/src/components/MainLayout.tsx index 6cf12ea4bd..9277833aba 100644 --- a/gui/src/components/MainLayout.tsx +++ b/gui/src/components/MainLayout.tsx @@ -21,7 +21,7 @@ import { ClearDriftCompensationButton } from './ClearDriftCompensationButton'; import { useWebsocketAPI } from '../hooks/websocket-api'; import { useStatusContext, parseStatusToLocale } from '../hooks/status-system'; import { Localized } from '@fluent/react'; -import { WarningBox } from './commons/TipBox'; +import { TipBox } from './commons/TipBox'; import { useAppContext } from '../hooks/app'; import { TrackingPauseButton } from './TrackingPauseButton'; @@ -133,11 +133,11 @@ export function MainLayoutRoute({ vars={parseStatusToLocale(status, trackers)} key={status.id} > - + {`Warning, you should fix ${ StatusData[status.dataType] }`} - + ))} diff --git a/gui/src/components/TopBar.tsx b/gui/src/components/TopBar.tsx index 3ab59affa0..d3ac45770b 100644 --- a/gui/src/components/TopBar.tsx +++ b/gui/src/components/TopBar.tsx @@ -15,8 +15,9 @@ import { ProgressBar } from './commons/ProgressBar'; import { Typography } from './commons/Typography'; import { DownloadIcon } from './commons/icon/DownloadIcon'; import { open } from '@tauri-apps/api/shell'; -import { GH_REPO, VersionContext } from '../App'; +import { GH_REPO, VersionContext, DOCS_SITE } from '../App'; import classNames from 'classnames'; +import { QuestionIcon } from './commons/icon/QuestionIcon'; export function TopBar({ progress, @@ -115,6 +116,17 @@ export function TopBar({ className="flex justify-end items-center px-2 gap-2 z-50" data-tauri-drag-region > +
+ open(DOCS_SITE).catch(() => window.open(DOCS_SITE, '_blank')) + } + > + +
appWindow.minimize()} diff --git a/gui/src/components/commons/TipBox.tsx b/gui/src/components/commons/TipBox.tsx index f4a83ed7c2..441b5ee6d1 100644 --- a/gui/src/components/commons/TipBox.tsx +++ b/gui/src/components/commons/TipBox.tsx @@ -4,14 +4,32 @@ import { WarningIcon } from './icon/WarningIcon'; import { Typography } from './Typography'; import classNames from 'classnames'; -export function TipBox({ children }: { children: ReactNode }) { +export function TipBox({ + children, + hideIcon = false, + whitespace = false, +}: { + children: ReactNode; + hideIcon?: boolean; + whitespace?: boolean; +}) { return (
-
+
- {children} + + {children} +
); diff --git a/gui/src/components/commons/icon/PauseIcon.tsx b/gui/src/components/commons/icon/PauseIcon.tsx index bef56c30d5..1d83b1c2df 100644 --- a/gui/src/components/commons/icon/PauseIcon.tsx +++ b/gui/src/components/commons/icon/PauseIcon.tsx @@ -1,6 +1,6 @@ export function PauseIcon({ width = 33 }: { width?: number }) { return ( - + ); diff --git a/gui/src/components/commons/icon/PlayIcon.tsx b/gui/src/components/commons/icon/PlayIcon.tsx index b414622b57..6b8a89a09d 100644 --- a/gui/src/components/commons/icon/PlayIcon.tsx +++ b/gui/src/components/commons/icon/PlayIcon.tsx @@ -1,6 +1,6 @@ export function PlayIcon({ width = 33 }: { width?: number }) { return ( - + ); diff --git a/gui/src/components/commons/icon/QuestionIcon.tsx b/gui/src/components/commons/icon/QuestionIcon.tsx new file mode 100644 index 0000000000..88f626b757 --- /dev/null +++ b/gui/src/components/commons/icon/QuestionIcon.tsx @@ -0,0 +1,17 @@ +export function QuestionIcon({ width = 35 }: { width?: number }) { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/TaybolIcon.tsx b/gui/src/components/commons/icon/TaybolIcon.tsx new file mode 100644 index 0000000000..0650e89246 --- /dev/null +++ b/gui/src/components/commons/icon/TaybolIcon.tsx @@ -0,0 +1,22 @@ +export function TaybolIcon({ width = 784 }: { width?: string | number }) { + return ( + + + + + + + ); +} diff --git a/gui/src/components/commons/icon/TrashIcon.tsx b/gui/src/components/commons/icon/TrashIcon.tsx index 74c87d7ee4..98bc81cfc0 100644 --- a/gui/src/components/commons/icon/TrashIcon.tsx +++ b/gui/src/components/commons/icon/TrashIcon.tsx @@ -4,7 +4,7 @@ export function TrashIcon({ width = 33 }: { width: number }) { xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={width} - height="24" + height="29" > >; highlightedRoles?: BodyPart[]; onRoleSelected: (role: BodyPart) => void; diff --git a/gui/src/components/onboarding/pages/CalibrationTutorial.tsx b/gui/src/components/onboarding/pages/CalibrationTutorial.tsx index fb96a18a32..570015acbd 100644 --- a/gui/src/components/onboarding/pages/CalibrationTutorial.tsx +++ b/gui/src/components/onboarding/pages/CalibrationTutorial.tsx @@ -9,6 +9,7 @@ import { ProgressBar } from '../../commons/ProgressBar'; import { LoaderIcon, SlimeState } from '../../commons/icon/LoaderIcon'; import { useCountdown } from '../../../hooks/countdown'; import classNames from 'classnames'; +import { TaybolIcon } from '../../commons/icon/TaybolIcon'; export enum CalibrationStatus { SUCCESS, @@ -66,7 +67,7 @@ export function CalibrationTutorialPage() { } }, [calibrationStatus, l10n]); - applyProgress(0.45); + applyProgress(0.43); return ( <> @@ -137,7 +138,7 @@ export function CalibrationTutorialPage() {
-
- +
+ + {/* */}
diff --git a/gui/src/components/onboarding/pages/ConnectTracker.tsx b/gui/src/components/onboarding/pages/ConnectTracker.tsx index 3166206fdc..d266f18468 100644 --- a/gui/src/components/onboarding/pages/ConnectTracker.tsx +++ b/gui/src/components/onboarding/pages/ConnectTracker.tsx @@ -217,7 +217,7 @@ export function ConnectTrackersPage() { ? '/' : bnoExists ? '/onboarding/calibration-tutorial' - : '/onboarding/trackers-assign' + : '/onboarding/assign-tutorial' } className="ml-auto" > diff --git a/gui/src/components/onboarding/pages/ResetTutorial.tsx b/gui/src/components/onboarding/pages/ResetTutorial.tsx index aac7c6d764..c030ad6f60 100644 --- a/gui/src/components/onboarding/pages/ResetTutorial.tsx +++ b/gui/src/components/onboarding/pages/ResetTutorial.tsx @@ -2,58 +2,221 @@ import { useLocalization } from '@fluent/react'; import { useOnboarding } from '../../../hooks/onboarding'; import { Button } from '../../commons/Button'; import { Typography } from '../../commons/Typography'; -import { useState } from 'react'; +import { useState, useMemo, useEffect } from 'react'; import { SkipSetupWarningModal } from '../SkipSetupWarningModal'; import { SkipSetupButton } from '../SkipSetupButton'; +import { + BodyPart, + ResetResponseT, + ResetStatus, + ResetType, + RpcMessage, + SettingsRequestT, + SettingsResponseT, +} from 'solarxr-protocol'; +import { useTrackers } from '../../../hooks/tracker'; +import { BodyDisplay } from '../../commons/BodyDisplay'; +import { useWebsocketAPI } from '../../../hooks/websocket-api'; +import classNames from 'classnames'; export function ResetTutorialPage() { const { l10n } = useLocalization(); const { applyProgress, skipSetup } = useOnboarding(); const [skipWarning, setSkipWarning] = useState(false); - + const { useAssignedTrackers } = useTrackers(); + const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); + const [curIndex, setCurIndex] = useState(0); + const [tapSettings, setTapSettings] = useState([]); applyProgress(0.8); + const assignedTrackers = useAssignedTrackers(); + + const highestTorsoTracker = useMemo( + () => + assignedTrackers + .filter((x) => + TORSO_PARTS.includes(x.tracker.info?.bodyPart ?? BodyPart.NONE) + ) + .sort( + (a, b) => + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + TORSO_PARTS.indexOf(a.tracker.info!.bodyPart)! - + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + TORSO_PARTS.indexOf(b.tracker.info!.bodyPart)! + ), + [assignedTrackers] + ); + + const highestRightLegTracker = useMemo( + () => + assignedTrackers + .filter((x) => + RIGHT_LEG_PARTS.includes(x.tracker.info?.bodyPart ?? BodyPart.NONE) + ) + .sort( + (a, b) => + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + RIGHT_LEG_PARTS.indexOf(a.tracker.info!.bodyPart)! - + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + RIGHT_LEG_PARTS.indexOf(b.tracker.info!.bodyPart)! + ), + [assignedTrackers] + ); + + const highestLeftLegTracker = useMemo( + () => + assignedTrackers + .filter((x) => + LEFT_LEG_PARTS.includes(x.tracker.info?.bodyPart ?? BodyPart.NONE) + ) + .sort( + (a, b) => + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + LEFT_LEG_PARTS.indexOf(a.tracker.info!.bodyPart)! - + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + LEFT_LEG_PARTS.indexOf(b.tracker.info!.bodyPart)! + ), + [assignedTrackers] + ); + + useRPCPacket( + RpcMessage.ResetResponse, + ({ status, resetType }: ResetResponseT) => { + if (status !== ResetStatus.STARTED) return; + console.log(status); + if (resetType === RESET_TYPE_ORDER[curIndex]) { + setCurIndex(curIndex + 1); + } + } + ); + + useEffect(() => { + sendRPCPacket(RpcMessage.SettingsRequest, new SettingsRequestT()); + }, []); + + useRPCPacket( + RpcMessage.SettingsResponse, + ({ tapDetectionSettings }: SettingsResponseT) => { + if ( + !tapDetectionSettings || + !tapDetectionSettings.yawResetTaps || + !tapDetectionSettings.fullResetTaps || + !tapDetectionSettings.mountingResetTaps + ) + return; + setTapSettings([ + tapDetectionSettings.yawResetTaps, + tapDetectionSettings.fullResetTaps, + tapDetectionSettings.mountingResetTaps, + ]); + } + ); + + const order = [ + highestTorsoTracker[0], + highestLeftLegTracker[0], + highestRightLegTracker[0], + ]; + return ( - <> -
- setSkipWarning(true)} - > -
-
-
- - {l10n.getString('onboarding-reset_tutorial')} - - {l10n.getString('onboarding-wip')} - +
+ setSkipWarning(true)} + > +
+
+
+ + {l10n.getString('onboarding-reset_tutorial')} + + + {l10n.getString('onboarding-reset_tutorial-description')} + +
+ + + + + +
+
= order.length && 'hidden' + )} + > + + {l10n.getString(`onboarding-reset_tutorial-${curIndex}`, { + taps: tapSettings[curIndex], + })} - - {l10n.getString('onboarding-reset_tutorial-description')} +
+
+
+ +
= order.length && 'hidden' + )} + > + + {l10n.getString(`onboarding-reset_tutorial-${curIndex}`, { + taps: tapSettings[curIndex], + })} -
- - -
- setSkipWarning(false)} - isOpen={skipWarning} - >
- + setSkipWarning(false)} + isOpen={skipWarning} + > +
); } + +export const TORSO_PARTS = [BodyPart.CHEST, BodyPart.WAIST, BodyPart.HIP]; +export const LEFT_LEG_PARTS = [ + BodyPart.LEFT_UPPER_LEG, + BodyPart.LEFT_LOWER_LEG, +]; +export const RIGHT_LEG_PARTS = [ + BodyPart.RIGHT_UPPER_LEG, + BodyPart.RIGHT_LOWER_LEG, +]; + +export const RESET_TYPE_ORDER = [ + ResetType.Yaw, + ResetType.Full, + ResetType.Mounting, +]; diff --git a/gui/src/components/onboarding/pages/WifiCreds.tsx b/gui/src/components/onboarding/pages/WifiCreds.tsx index 2e9aa844c8..382dc7c094 100644 --- a/gui/src/components/onboarding/pages/WifiCreds.tsx +++ b/gui/src/components/onboarding/pages/WifiCreds.tsx @@ -101,7 +101,7 @@ export function WifiCredsPage() { to={ bnoExists ? '/onboarding/calibration-tutorial' - : '/onboarding/trackers-assign' + : '/onboarding/assign-tutorial' } > {l10n.getString('onboarding-wifi_creds-skip')} diff --git a/gui/src/components/onboarding/pages/assignment-preparation/AssignmentTutorial.tsx b/gui/src/components/onboarding/pages/assignment-preparation/AssignmentTutorial.tsx new file mode 100644 index 0000000000..864c9ba20a --- /dev/null +++ b/gui/src/components/onboarding/pages/assignment-preparation/AssignmentTutorial.tsx @@ -0,0 +1,104 @@ +import { useLocalization } from '@fluent/react'; +import { useOnboarding } from '../../../../hooks/onboarding'; +import { Button } from '../../../commons/Button'; +import { Typography } from '../../../commons/Typography'; +import { useState } from 'react'; +import { SkipSetupWarningModal } from '../../SkipSetupWarningModal'; +import { SkipSetupButton } from '../../SkipSetupButton'; +import { useTrackers } from '../../../../hooks/tracker'; +import { useBnoExists } from '../../../../hooks/imu-logic'; +import { StickerSlime } from './StickerSlime'; +import { TrackerArrow } from './TrackerArrow'; +import { ExtensionArrow } from './ExtensionArrow'; + +export function AssignmentTutorialPage() { + const { l10n } = useLocalization(); + const { applyProgress, skipSetup } = useOnboarding(); + const [skipWarning, setSkipWarning] = useState(false); + const { useConnectedTrackers } = useTrackers(); + const connectedTrackers = useConnectedTrackers(); + const bnoExists = useBnoExists(connectedTrackers); + + applyProgress(0.46); + + return ( + <> +
+ setSkipWarning(true)} + > +
+
+ + {l10n.getString('onboarding-assignment_tutorial')} + +
+
+
+
+
+ + {l10n.getString( + 'onboarding-assignment_tutorial-first_step' + )} + +
+
+ +
+
+
+
+ + {l10n.getString( + 'onboarding-assignment_tutorial-second_step' + )} + +
+
+ +
+
+ + {l10n.getString( + 'onboarding-assignment_tutorial-second_step-continuation' + )} + +
+
+ +
+
+
+
+ + +
+
+
+ setSkipWarning(false)} + isOpen={skipWarning} + > +
+ + ); +} diff --git a/gui/src/components/onboarding/pages/assignment-preparation/ExtensionArrow.tsx b/gui/src/components/onboarding/pages/assignment-preparation/ExtensionArrow.tsx new file mode 100644 index 0000000000..a27215e1f4 --- /dev/null +++ b/gui/src/components/onboarding/pages/assignment-preparation/ExtensionArrow.tsx @@ -0,0 +1,35 @@ +export function ExtensionArrow({ width = 731 }: { width?: number | string }) { + return ( + + + + + + + + + + ); +} diff --git a/gui/src/components/onboarding/pages/assignment-preparation/StickerSlime.tsx b/gui/src/components/onboarding/pages/assignment-preparation/StickerSlime.tsx new file mode 100644 index 0000000000..abeb81a0be --- /dev/null +++ b/gui/src/components/onboarding/pages/assignment-preparation/StickerSlime.tsx @@ -0,0 +1,47 @@ +import { useLocalization } from '@fluent/react'; + +export function StickerSlime({ width = 820 }: { width?: number | string }) { + const { l10n } = useLocalization(); + return ( + + + + + + + {l10n.getString('onboarding-assignment_tutorial-sticker')} + + + + + ); +} diff --git a/gui/src/components/onboarding/pages/assignment-preparation/TrackerArrow.tsx b/gui/src/components/onboarding/pages/assignment-preparation/TrackerArrow.tsx new file mode 100644 index 0000000000..5ba3e53384 --- /dev/null +++ b/gui/src/components/onboarding/pages/assignment-preparation/TrackerArrow.tsx @@ -0,0 +1,34 @@ +export function TrackerArrow({ width = 1300 }: { width?: string | number }) { + return ( + + + + + + + + + + ); +} diff --git a/gui/src/components/onboarding/pages/body-proportions/ProportionsChoose.tsx b/gui/src/components/onboarding/pages/body-proportions/ProportionsChoose.tsx index 704ed9ad95..d54e1dab95 100644 --- a/gui/src/components/onboarding/pages/body-proportions/ProportionsChoose.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/ProportionsChoose.tsx @@ -63,6 +63,13 @@ export function ProportionsChoose() { {l10n.getString('onboarding-choose_proportions')} + + {l10n.getString('onboarding-choose_proportions-description')} +
diff --git a/gui/src/components/onboarding/pages/mounting/MountingChoose.tsx b/gui/src/components/onboarding/pages/mounting/MountingChoose.tsx index 186f9c936b..59081e9a16 100644 --- a/gui/src/components/onboarding/pages/mounting/MountingChoose.tsx +++ b/gui/src/components/onboarding/pages/mounting/MountingChoose.tsx @@ -6,6 +6,7 @@ import { SkipSetupButton } from '../../SkipSetupButton'; import classNames from 'classnames'; import { Typography } from '../../../commons/Typography'; import { Button } from '../../../commons/Button'; + export function MountingChoose() { const { l10n } = useLocalization(); const { applyProgress, skipSetup, state } = useOnboarding(); @@ -26,6 +27,13 @@ export function MountingChoose() { {l10n.getString('onboarding-choose_mounting')} + + {l10n.getString('onboarding-choose_mounting-description')} +
diff --git a/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx b/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx index b471822a30..975e61aa87 100644 --- a/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx +++ b/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx @@ -28,7 +28,6 @@ import { NeckWarningModal } from '../../NeckWarningModal'; import { TrackerSelectionMenu } from './TrackerSelectionMenu'; import { SkipSetupWarningModal } from '../../SkipSetupWarningModal'; import { SkipSetupButton } from '../../SkipSetupButton'; -import { useBnoExists } from '../../../../hooks/imu-logic'; import { useConfig } from '../../../../hooks/config'; import { playTapSetupSound } from '../../../../sounds/sounds'; @@ -46,7 +45,7 @@ interface FlatDeviceTrackerDummy { export function TrackersAssignPage() { const { l10n } = useLocalization(); - const { useAssignedTrackers, trackers, useConnectedTrackers } = useTrackers(); + const { useAssignedTrackers, trackers } = useTrackers(); const { applyProgress, skipSetup, state } = useOnboarding(); const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); @@ -57,9 +56,7 @@ export function TrackersAssignPage() { const [selectedRole, setSelectRole] = useState(BodyPart.NONE); const assignedTrackers = useAssignedTrackers(); const [skipWarning, setSkipWarning] = useState(false); - const connectedTrackers = useConnectedTrackers(); - const bnoExists = useBnoExists(connectedTrackers); const { config } = useConfig(); const [tapDetectionSettings, setTapDetectionSettings] = useState diff --git a/gui/tailwind.config.cjs b/gui/tailwind.config.cjs index d4105ad9a7..66066afaae 100644 --- a/gui/tailwind.config.cjs +++ b/gui/tailwind.config.cjs @@ -158,6 +158,7 @@ module.exports = { xs: '800px', sm: '900px', md: '1100px', + 'md-max': { raw: 'not (min-width: 1100px)' }, lg: '1300px', xl: '1600px', }, @@ -219,8 +220,8 @@ module.exports = { 'slime-yellow': `linear-gradient(135deg, ${colors['yellow-accent'][100]} 50%, ${colors['yellow-background'][700]} 50% 100%)`, 'slime-orange': `linear-gradient(135deg, ${colors['orange-accent'][100]} 50%, ${colors['orange-background'][700]} 50% 100%)`, 'slime-red': `linear-gradient(135deg, ${colors['red-accent'][100]} 50%, ${colors['red-background'][700]} 50% 100%)`, - 'dark': `linear-gradient(135deg, ${colors['dark-accent'][100]} 50%, ${colors['dark-background'][700]} 50% 100%)`, - 'light': `linear-gradient(135deg, ${colors['light-accent'][100]} 50%, ${colors['light-background'][700]} 50% 100%)`, + dark: `linear-gradient(135deg, ${colors['dark-accent'][100]} 50%, ${colors['dark-background'][700]} 50% 100%)`, + light: `linear-gradient(135deg, ${colors['light-accent'][100]} 50%, ${colors['light-background'][700]} 50% 100%)`, 'trans-flag': `linear-gradient(135deg, ${colors['trans-blue'][800]} 40%, ${colors['trans-blue'][700]} 40% 70%, ${colors['trans-blue'][600]} 70% 100%)`, }, },