From df167ba1d855f185bd5ec87250149d320c8a5dc6 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 19 Jul 2021 13:26:54 -0400 Subject: [PATCH] Avatar editor works --- src/assets/images/avatareditor/ca-icon.png | Bin 171 -> 259 bytes .../images/avatareditor/ca-selected-icon.png | Bin 242 -> 335 bytes src/assets/images/avatareditor/cc-icon.png | Bin 281 -> 282 bytes .../images/avatareditor/cc-selected-icon.png | Bin 265 -> 338 bytes src/assets/images/avatareditor/ch-icon.png | Bin 154 -> 228 bytes .../images/avatareditor/ch-selected-icon.png | Bin 171 -> 260 bytes src/assets/images/avatareditor/cp-icon.png | Bin 234 -> 252 bytes .../images/avatareditor/cp-selected-icon.png | Bin 199 -> 280 bytes src/assets/images/avatareditor/ea-icon.png | Bin 155 -> 251 bytes .../images/avatareditor/ea-selected-icon.png | Bin 227 -> 298 bytes src/assets/images/avatareditor/fa-icon.png | Bin 140 -> 234 bytes .../images/avatareditor/fa-selected-icon.png | Bin 195 -> 286 bytes src/assets/images/avatareditor/ha-icon.png | Bin 156 -> 241 bytes .../images/avatareditor/ha-selected-icon.png | Bin 220 -> 285 bytes src/assets/images/avatareditor/he-icon.png | Bin 173 -> 267 bytes .../images/avatareditor/he-selected-icon.png | Bin 248 -> 338 bytes src/assets/images/avatareditor/hr-icon.png | Bin 173 -> 257 bytes .../images/avatareditor/hr-selected-icon.png | Bin 238 -> 348 bytes src/assets/images/icons/loading-icon.png | Bin 181 -> 222 bytes src/assets/styles/bootstrap/_variables.scss | 2 + src/assets/styles/icons.scss | 929 +++++++++--------- src/layout/card/grid/NitroCardGridView.scss | 11 + src/layout/card/grid/NitroCardGridView.tsx | 15 +- .../card/grid/NitroCardGridView.types.ts | 7 + .../grid/context/NitroCardGridContext.tsx | 13 + .../context/NitroCardGridContext.types.ts | 11 + src/layout/card/grid/context/index.ts | 2 + .../card/grid/item/NitroCardGridItemView.scss | 42 +- .../card/grid/item/NitroCardGridItemView.tsx | 7 +- .../grid/item/NitroCardGridItemView.types.ts | 1 + src/views/avatar-editor/AvatarEditorView.scss | 49 +- src/views/avatar-editor/AvatarEditorView.tsx | 103 +- .../avatar-editor/common/AvatarEditor.ts | 33 +- .../common/AvatarEditorGridColorItem.ts | 13 + .../common/AvatarEditorGridPartItem.ts | 28 +- src/views/avatar-editor/common/BodyModel.ts | 5 +- .../avatar-editor/common/CategoryBaseModel.ts | 6 +- .../avatar-editor/common/CategoryData.ts | 4 +- src/views/avatar-editor/common/FigureData.ts | 271 +++++ src/views/avatar-editor/common/HeadModel.ts | 3 +- src/views/avatar-editor/common/LegModel.ts | 3 +- src/views/avatar-editor/common/TorsoModel.ts | 3 +- .../AvatarEditorFigurePreviewView.tsx | 28 + .../AvatarEditorFigurePreviewView.types.ts | 6 + .../AvatarEditorFigureSetItemView.tsx | 25 +- .../figure-set/AvatarEditorFigureSetView.tsx | 17 +- .../AvatarEditorFigureSetView.types.ts | 2 + .../views/model/AvatarEditorModelView.tsx | 73 +- .../model/AvatarEditorModelView.types.ts | 1 + .../AvatarEditorPaletteSetItem.tsx | 26 + .../AvatarEditorPaletteSetItem.types.ts | 7 + .../AvatarEditorPaletteSetView.tsx | 29 + .../AvatarEditorPaletteSetView.types.ts | 11 + .../PurchasableClothingConfirmView.tsx | 3 +- .../shared/avatar-image/AvatarImage.scss | 1 + src/views/toolbar/ToolbarView.tsx | 15 +- 56 files changed, 1255 insertions(+), 550 deletions(-) create mode 100644 src/layout/card/grid/context/NitroCardGridContext.tsx create mode 100644 src/layout/card/grid/context/NitroCardGridContext.types.ts create mode 100644 src/layout/card/grid/context/index.ts create mode 100644 src/views/avatar-editor/common/FigureData.ts create mode 100644 src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx create mode 100644 src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts create mode 100644 src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx create mode 100644 src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts create mode 100644 src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx create mode 100644 src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts diff --git a/src/assets/images/avatareditor/ca-icon.png b/src/assets/images/avatareditor/ca-icon.png index 14de95e26f2463661578fb82fc04ffb8f74b791c..c9803b950578cac2d62297c3454c19d713d8d3c7 100644 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%3?x6Bmj(hU#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;R0X`wFt5>fEGQAZu5`h#`NswRge}<>q4ZMIn&H|6fVg?4j!ywFfJby(B zP_V+&#W6%9cxivM&;bRGBVYbaUzZ}j;r#qGEiW$#6-^2?(eU5WF z=e}LiFSy#}Q{B<&8e+XdhqzbXe^;Zro#VK=y~;z$35G^TvP-AE|1Ngu!j#@iZ#~zo yU2=cTt7)OftPg8F%Mapy_2BZ>_Fv}{&M})8G2XU!yUq=C1B0ilpUXO@geCx?xL;)e literal 171 zcmV;c095}+Nk%w1VHp4!0CxZYA^8LW00031EC2ui02u%o0D$@V`Tqd_2!a3u2pkBY zpuvL%2P!03P#^$@5CbG!DDh!Mga;j3WO$Jx!-owchV-Z~q{W6CNtUcAQKL$VCQrWf zcrxS6g$N_wB7`D?eh4inFTGlsJ(B9jS68QLIZL ZYTYSw>`<{rk2VFXmg-N96G;XH06UwrK05#a diff --git a/src/assets/images/avatareditor/ca-selected-icon.png b/src/assets/images/avatareditor/ca-selected-icon.png index 3f5cda18cf1d8dc82c9fe91c4cabf19c1c9b8644..b118c3ed606a0dcc4f80f16b734481d1f9648bf5 100644 GIT binary patch delta 319 zcmeywc%Es3WIZzj1H)(Y(m)`^SRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv=#@z$e7D z)QW#eiTI-f%Ksnu2X;BZzqy>)hU0a^L(Y$6|Im407jg!2!PpdggsS5W@{VjC1-t@7$ zjpi(i zubuxZA8#zW^pjCbIeg;IxD!$Nru)>tyP8z->4dg@TyW<5y?D8uTz_Zv9%}}=oWax8 K&t;ucLK6U5QHHYs delta 225 zcmV<703QF(0`dWn8Gi-<006}4g<}8!0J%v-K~zYI(b3-FVa`6Dn`Kzp7CnTBd+g67dC*026}v@9jFQd$g<-k?4067@nnSC#=x; b?up0-YC9%8wSEWh00000NkvXXu0mjf=(J~_ diff --git a/src/assets/images/avatareditor/cc-icon.png b/src/assets/images/avatareditor/cc-icon.png index 5099b67204c375f7d05f9c05b0451c7614941837..4a8844e49c173bce47e93ac4fdc082b9a02db93b 100644 GIT binary patch delta 266 zcmbQqG>d71WIZzj14HT#cOc2YSRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv@1(z$e6Y z_3G6?rnh27B9LM#3Gxg6&+v4+ffta+S>O>_%)r2R7=#&*=dVZs3if-tIEGmGPwfxn zJD|Yh^!4BLxJ<^mE9LjOr0z+}OP*vXQ~y0ivFjj*QZ`HVu?VSzKiB!vuWx77OUkj` z*Q~j_R<+;GOzz3i^kefD-cX9D_kI$pfA-&5{o2p-Uf675tIDta{OpnKrQgr~@ywgF zZi3Y8y(_~`-BS(?zFq!Z{p%8|g!AdupM{Sz@*SN1k!8j6KMa4qF>S0rcjgn&Z492S LelF{nof4V=4+Clh delta 265 zcmV+k0rviy0+|Ak8Gi-<002^Ew=w_#0N_bPK~zYI)mG6C10e`gQ QK#wqZy85}Sb4q9e0QFyi`2YX_ delta 248 zcmVbf>5E`bVU&CcX2{j7VI0l8HDo;4AyM`%Gx>(ez0%5T>2Z5yN7>l^5BvG;Yajh^ zmXMc0Y$caMb5{FhIk)!g-Ww9i|bM*~1`Iez)84fpnol+q2e&Nwrd*x=v*0000wb?FL>z9%q3^WHAE+-(e7DJf6QI z1t=Kl>Ealo5&X7~k?(*42lLba^W{V~SQz|1pm)n*^&_EV$rU_h0pd>j-2u&e-)(vP zNUl+1c3;|ef%UGYAEzee**{vhYQ6ZE<@M9e+aKobv|r+@T_0t6sc)AOzgZ4b(3$x= R{ehM+c)I$ztaD0e0su4!N%{Z) literal 154 zcmZ?wbhEHblx2`$C}&_${K>+|00cT90wmV(pW#0ca1=5ya)?MQNI2NY!70TvK|t|v zBe$|#%MF18&RwFqYI{63EOKd<7QvtYXYby9AtTu4%PmiZLn^zX1eC2N zny$Rfa7$GxKl@yvo`u)qpgb%0<)^Z(7kr+`+!65I%;K%5wT{!z6$;XmHyLdYn;E!v xs$;9E8Ef?C=eN?=-+lD{+WeZ0`5St7Ficv=@`S(Y+I*nJ44$rjF6*2UngCQATr>ax literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2QbnFFjv*eMZznnO9Z=w4Ir!th z{$*ib$D|dmy_(f7HyU?%xFnp=T6ERIDtd17-d*LAjMpE``#HT^x+0Wcxh=osu=j$M z;YS`!4GVq)$fu*)50$R^|L9Sb%Kv-ZSYQ0!f1lDO;W-ajNS%G}E0G|-o z)vH$nncj*Si9m{}B*-uLKf}}Q23|lOXMsm#F#`kNVGw3Kp1&dmC|Ky};uxY4yta>< zuR(#w`Qg9mWq);?BTWLOHJ17}8ZKlsObOh&^t4#$%!7WRg2vVVId>lLxTW!c_i3Zw zS~XdJJRM17vE{^uiN3+{;vy>a$an^Niuyad(Yk#Ki%A$Ycq zx&)zFjT9ZFp^QztPML^NI!iqf1$*gCkKFH#%uJ27Zr%4P`1UjU*SOWV2ZM+NS%G|^0G|-o z`Sa&5Tei%xL;K)wqnYPLfWoc{iU~l9tt7}V_&*3RY~H_QKTw3Tz$3Dlfr0NZ2s0kf zUy%Y7to3wp4ABT)J0Xy-L4n6v^vS>a@NKc%51jepTzhfZyGDuaj%G<`XY^0&YPIY! zD)V-}I#s7lnD$m^uB&++`OU3K1uuAk7GWpALd%gW75(;z)gQu&X%Q~k7 G#wGxLTxY5P delta 182 zcmV;n07?It0>=T68Gi-<008Z2O}_vD0FFsSK~zYI?Ulh2zz_^X!}$MSPA^TT!swFV zQ16Ij#R`F$sX}cq)E17$CNQuyj&3Fs*TSvjmWm7Uq$WlZ_V9>D$D}AM!Yf4uj@UYX zwh5=(?B3(nH@rJuDn?tygX~tn#b<1y$gMq|S$Xs2f`WkgPcP5^*G^me7(shx?c?L| kI#7=_=CAa4yapn=0N-I4I!*5a2><{907*qoM6N<$g8DC2eENn{1`*#dk*TvxAN4P<&NW+VbBrjj7P;QtIyw;Ol?d7K3vk;M!Qe1}1p@p%4< z6rf;%r;B5VMsR7LHy?u{kJItr@l_3%`rYm?V)g2|ZzR9bE{5xkV7rX@dY?&sNwHeW zSN4QiJ*xQj|&KtsII?S=#xz@NXRLSDxzI>gztmzv^kx13es6AH78|{>K_<6k* o^!+p0h3^gHS)UcX!YUeGT0cbaar>mdKI;Vst0AOQM?*IS* literal 155 zcmZ?wbhEHbRAvxhC}&_${K>+|00cT90wmV(pW#0ca1=2xa>!^HG&nZ12+O(5*zoWG z11rB(OvHsm=MDygsE~-lwImR2HTlYc&WK>f!vXcy^Y)_q`<= zg^OJ}Y(0Z`JU^>A%@j8^`Vw(zMbHwBg>E4lUzhqW6ke#;TXFgMxiyBJVzLqf4Aua1 Ck2U}R diff --git a/src/assets/images/avatareditor/ea-selected-icon.png b/src/assets/images/avatareditor/ea-selected-icon.png index 56c804c6200be332ba41be5f733be24fd4a98fda..e7678c4a6e23d14dce0ebe95250d35b4a9d2878a 100644 GIT binary patch delta 282 zcmaFNxQc0lWIZzj1HI_+Q(22yM#L4LtN!T0wMe=gS;`o)(NvD^$kv%@#D$~7T!(Y9+<@26hp|J$-6*2iO? z(t$H7`iGJ@3;G;R$8`K=aQG0Oru7dg`$;#b=6wJ6Kq|Ig}zPWydWVT ZD}0*uL$uyhZJ^^AJYD@<);T3K0RUFRZ8HD> delta 210 zcmV;@04@Kj0^95-(;N5*7BlHyDArU;CF7M>hgbye2A@=KnnjxLF{%oNn{1`*#dk*TvxAN4N|U{kqD%iN`m}?|1&(@Zr}yvaTa()7BevL9R^{>I6wS1U2bcM<}RJzH-BHSlk)88@eo+xZ`JbACQvcx@2m8x z>hj+b1??}UvYcGIY07rVBwe;SGc!LOx$d{SCG}YHh98TgE6YD#o0^k#=Ka~ch-a*q X?lT^D)k}>9TE*b$>gTe~DWM4fpL|kq literal 140 zcmZ?wbhEHblx7fNC}&_${K>+|00cT90wmV(pW#0ca3nJ@vT!ggNI2NY!K$Q^5wP%Z z8xOCW&5Z!XgB`+}VMl%#B)T@r>&l(^@iEDxL&3i&MAItEYc=P|P42d*KYl z2}=4K*?5v-COi^-n7ZO~A+wPJdrmj=#gpeOT{J=sxep5;`X)R@?au9O_pD>n>t4oR z+Zv^OPBDE^nTGw-V=K6WeQH;FT3l@Z`g}=RPv7lpac528Gi-<004Y~Mt}eS0E$UOK~zYI?Uc<9fG`My3-SG58IvX30rvyN zg9pEZONecQGQ`XPpgjNxp4g-&o4RLsD-o2fcVE+u!7Av)(&u_9z%%vHtz^yYlOIt+ zDDDjFdS_9ge=ns|Uq}R{b$&poe-YKO147|DI}zO)<<7F(q$?Cw<_|;Ro>5_CvSIAH gYJ7e`xUCQ11|LTiHQKRo&W#< diff --git a/src/assets/images/avatareditor/ha-icon.png b/src/assets/images/avatareditor/ha-icon.png index 06d6328b47536d07ad005cf2d01ec803feb27f1d..f0a819181a29792921dad2a3f95d3c8ff3d10ee4 100644 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3-ps5|6h4DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheYymzYuB%tC1~R=BGZKLmQ%R6t@PCG<+YP*cJkA1-$YKTtzQZ8Qcszea z3Q#c3)5S4FBY18er|(%y z{=_9$w%KyEub0!G5_Va3d5?Ed=dBWH?j1)iL|EQ>YM3Q*n0sTPNV)N)-v4J4t3UFb euC6ot?y~2F5aTSBDtA7hjSQZyelF{r5}E*2KvHM` literal 156 zcmZ?wbhEHblw=TNC}&_${K>+|00cT90wmV(pW#0ca1=8za>#fDBrq_rb8CfE7&shm z;Z~N?c@d!G+`(cPHD^b_V%L5S^SBa^pp;`>it=49GdCo9O%RSPn!-8h*@0=sn#aym z7^@tgYghk>$4W%`$U?jBPiIa}S#o)~U$v4;W>J>ws!;z!XSz&Zd#;yV*d_bgM1jE? E0Bi6!)&Kwi diff --git a/src/assets/images/avatareditor/ha-selected-icon.png b/src/assets/images/avatareditor/ha-selected-icon.png index 0d0d663844f911d6ebfe5b85e0f2d98ca7efd9ad..4c81ece52017e6bc405c53de21fe9909f3681724 100644 GIT binary patch delta 269 zcmcb^IG1UHWIZzj0|Qgy@fIM(SRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv@20z$e7j z$xQSAqeItrbS@}P1B&fbUGER1SWANZg8u^n!|!c;!9W4d0*}aI1_r*vAk26?e?GTD_M^4_x$mE+lPEP}n-L zE8uQ)^<>+_-)G)@ENs=Cs5~!i=j$55zN9Ecbq}#jv4|8Uzj7lQCHs3t3ZND~H# z!g2O0vBuRqvvN|B7Rbt4$=;_NVtW!zFf+a(QSlrgS)|32XGFDYwu+RnsDKj?uafQX z{s}v4%Wv&ps7Byw>xL<-%CSoqeGfO1Q=-$S!vBPXh%Sc=FeLpD0u}%O002ovPDHLk FV1nEuRYU*) diff --git a/src/assets/images/avatareditor/he-icon.png b/src/assets/images/avatareditor/he-icon.png index 5cc990dfce0c79cfffc39a745ec4153d92762a07..7cf6dc4c73ce9016b79aef9c886bbf842859c3b8 100644 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^@<1%j!3-ofKU^XUq!^2X+?^QKos)S9vjzBsxUOEk8p!lk%t!=MOeH~n!T%YaZa44(@;D1TB8wRq_zr_Gpyr+tv%qUoUrjoH&hw1Q2zL$r9Zej3r^>bP0 Hl+XkKr9@%l literal 173 zcmZ?wbhEHblxL7;C}&_${K>+|00cT90wmV(pW#0caI`Qma>#HfG#qT^5EP0zaY5m5 zJ1e(biv+`>qa70BVS79RAGkHiTbg}Y5xB&yRY<+fWap Xl5}yE?Cxnx!#0U5Eo+q!V6X-Ny2(OK diff --git a/src/assets/images/avatareditor/he-selected-icon.png b/src/assets/images/avatareditor/he-selected-icon.png index e231488a613c87a6140d6833cfcde5ddc4e63806..32633559b9cba03803a5ac7f0b9d669bd521393f 100644 GIT binary patch delta 322 zcmeytc!_C(WIZzj1HNS%G}%0G|-o zEEl<%X~vEn+86tM4*oWpd0yn<*0%pQHvr{}xZD$g6lY10U+{k@UQz2)!fjFyYr$DK`=oD*xiS-$)ExxiwDx_9S3=TteWw3X&yT5| z?(?Xt&b52)6+d+Fo=3tVNK#bUi|49E_Pl>hAfoK!4CgZ)CScQ)2fzv?A=dP$5O8iO zA4*tDK!o#BMGqd)OkFL=0&_SexQ2!@$LrF>^;hjz@Th}#Y__|k!FS!8;*oQ20_M2Y h!=laaE$AyEdH}2wAWT(2=7svjzBsxUOEk8p!lk%t!=MOeH~n!T%YaZa44(@;D1TB8wRq_zr_G- x=A1mb%3EuL{k@dTcOIu%uNZE!IDFVpzlM`3y6(@BdY}s!JYD@<);T3K0RY~WTu}f3 literal 173 zcmZ?wbhEHblx2`)C}&_${K>+|00cT90wmV(pW#0caI`Qma>!^HG#qSZ<(E=9G2wwz z8^0`D#)}Dyjy4KwrtPUHRCeoAV5|_4oV57(L{;fLmzkTA4o=ds_v@KC;o0d9snBOj zI)hWr^k|53sm|Q2c4)qszmreYm&ZYK17fXey-Hu5UJLE8z+epk^+H1p diff --git a/src/assets/images/avatareditor/hr-selected-icon.png b/src/assets/images/avatareditor/hr-selected-icon.png index 65c03c05697ec2532f71e200800f4ec20eb2c30e..c694b82a5097b6f2ff485fe696db74429cb2b0e0 100644 GIT binary patch delta 332 zcmaFIc!z0%WIZzj1H-R7SG9o@V{wqX6T`Z5GB1G~mUKs7M+SzC{oH>NS%G~10G|+7 zAl=s177`M2blX}W`%i$yJRrqd666>B9|#zJZ{rIF3UC&9L>4nJ@ErzW#^d=bQh=3D>t-LW37x7!*n?pnO*+>Mhwr3*v1icS7tvp%=# z;34^}9gFt1ZlA`P`=f0(-{Jm4K(b>RhEo5BRS>U9+&}!>;xu z2WRDjejiR5cAoli<>?-k-)3qzcd&p7(8A5T-G@yGywoCbB-tg delta 221 zcmV<303!d~0`38j8Gi-<007MbB^dw!0JTX(K~zYI)s^cGfFKBkvGxA1Osi!pxf^yl zf7%kyCor)fA{dea%Ko+1iDrdooyNOP;8UkzM8u1OW&&By7CHh*yruFE)fqZ6%M0W6 zOnW8XM@jRZa&+T4KHQc%93mTwF@;PoZ6a}oa2Hsi-WjSHx>kYEWGeL)9Wf!brWtLb;&z-<>}4djZM< XLYg8xGa7)p00000NkvXXu0mjf-jZOF diff --git a/src/assets/images/icons/loading-icon.png b/src/assets/images/icons/loading-icon.png index 50d132b3e4e950ee4f6ab1622d9ebcb51fc157b2..e3d64d0bd0ee67afa9495f18681ad747c1abcfbe 100644 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^fa|ZZ?xYpO#pFVvW$ZPMP(Ey~FOM?7@|Nm#Weu@{UmVvXtBeIx*f$uN~ zGak=hkpdL-_jGX#(FpGC@A1W6X46^#_=zopr0597~LjV8( diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index 4298f5a2..1d1de900 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -78,6 +78,8 @@ $mirage: #131e25 !default; $aztec: #0d171d !default; $cello-light: #21516e !default; $cello-dark: #1e465e !default; +$pale-sky: #677181 !default; +$oslo-gray: #8F9297 !default; $success: $green !default; $info: $cyan !default; diff --git a/src/assets/styles/icons.scss b/src/assets/styles/icons.scss index 65b58de7..a56cfd12 100644 --- a/src/assets/styles/icons.scss +++ b/src/assets/styles/icons.scss @@ -2,502 +2,499 @@ line-height: 0 !important; } -i { - - &.icon { - display: inline-block; - outline: 0; - background-color: transparent; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - - &.icon-nitro-light { - background-image: url('../images/nitro/nitro-n-light.svg'); - } - - &.icon-nitro-dark { - background-image: url('../images/nitro/nitro-n-dark.svg'); - } - - &.icon-nitro-light, - &.icon-nitro-dark { - width: 100%; - height: 40px; - } - - &.icon-catalog { - background-image: url('../images/toolbar/icons/catalog.png'); - width: 37px; - height: 36px; - } - - &.icon-rooms { - background-image: url('../images/toolbar/icons/rooms.png'); - width: 44px; - height: 30px; - } - - &.icon-house { - background-image: url('../images/toolbar/icons/house.png'); - height: 30px; - width: 32px; - } - - &.icon-inventory { - background-image: url('../images/toolbar/icons/inventory.png'); - height: 41px; - width: 44px; - } - - &.icon-modtools { - background-image: url('../images/toolbar/icons/modtools.png'); - height: 34px; - width: 29px; - } - - &.icon-friendall { - background-image: url('../images/toolbar/icons/friend_all.png'); - height: 33px; - width: 32px; - } - - &.icon-friendsearch { - background-image: url('../images/toolbar/icons/friend_search.png'); - height: 33px; - width: 29px; - } - - &.icon-sendmessage { - background-image: url('../images/toolbar/icons/sendmessage.png'); - width: 20px; - height: 21px; - } - - &.icon-me-talents { - background-image: url('../images/toolbar/icons/me-menu/talents.png'); - width: 32px; - height: 30px; - } - - &.icon-me-helper-tool { - background-image: url('../images/toolbar/icons/me-menu/helper-tool.png'); - width: 32px; - height: 30px; - } - - &.icon-me-profile { - background-image: url('../images/toolbar/icons/me-menu/profile.png'); - width: 32px; - height: 30px; - } - - &.icon-me-forums { - background-image: url('../images/toolbar/icons/me-menu/forums.png'); - width: 32px; - height: 30px; - } - - &.icon-me-rooms { - background-image: url('../images/toolbar/icons/me-menu/my-rooms.png'); - width: 30px; - height: 30px; - } - - &.icon-me-achievements { - background-image: url('../images/toolbar/icons/me-menu/achievements.png'); - width: 31px; - height: 30px; - } - - &.icon-me-clothing { - background-image: url('../images/toolbar/icons/me-menu/clothing.png'); - width: 27px; - height: 30px; - } - - &.icon-me-settings { - background-image: url('../images/toolbar/icons/me-menu/cog.png'); - width: 28px; - height: 34px; - } - - &.icon-joinroom { - background-image: url('../images/toolbar/icons/joinroom.png'); - width: 21px; - height: 21px; - } - - &.icon-habbo { - background-image: url('../images/toolbar/icons/habbo.png'); - width: 28px; - height: 28px; - } - - &.icon-camera { - background-image: url('../images/toolbar/icons/camera.png'); - width: 38px; - height: 45px; - } - - &.icon-message { - background-image: url('../images/toolbar/icons/message.png'); - width: 36px; - height: 32px; - - &.is-unseen { - background-image: url('../images/toolbar/icons/message_unsee.gif'); - } - } - - &.icon-wired-trigger { - background-image: url('../images/wired/icon_trigger.png'); - width: 13px; - height: 14px; - } - - &.icon-wired-condition { - background-image: url('../images/wired/icon_condition.png'); - width: 13px; - height: 14px; - } +.icon { + display: inline-block; + outline: 0; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + + &.icon-nitro-light { + background-image: url('../images/nitro/nitro-n-light.svg'); + } + + &.icon-nitro-dark { + background-image: url('../images/nitro/nitro-n-dark.svg'); + } + + &.icon-nitro-light, + &.icon-nitro-dark { + width: 100%; + height: 40px; + } + + &.icon-catalog { + background-image: url('../images/toolbar/icons/catalog.png'); + width: 37px; + height: 36px; + } + + &.icon-rooms { + background-image: url('../images/toolbar/icons/rooms.png'); + width: 44px; + height: 30px; + } + + &.icon-house { + background-image: url('../images/toolbar/icons/house.png'); + height: 30px; + width: 32px; + } + + &.icon-inventory { + background-image: url('../images/toolbar/icons/inventory.png'); + height: 41px; + width: 44px; + } + + &.icon-modtools { + background-image: url('../images/toolbar/icons/modtools.png'); + height: 34px; + width: 29px; + } + + &.icon-friendall { + background-image: url('../images/toolbar/icons/friend_all.png'); + height: 33px; + width: 32px; + } + + &.icon-friendsearch { + background-image: url('../images/toolbar/icons/friend_search.png'); + height: 33px; + width: 29px; + } + + &.icon-sendmessage { + background-image: url('../images/toolbar/icons/sendmessage.png'); + width: 20px; + height: 21px; + } + + &.icon-me-talents { + background-image: url('../images/toolbar/icons/me-menu/talents.png'); + width: 32px; + height: 30px; + } + + &.icon-me-helper-tool { + background-image: url('../images/toolbar/icons/me-menu/helper-tool.png'); + width: 32px; + height: 30px; + } + + &.icon-me-profile { + background-image: url('../images/toolbar/icons/me-menu/profile.png'); + width: 32px; + height: 30px; + } + + &.icon-me-forums { + background-image: url('../images/toolbar/icons/me-menu/forums.png'); + width: 32px; + height: 30px; + } + + &.icon-me-rooms { + background-image: url('../images/toolbar/icons/me-menu/my-rooms.png'); + width: 30px; + height: 30px; + } + + &.icon-me-achievements { + background-image: url('../images/toolbar/icons/me-menu/achievements.png'); + width: 31px; + height: 30px; + } + + &.icon-me-clothing { + background-image: url('../images/toolbar/icons/me-menu/clothing.png'); + width: 27px; + height: 30px; + } + + &.icon-me-settings { + background-image: url('../images/toolbar/icons/me-menu/cog.png'); + width: 28px; + height: 34px; + } + + &.icon-joinroom { + background-image: url('../images/toolbar/icons/joinroom.png'); + width: 21px; + height: 21px; + } + + &.icon-habbo { + background-image: url('../images/toolbar/icons/habbo.png'); + width: 28px; + height: 28px; + } + + &.icon-camera { + background-image: url('../images/toolbar/icons/camera.png'); + width: 38px; + height: 45px; + } + + &.icon-message { + background-image: url('../images/toolbar/icons/message.png'); + width: 36px; + height: 32px; + + &.is-unseen { + background-image: url('../images/toolbar/icons/message_unsee.gif'); + } + } + + &.icon-wired-trigger { + background-image: url('../images/wired/icon_trigger.png'); + width: 13px; + height: 14px; + } + + &.icon-wired-condition { + background-image: url('../images/wired/icon_condition.png'); + width: 13px; + height: 14px; + } + + &.icon-wired-action { + background-image: url('../images/wired/icon_action.png'); + width: 13px; + height: 14px; + } + + &.arrow-left-icon { + background-image: url('../images/avatareditor/arrow-left-icon.png'); + width: 28px; + height: 21px; + } + + &.arrow-right-icon { + background-image: url('../images/avatareditor/arrow-right-icon.png'); + width: 28px; + height: 21px; + } + + &.clear-icon { + background-image: url('../images/avatareditor/clear-icon.png'); + width: 16px; + height: 16px; + } + + &.ca-icon { + background-image: url('../images/avatareditor/ca-icon.png'); + width: 30px; + height: 24px; + background + + &.selected { + background-image: url('../images/avatareditor/ca-selected-icon.png'); + } + } - &.icon-wired-action { - background-image: url('../images/wired/icon_action.png'); - width: 13px; - height: 14px; - } + &.cc-icon { + background-image: url('../images/avatareditor/cc-icon.png'); + width: 31px; + height: 29px; + + &.selected { + background-image: url('../images/avatareditor/cc-selected-icon.png'); + } + } + + &.ch-icon { + background-image: url('../images/avatareditor/ch-icon.png'); + width: 29px; + height: 24px; - &.arrow-left-icon { - background-image: url('../images/avatareditor/arrow-left-icon.png'); - width: 28px; - height: 21px; + &.selected { + background-image: url('../images/avatareditor/ch-selected-icon.png'); } + } - &.arrow-right-icon { - background-image: url('../images/avatareditor/arrow-right-icon.png'); - width: 28px; - height: 21px; - } + &.cp-icon { + background-image: url('../images/avatareditor/cp-icon.png'); + width: 25px; + height: 25px; - &.clear-icon { - background-image: url('../images/avatareditor/clear-icon.png'); - width: 16px; - height: 16px; + &.selected { + background-image: url('../images/avatareditor/cp-selected-icon.png'); } + } - &.ca-icon { - background-image: url('../images/avatareditor/ca-icon.png'); - width: 30px; - height: 24px; + &.ea-icon { + background-image: url('../images/avatareditor/ea-icon.png'); + width: 35px; + height: 16px; - &.selected { - background-image: url('../images/avatareditor/ca-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/ea-selected-icon.png'); } + } - &.cc-icon { - background-image: url('../images/avatareditor/cc-icon.png'); - width: 31px; - height: 29px; + &.fa-icon { + background-image: url('../images/avatareditor/fa-icon.png'); + width: 27px; + height: 20px; - &.selected { - background-image: url('../images/avatareditor/cc-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/fa-selected-icon.png'); } + } - &.ch-icon { - background-image: url('../images/avatareditor/ch-icon.png'); - width: 29px; - height: 24px; + &.female-icon { + background-image: url('../images/avatareditor/female-icon.png'); + width: 18px; + height: 27px; - &.selected { - background-image: url('../images/avatareditor/ch-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/female-selected-icon.png'); } + } - &.cp-icon { - background-image: url('../images/avatareditor/cp-icon.png'); - width: 25px; - height: 25px; + &.ha-icon { + background-image: url('../images/avatareditor/ha-icon.png'); + width: 25px; + height: 22px; - &.selected { - background-image: url('../images/avatareditor/cp-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/ha-selected-icon.png'); } + } - &.ea-icon { - background-image: url('../images/avatareditor/ea-icon.png'); - width: 35px; - height: 16px; + &.he-icon { + background-image: url('../images/avatareditor/he-icon.png'); + width: 31px; + height: 27px; - &.selected { - background-image: url('../images/avatareditor/ea-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/he-selected-icon.png'); } + } - &.fa-icon { - background-image: url('../images/avatareditor/fa-icon.png'); - width: 27px; - height: 20px; + &.hr-icon { + background-image: url('../images/avatareditor/hr-icon.png'); + width: 29px; + height: 25px; - &.selected { - background-image: url('../images/avatareditor/fa-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/hr-selected-icon.png'); } + } - &.female-icon { - background-image: url('../images/avatareditor/female-icon.png'); - width: 18px; - height: 27px; + &.lg-icon { + background-image: url('../images/avatareditor/lg-icon.png'); + width: 19px; + height: 20px; - &.selected { - background-image: url('../images/avatareditor/female-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/lg-selected-icon.png'); } + } - &.ha-icon { - background-image: url('../images/avatareditor/ha-icon.png'); - width: 25px; - height: 22px; + &.loading-icon { + background-image: url('../images/icons/loading-icon.png'); + width: 17px; + height: 21px; + } - &.selected { - background-image: url('../images/avatareditor/ha-selected-icon.png'); - } + &.male-icon { + background-image: url('../images/avatareditor/male-icon.png'); + width: 21px; + height: 21px; + + &.selected { + background-image: url('../images/avatareditor/male-selected-icon.png'); } - - &.he-icon { - background-image: url('../images/avatareditor/he-icon.png'); - width: 31px; - height: 27px; - - &.selected { - background-image: url('../images/avatareditor/he-selected-icon.png'); - } - } - - &.hr-icon { - background-image: url('../images/avatareditor/hr-icon.png'); - width: 29px; - height: 25px; - - &.selected { - background-image: url('../images/avatareditor/hr-selected-icon.png'); - } - } - - &.lg-icon { - background-image: url('../images/avatareditor/lg-icon.png'); - width: 19px; - height: 20px; - - &.selected { - background-image: url('../images/avatareditor/lg-selected-icon.png'); - } - } - - &.loading-icon { - background-image: url('../images/avatareditor/loading-icon.png'); - width: 21px; - height: 25px; - } - - &.male-icon { - background-image: url('../images/avatareditor/male-icon.png'); - width: 21px; - height: 21px; - - &.selected { - background-image: url('../images/avatareditor/male-selected-icon.png'); - } - } - - &.sh-icon { - background-image: url('../images/avatareditor/sh-icon.png'); - width: 37px; - height: 10px; - - &.selected { - background-image: url('../images/avatareditor/sh-selected-icon.png'); - } - } - - &.wa-icon { - background-image: url('../images/avatareditor/wa-icon.png'); - width: 36px; - height: 18px; - - &.selected { - background-image: url('../images/avatareditor/wa-selected-icon.png'); - } - } - - &.chatstyles-icon { - background-image: url('../images/chat/styles-icon.png'); - width: 17px; - height: 19px; - } - - &.pencil-icon { - background-image: url('../images/infostand/pencil-icon.png'); - width: 17px; - height: 18px; - } - - &.trade-locked-icon { - background-image: url('../images/inventory/trading/locked-icon.png'); - width: 29px; - height: 43px; - } - - &.trade-unlocked-icon { - background-image: url('../images/inventory/trading/unlocked-icon.png'); - width: 29px; - height: 43px; - } - - &.modtool-room-icon { - background-image: url('../images/modtool/room.png'); - width: 20px; - height: 15px; - } - - &.modtool-chatlog-icon { - background-image: url('../images/modtool/chatlog.gif'); - width: 20px; - height: 15px; - } - - &.modtool-user-icon{ - background-image: url('../images/modtool/user.gif'); - width: 20px; - height: 15px; - } - - &.modtool-reports-icon { - background-image: url('../images/modtool/reports.png'); - width: 20px; - height: 15px; - } - - &.modtool-wrench-icon { - background-image: url('../images/modtool/wrench.gif'); - width: 20px; - height: 15px; - } - - &.modtool-key-icon { - background-image: url('../images/modtool/key.gif'); - width: 20px; - height: 15px; - } - - &.icon-catalogue-hc_small { - background-image: url('../images/catalog/hc_small.png'); - height: 17px; - width: 31px; - } - - &.icon-catalogue-hc_big { - background: url('../images/catalog/hc_big.png'); - width: 68px; - height: 40px; - } - - &.icon-sign-exclamation { - background: url('../images/icons/sign-exclamation.png'); - width: 7px; - height: 17px; - } - - &.icon-sign-heart { - background: url('../images/icons/sign-heart.png'); - width: 15px; - height: 13px; - } - - &.icon-sign-red { - background: url('../images/icons/sign-red.png'); - width: 11px; - height: 19px; - } - - &.icon-sign-yellow { - background: url('../images/icons/sign-yellow.png'); - width: 11px; - height: 19px; - } - - &.icon-sign-skull { - background: url('../images/icons/sign-skull.png'); - width: 12px; - height: 12px; - } - - &.icon-sign-smile { - background: url('../images/icons/sign-smile.png'); - width: 7px; - height: 14px; - } - - &.icon-sign-soccer { - background: url('../images/icons/sign-soccer.png'); - width: 20px; - height: 20px; - } - - &.icon-camera-colormatrix { - background: url('../images/icons/camera-colormatrix.png'); - width: 32px; - height: 14px; - } - - &.icon-camera-composite { - background: url('../images/icons/camera-composite.png'); - width: 32px; - height: 14px; - } - - &.icon-user-profile { - background: url('../images/icons/user-profile.png'); - width: 13px; - height: 11px; - - &:hover { - background: url('../images/icons/user-profile-hover.png'); - } - } - - &.icon-fb-profile { - background: url('../images/toolbar/icons/friend-bar/profile.png'); - width: 21px; - height: 21px; - } - - &.icon-fb-chat { - background: url('../images/toolbar/icons/friend-bar/chat.png'); - width: 20px; - height: 21px; - } - - &.icon-fb-visit { - background: url('../images/toolbar/icons/friend-bar/visit.png'); - width: 21px; - height: 21px; - } - - &.spin { - animation: rotating 1s linear infinite; - } - - @keyframes rotating { - from { - transform: rotate(0); - } - - to { - transform: rotate(360deg); - } + } + + &.sh-icon { + background-image: url('../images/avatareditor/sh-icon.png'); + width: 37px; + height: 10px; + + &.selected { + background-image: url('../images/avatareditor/sh-selected-icon.png'); + } + } + + &.wa-icon { + background-image: url('../images/avatareditor/wa-icon.png'); + width: 36px; + height: 18px; + + &.selected { + background-image: url('../images/avatareditor/wa-selected-icon.png'); + } + } + + &.chatstyles-icon { + background-image: url('../images/chat/styles-icon.png'); + width: 17px; + height: 19px; + } + + &.pencil-icon { + background-image: url('../images/infostand/pencil-icon.png'); + width: 17px; + height: 18px; + } + + &.trade-locked-icon { + background-image: url('../images/inventory/trading/locked-icon.png'); + width: 29px; + height: 43px; + } + + &.trade-unlocked-icon { + background-image: url('../images/inventory/trading/unlocked-icon.png'); + width: 29px; + height: 43px; + } + + &.modtool-room-icon { + background-image: url('../images/modtool/room.png'); + width: 20px; + height: 15px; + } + + &.modtool-chatlog-icon { + background-image: url('../images/modtool/chatlog.gif'); + width: 20px; + height: 15px; + } + + &.modtool-user-icon{ + background-image: url('../images/modtool/user.gif'); + width: 20px; + height: 15px; + } + + &.modtool-reports-icon { + background-image: url('../images/modtool/reports.png'); + width: 20px; + height: 15px; + } + + &.modtool-wrench-icon { + background-image: url('../images/modtool/wrench.gif'); + width: 20px; + height: 15px; + } + + &.modtool-key-icon { + background-image: url('../images/modtool/key.gif'); + width: 20px; + height: 15px; + } + + &.icon-catalogue-hc_small { + background-image: url('../images/catalog/hc_small.png'); + height: 17px; + width: 31px; + } + + &.icon-catalogue-hc_big { + background: url('../images/catalog/hc_big.png'); + width: 68px; + height: 40px; + } + + &.icon-sign-exclamation { + background: url('../images/icons/sign-exclamation.png'); + width: 7px; + height: 17px; + } + + &.icon-sign-heart { + background: url('../images/icons/sign-heart.png'); + width: 15px; + height: 13px; + } + + &.icon-sign-red { + background: url('../images/icons/sign-red.png'); + width: 11px; + height: 19px; + } + + &.icon-sign-yellow { + background: url('../images/icons/sign-yellow.png'); + width: 11px; + height: 19px; + } + + &.icon-sign-skull { + background: url('../images/icons/sign-skull.png'); + width: 12px; + height: 12px; + } + + &.icon-sign-smile { + background: url('../images/icons/sign-smile.png'); + width: 7px; + height: 14px; + } + + &.icon-sign-soccer { + background: url('../images/icons/sign-soccer.png'); + width: 20px; + height: 20px; + } + + &.icon-camera-colormatrix { + background: url('../images/icons/camera-colormatrix.png'); + width: 32px; + height: 14px; + } + + &.icon-camera-composite { + background: url('../images/icons/camera-composite.png'); + width: 32px; + height: 14px; + } + + &.icon-user-profile { + background: url('../images/icons/user-profile.png'); + width: 13px; + height: 11px; + + &:hover { + background: url('../images/icons/user-profile-hover.png'); + } + } + + &.icon-fb-profile { + background: url('../images/toolbar/icons/friend-bar/profile.png'); + width: 21px; + height: 21px; + } + + &.icon-fb-chat { + background: url('../images/toolbar/icons/friend-bar/chat.png'); + width: 20px; + height: 21px; + } + + &.icon-fb-visit { + background: url('../images/toolbar/icons/friend-bar/visit.png'); + width: 21px; + height: 21px; + } + + &.spin { + animation: rotating 1s linear infinite; + } + + @keyframes rotating { + from { + transform: rotate(0); + } + + to { + transform: rotate(360deg); } } } diff --git a/src/layout/card/grid/NitroCardGridView.scss b/src/layout/card/grid/NitroCardGridView.scss index 44a1ee42..e424066a 100644 --- a/src/layout/card/grid/NitroCardGridView.scss +++ b/src/layout/card/grid/NitroCardGridView.scss @@ -10,6 +10,17 @@ } } } + + .row-cols-4 { + + .col { + padding-right: 0.25rem; + + &:nth-child(4n+4) { + padding-right: 0; + } + } + } .row-cols-5 { diff --git a/src/layout/card/grid/NitroCardGridView.tsx b/src/layout/card/grid/NitroCardGridView.tsx index 25b9fe47..4726910c 100644 --- a/src/layout/card/grid/NitroCardGridView.tsx +++ b/src/layout/card/grid/NitroCardGridView.tsx @@ -1,15 +1,18 @@ import { FC } from 'react'; -import { NitroCardGridViewProps } from './NitroCardGridView.types'; +import { NitroCardGridContextProvider } from './context/NitroCardGridContext'; +import { NitroCardGridThemes, NitroCardGridViewProps } from './NitroCardGridView.types'; export const NitroCardGridView: FC = props => { - const { columns = 5, children = null } = props; + const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, children = null } = props; return ( -
-
- { children } + +
+
+ { children } +
-
+ ); } diff --git a/src/layout/card/grid/NitroCardGridView.types.ts b/src/layout/card/grid/NitroCardGridView.types.ts index b24763d1..58c052ac 100644 --- a/src/layout/card/grid/NitroCardGridView.types.ts +++ b/src/layout/card/grid/NitroCardGridView.types.ts @@ -1,4 +1,11 @@ export interface NitroCardGridViewProps { columns?: number; + theme?: string; +} + +export class NitroCardGridThemes +{ + public static THEME_DEFAULT: string = 'theme-default'; + public static THEME_SHADOWED: string = 'theme-shadowed'; } diff --git a/src/layout/card/grid/context/NitroCardGridContext.tsx b/src/layout/card/grid/context/NitroCardGridContext.tsx new file mode 100644 index 00000000..18661b76 --- /dev/null +++ b/src/layout/card/grid/context/NitroCardGridContext.tsx @@ -0,0 +1,13 @@ +import { createContext, FC, useContext } from 'react'; +import { INitroCardGridContext, NitroCardGridContextProps } from './NitroCardGridContext.types'; + +const NitroCardGridContext = createContext({ + theme: null +}); + +export const NitroCardGridContextProvider: FC = props => +{ + return { props.children } +} + +export const useNitroCardGridContext = () => useContext(NitroCardGridContext); diff --git a/src/layout/card/grid/context/NitroCardGridContext.types.ts b/src/layout/card/grid/context/NitroCardGridContext.types.ts new file mode 100644 index 00000000..a0f97c95 --- /dev/null +++ b/src/layout/card/grid/context/NitroCardGridContext.types.ts @@ -0,0 +1,11 @@ +import { ProviderProps } from 'react'; + +export interface INitroCardGridContext +{ + theme: string; +} + +export interface NitroCardGridContextProps extends ProviderProps +{ + +} diff --git a/src/layout/card/grid/context/index.ts b/src/layout/card/grid/context/index.ts new file mode 100644 index 00000000..9e3f79e8 --- /dev/null +++ b/src/layout/card/grid/context/index.ts @@ -0,0 +1,2 @@ +export * from './NitroCardGridContext'; +export * from './NitroCardGridContext.types'; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index 2ff2f0fd..19f6c716 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -1,15 +1,49 @@ .grid-item-container { - height: 48px; - max-height: 48px; + height: 50px; + max-height: 50px; .grid-item { + position: relative; width: 100%; height: 100%; - border-color: $grid-border-color !important; - background-color: $grid-bg-color; background-position: center; background-repeat: no-repeat; overflow: hidden; + + &.theme-default { + border-radius: $border-radius; + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + border: nth(map-values($border-widths), 2) solid; + } + + &.theme-shadowed { + border-radius: $border-radius; + background-color: $light; + + &::after { + position: absolute; + content: ''; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-radius: $border-radius; + border-bottom: 2px solid white; + border-right: 2px solid white; + box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2); + } + + &.active { + border: nth(map-values($border-widths), 2) solid; + border-color: $oslo-gray !important; + background-color: #F5F5F5; + + &:after { + content: unset; + } + } + } &.active { border-color: $grid-active-border-color !important; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.tsx b/src/layout/card/grid/item/NitroCardGridItemView.tsx index 985a24bd..445851e1 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.tsx +++ b/src/layout/card/grid/item/NitroCardGridItemView.tsx @@ -1,16 +1,19 @@ import { FC } from 'react'; import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { useNitroCardGridContext } from '../context'; +import { NitroCardGridThemes } from '../NitroCardGridView.types'; import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; export const NitroCardGridItemView: FC = props => { - const { itemImage = null, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; + const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; + const { theme = NitroCardGridThemes.THEME_DEFAULT } = useNitroCardGridContext(); const imageUrl = `url(${ itemImage })`; return (
-
+
{ (itemCount > 1) && { itemCount } } { itemUnique && diff --git a/src/layout/card/grid/item/NitroCardGridItemView.types.ts b/src/layout/card/grid/item/NitroCardGridItemView.types.ts index da6295c3..52e0242c 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.types.ts +++ b/src/layout/card/grid/item/NitroCardGridItemView.types.ts @@ -3,6 +3,7 @@ import { DetailsHTMLAttributes } from 'react'; export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes { itemImage?: string; + itemColor?: string; itemActive?: boolean; itemCount?: number; itemUnique?: boolean; diff --git a/src/views/avatar-editor/AvatarEditorView.scss b/src/views/avatar-editor/AvatarEditorView.scss index ecc8cf0c..d94a3cdc 100644 --- a/src/views/avatar-editor/AvatarEditorView.scss +++ b/src/views/avatar-editor/AvatarEditorView.scss @@ -1,8 +1,51 @@ .nitro-avatar-editor { - width: 550px; + width: 600px; .content-area { - height: 300px; - max-height: 300px; + height: 330px; + max-height: 330px; + } + + .figure-preview-container { + position: relative; + height: 100%; + background-color: $pale-sky; + overflow: hidden; + z-index: 1; + + .avatar-image { + margin: 45px auto 0; + z-index: 2; + } + + .arrow-container { + position: absolute; + width: 100%; + margin: 0 auto; + display: flex; + justify-content: center; + bottom: 12px; + z-index: 3; + + .icon { + cursor: pointer; + } + + .arrow-left-icon { + margin-right: 10px; + } + } + + &:after { + position: absolute; + content: ''; + top: 75%; + bottom: 0; + left: 0; + right: 0; + border-radius: 50%; + background-color: red; + transform: scale(2); + } } } diff --git a/src/views/avatar-editor/AvatarEditorView.tsx b/src/views/avatar-editor/AvatarEditorView.tsx index 8fe50d8c..b8d5a07d 100644 --- a/src/views/avatar-editor/AvatarEditorView.tsx +++ b/src/views/avatar-editor/AvatarEditorView.tsx @@ -1,5 +1,6 @@ import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { GetSessionDataManager } from '../../api'; import { AvatarEditorEvent } from '../../events/avatar-editor'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; @@ -7,6 +8,7 @@ import { LocalizeText } from '../../utils/LocalizeText'; import { AvatarEditorViewProps } from './AvatarEditorView.types'; import { AvatarEditor } from './common/AvatarEditor'; import { BodyModel } from './common/BodyModel'; +import { FigureData } from './common/FigureData'; import { HeadModel } from './common/HeadModel'; import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel'; import { LegModel } from './common/LegModel'; @@ -24,6 +26,79 @@ export const AvatarEditorView: FC = props => const [ activeCategory, setActiveCategory ] = useState(null); const [ isInitalized, setIsInitalized ] = useState(false); + const selectCategory = useCallback((name: string) => + { + setActiveCategory(categories.get(name)); + }, [ categories ]); + + const resetCategories = useCallback((editor: AvatarEditor) => + { + const categories = new Map(); + + categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(editor)); + categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(editor)); + categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(editor)); + categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(editor)); + + setCategories(categories); + setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); + }, []); + + const selectGender = useCallback((gender: string) => + { + if(gender === avatarEditor.gender) return; + + avatarEditor.gender = gender; + + resetCategories(avatarEditor); + }, [ avatarEditor, resetCategories ]); + + const loadAvatarInEditor = useCallback((figure: string, gender: string, reset: boolean = true) => + { + if(!avatarEditor) return; + + switch(gender) + { + case FigureData.MALE: + case 'm': + case 'M': + gender = FigureData.MALE; + break; + case FigureData.FEMALE: + case 'f': + case 'F': + gender = FigureData.FEMALE; + break; + default: + gender = FigureData.MALE; + } + + let update = false; + + if(gender !== avatarEditor.gender) + { + avatarEditor.gender = gender; + + update = true; + } + + const figureData = avatarEditor.figureData; + + if(!figureData) return; + + if(figure !== figureData.getFigureString()) + { + update = true; + } + + figureData.loadAvatarData(figure, gender); + + if(update) + { + resetCategories(avatarEditor); + } + }, [ avatarEditor, resetCategories ]); + const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => { switch(event.type) @@ -35,7 +110,7 @@ export const AvatarEditorView: FC = props => setIsVisible(false); return; case AvatarEditorEvent.TOGGLE_EDITOR: - setIsVisible(value => !value); + setIsVisible(prevValue => !prevValue); return; } }, []); @@ -44,11 +119,6 @@ export const AvatarEditorView: FC = props => useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); - const selectCategory = useCallback((name: string) => - { - setActiveCategory(categories.get(name)); - }, [ categories ]); - useEffect(() => { if(!isVisible || isInitalized) return; @@ -56,26 +126,23 @@ export const AvatarEditorView: FC = props => const newEditor = new AvatarEditor(); setAvatarEditor(newEditor); - - const categories = new Map(); - - categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(newEditor)); - categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(newEditor)); - categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(newEditor)); - categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(newEditor)); - - setCategories(categories); - setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); setIsInitalized(true); }, [ isVisible, isInitalized ]); + useEffect(() => + { + if(!isVisible || !avatarEditor) return; + + loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender); + }, [ isVisible, avatarEditor, loadAvatarInEditor ]); + return ( { isVisible && setIsVisible(false) } /> - { categories && Array.from(categories.keys()).map(category => + { categories && (categories.size > 0) && Array.from(categories.keys()).map(category => { return ( selectCategory(category) }> @@ -85,7 +152,7 @@ export const AvatarEditorView: FC = props => })} - { activeCategory && } + { activeCategory && } } diff --git a/src/views/avatar-editor/common/AvatarEditor.ts b/src/views/avatar-editor/common/AvatarEditor.ts index 4bd882b6..3ba88477 100644 --- a/src/views/avatar-editor/common/AvatarEditor.ts +++ b/src/views/avatar-editor/common/AvatarEditor.ts @@ -1,9 +1,10 @@ -import { FigureData, IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; +import { IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; import { GetAvatarRenderManager, GetConfiguration, GetSessionDataManager } from '../../../api'; import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; import { CategoryBaseModel } from './CategoryBaseModel'; import { CategoryData } from './CategoryData'; +import { FigureData } from './FigureData'; const MAX_PALETTES: number = 2; const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007'; @@ -11,16 +12,13 @@ const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62 export class AvatarEditor { - private _figureStructureData: IStructureData; - private _figures: Map; - private _gender: string; + private _figureStructureData: IStructureData = GetAvatarRenderManager().structureData; + private _figures: Map = new Map(); + private _gender: string = FigureData.MALE; + private _notifier: () => void = null; constructor() { - this._figureStructureData = GetAvatarRenderManager().structureData; - this._figures = new Map(); - this._gender = FigureData.MALE; - const maleFigure = new FigureData(); const femaleFigure = new FigureData(); @@ -160,6 +158,7 @@ export class AvatarEditor if(partSet.isSellable) { + isValid = false; //isValid = (this._inventoryService && this._inventoryService.hasFigureSetId(partSet.id)); } @@ -284,6 +283,24 @@ export class AvatarEditor public set gender(gender: string) { + if(this._gender === gender) return; + this._gender = gender; + + if(this.figureData) this.figureData.notify = this.notify; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + if(this.figureData) this.figureData.notify = notifier; + + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts index b6e99efd..9757b1fc 100644 --- a/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts +++ b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts @@ -6,6 +6,7 @@ export class AvatarEditorGridColorItem private _isDisabled: boolean; private _isHC: boolean; private _isSelected: boolean; + private _notifier: () => void; constructor(partColor: IPartColor, isDisabled: boolean = false) { @@ -48,5 +49,17 @@ export class AvatarEditorGridColorItem public set isSelected(flag: boolean) { this._isSelected = flag; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts index f22b3718..4ac82a7f 100644 --- a/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts +++ b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts @@ -1,5 +1,6 @@ -import { AvatarFigurePartType, FigureData, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroContainer, NitroSprite, TextureUtils } from 'nitro-renderer'; +import { AvatarFigurePartType, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroContainer, NitroSprite, TextureUtils } from 'nitro-renderer'; import { GetAvatarRenderManager } from '../../../api'; +import { FigureData } from './FigureData'; export class AvatarEditorGridPartItem implements IAvatarImageListener { @@ -47,6 +48,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener private _isSelected: boolean; private _disposed: boolean; private _isInitalized: boolean; + private _notifier: () => void; constructor(partSet: IFigurePartSet, partColors: IPartColor[], useColors: boolean = true, isDisabled: boolean = false) { @@ -210,6 +212,8 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener if(this._isDisabled) this.setAlpha(container, 0.2); this._imageUrl = TextureUtils.generateImageUrl(container); + + if(this.notify) this.notify(); } private setAlpha(container: NitroContainer, alpha: number): NitroContainer @@ -259,21 +263,21 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener return this._partSet; } - public set colors(partColors: IPartColor[]) + public set partColors(partColors: IPartColor[]) { this._partColors = partColors; this.update(); } - public get isDisabledForWearing(): boolean + public get isDisabled(): boolean { return this._isDisabled; } - public set iconImage(k: NitroContainer) + public set thumbContainer(container: NitroContainer) { - this._thumbContainer = k; + this._thumbContainer = container; this.update(); } @@ -283,7 +287,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener return this._imageUrl; } - public get colorLayerCount(): number + public get maxColorIndex(): number { return this._maxColorIndex; } @@ -316,5 +320,17 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener public set isSelected(flag: boolean) { this._isSelected = flag; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/BodyModel.ts b/src/views/avatar-editor/common/BodyModel.ts index b1419c10..41971d51 100644 --- a/src/views/avatar-editor/common/BodyModel.ts +++ b/src/views/avatar-editor/common/BodyModel.ts @@ -1,6 +1,7 @@ -import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, FigureData, IAvatarImageListener } from 'nitro-renderer'; +import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from 'nitro-renderer'; import { GetAvatarRenderManager } from '../../../api'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class BodyModel extends CategoryBaseModel implements IAvatarImageListener { @@ -50,7 +51,7 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener { sprite.y = 10; - part.iconImage = sprite; + part.thumbContainer = sprite; setTimeout(() => avatarImage.dispose(), 0); } diff --git a/src/views/avatar-editor/common/CategoryBaseModel.ts b/src/views/avatar-editor/common/CategoryBaseModel.ts index d7ea50a2..9d1100ee 100644 --- a/src/views/avatar-editor/common/CategoryBaseModel.ts +++ b/src/views/avatar-editor/common/CategoryBaseModel.ts @@ -174,7 +174,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel if(!partItem) return; - if(partItem.isDisabledForWearing) + if(partItem.isDisabled) { categoryData.selectPartIndex(selectedPartIndex); @@ -183,7 +183,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel return; } - this._maxPaletteCount = partItem.colorLayerCount; + this._maxPaletteCount = partItem.maxColorIndex; this._editor.figureData.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true); } @@ -233,7 +233,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel public get maxPaletteCount(): number { - return this._maxPaletteCount; + return (this._maxPaletteCount || 1); } public set maxPaletteCount(count: number) diff --git a/src/views/avatar-editor/common/CategoryData.ts b/src/views/avatar-editor/common/CategoryData.ts index 54ffaa89..1b740037 100644 --- a/src/views/avatar-editor/common/CategoryData.ts +++ b/src/views/avatar-editor/common/CategoryData.ts @@ -266,7 +266,7 @@ export class CategoryData if(!partItem) return null; - return colorIds.slice(0, Math.max(partItem.colorLayerCount, 1)); + return colorIds.slice(0, Math.max(partItem.maxColorIndex, 1)); } private getSelectedColors(): IPartColor[] @@ -333,7 +333,7 @@ export class CategoryData for(const partItem of this._parts) { - if(partItem) partItem.colors = partColors; + if(partItem) partItem.partColors = partColors; } } diff --git a/src/views/avatar-editor/common/FigureData.ts b/src/views/avatar-editor/common/FigureData.ts new file mode 100644 index 00000000..2e447cb3 --- /dev/null +++ b/src/views/avatar-editor/common/FigureData.ts @@ -0,0 +1,271 @@ +export class FigureData +{ + public static MALE: string = 'M'; + public static FEMALE: string = 'F'; + public static UNISEX: string = 'U'; + public static SCALE: string = 'h'; + public static STD: string = 'std'; + public static DEFAULT_FRAME: string = '0'; + public static FACE: string = 'hd'; + public static HAIR: string = 'hr'; + public static HAT: string = 'ha'; + public static HEAD_ACCESSORIES: string = 'he'; + public static EYE_ACCESSORIES: string = 'ea'; + public static FACE_ACCESSORIES: string = 'fa'; + public static JACKET: string = 'cc'; + public static SHIRT: string = 'ch'; + public static CHEST_ACCESSORIES: string = 'ca'; + public static CHEST_PRINTS: string = 'cp'; + public static TROUSERS: string = 'lg'; + public static SHOES: string = 'sh'; + public static TROUSER_ACCESSORIES: string = 'wa'; + public static PREVIEW_AVATAR_DIRECTION: number = 4; + + private _data: Map; + private _colors: Map; + private _gender: string = 'M'; + private _avatarEffectType: number = -1; + private _notifier: () => void = null; + + public loadAvatarData(figureString: string, gender: string): void + { + this._data = new Map(); + this._colors = new Map(); + this._gender = gender; + + this.parseFigureString(figureString); + this.updateView(); + } + + private parseFigureString(figure: string): void + { + if(!figure) return; + + const sets = figure.split('.'); + + if(!sets || !sets.length) return; + + for(const set of sets) + { + const parts = set.split('-'); + + if(!parts.length) continue; + + const setType = parts[0]; + const setId = parseInt(parts[1]); + const colorIds: number[] = []; + + let offset = 2; + + while(offset < parts.length) + { + colorIds.push(parseInt(parts[offset])); + + offset++; + } + + if(!colorIds.length) colorIds.push(0); + + this.savePartSetId(setType, setId, false); + this.savePartSetColourId(setType, colorIds, false); + } + } + + public getPartSetId(partSetId: string): number + { + const existing = this._data.get(partSetId); + + if(existing !== undefined) return existing; + + return -1; + } + + public getColourIds(colorId: string): number[] + { + const existing = this._colors.get(colorId); + + if(existing !== undefined) return existing; + + return []; + // return [this._avatarEditor._Str_24919(k)]; + } + + public getFigureString(): string + { + let figureString = ''; + const setParts: string[] = []; + + for(const [ setType, setId ] of this._data.entries()) + { + const colorIds = this._colors.get(setType); + + let setPart = ((setType + '-') + setId); + + if(colorIds && colorIds.length) + { + let i = 0; + + while(i < colorIds.length) + { + setPart = (setPart + ('-' + colorIds[i])); + + i++; + } + } + + setParts.push(setPart); + } + + let i = 0; + + while(i < setParts.length) + { + figureString = (figureString + setParts[i]); + + if(i < (setParts.length - 1)) figureString = (figureString + '.'); + + i++; + } + + return figureString; + } + + public savePartData(k: string, _arg_2: number, _arg_3: number[], _arg_4: boolean = false): void + { + this.savePartSetId(k, _arg_2, _arg_4); + this.savePartSetColourId(k, _arg_3, _arg_4); + } + + private savePartSetId(k: string, _arg_2: number, _arg_3: boolean = true): void + { + switch(k) + { + case FigureData.FACE: + case FigureData.HAIR: + case FigureData.HAT: + case FigureData.HEAD_ACCESSORIES: + case FigureData.EYE_ACCESSORIES: + case FigureData.FACE_ACCESSORIES: + case FigureData.SHIRT: + case FigureData.JACKET: + case FigureData.CHEST_ACCESSORIES: + case FigureData.CHEST_PRINTS: + case FigureData.TROUSERS: + case FigureData.SHOES: + case FigureData.TROUSER_ACCESSORIES: + if(_arg_2 >= 0) + { + this._data.set(k, _arg_2); + } + else + { + this._data.delete(k); + } + break; + } + + if(_arg_3) this.updateView(); + } + + public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void + { + switch(k) + { + case FigureData.FACE: + case FigureData.HAIR: + case FigureData.HAT: + case FigureData.HEAD_ACCESSORIES: + case FigureData.EYE_ACCESSORIES: + case FigureData.FACE_ACCESSORIES: + case FigureData.SHIRT: + case FigureData.JACKET: + case FigureData.CHEST_ACCESSORIES: + case FigureData.CHEST_PRINTS: + case FigureData.TROUSERS: + case FigureData.SHOES: + case FigureData.TROUSER_ACCESSORIES: + this._colors.set(k, _arg_2); + break; + } + + if(_arg_3) this.updateView(); + } + + public getFigureStringWithFace(k: number, override = true): string + { + let figureString = ''; + + const setTypes: string[] = [ FigureData.FACE ]; + const figureSets: string[] = []; + + for(const setType of setTypes) + { + const colors = this._colors.get(setType); + + if(colors === undefined) continue; + + let setId = this._data.get(setType); + + if((setType === FigureData.FACE) && override) setId = k; + + let figureSet = ((setType + '-') + setId); + + if(setId >= 0) + { + let i = 0; + + while(i < colors.length) + { + figureSet = (figureSet + ('-' + colors[i])); + + i++; + } + } + + figureSets.push(figureSet); + } + + let i = 0; + + while(i < figureSets.length) + { + figureString = (figureString + figureSets[i]); + + if(i < (figureSets.length - 1)) figureString = (figureString + '.'); + + i++; + } + + return figureString; + } + + public updateView(): void + { + if(this.notify) this.notify(); + } + + public get gender(): string + { + return this._gender; + } + + public set avatarEffectType(k: number) + { + this._avatarEffectType = k; + } + + public get avatarEffectType(): number + { + return this._avatarEffectType; + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; + } +} diff --git a/src/views/avatar-editor/common/HeadModel.ts b/src/views/avatar-editor/common/HeadModel.ts index 1635b79a..bb6276e8 100644 --- a/src/views/avatar-editor/common/HeadModel.ts +++ b/src/views/avatar-editor/common/HeadModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class HeadModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/common/LegModel.ts b/src/views/avatar-editor/common/LegModel.ts index 73b7bafe..02aec797 100644 --- a/src/views/avatar-editor/common/LegModel.ts +++ b/src/views/avatar-editor/common/LegModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class LegModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/common/TorsoModel.ts b/src/views/avatar-editor/common/TorsoModel.ts index 089ca366..2875ffa4 100644 --- a/src/views/avatar-editor/common/TorsoModel.ts +++ b/src/views/avatar-editor/common/TorsoModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class TorsoModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx new file mode 100644 index 00000000..73e37a69 --- /dev/null +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx @@ -0,0 +1,28 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; +import { AvatarEditorFigurePreviewViewProps } from './AvatarEditorFigurePreviewView.types'; + +export const AvatarEditorFigurePreviewView: FC = props => +{ + const { editor = null } = props; + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); + + useEffect(() => + { + if(!editor) return; + + editor.notify = rerender; + + return () => + { + editor.notify = null; + } + }, [ editor, rerender ] ); + + return +} diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts new file mode 100644 index 00000000..0bfcf8f9 --- /dev/null +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts @@ -0,0 +1,6 @@ +import { AvatarEditor } from '../../common/AvatarEditor'; + +export interface AvatarEditorFigurePreviewViewProps +{ + editor: AvatarEditor; +} diff --git a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx index fcb268cc..ef4c0cc4 100644 --- a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx +++ b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx @@ -1,16 +1,31 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, useCallback, useEffect, useState } from 'react'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { AvatarEditorFigureSetItemViewProps } from './AvatarEditorFigureSetItemView.types'; export const AvatarEditorFigureSetItemView: FC = props => { const { partItem = null, onClick = null } = props; - const [ imageUrl, setImageUrl ] = useState(null); + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); useEffect(() => { - setImageUrl(partItem.imageUrl); - }, [ partItem.imageUrl ]); + partItem.notify = rerender; - return onClick(partItem) } /> + return () => + { + partItem.notify = null; + } + }) + + return ( + onClick(partItem) }> + { partItem.isHC && } + + ); } diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx index e16afae6..c97fffdd 100644 --- a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx @@ -1,28 +1,33 @@ import { FC, useCallback } from 'react'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; +import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem'; import { AvatarEditorFigureSetItemView } from '../figure-set-item/AvatarEditorFigureSetItemView'; import { AvatarEditorFigureSetViewProps } from './AvatarEditorFigureSetView.types'; export const AvatarEditorFigureSetView: FC = props => { - const { model = null, category = null } = props; + const { model = null, category = null, setMaxPaletteCount = null } = props; - const selectPart = useCallback((part: AvatarEditorGridPartItem) => + const selectPart = useCallback((item: AvatarEditorGridPartItem) => { - const index = category.parts.indexOf(part); + const index = category.parts.indexOf(item); if(index === -1) return; model.selectPart(category.name, index); - }, [ model, category ]); + + const partItem = category.getCurrentPart(); + + setMaxPaletteCount(partItem.maxColorIndex || 1); + }, [ model, category, setMaxPaletteCount ]); return ( - + { (category.parts.length > 0) && category.parts.map((item, index) => { return ; }) } - ) + ); } diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts index b44992be..d2e9e5cf 100644 --- a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts @@ -1,3 +1,4 @@ +import { Dispatch, SetStateAction } from 'react'; import { CategoryData } from '../../common/CategoryData'; import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; @@ -5,4 +6,5 @@ export interface AvatarEditorFigureSetViewProps { model: IAvatarEditorCategoryModel; category: CategoryData; + setMaxPaletteCount: Dispatch>; } diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx index 4dfc58d0..c842c94e 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx @@ -1,17 +1,19 @@ +import { UserFigureComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; +import { SendMessageHook } from '../../../../hooks'; +import { LocalizeText } from '../../../../utils/LocalizeText'; import { CategoryData } from '../../common/CategoryData'; +import { FigureData } from '../../common/FigureData'; +import { AvatarEditorFigurePreviewView } from '../figure-preview/AvatarEditorFigurePreviewView'; import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView'; +import { AvatarEditorPaletteSetView } from '../palette-set/AvatarEditorPaletteSetView'; import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types'; export const AvatarEditorModelView: FC = props => { - const { model = null, editor = null } = props; + const { model = null, editor = null, selectGender = null } = props; const [ activeCategory, setActiveCategory ] = useState(null); - - const selectGender = useCallback((gender: string) => - { - editor.gender = gender; - }, [ editor ]); + const [ maxPaletteCount, setMaxPaletteCount ] = useState(1); const selectCategory = useCallback((name: string) => { @@ -27,12 +29,19 @@ export const AvatarEditorModelView: FC = props => { if(!part || !part.isSelected) continue; - model.maxPaletteCount = part.colorLayerCount; + setMaxPaletteCount(part.maxColorIndex || 1); break; } }, [ model ]); + const saveFigure = useCallback(() => + { + const figureData = editor.figureData; + + SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString())); + }, [ editor ]); + useEffect(() => { model.init(); @@ -45,16 +54,54 @@ export const AvatarEditorModelView: FC = props => } }, [ model, selectCategory ]); - if(!activeCategory) return null; + if(!model || !activeCategory) return null; return (
-
-
- +
+ { model.canSetGender && + <> + selectGender(FigureData.MALE) } /> + selectGender(FigureData.FEMALE) } /> + } + { !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name => + { + const category = model.categories.get(name); + + return ( + selectCategory(name) } /> + ); + })} +
+
+ +
+
+
+ +
+ + +
+
+
+
+ + +
+ +
+
+
+ { (maxPaletteCount >= 1) && + } + { (maxPaletteCount === 2) && + }
-
-
); } diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts index 322e9a86..dc81491a 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts @@ -5,4 +5,5 @@ export interface AvatarEditorModelViewProps { model: IAvatarEditorCategoryModel; editor: AvatarEditor; + selectGender: (gender: string) => void; } diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx new file mode 100644 index 00000000..2dab88d1 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx @@ -0,0 +1,26 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { AvatarEditorPaletteSetItemProps } from './AvatarEditorPaletteSetItem.types'; + +export const AvatarEditorPaletteSetItem: FC = props => +{ + const { colorItem = null, onClick = null } = props; + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); + + useEffect(() => + { + colorItem.notify = rerender; + + return () => + { + colorItem.notify = null; + } + }) + + return onClick(colorItem) } /> +} diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts new file mode 100644 index 00000000..5930f9a4 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts @@ -0,0 +1,7 @@ +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; + +export interface AvatarEditorPaletteSetItemProps +{ + colorItem: AvatarEditorGridColorItem; + onClick: (item: AvatarEditorGridColorItem) => void; +} diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx new file mode 100644 index 00000000..fc8c4fc9 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx @@ -0,0 +1,29 @@ +import { FC, useCallback } from 'react'; +import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; +import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; +import { AvatarEditorPaletteSetItem } from '../palette-set-item/AvatarEditorPaletteSetItem'; +import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.types'; + +export const AvatarEditorPaletteSetView: FC = props => +{ + const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props; + + const selectColor = useCallback((item: AvatarEditorGridColorItem) => + { + const index = paletteSet.indexOf(item); + + if(index === -1) return; + + model.selectColor(category.name, index, paletteIndex); + }, [ model, category, paletteSet, paletteIndex ]); + + return ( + + { (paletteSet.length > 0) && paletteSet.map((item, index) => + { + return ; + }) } + + ); +} diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts new file mode 100644 index 00000000..9fa8e2b6 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts @@ -0,0 +1,11 @@ +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; +import { CategoryData } from '../../common/CategoryData'; +import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; + +export interface AvatarEditorPaletteSetViewProps +{ + model: IAvatarEditorCategoryModel; + category: CategoryData; + paletteSet: AvatarEditorGridColorItem[]; + paletteIndex: number; +} diff --git a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx index 859a1f69..de3c10c4 100644 --- a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx +++ b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx @@ -1,8 +1,9 @@ -import { FigureData, RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from 'nitro-renderer'; +import { RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { GetAvatarRenderManager, GetConnection, GetFurnitureDataForRoomObject, GetSessionDataManager } from '../../../../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../../layout'; import { LocalizeText } from '../../../../../../../utils/LocalizeText'; +import { FigureData } from '../../../../../../avatar-editor/common/FigureData'; import { FurniCategory } from '../../../../../../inventory/common/FurniCategory'; import { AvatarImageView } from '../../../../../../shared/avatar-image/AvatarImageView'; import { useRoomContext } from '../../../../../context/RoomContext'; diff --git a/src/views/shared/avatar-image/AvatarImage.scss b/src/views/shared/avatar-image/AvatarImage.scss index c1d05822..f85ca9c4 100644 --- a/src/views/shared/avatar-image/AvatarImage.scss +++ b/src/views/shared/avatar-image/AvatarImage.scss @@ -5,4 +5,5 @@ background-repeat: no-repeat; background-position-x: center; background-position-y: -8px !important; + pointer-events: none; } diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index 28419e69..72ed9010 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -1,4 +1,4 @@ -import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, Wait } from 'nitro-renderer'; +import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserFigureEvent, Wait } from 'nitro-renderer'; import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/incoming/user/data/UserInfoEvent'; import { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser'; import { FC, useCallback, useState } from 'react'; @@ -17,6 +17,7 @@ export const ToolbarView: FC = props => const { isInRoom } = props; const [ userInfo, setUserInfo ] = useState(null); + const [ userFigure, setUserFigure ] = useState(null); const [ isMeExpanded, setMeExpanded ] = useState(false); const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0); @@ -28,10 +29,20 @@ export const ToolbarView: FC = props => const parser = event.getParser(); setUserInfo(parser.userInfo); + setUserFigure(parser.userInfo.figure); }, []); CreateMessageHook(UserInfoEvent, onUserInfoEvent); + const onUserFigureEvent = useCallback((event: UserFigureEvent) => + { + const parser = event.getParser(); + + setUserFigure(parser.figure); + }, []); + + CreateMessageHook(UserFigureEvent, onUserFigureEvent); + const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) => { setUnseenInventoryCount(event.count); @@ -116,7 +127,7 @@ export const ToolbarView: FC = props =>
setMeExpanded(!isMeExpanded) }> - { userInfo && } + { userFigure && }
{ (unseenAchievementsCount > 0) && (