From e88f403a084f679aeca9a92af3c63140beec1459 Mon Sep 17 00:00:00 2001 From: luisdralves Date: Fri, 15 Sep 2023 12:05:52 +0100 Subject: [PATCH] Improve code layout and remove repetition --- public/favicon.ico | Bin 0 -> 39727 bytes src/api/banknotes/get-country-banknotes.ts | 24 ++ src/api/coins/get-country-coins.ts | 24 ++ .../banknote.tsx => banknote/index.tsx} | 0 .../{scene/coin.tsx => coin/index.tsx} | 0 src/components/header/index.tsx | 70 ++++++ .../{scene => pile}/coin-instances.tsx | 2 +- src/components/{scene => pile}/index.tsx | 2 +- src/components/showcase/index.tsx | 118 +++++++++ src/components/showcase/info-box.tsx | 79 ++++++ src/pages/api/countries/[country]/[coin].ts | 37 --- src/pages/api/countries/[country]/index.ts | 35 --- src/pages/api/countries/index.ts | 10 - src/pages/api/hello.ts | 13 - src/pages/banknotes/[country].tsx | 69 ++++++ src/pages/coins/[country].tsx | 71 ++++++ src/pages/index.tsx | 53 ++-- src/pages/pile/[country].tsx | 93 +++---- src/pages/showcase-banknotes/[country].tsx | 225 ----------------- src/pages/showcase/[country].tsx | 234 ------------------ src/styles/globals.css | 4 + src/types/coin.ts | 2 +- 22 files changed, 538 insertions(+), 627 deletions(-) create mode 100644 public/favicon.ico create mode 100644 src/api/banknotes/get-country-banknotes.ts create mode 100644 src/api/coins/get-country-coins.ts rename src/components/{scene/banknote.tsx => banknote/index.tsx} (100%) rename src/components/{scene/coin.tsx => coin/index.tsx} (100%) create mode 100644 src/components/header/index.tsx rename src/components/{scene => pile}/coin-instances.tsx (96%) rename src/components/{scene => pile}/index.tsx (96%) create mode 100644 src/components/showcase/index.tsx create mode 100644 src/components/showcase/info-box.tsx delete mode 100644 src/pages/api/countries/[country]/[coin].ts delete mode 100644 src/pages/api/countries/[country]/index.ts delete mode 100644 src/pages/api/countries/index.ts delete mode 100644 src/pages/api/hello.ts create mode 100644 src/pages/banknotes/[country].tsx create mode 100644 src/pages/coins/[country].tsx delete mode 100644 src/pages/showcase-banknotes/[country].tsx delete mode 100644 src/pages/showcase/[country].tsx diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6fb85c5dab0a15bea4054d88f7a09f5614a418d0 GIT binary patch literal 39727 zcmeI430zKF_xPV?GK2<75h|5R^P~|ang>!TiAD{E3PnYdAwroNiRJ-~8dM}>gD9nx zCNzf#k^XC?=f1tq?>!_TJ|_$0ZOb2s8u~3IZqL69<8? z2J%Wu-;Q~g5(wIJ2n1o_Z^tp*1i}t;0)dlr=y)1|F!um~Fbz^{Z$nKW+&N7k9MaKR zF@>Iu9!yPHskU4XYmo_1Pv~_w?<5d7@>ecbHrQF+S-UI5pd$3cn;q|SrKS`=5nn<% z|M2-~&mxYg&NwP^Zeox|$fjh?^m8ji7Vb(eIw|tttVn6VN~^g6a#mswV#La3-Qi-J zNv%Bj;H2rBY}09jPSXa}opJlxLMt*)FC)&eHZDrx!)nbQx7yqfA=~p@x@7WtKKD=E z^|tw5z(VaXxgW}G3tL-GBh8(r${OkTQ9st;ss%UwDL$QJLf%xBD-B4#LM^6_jIuFyycv2~`ll(st}m|nFh z!_>9yaE#!5?jFinmdUCqg30;pmby}eEQjP9vca9nH5X!z1Q?0(d9gKVUcFn$5Tr_V?A45>h@`iCHdk*hPDm@I*rPj>XZOvSN|9wH zSBkoWFL1WC@u)o$QhdL0Hb*(D%Z8iW8Wgt-W_9X$HZNtiI8iFSZ`umqQ@QQB4zh(8 zg>=^Lf3IV)%I^bDx2SgP&6xOeTvTpyuaIL;@7gU^@83b!rT<-t+VD;e$$HsRj z>$DsWeAsy;_CoOXixD-hJ3f1+uP{B{vFTiP4$~(oiH?gE@^y0CRH<6o!u{V{e=RSJ zyO^ZYVsLgtm~pV`0Uu6z%Cqf@b1Fkl^m=^ZU<#@i*x2dJ*%oo>qG;^)O#fZMBD#j$ z7Y%})_MH(|F+Fauay3E3@YAKuDHf|2rvystUtCkuoVu4+f+Fx*we`B7l+(H8yu!5t zpBHLP=$2*!9UAa3`Kz+MyR@&wr%Y&^ngT$XY z`hE>ek|{}T*qHUkZgsrY=Yubl!_$SN)>Gf3H&54g)2?1s7O5XyAZcP9YTYq0Hfc)9 z)w}akD&ll5$T?JgJz#Qu)~eWLJTesJ?w1!wZD^TU8Tnv(dqVn??NbjOVXVF;d*JL@ z-Ipfzu_|_fi?jBt`~>JvZ~nhW7cM>I`wGQ zu$OHVE@YE1@yIGV!1CF4m8Qh`N`)P6zW3q+m)jWn^XXb9&#tx1Go#|GXg7PM(r+WG zd^AsEL!_rpxOIP8kDr!$W$;vs`$t`KOWm~A)5|Mg)()rLJg?4X*(1$z>qv%kn+;f8 zPy49KJoZgob>m2@ZRK*)qgP^kUR(;cKE-e@nx~CFhhL)P?ezG7q^3mMBi2QFN$HZY z2W+>caLYVWezLalvct-_u+2FNZH>Mw51E|Y(%a_ZD>ZwzO9Pc|x2DJOTWg~$XRe=~ zu5eSjvVU*zrZahxis}d4m3gJwq4~kS|OaF73_>N6n5lwXNk4lk32dz zv*7Fg(j+PQHp+!s(ct-dJ3DB#Nan=R|yXsD;>$L#0e3wpNXrrzST zzC#=n!%Qwnwl(rVi$I>;FNOS7Os}T)#Dq=^Gm7AEyNTso9$gov&yvrOZwR^Q!yh4J z-{|*{b@Q!eol8p6l(SB$H`P<0J8?y2JLj1Q+Jfo%OlMTV#P(ReiD6GKEwyzdecTzPI_jq zUElZh)|Z$gb6D<8-lT^Ga7ICT%%2shnRoBw||dp329p{GM!w?C#Idk63k+-=_-}G zV~=xCN~@krZV-NZhEZkCqegCrJNl3&uCH|BI-H;rqj5s?qMxL3?Ut;&ZWR|69$xoC zJ?vg#SGYZ6{)50phKgU@pT9A5HO$&R)C*P?eTC_Pkr zaw3sZ`h-QHk)5KSN#_xdbMdwo_oh&6TGa2+8t-vBK6GH(E($JnU-y3B6&Hn6Q-Xu=m#5H}V-IFa?7fpe>{f;%yT6_0X6>j(1 zLM?30`L5VlR5RRr%_k{_S6v|koAxj8vI-8lYFf>;zV3d;iLc(=;&{76)d}gZbD-vJJ``bR25S^>gP(s-#>-^ElU$&tAdZAxP>qOd4 z*Kl`xXW=s^<++x9bZXHG?cG(!AkZs&Swf+WKYU;4oSuU&y-SWiI3joG1yMl>Hw?szMWs&e7wt^1wm72cTC>5oZo>U(GP=c&vK^8q z4(@84A8S^a?`~Pi;$MCF=~PYErw$pl3pVO5G>VXX>|AXxc34wnwfENB@ltE9yS;CF z}JVhs}Yd_EXzg-FO|>m* z#zpZ0o^#Vm&5DEUubRfgW|F=5n8@8$AurJv{03)VvRemrPHuWMM?uf>v{6AGgU!`K ztJ(7LE2Fhcvo6|uJzh=lS+zRG<+M*p%0p?DP3AY^9xi8Gx9P5IR-JxWZ%#p$3+us% zd0J8wx0v{K<8BltZM$IXL$9w!e_|c01+U1xa}JL_kP>h}OHyL_PVubUvx`?p%O1&a71E2mZ?k<}ccn+8N4DtJ$0tg5 zSGtGtwQawpovD*(e3ZrQ@@kJwF4y|=)mW6Ss$YL<@p!v^yBlxW`5UZ4SMU4FvxF6M zvQsSY?l;^NJ9}Nr_R?VO4ZfjM0?k!s%CizKS| zI$yRvu)vFLV`n=d{B#0nI$MeXWB zUbxNOo_2q7omh&2Y^7Xeb!t@m$%YADOOKY6S*<_trR~AG<^>8iR;pbr+>EB?`@DN2 z7ph4JP)rl6qoGY*GRsX-`2OtObrK7%G%2!1mbj)<^+pyv<&vXNN_!C6%DuwnfKAES zdRnRA+12k;PSDP5Nfop7j6P1IR3!eu?@^S#(}elF!cW6LFMo1pc4Ro)%$V2v7Q~wJ z*i$HF_LwGCQ-sn!3NlE{XUfPDi9RZSPyZ$R(XdBh_h&9*q~wgcujeFuPkrj4=#|tW z0sWy;K8{_i;^(!);o^5;n7izpy6-W^S~utRvUu%qkNyIe$(20D_ECqPM7^CqK`(zG zRj%+r$M$^hT!*7!;s?!>OEVP$@646rb$obU`Fd~7Mt>HEsWQ#SB|~Z1RW3UQ@+n7J zFsn|P>vG$+++xmT z63@wYJrTu{?qynZ?^>kH&DT!zE>KwFZB|#wX=O9>w!UtHm|RKH4^ z_JCsEJ)u(m)o})ywAMzOEaWwA~t6T-^S{&f;Sy5!7zc{lTS_Rl|hCHB0DAn!htWr(-_bkpSl#W{qX3ffs5n z<~Ap?1hcv6v@MDit(f8Tp4-1wOWkx%x^xEhw93}rOZGd&zHC0$ZN_l-?C(^ykZI4pRx*GG!H6uB>wiXZGkiG2si-j0=@+?fo|`g?4N`dHwN= zIcXv}ks0suC~57do~5?f>wdDM*Yl;P%z}idm5cQE+$v4wUR^qO$-RwJQlB|&uxiP5;k`_FR_>APC)|Wf~3OQueVH}hDA4VIcGkmd*+a5-up;QV8S-H zRLYh#g@^3s%A98|U$c7d9N<6^ENpVHrtPBRWA>OYV%|q7BSLA|-gM!(^Q9c071mE`E*8DBe}Acb8^wB73jeuT{p&x_ZRwlk1__d$Q>9TVCo|~1FD>Ask zjB@UI%gDYRFuf%o!`F~PwO0P-B!=#^0>{PI9!Cl}M;)SferoG|Cn1&lkl&X>mz_DJ z=RIywYhb0Dp&*rCDf`T}-YeAAtxo=Sj9yIT20>TfudZDWlnY8@Tj;0FV9S3c%;@UX z-)mhjv{291-m6>PQCKMCe5H-x-VJ5uE6Y{XmZ;x+YGu8N-aIRQI~TV>L|~RIyYJ-_ zd|q~jJNK0Ps4a5Zq9RSPWr04S=(ULT3e$tBTaWn%O)rUD5l1*I_$HS94MCPUWzYS_ zD+k&aNNJl#w!iB;IrA}_e~2x8(Obi$Ns9@tmwE|0t({-%C?j=ea@np5ZR&nBhvE~x zYBJ%#?UMC7Vzby2toO>E`4lDPlbvbRC7~gFIJDhe!7eUB;O_b$UJ;e3ta~2>CM;=m zYCcABOgE-(!1bKx>zD;HB6E0knnb0H5(IXa9otPY+2_*w76Jc{42xW>-^*^$IMj3f zd4;Ma&*RosP6F?mZnjtMRUB(9JN0xkC)Kt*y3+A=VUzQ8LSV2}rn+2bUcbN>XL^d* zj3N^OwVm-<;#*}WdR-8F#$(bPy2kx(Tf&6tf>+C#&6*|$h$>pj*HRNAt@OVCSpH>lUO}w*RP2! z6CUw}@>jK6^0+&cGd~EJrA)m=yn&)@UH5|sF8f_(KAeO`(e|8AZr38K z=ENya)u&N7@0{15n?Fs3EvJ@Y59e&Zuw7cJ!Zqcx!Bo#LRL>88v&WNNc%cn{N5;I3 zAMP_Prk%ByhO*8m#1Cln{{x;^VGJj;m+l$9T^4OYVl6lg+==V znjM_2BhF0ibye7uX1UU+kY4j~%eu;)cl*0krxdSZ$h_-QBF6vjbEN;Wu;gmCykx0o zvuVQ5%fA$wt6jDuvCRGGj`)QIiR?CS#1;u`3;R?evbg;YjeLRonZz^&#wC~OW-1-Y z4s8!&>NaU(>sN5pR?T_0M80e5MZv8nXsm)xo)Wdmcp#bAduer$n9Ji$8seoN4fXYo z0G&xU;8KvIIN4vwvCF zb6NGRn^TX&i?7eBnAl>g&KWg|U8yw7o3`vIt5vXV@=CVyMQdWV>|D~auVGKVzXOYW zbHB8>A4j!@tjBKe)(hcOeW`ZoH9|G^>BT1+dXo1W$mV!|eJbR+dDSCBK5-uP0~@y9 znbSP4-C>qT5zT#xvzroRUE2IaS0%1eIc&hIlfZ7;H@U6+@^f8Z-;A@0mx?Le#oO8H zzSwU0_&i~Lnv_{~wnS#dO|DML8$k=+l)sIA$G^TO>^&7GUJOE+9sd88HDv-@Tn^@nTrJ@=H%3Ji@H&9xsLbvziy z`lzI)Up8MdIo_1ja>HiRuAVRjOOfm^IvY9t8zy#5z2ajRUXgSpdETSjCUUWhm5RF$ zEA;J5mFiP`l6%-LyY|#_tpO8f8k>V2@z0K*TW4}Xx5HsgJA+QU*80iYytj00F_kpg zm~FMSNlUciS*Pz;!HG^@TT3P$UlplzQHIw3L3M(8v_w+}Qjqa}woA6p;_ou3tRx@87G&E1+c6<_OAaA(Kw7ihv480T`+lC15Z~nVOOmSk*!)e%i^4_j( zcpDQxU17C?17|A_Te(xf;2lggT!a%T(g9N2kc+X+^M25;MJ!zu2&I+b!KrV~3RDH74TGHp~22 zqi<-46^onpZ<%rLt@xSG6rQcE&5et;ttK#;v~3rf^rCtzN5L-TB`!8;&lMKSB-Bpt zoZ2pWzQ&8fn^z}B=iJg4cIA_!4<<_8pnlJPis2Q*l!YdG&k7VaYbIZ%$y`J@ysj}t zXyP8G=a-lHYF&3bptz^8&v)S|CcbINvl)Bg!%(w5xnnY zwJ*tel+gZuxM2@#kH3W)Cv!wrpKo9amn&UdJgZ zbL`^@&$l{pJ*U>qB#674?X_L0!qd#}zPrXyF0{`_bss^xh3|UXeEOae@jYShr>xi1 zetY)BJVI7Nvi>ffjCFnosphBB(Mp{CqYeHXkYwEpD$9rmyk?fKA zmL4|RoZSu2q}@8+Q(Z1TY15Vvbvv!AjOFebg=~KhU%BQ!_N}%@Le5e)<(A_pHM;P=1GLZ z<+Ixb3^VUvikY;X-dMgZI&7QLW}YV>wHPQS>ssxzWyz{)OwgF0_rTb{#{7&G$GNOl zc)KyrPQp&OAd|)DIJ3H1zob$3%HWQxOIY)A4W#?2g_obW7X@pukyQ}m${d~O&h)A_ znk60OOqw@~;8n|=n6j8MCNa&&F*m50=RLprSfSW;bMms3+TNj<*v`;^)_Z)oe0nq2aL8KsvJm6>h^Rw;p!6*9uCuJEp zuK|9f4|q>E0eBr}14%&i5SYg@tV12t{Slk!8)NtYv;buIwTRkXm*3bsWXXsZku z$sfjoG5v~ALSy*+mf!`10TuwR-Q;8m6m|oo@w|gFT(9N;<1O&XFySbGK1lsyEV97Q z%0g)954-?~wm(B2=UKc)NyQBch zw}STM&PhF#I|0nVXhN?4crEn-q;ZY+F!3^l_z@x3|MBkUSnZ9a z|K#qUm>=o*kj_~8kJni{Pz2!I<_9CXz_w@uZIRk1J^t1Bf3-a^9-OmJ1L6SgUw>85h6I53 zEZQdeAx(cZ{$Fj6@l*nu!1wkrpfYAbn`j$-koFyqe>MJJZT|{lSPJ}ZK_4vu=@|TK z{5U7#dM^hU0QfFzBtc)K{;xvW?>O(IF`y6hMe6@o`(HX__YI`|KrNsJkdt#zNa`P- zdFPT-9_KRjfxbxnV@y9PH-gbUP(ITB z~ z*MLKSIj|fM1<*F<5SYg@tTP8t7u#T4v_Z5-F2xuyma)i4{m17QoLg0a2|r*E@5gw6 zTwLVJ@Lb_@QU~x7XdD9bScY{YT~p-jVc#)^u?o5VzXc<%z~nI+!?E87;C`K4jK8A{ zeeDOvdfuVQppff7KEKlp)sHoyga+~e-ZS{V<9GBKZQ}kn7El1t=g$hc{$Ki8W5e3v zTqy?}1a0d4?3(-s3wz-s{CUwi@Z zUPmyGWmtzgsEci|tqL#`7*82X|8Y;e08j$VfnC5cAPBfH1m>{}>&yWqU_LN>4xJ9i zT!0jy2IvE8hrs*_0P9c(?`vw{cggqq&jOCs0bGZ2fJWdQ@FR0G>Yy&R$psDr*k8OJ z{w+eT|IrW}AK(d;0C+u)?#Ve_F`(zZrt614iq|c+}N{4-a4#@J|W3 z{*OoB#$p5CWlR4<1MoBb$7}cnfX~S|CtL<_y+<&QWmt#v_m8f7&p>xM@OR6P_8PZwQ2A$Ts>Q9S7X^$o&SNBbg-Ee_Zdj15_h5 z8i#VUjXub&t+?0wyM$c-uY+^k>-}!Q=S$odkzNBKzuWOJ`?zl<_5XMEAIF$n|3inx z_q(&Z$@Cwu$!);@57)mu^b_YC(rWB<3Lx!2@p!z}KN|3X zYp64THi`C0Q=E_f&h-!65rhETdyvL5{J06~asPvJ_Htk>`yXtBZPCVXo1}S+0b}_m zLv8>zuC|R_jWNuU_J-ZT>F`?$@{gWncsFz4xD}gSyxT+y0S1Bk*Sg{*1t%5%>p2U|iv~c)qgvt`%g-hPoS%ZW5q9!g8sk&rkoIUKBf?) z7p4TyuY|!A{=k321Q3S*q`18$%&jNv{FYLD>rXvhJ{}L$Q)5CgP>%`p|6A($Ers3> z9xD!|(EGt-29gwpt$wigm|~QW4n{dFC6@oCH|UNynt!Dqp%_P*IO@c+Ks+lL0GJ6c>I|RoD?UVE0 z0_ACd2cQo~0k|}A4uN?r!#dPKU2H?n7W(+v^MHLHssAQW_ld-36C8U3LI54`qk_8F z2HT>I;r&1#=xZ!850pKDhXB4uF$9Lo1UN_mhWoh#$CAU9elm|X(AIF<=<7$ug9h}> zfF~sFu@A$~0~;Jy57T)Kc}0Mnpx=?^|B+%sTWFKm2lRzLM-$u`?gDxNVmo3=8b8i& z4a4*>&kmsc%=~W+?Zk)Lq7Ae~Y9D=$CVEi$4j{%%OmVFty?)5WF9&+|KrZkr^S=YM zmj}iYKc2^AfEY8TI3IWdoB*ki#*gQ$9{36jxA8N1w1KvUUkBJ1^f{7{Ue9kq(O@KH zC?}17v^alu{vU4hd-0RTgZjA78c9g?hx@`jo;#e=_W-{-|D(O1iGQ^7HB$V)WB&iU z;=c{!BnkYgpbfM&{G5(;{Oh4Tj`0j&_`DB?gF-s~-B7A9R5u<8+8RFpk2U^wXnz{O z-$lr+zq6tI89*GP-w{9BB-*cmJo+3-NXL`dj+kN}hMx!AKcoW0dQ9=0O8~zrXoK|n z!TkgJ97)C+KiXLb{Eqz_?yrZB%a82eMvI@^`it@7o;H-k7t!x4D97`I^CzzBBkiBD z4s}o$=Uig@;b{nze{cUxE`GG<32*`<2{Tk+A8?Ht?sIq^>wfn61#P2`?+I!A-&=o& z+rzQ30V;suasNslZK2H{{XL8{ew?p3fUyYbI{|sX&+gyyq3sr6E-)4$7eAJf6Iv+5 z{roHdV@5DP6`%re%!GlBKp>C~;JcEi!1Ez6k7ZbgI#z%FC13+C|Kgf+kD3pJ1Jpz?6$w=}4?0$X%cpvS34(>h1Q^>_X zp8K&o5bW@Cf%^sQ<9G>a{M}$!VZ4kF*&4o|$M-onhmM!v-uf9p9HalW`0-rgJx7cm z)A781(AIF<<9+>r`N97;QXh#Q+>7r61c9-vm8gsNFSbP+!(&Gu<9+{v$?xvxN1H!+ zp*`vRiF5AoxQY4SF@IwGD9ixbA8kMXE9+O-kPk?Ho8TI615^OSG5gi@ckds_4aQt3 z#JzYvfP1m8z*zc$ZSn!MfwulBnF5Z9`{w}2<9&d8W!y8@4S{(q!#dQ#-%fvJKM&1+ zo6v&gX#nYd9?P)qkNg>dfBgu2`*H{-ltIB1KDvV01;1#*UH;%_VK8gJ*G+>@uY;e5 z!KzA3aS_0$_18mbJxQ8BbUb2;zmh@we7T_%z2Gr;umA6qSpH2P)Cct_A%%GIi7A%D zQ+7V45cgmT{lJt8`hck?Nvb$>{4ISAU&VnQ!@z&16d%7GL;K=f`j*X!qB5S~!FJk?|Y>eD{LC%}D?nz*+!*3&lK^VIAs> zw=jc2Gawdt3gG2|`_BF$Fpp(e7YD2dSb$#@3NV0uy9?kg3Rl_>fx6g66F?h3D>%Nm z?;!f^fc$mfDBu9#m>`(PGOR-#qJAgj(Z=@#&zmN|Gfa^K@)ZEu!uLnP0G{K~-Zfwy z>I4DU2HT6zB)?0peY&1$pAW*&p&aGZ6*%q#f&AAYFh2*_00aX!0PI)Y5SYg@tg`^-0;KJs=)VM?r&<8? z-34I03jv}SLx$-87UZ7|9TQ_6DaAIZi*1PQ(H5z!fdU+JwBt@%3CBeLq<-+4dI+Qg zF+*S;%dn1AA7dcrfB5(qfexvV`Y#8C9RTiq839@V&mn?&EWJepFBw+hAL?kG4pK=pWBP5D)<1IADKJ3<2W#aULug+aGL${?P{7A{C;4 zVvLwp0W3p`!jQHBSY8X@7!AM2;E=4K4(ehXY>PI~7O4#Pk9xfTzU!YbqzJo~!T)~} z))DJ-AnyXG0E>WmLkJ9&xk8FMXp7kH5aiJosSNjD0+l$=6MYkPVFxt$Z?5tEGSMEU z9{}uE;}Dp~vf(=To7oWnZIF}U{w>HU3@cNHd<4({d1x8zoiT;OQ z|ESLfNC4^pUN?vuAOk1@Yk(a9UauGvatd$*^Z;&PG`~{JqjqC6+#yrM!55P5(0{9sr`X6qaxW40h=Lnb$f%&7r zb>L^#cWCy1WVnC4UxENU@AUsi^FIYxhdQWByvLqEehx5J!E=b$9`^qj@FUj@s0|A0 z;uv9DJa1aSSVbEe5YPEP;UC8g#}51OPmDjf9b9jQui3=w568n1AYOkCkRR##Be!;g z`VR@-JDLFAOL$KWzZXW!kH`H7?*0-M$gKx({&@re-EvCVkPNb@hw#dzPb z0b{vO#yh_Md3%Ge4L-uZ5UYpx3Hk6U!;3&s4|8}v;58z0 zC476p;Dq$A_Y{Bc8J!BQaj)YGTpR-PcpqZjXfhuvQ-C%A@7cs5Fpp)az&wB`xG%?b z#tWDP90u^&1otNF0M3C3=CKUxP=_d+Akzt)1||d1KoNj@4@_%^z z!%*?P_Slb+WIj}2|J#7!@nas#unu)b6Vm$y$Ilng1ip8_jAnP#I$UhLM%5Uq#8IXr Ifq_8yfA6`)ivR!s literal 0 HcmV?d00001 diff --git a/src/api/banknotes/get-country-banknotes.ts b/src/api/banknotes/get-country-banknotes.ts new file mode 100644 index 0000000..c40f847 --- /dev/null +++ b/src/api/banknotes/get-country-banknotes.ts @@ -0,0 +1,24 @@ +import { CoinProps } from "@/types/coin"; +import { readFile, readdir } from "fs/promises"; +import path from "path"; + +export const getCountryBanknotes = async (country: string) => { + try { + const banknoteIds = await readdir(path.join("./public/banknotes", country)); + + const banknotes: CoinProps[] = []; + + for (const banknoteId of banknoteIds) { + const banknote = await readFile( + path.join("./public/banknotes", country, banknoteId), + { encoding: "utf-8" }, + ); + + banknotes.push(JSON.parse(banknote)); + } + + return banknotes; + } catch { + return []; + } +}; diff --git a/src/api/coins/get-country-coins.ts b/src/api/coins/get-country-coins.ts new file mode 100644 index 0000000..e7f9f62 --- /dev/null +++ b/src/api/coins/get-country-coins.ts @@ -0,0 +1,24 @@ +import { CoinProps } from "@/types/coin"; +import { readFile, readdir } from "fs/promises"; +import path from "path"; + +export const getCountryCoins = async (country: string) => { + try { + const coinIds = await readdir(path.join("./public/coins", country)); + + const coins: CoinProps[] = []; + + for (const coinId of coinIds) { + const coin = await readFile( + path.join("./public/coins", country, coinId), + { encoding: "utf-8" }, + ); + + coins.push(JSON.parse(coin)); + } + + return coins; + } catch { + return []; + } +}; diff --git a/src/components/scene/banknote.tsx b/src/components/banknote/index.tsx similarity index 100% rename from src/components/scene/banknote.tsx rename to src/components/banknote/index.tsx diff --git a/src/components/scene/coin.tsx b/src/components/coin/index.tsx similarity index 100% rename from src/components/scene/coin.tsx rename to src/components/coin/index.tsx diff --git a/src/components/header/index.tsx b/src/components/header/index.tsx new file mode 100644 index 0000000..92b1a52 --- /dev/null +++ b/src/components/header/index.tsx @@ -0,0 +1,70 @@ +type Props = { + route: "pile" | "coins" | "banknotes"; + country: string; + coinCount: number; + banknoteCount: number; +}; + +export const Header = ({ route, country, banknoteCount, coinCount }: Props) => ( +
+ +
+ {route !== "pile" && coinCount > 0 && ( + + )} + {route !== "coins" && coinCount > 0 && ( + + )} + {route !== "banknotes" && banknoteCount > 0 && ( + + )} +
+
+); diff --git a/src/components/scene/coin-instances.tsx b/src/components/pile/coin-instances.tsx similarity index 96% rename from src/components/scene/coin-instances.tsx rename to src/components/pile/coin-instances.tsx index 538137a..2fc7bf8 100644 --- a/src/components/scene/coin-instances.tsx +++ b/src/components/pile/coin-instances.tsx @@ -1,5 +1,5 @@ import { CoinProps } from "@/types/coin"; -import { CoinInstance } from "./coin"; +import { CoinInstance } from "../coin"; import { useEffect, useRef } from "react"; import { InstancedMesh } from "three"; import { useCylinder } from "@react-three/cannon"; diff --git a/src/components/scene/index.tsx b/src/components/pile/index.tsx similarity index 96% rename from src/components/scene/index.tsx rename to src/components/pile/index.tsx index 4ebece0..376f5b3 100644 --- a/src/components/scene/index.tsx +++ b/src/components/pile/index.tsx @@ -20,7 +20,7 @@ const Plane = (props: PlaneProps) => { ); }; -export const Scene = ({ coins }: Props) => ( +export const Pile = ({ coins }: Props) => ( diff --git a/src/components/showcase/index.tsx b/src/components/showcase/index.tsx new file mode 100644 index 0000000..751f5ab --- /dev/null +++ b/src/components/showcase/index.tsx @@ -0,0 +1,118 @@ +import { CoinProps } from "@/types/coin"; +import { Canvas, MeshProps, useFrame } from "@react-three/fiber"; +import { Suspense, useRef, useState } from "react"; +import { CoinInstance } from "@/components/coin"; +import { Mesh } from "three"; +import { OrbitControls } from "@react-three/drei"; +import { BanknoteInstance } from "@/components/banknote"; +import { InfoBox } from "./info-box"; + +type Props = { + category: "coins" | "banknotes"; + types: CoinProps[]; +}; + +const SpinninType = ({ + isSelected, + category, + typeProps, + ...props +}: { typeProps: CoinProps; isSelected?: boolean } & MeshProps & + Pick) => { + const ref = useRef(null!); + const Instance = category === "banknotes" ? BanknoteInstance : CoinInstance; + + useFrame((_state, delta) => { + if (!isSelected) { + return; + } + + if (category === "banknotes") { + ref.current.rotation.y += delta; + return; + } + + switch (typeProps.orientation) { + case "medal": + ref.current.rotation.x += delta; + break; + + default: + ref.current.rotation.z += delta; + break; + } + }); + + return ( + + + + + + ); +}; + +const Row = ({ + category, + types, + selectedIndex, +}: Props & { selectedIndex: number }) => { + const ref = useRef(null!); + const spacing = category === "banknotes" ? 8 : 6; + + useFrame(() => { + const xPosition = Math.round(10 * ref.current.position.x) / 10; + const target = -selectedIndex * spacing; + + if (xPosition > target) { + ref.current.position.x -= Math.abs(xPosition - target) / 16; + } + + if (xPosition < target) { + ref.current.position.x += Math.abs(xPosition - target) / 16; + } + }); + + return ( + + {types.map( + (type, index) => + Math.abs(index - selectedIndex) <= 1 && ( + + + + ), + )} + + ); +}; + +export const Showcase = (props: Props) => { + const [selectedIndex, selectIndex] = useState(0); + + return ( + <> + + + + + + + + + + + ); +}; diff --git a/src/components/showcase/info-box.tsx b/src/components/showcase/info-box.tsx new file mode 100644 index 0000000..b95a225 --- /dev/null +++ b/src/components/showcase/info-box.tsx @@ -0,0 +1,79 @@ +import { CoinProps } from "@/types/coin"; +import { Dispatch, SetStateAction } from "react"; + +export const InfoBox = ({ + category, + type, + maxIndex, + selectIndex, + selectedIndex, +}: { + category: "banknotes" | "coins"; + type: CoinProps; + maxIndex: number; + selectIndex: Dispatch>; + selectedIndex: number; +}) => { + return ( +
+
+ {type.issuer.name} +

{type.title}

+

{type.min_year + " - " + type.max_year}

+ {(type.count ?? 1) + " in collection"} + {category === "coins" && ( + <> +

{type.weight + "g"}

+

{type.size + "mm"}

+

{type.thickness + "mm"}

+ + )} +
+ +
+ + + +
+
+ ); +}; diff --git a/src/pages/api/countries/[country]/[coin].ts b/src/pages/api/countries/[country]/[coin].ts deleted file mode 100644 index 9cd3c8f..0000000 --- a/src/pages/api/countries/[country]/[coin].ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { NextApiHandler } from "next"; -import { readFile } from "fs/promises"; -import path from "path"; - -const handler: NextApiHandler = async ( - req, - res, -) => { - if (typeof req.query.country !== "string") { - res.status(400).json({ - message: `Invalid country "${JSON.stringify(req.query.country)}"`, - }); - return; - } - - if (typeof req.query.coin !== "string") { - res - .status(400) - .json({ message: `Invalid coin "${JSON.stringify(req.query.coin)}"` }); - return; - } - - try { - const coin = await readFile( - path.join("./public/coins", req.query.country, `${req.query.coin}.json`), - { encoding: "utf-8" }, - ); - - res.status(200).json(JSON.parse(coin)); - } catch { - res.status(404).json({ - message: `Coin "${req.query.country}/${req.query.coin}" not found`, - }); - } -}; - -export default handler; diff --git a/src/pages/api/countries/[country]/index.ts b/src/pages/api/countries/[country]/index.ts deleted file mode 100644 index 5c34462..0000000 --- a/src/pages/api/countries/[country]/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { NextApiHandler } from "next"; -import { readdir } from "fs/promises"; -import path from "path"; - -const handler: NextApiHandler = async ( - req, - res, -) => { - if (typeof req.query.country !== "string") { - res.status(400).json({ - message: `Invalid country "${JSON.stringify(req.query.country)}"`, - }); - return; - } - - try { - const countryCoins = await readdir( - path.join("./public/coins", req.query.country), - ); - - res - .status(200) - .json( - countryCoins - .filter((file) => file.endsWith(".json")) - .map((file) => file.replace(/\.json$/, "")), - ); - } catch { - res - .status(404) - .json({ message: `Country "${req.query.country}" not found` }); - } -}; - -export default handler; diff --git a/src/pages/api/countries/index.ts b/src/pages/api/countries/index.ts deleted file mode 100644 index 320a2c2..0000000 --- a/src/pages/api/countries/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { readdir } from "fs/promises"; -import type { NextApiHandler } from "next"; - -const handler: NextApiHandler = async (_req, res) => { - const countries = await readdir("./public/coins"); - - res.status(200).json(countries); -}; - -export default handler; diff --git a/src/pages/api/hello.ts b/src/pages/api/hello.ts deleted file mode 100644 index ea77e8f..0000000 --- a/src/pages/api/hello.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; - -type Data = { - name: string; -}; - -export default function handler( - req: NextApiRequest, - res: NextApiResponse, -) { - res.status(200).json({ name: "John Doe" }); -} diff --git a/src/pages/banknotes/[country].tsx b/src/pages/banknotes/[country].tsx new file mode 100644 index 0000000..720baf1 --- /dev/null +++ b/src/pages/banknotes/[country].tsx @@ -0,0 +1,69 @@ +import Head from "next/head"; +import { GetStaticPaths, GetStaticProps, NextPage } from "next"; +import { CoinProps } from "@/types/coin"; +import { readdir } from "fs/promises"; +import { Showcase } from "@/components/showcase"; +import { Header } from "@/components/header"; +import { getCountryBanknotes } from "@/api/banknotes/get-country-banknotes"; +import { getCountryCoins } from "@/api/coins/get-country-coins"; + +type Props = { + country: string; + coinCount: number; + banknoteCount: number; + banknotes: CoinProps[]; +}; + +const BanknotesPage: NextPage = ({ banknotes, ...props }) => ( + <> + + Banknotes + + + + + +
+ +
+ +
+ +); + +export const getStaticProps: GetStaticProps = async ({ params }) => { + if (typeof params?.country !== "string") { + return { + notFound: true, + }; + } + + const coins = await getCountryCoins(params.country); + const banknotes = await getCountryBanknotes(params.country); + + return { + props: { + country: params.country, + coinCount: coins.reduce((total, coin) => total + (coin.count ?? 1), 0), + banknoteCount: banknotes.reduce( + (total, banknote) => total + (banknote.count ?? 1), + 0, + ), + banknotes: banknotes.sort((a, b) => a.min_year - b.min_year), + }, + }; +}; + +export const getStaticPaths: GetStaticPaths = async () => { + const countries = await readdir("./public/banknotes"); + + return { + fallback: false, + paths: countries.map((country) => ({ params: { country } })), + }; +}; + +export default BanknotesPage; diff --git a/src/pages/coins/[country].tsx b/src/pages/coins/[country].tsx new file mode 100644 index 0000000..e5cdb80 --- /dev/null +++ b/src/pages/coins/[country].tsx @@ -0,0 +1,71 @@ +import Head from "next/head"; +import { GetStaticPaths, GetStaticProps, NextPage } from "next"; +import { CoinProps } from "@/types/coin"; +import { readdir } from "fs/promises"; +import { Showcase } from "@/components/showcase"; +import { Header } from "@/components/header"; +import { getCountryBanknotes } from "@/api/banknotes/get-country-banknotes"; +import { getCountryCoins } from "@/api/coins/get-country-coins"; + +type Props = { + country: string; + coinCount: number; + banknoteCount: number; + coins: CoinProps[]; +}; + +const CoinsPage: NextPage = ({ coins, ...props }) => ( + <> + + Coins + + + + + +
+ +
+ +
+ +); + +export const getStaticProps: GetStaticProps = async ({ params }) => { + if (typeof params?.country !== "string") { + return { + notFound: true, + }; + } + + const coins = await getCountryCoins(params.country); + const banknotes = await getCountryBanknotes(params.country); + + console.log({ coins, banknotes }); + + return { + props: { + country: params.country, + banknoteCount: banknotes.reduce( + (total, banknote) => total + (banknote.count ?? 1), + 0, + ), + coinCount: coins.reduce((total, coin) => total + (coin.count ?? 1), 0), + coins: coins.sort((a, b) => a.min_year - b.min_year), + }, + }; +}; + +export const getStaticPaths: GetStaticPaths = async () => { + const countries = await readdir("./public/coins"); + + return { + fallback: false, + paths: countries.map((country) => ({ params: { country } })), + }; +}; + +export default CoinsPage; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 3393de7..2692df9 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -2,19 +2,23 @@ import Head from "next/head"; import { GetStaticProps, NextPage } from "next"; import { readdir } from "fs/promises"; import { useMemo } from "react"; +import { getCountryCoins } from "@/api/coins/get-country-coins"; +import { getCountryBanknotes } from "@/api/banknotes/get-country-banknotes"; type Props = { - banknoteCountries: string[]; - coinCountries: string[]; + countsByCountry: Record< + string, + { + coinCount: number; + banknoteCount: number; + } + >; }; -const CountriesPage: NextPage = ({ - banknoteCountries, - coinCountries, -}) => { +const CountriesPage: NextPage = ({ countsByCountry }) => { const countries = useMemo( - () => Array.from(new Set([...banknoteCountries, ...coinCountries])).sort(), - [banknoteCountries, coinCountries], + () => Object.keys(countsByCountry).sort(), + [countsByCountry], ); return ( @@ -51,10 +55,14 @@ const CountriesPage: NextPage = ({ width: "min(640px, 95vw)", }} > - {coinCountries.includes(country) ? ( + {countsByCountry[country].coinCount > 0 ? ( <> - {"pile"} - {"coins"} + + {"pile (" + countsByCountry[country].coinCount + ")"} + + + {"coins (" + countsByCountry[country].coinCount + ")"} + ) : ( <> @@ -63,8 +71,10 @@ const CountriesPage: NextPage = ({ )} - {banknoteCountries.includes(country) ? ( - {"banknotes"} + {countsByCountry[country].banknoteCount > 0 ? ( + + {"banknotes (" + countsByCountry[country].banknoteCount + ")"} + ) : (
)} @@ -79,11 +89,24 @@ const CountriesPage: NextPage = ({ export const getStaticProps: GetStaticProps = async () => { const coinCountries = await readdir("./public/coins"); const banknoteCountries = await readdir("./public/banknotes"); + const countsByCountry: Props["countsByCountry"] = {}; + + for (const country of new Set([...coinCountries, ...banknoteCountries])) { + countsByCountry[country] = { + coinCount: (await getCountryCoins(country)).reduce( + (total, coin) => total + (coin.count ?? 1), + 0, + ), + banknoteCount: (await getCountryBanknotes(country)).reduce( + (total, banknote) => total + (banknote.count ?? 1), + 0, + ), + }; + } return { props: { - banknoteCountries, - coinCountries, + countsByCountry, }, }; }; diff --git a/src/pages/pile/[country].tsx b/src/pages/pile/[country].tsx index 78eea12..59a1f07 100644 --- a/src/pages/pile/[country].tsx +++ b/src/pages/pile/[country].tsx @@ -1,75 +1,58 @@ import Head from "next/head"; -import { Scene } from "@/components/scene"; +import { Pile } from "@/components/pile"; import { GetStaticPaths, GetStaticProps, NextPage } from "next"; import { CoinProps } from "@/types/coin"; -import { readFile, readdir } from "fs/promises"; -import path from "path"; +import { readdir } from "fs/promises"; +import { Header } from "@/components/header"; +import { getCountryBanknotes } from "@/api/banknotes/get-country-banknotes"; +import { getCountryCoins } from "@/api/coins/get-country-coins"; type Props = { + country: string; + coinCount: number; + banknoteCount: number; coins: CoinProps[]; }; -const Home: NextPage = ({ coins }) => { - return ( - <> - - Coins - - - - -
- +const PilePage: NextPage = ({ coins, ...props }) => ( + <> + + Coin pile + + + + - -
- - ); -}; +
-export const getStaticProps: GetStaticProps = async (ctx) => { - if (typeof ctx.params?.country !== "string") { +
+ +
+ +); + +export const getStaticProps: GetStaticProps = async ({ params }) => { + if (typeof params?.country !== "string") { return { notFound: true, }; } - const coinIds = await readdir( - path.join("./public/coins", ctx.params.country), - ); - - const coins: CoinProps[] = []; - - for (const coinId of coinIds) { - const coin = await readFile( - path.join("./public/coins", ctx.params.country, coinId), - { encoding: "utf-8" }, - ); - - coins.push(JSON.parse(coin)); - } + const coins = await getCountryCoins(params.country); + const banknotes = await getCountryBanknotes(params.country); return { props: { - coins, + country: params.country, + banknoteCount: banknotes.reduce( + (total, banknote) => total + (banknote.count ?? 1), + 0, + ), + coinCount: coins.reduce((total, coin) => total + (coin.count ?? 1), 0), + coins: coins.sort((a, b) => a.min_year - b.min_year), }, }; }; @@ -83,4 +66,4 @@ export const getStaticPaths: GetStaticPaths = async () => { }; }; -export default Home; +export default PilePage; diff --git a/src/pages/showcase-banknotes/[country].tsx b/src/pages/showcase-banknotes/[country].tsx deleted file mode 100644 index 4f23616..0000000 --- a/src/pages/showcase-banknotes/[country].tsx +++ /dev/null @@ -1,225 +0,0 @@ -import Head from "next/head"; -import { GetStaticPaths, GetStaticProps, NextPage } from "next"; -import { CoinProps } from "@/types/coin"; -import { Canvas, MeshProps, useFrame } from "@react-three/fiber"; -import { Dispatch, SetStateAction, Suspense, useRef, useState } from "react"; -import { Mesh } from "three"; -import { OrbitControls } from "@react-three/drei"; -import path from "path"; -import { readFile, readdir } from "fs/promises"; -import { BanknoteInstance } from "@/components/scene/banknote"; - -type Props = { - banknotes: CoinProps[]; -}; - -const SpinninBanknote = ({ - isSelected, - coinProps, - ...props -}: { coinProps: CoinProps; isSelected?: boolean } & MeshProps) => { - const ref = useRef(null!); - - useFrame((_state, delta) => { - if (isSelected) { - ref.current.rotation.y += delta; - } - }); - - return ( - - - - - - ); -}; - -const Row = ({ - banknotes, - selectedIndex, -}: Props & { selectedIndex: number }) => { - const ref = useRef(null!); - - useFrame(() => { - const xPosition = Math.round(10 * ref.current.position.x) / 10; - const target = -selectedIndex * 8; - - if (xPosition > target) { - ref.current.position.x -= Math.abs(xPosition - target) / 16; - } - - if (xPosition < target) { - ref.current.position.x += Math.abs(xPosition - target) / 16; - } - }); - - return ( - - {banknotes.map((coin, index) => ( - - - - ))} - - ); -}; - -const InfoBox = ({ - coin, - maxIndex, - selectIndex, -}: { - coin: CoinProps; - maxIndex: number; - selectIndex: Dispatch>; -}) => { - return ( -
-
- {coin.issuer.name} -

{coin.title}

-

{coin.min_year + " - " + coin.max_year}

- {(coin.count ?? 1) + " in collection"} -
- -
- - - -
-
- ); -}; - -const CountryPage: NextPage = ({ banknotes }) => { - const [selectedIndex, selectIndex] = useState(0); - - return ( - <> - - Coins - - - - -
- - - - - - - - - - - -
- - ); -}; - -export const getStaticProps: GetStaticProps = async (ctx) => { - console.log(ctx.params?.country); - if (typeof ctx.params?.country !== "string") { - return { - notFound: true, - }; - } - - const coinIds = await readdir( - path.join("./public/banknotes", ctx.params?.country), - ); - const banknotes: CoinProps[] = []; - - for (const coinId of coinIds) { - const coin = await readFile( - path.join("./public/banknotes", ctx.params.country, coinId), - { encoding: "utf-8" }, - ); - - banknotes.push(JSON.parse(coin)); - } - - return { - props: { - banknotes: banknotes.sort((a, b) => a.min_year - b.min_year), - }, - }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { - const countries = await readdir("./public/banknotes"); - - return { - fallback: false, - paths: countries.map((country) => ({ params: { country } })), - }; -}; - -export default CountryPage; diff --git a/src/pages/showcase/[country].tsx b/src/pages/showcase/[country].tsx deleted file mode 100644 index c327d0b..0000000 --- a/src/pages/showcase/[country].tsx +++ /dev/null @@ -1,234 +0,0 @@ -import Head from "next/head"; -import { GetStaticPaths, GetStaticProps, NextPage } from "next"; -import { CoinProps } from "@/types/coin"; -import { Canvas, MeshProps, useFrame } from "@react-three/fiber"; -import { Dispatch, SetStateAction, Suspense, useRef, useState } from "react"; -import { CoinInstance } from "@/components/scene/coin"; -import { Mesh } from "three"; -import { OrbitControls } from "@react-three/drei"; -import path from "path"; -import { readFile, readdir } from "fs/promises"; - -type Props = { - coins: CoinProps[]; -}; - -const SpinninCoin = ({ - isSelected, - coinProps, - ...props -}: { coinProps: CoinProps; isSelected?: boolean } & MeshProps) => { - const ref = useRef(null!); - - useFrame((_state, delta) => { - if (!isSelected) { - return; - } - - switch (coinProps.orientation) { - case "medal": - ref.current.rotation.x += delta; - break; - - default: - ref.current.rotation.z += delta; - break; - } - }); - - return ( - - - - - - ); -}; - -const Row = ({ coins, selectedIndex }: Props & { selectedIndex: number }) => { - const ref = useRef(null!); - - useFrame(() => { - const xPosition = Math.round(10 * ref.current.position.x) / 10; - const target = -selectedIndex * 6; - - if (xPosition > target) { - ref.current.position.x -= Math.abs(xPosition - target) / 16; - } - - if (xPosition < target) { - ref.current.position.x += Math.abs(xPosition - target) / 16; - } - }); - - return ( - - {coins.map((coin, index) => ( - - - - ))} - - ); -}; - -const InfoBox = ({ - coin, - maxIndex, - selectIndex, -}: { - coin: CoinProps; - maxIndex: number; - selectIndex: Dispatch>; -}) => { - return ( -
-
- {coin.issuer.name} -

{coin.title}

-

{coin.min_year + " - " + coin.max_year}

- {(coin.count ?? 1) + " in collection"} -

{coin.weight + "g"}

-

{coin.size + "mm"}

-

{coin.thickness + "mm"}

-
- -
- - - -
-
- ); -}; - -const CountryPage: NextPage = ({ coins }) => { - const [selectedIndex, selectIndex] = useState(0); - - return ( - <> - - Coins - - - - -
- - - - - - - - - - - -
- - ); -}; - -export const getStaticProps: GetStaticProps = async (ctx) => { - if (typeof ctx.params?.country !== "string") { - return { - notFound: true, - }; - } - - const coinIds = await readdir( - path.join("./public/coins", ctx.params?.country), - ); - const coins: CoinProps[] = []; - - for (const coinId of coinIds) { - const coin = await readFile( - path.join("./public/coins", ctx.params.country, coinId), - { encoding: "utf-8" }, - ); - - coins.push(JSON.parse(coin)); - } - - return { - props: { - coins: coins.sort((a, b) => a.min_year - b.min_year), - }, - }; -}; - -export const getStaticPaths: GetStaticPaths = async () => { - const countries = await readdir("./public/coins"); - - return { - fallback: false, - paths: countries.map((country) => ({ params: { country } })), - }; -}; - -export default CountryPage; diff --git a/src/styles/globals.css b/src/styles/globals.css index 72d127f..60a2f2a 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -10,6 +10,10 @@ body { overflow-x: hidden; } +#scene-root { + background-color: #111; +} + #scene-root > div:first-child { height: 100vh !important; } diff --git a/src/types/coin.ts b/src/types/coin.ts index bb1bd63..753f06d 100644 --- a/src/types/coin.ts +++ b/src/types/coin.ts @@ -14,7 +14,7 @@ export type CoinProps = { id: number; url: string; title: string; - category: "coin" | "exonumia"; + category: "banknote" | "coin" | "exonumia"; issuer: { code: string; name: string;