From 0e8de8d49921f3a640c420058904b773918222b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?s=E1=B4=8F=CA=9F=CA=99=C9=AA=20=E2=98=94=EF=B8=8F?= Date: Mon, 29 Apr 2024 08:57:00 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=ED=98=84=20(#95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: memberImage 컴포넌트 마이그레이션 및 props 수정 * refactor: memberInfo 컴포넌트 마이그레이션 및 디자인 수정 * feat: postCounterBox 컴포넌트 구현 * refactor: memberPage 마이그레이션 * feat: memberPostPage 구현 * feat: starRating 컴포넌트 구현 * refactor: memberReviewItem 컴포넌트 마이그레이션 및 수정 * refactor: memberReviewList 컴포넌트 디자인 수정 * refactor: 세부 디자인 수정 * refactor: memberRecipeList 디자인 수정 * refactor: 세부 레이아웃 수정 * refactor: 필요없는 css 삭제 * refactor: 화살표 svg 위치 수정 * chore: 사용하지 않는 페이지 삭제 * fix: webpack vanilla error hash 값 추가하여 해결 * refactor: review item 일부 컴포넌트로 분리 * feat: 작성한 꿀조합/리뷰 클릭에 따른 페이지 이동 구현 * chore: 사용하지 않는 css 삭제 * refactor: member에 recipeCount, reviewCount 추가 * refactor: 세부 디자인 반영 * refactor: camera2 아이콘 교체 * chore: svg 속성 카멜 케이스로 자동 변경 * fix: css 순서 오류 방지 * chore: lint 적용 * refactor: memberModifyInput 스타일 마이그레이션 및 수정 * refactor: 레이아웃 변경 * refactor: memberModifyPage 디자인 마이그레이션 및 수정 * chore: 주석 추가 --- .storybook/preview-body.html | 26 +-- src/assets/defaultProfile.png | Bin 2506 -> 16739 bytes .../Common/SectionHeader/sectionHeader.css.ts | 1 - .../Common/StarRating/StarRating.stories.tsx | 17 ++ .../Common/StarRating/StarRating.tsx | 37 +++++ .../Common/StarRating/starRating.css.ts | 23 +++ src/components/Common/Svg/SvgSprite.tsx | 26 +-- src/components/Common/TopBar/TopBar.tsx | 8 +- src/components/Common/TopBar/topBar.css.ts | 1 - src/components/Common/index.ts | 1 + .../Members/MemberImage/MemberImage.tsx | 22 +-- .../Members/MemberImage/memberImage.css.ts | 6 + .../MemberModifyInput.stories.tsx | 16 ++ .../MemberModifyInput/MemberModifyInput.tsx | 50 +++--- .../memberModifyInput.css.ts | 34 ++++ .../MemberRecipeList/MemberRecipeList.tsx | 92 +++-------- .../MemberRecipeList/memberRecipeList.css.ts | 9 + .../MemberReviewItem.stories.tsx | 22 ++- .../MemberReviewItem/MemberReviewItem.tsx | 104 +++--------- .../MemberReviewItem/memberReviewItem.css.ts | 13 ++ .../MemberReviewList/MemberReviewList.tsx | 86 +++------- ...nfo.stories.tsx => MemberInfo.stories.tsx} | 0 .../Members/MembersInfo/MembersInfo.tsx | 61 +++---- .../Members/MembersInfo/memberInfo.css.ts | 22 +++ .../PostCounterBox/PostCounterBox.stories.tsx | 17 ++ .../Members/PostCounterBox/PostCounterBox.tsx | 41 +++++ .../PostCounterBox/postCounterBox.css.ts | 25 +++ src/components/Members/index.ts | 1 + .../Recipe/CommentForm/CommentForm.tsx | 2 +- .../Review/ReviewItem/ReviewItem.tsx | 51 +----- .../Review/ReviewItem/reviewItem.css.ts | 22 --- .../ReviewItemInfo/ReviewItemInfo.stories.tsx | 30 ++++ .../Review/ReviewItemInfo/ReviewItemInfo.tsx | 33 ++++ .../ReviewItemInfo/reviewItemInfo.css.ts | 8 + src/components/Review/index.ts | 1 + .../Search/SearchInput/searchInput.css.ts | 1 + src/constants/index.ts | 5 + src/mocks/data/memberRecipes.json | 66 +++----- src/mocks/data/memberReviews.json | 31 +++- src/mocks/data/members.json | 4 +- src/mocks/handlers/memberHandlers.ts | 10 +- src/pages/MemberModifyPage.tsx | 155 ------------------ .../MemberModifyPage/MemberModifyPage.tsx | 141 ++++++++++++++++ .../MemberModifyPage/memberModifyPage.css.ts | 83 ++++++++++ src/pages/MemberPage.tsx | 40 ----- src/pages/MemberPage/MemberPage.tsx | 36 ++++ src/pages/MemberPage/memberPage.css.ts | 5 + src/pages/MemberPostPage/MemberPostPage.tsx | 42 +++++ src/pages/MemberRecipePage.tsx | 32 ---- src/pages/MemberReviewPage.tsx | 32 ---- src/pages/ProductPage/ProductPage.tsx | 2 +- src/router/index.tsx | 21 +-- src/types/common.ts | 1 + src/types/member.ts | 2 + src/types/recipe.ts | 2 - src/types/response.ts | 4 +- src/types/review.ts | 5 +- webpack.common.js | 7 +- 58 files changed, 906 insertions(+), 729 deletions(-) create mode 100644 src/components/Common/StarRating/StarRating.stories.tsx create mode 100644 src/components/Common/StarRating/StarRating.tsx create mode 100644 src/components/Common/StarRating/starRating.css.ts create mode 100644 src/components/Members/MemberImage/memberImage.css.ts create mode 100644 src/components/Members/MemberModifyInput/MemberModifyInput.stories.tsx create mode 100644 src/components/Members/MemberModifyInput/memberModifyInput.css.ts create mode 100644 src/components/Members/MemberRecipeList/memberRecipeList.css.ts create mode 100644 src/components/Members/MemberReviewItem/memberReviewItem.css.ts rename src/components/Members/MembersInfo/{MyPageInfo.stories.tsx => MemberInfo.stories.tsx} (100%) create mode 100644 src/components/Members/MembersInfo/memberInfo.css.ts create mode 100644 src/components/Members/PostCounterBox/PostCounterBox.stories.tsx create mode 100644 src/components/Members/PostCounterBox/PostCounterBox.tsx create mode 100644 src/components/Members/PostCounterBox/postCounterBox.css.ts create mode 100644 src/components/Review/ReviewItemInfo/ReviewItemInfo.stories.tsx create mode 100644 src/components/Review/ReviewItemInfo/ReviewItemInfo.tsx create mode 100644 src/components/Review/ReviewItemInfo/reviewItemInfo.css.ts delete mode 100644 src/pages/MemberModifyPage.tsx create mode 100644 src/pages/MemberModifyPage/MemberModifyPage.tsx create mode 100644 src/pages/MemberModifyPage/memberModifyPage.css.ts delete mode 100644 src/pages/MemberPage.tsx create mode 100644 src/pages/MemberPage/MemberPage.tsx create mode 100644 src/pages/MemberPage/memberPage.css.ts create mode 100644 src/pages/MemberPostPage/MemberPostPage.tsx delete mode 100644 src/pages/MemberRecipePage.tsx delete mode 100644 src/pages/MemberReviewPage.tsx diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html index 39ca6ff3f..138ea3ede 100644 --- a/.storybook/preview-body.html +++ b/.storybook/preview-body.html @@ -42,19 +42,19 @@ - - - + + + + + + + + + @~0drDELIAGL9O(c600d`2O+f$vv5yPR_U79(7b!CJYS`ObYthKVJtw)&cec`6^#-@>t7>1EI%H*G&`dJ*CsMcRU0 zZHVByh>+k0pqK7SMyGGPylvb17rWf_WP~lWGI@PPiWm-mp|H8 zUGBEYF3bDvnAYeg1++bI+6%Q6yUGwjgapH(cKa^hI@vuRl`nUO_f9`)6w2SZ2QK^W z*-VHC3HqUS{MoVagF^$&rk~Bm6Jl1Apnuo@wtV31Y-05FtYf~!t^(jW)unfWzJtjY+eaSE*NT8qJl@G5^ z7Jo$Tu@<5x>4BeV1%LGvrV*w!39i}w*o6qf2to#@eaCb;6{al-BBsxDfc6v;#6$}7 zY}RQ<0wa^tFM%%o2}CdrAg6-e|4=w*uudxy=x2AWgWvyhWcQzj(6CG7)F%;!m^LKP zPyaw{|G>0zxFQ&i@bneJo&^1cEVBDYl%E*_@ej1`gi~^!4Pgvr{&f0JAVPqd1PNg3 zzfb|qFhSU!1p3JzJPJ*JDiZab(I|w|@wnCIQCO0|NPCEA|FZ+u`w3x10%iYqdw+@m z)14!jMQDRPu)``DHEc-GAN_q_PJnfYV0OZ0drVvXm(RdtgarwV+#mn@vqAs&`*paz ze)PKi=;-mHug|BxZ?kD|I&FxOo6BKGMoKhhB`k<1SWbeOPJqVNKGe7NqOnEpTYAyb z;YLTd7rh>zy6+P*5W)etTqJ>ANMJ*HN(|DIqmdBfKvsGz=BCA9PHK$!kzp<9O$|&Y zf~6#wsRZD{Z*1#BMO_!J)O4bSzZcqGGmdEJVQ+nlv<<<=Oti8ezG!avSlID)QOFDz~#JV-UNgNT|GXuipkU{3%{aPPLalLTqtWp zL;vZ*pZD~U5Dsiwk&bN}=3@QQG(`@c8Z!0g`u5>!xm789 zKQYdwcIULDXxzJHo|rI6viOtKf*%2H{ScoZAm&lPZ#+i8_!+;}gdiF}A{)xA6?bjU!l!PUr~HN}=M3{3LQDixNzk7LePX&3z#}Hh zh4OY3eo~89_LnOYXkhVgUX_7|w=cj_vELo`VQ()Nz3!E@?v{I5_`YsAN;+l1_sC

rpTEqt$6yi61;b;M(yx4LvCL;7mw`7mj##_ zz7T@g+1x#&15n0*~C8 zha`DjHf;u#k!#oyitZMsy+it`@Bef<7sAk9Z)x-3#rI3`!h5BtY3e~*Vl-|NyZq}9 zFIOhd5De`40k5&(yRHa>DvaHJic!;M!`?GaJa;GxH9`i>?!+DI=i-Sku13BnNeXY^Cw+bMT1 zV;Z8TPolcr9yCax>*+TxqVRaFBEZ@usrc@fR%2_yoZ$bk^CHlGMizf-$QS=`bo6TY z`*))8^uZ|gHHq-!Z)`xWkk)XTXFzO0Ly?$8>oG+LDGBnD3yTL!ISkk zFVg1u@-}q$dPVc^m7fh=z+6DI`yYL92^NXuIRsqnesOdg_KVG53oFs%*6`+OC;sF= zV}t&jLAbf8v2q`Sf+Z4jSeT5(If+O~jKcJR_LR2vN8iB|AY>#6XCV!vkLN6HZs#(a>&#;Fe5L^v z_1)+cyPi8Cck~U*(y?+u5|-yBs|7$Omu3%t&a?)tUt)AR__h6-gQ<=SvH4q10=-pY z3QfK0GZmo2?Dh_PrNL)UL0{BT^xEgakxj|6&%}j~GLfI4^ z*`621WDrL=!M=Vny^W@v1mWZdoGop|%Z24Qe!fX9er9Ykh;*wsw2ZQ@6j?J>BD+a( z&fpQ<0npr0L9IT+_NTVb6M(jVZ>=GPP8To=9hD*WT@K(%lK8X(eO?>d#G&r$v!SX* z!y(x$J`^8`gkX9%llN9GNWnLDE>jWk@Kc&5=O0Wx2~K^#)M`I~iq2bys__AB{_~A! z?et)Q?D}_ZnkULm3Kok~o0c4n)L@Pv7r0w?cz=hn@Oe{uzq>!Rf#y!Yi25@4MJaT; zK@)|@5iibx(|F8&3yet1W3L{K@c(wZ*yVconYQ`xr#63tDQoqxnm#)a%|G;SUepvN$8 z0{si!WSP@i$a`ath7T^(Nf7Qzod<6g>3H|76YV`37Gx)?sQB-GcBzV$gpcGpakI#Q zDMEi|=v}Z7bbMdfSBCwc)TvC&g*gehOVo~S>*uHp&Zxop_q6G0-ng3$vxfH!YWX@b zyP+%MJJ1Vx`_wHx&W^lvITeZ>_@ulYbQCz(f+*W+9@SI<_qG$*vD%CF^+knD`8*>e1V0$jqO* zDLXvs8FcLz5~I2yvuM&J=vRX*NsME``sM0Q{I6$E2@#r9B=omGwE*|sI$t#Xc%^$A zFH$$m97>tp<;DpR+4(1gg84oy%=9BAHh>q8$_8|uNRH9*wcFh4@oOi?lRF8F3z-V$^*6V>@zJRUMF8f%te2?oHy&Cxk^p`6K#Lf!U6&#R2mz9! zb$sX-4C~gh?Q3&||QmTXc7i4~He9`IF~P zDHUkdq7?kiA8Z=>OC&&dnGoQJ5TPbw{)7-b5gri|JSe7-KM)XSS%~o30dc{~tQQ@0 zjH~nYWKIH0T5Gf8!pr;1Rc{~4azFdd7R*f_R!`e2%1`SFqkJ)fkYjFg0C%qNVe>*i zDw}P1?Wh|i=Zi#ztAxea-e1o$CMHAz;}kI88D?LfHxE^*m;hCX-xDX8MI%GNh;QpL zBk&c0X}EovSD8jxLWs)^cKqX8ZgkfiGd>SXq5brFzcJC1z>-to6 zft9BKgJCR)$(tLGuYG#)$X{wYBm|%dG@EjL!UrjGDBrQvi>*t2sB5?3&65&Y?v#_D z=>RN+rhj{^A5Y{Yu;dgdu4u>JBh@P9dE<&S+$9mpA!t9_pVsUTtHPGq1cyz>>Ks2l zFEIp%2z8emYgYSqEmVdrRc^^0^OQZ;9^Awj$UYz zoyLZ|>;!CDo;LIsnm&wVe})MdsGpOhWphuVBA$05bLQ%1mS~(=zubda#I87Wao=h{fTuKlyzBv3g*=A*8;7Z=Lf(Ilo2%lvLzn|bYr%nEHg6^RCi86=30`9c6@o%VV) z94L06&!ZUyN*(8oh6L7Nr|N<-3^!s9ZHEP@sP9rY?*8-V#vv!8KQ6#iK=t*sw#QEd z!I319aIYzqp{P54~m`mj}N2pFNINf z;b@dX8in#<4DR^CiDh-S`{3#d@u3vnkosX4j2kC)La>(Td4=930PKF@^kM%#%QwLKaSzY3p{Y`hj?H zhS?j`04Kh52@$#w&NyD~z-}P`%^|icS&{8mL8S6#J6@C%fgKwH`piBNG|h032f#i? zR~rNS+QlsD<^xy)UAyY%j%^NEXbKT+JPCTds=-rqRR2r$bMi}gM~8V>y?VllF4^ej zrv>ojLp}KQA9muqpYFw)c|M#HCvnelCn{TJHVN3vI3r$m{{D}yu1&*`X5Vae^ z)~~MZu}PrmpM!Dhc!x%5m6^a0911 znw+0r-eeQUHX84r8-F{IE^z|+(MLOt2r3aHkJsn=u~JNb&+gr;Clu8`0JyBxsr0BuEzp>>nTNMna5^s#Y8R@IPX4Mq(zEOVwv- zX;%t8pHk`QpMa)Yq6)FC-%p-9jeSRJl&1XIJ96>mdly+YoSMu1GwVHAzrd$AYWDiYdlsqb@M=U7-!v); z-K8)S@nX|v%1O{H0iTm%$2WFqh?ThAs(GU)fn_A>xKuAYz3hHxs_n=U4{OmJznXmW z(IuyHih0UxU*SV$;`J9oajhMH`+789JQj@)<#dUY>o3m=T=h4?8GMb4gb4fy`FE5H z0lI|HYjgaFPvNkTG~@WR0vgJL8@OJdC8q$}DenEa3bjqWs*Blux8z{S{KRWB!nkV$ z%uk!<<*D;OP~cI+vdhF#rUdGepwE44#q4p8bo}_euiffFgY0}quQ>3M_!A;_VU>LF zjUC3{6Dz7oM&j7nlr7yh>=rq-@VpaeYwYOkmBllkCY3Ic^yyPZ8YAz=mu~i;S>BJ= zaU=LFlYjOBVgc+@8Q{M2dZ1`aQZ7~(1L(!Mg)RgQxnwymE#)DdP82K$LJY0lyqVN{8@dvjObbHasVSL}GD z$cam`Q!{^_w(mye6zgiIZtB#~ErB-W|LNBf$QXG0L>B#JAyb@?f#0VS-7VkeRC=0D zi!%M#xX_QA<;LQ5nq-MF)4P)f9pz80@G5`lIT0B4ozbu^w?TEWi?+$`5|ah9F@gm8 z*&Nlbw05qFCTl%Jh&ZLS#W23VWQ-lAdBO@a%N5@>Q$5_I*7eY`mvw@EzU>YxYJS-MsTa3$>8D)Lyrd66IaV)Jjx_p8dOljVk;%MW%i zczWc>VrJR|V-8&0iUgvPFdf4$CJ{+MlZrk^N}R4vf$6^MkA)T4Mh!C4%}Iup*?m}= zT_#GB9G{7+L{c)(;TcH+W{sM-<9vL!0aXp%h!G?Cf!pRIHEEDaz&@62>S}pE%iv(M zshkuY*~uQU*?l-5_BP ztjNa*JV__tRss;}2CO~cKrGp^0O zqVr1v^j2Hn;=3PoVtd?B_WA&5qR{l=;{L*BBL$#OqM_`vz`xN&-#~5?oqz3>Ycj>6 zm!p&ieJmsrV->DxB$E!u+WCHU8ZdTnqQaq4QnFH7jFaD$Y?wwSAP5Qcd^3DvUH)T# zQN{)c#sr2;l~*&yYAmfA@CP&%nWf#{CANJ_kEYa}oIF~r(hw=bU~E7)&d~{gN7_Y zWnR&?Wp2be8w?*XaiuA0Q4n)T%QxdB=yUt=?h&JDR$`nB1xr#?%CrJA3p+}T=&%Lw z`ed<-s#DQq#|ILfWws~N9+>On9mRs-&YYcM6wlnZ#*19}VCmE*#*U8+OxGs4D7#WV zJXYpVQRU_?ZO92Q{F-UvKdj2}N!-AX)pG5;jDR9xlyiEJVIf~{vW_!VP;xM1DFxAO zMpi&vuB^}mgc?IgV5Co*qYU*52|hesuO4q$mZkz^wgJ|&pAZ9M7RaFt=Uy$WpqUe0aO_i8V8uJsJ+v198pAAWy_TVzh3m@D)lt}RTzT$3pjj3WQzdr`_9a0%H` zQsU&g+1Rvk0~Re@fV{kXx#m#v_4f9nrltm0O3P4mvItkMl%b)kS6;tO1=$|H$)kLf z#Ay&zTRD$oVeKL@JCs?pQ{ESwug_Qq2}?sBNghgqfH|iC=MSGPZBeo)v2JOq9Nz<` zP_NO6z;9kB0-75v1pnTPG1z<7kY{6KqjCG~Tk+6CJCQSQUeMimFcvIWfLm|9MLm9J z?_Rw8@*b3xm*ZeDP%IzpAKl%D&u#E1TYdnY@~6Ij(utoJMvGLaDFSTTv;hzA+=;bo z*W!90DQ~{{W<0d>b0{e(!GAvg0*)R#E@ZOdZ(fa7<`u6S?qCF*WvItWjT(zK`RG$6 z24gf-kc~2W4nm2cpRAfnANsUJmP}r%G-?7E6Iihz<=PKP026~^BtV%&ZNL3&>{We# zY_|yYE)FmtNkDmv`?$eSJNC`gXMX8E5}e|EHt->%&p_zwbti zoNAXHKMy-U_gUO~?>)Ft@Wdi%mM>q9%a5)Ao-cYSl)PKgn0M~KlQ{=i#@s&KBfO-_L{JhCJI+7H{$ z2ob~|FlpKh+oAl$i?R5m%-9dU_SLW8>tFw`NJ~u>~b$ z*ROJR!V%O%=nzvPrJP(Kua!QHF>pn+;e_QOHHj>#^yW!WUfZo6&q<5D_5+$g$`>#v zF2G8smyWvR7&hMEhsE^aEiP{A^y!f zi1%e=W@ch4z_jx@b29Pu-}_xuRaN2q`3rdYm`kGDKHR$47oN_t=pm^h@urH>#rO(U zxT{cE19f7b&PS*)e5=cc3DCs`Y40|apPbA=BsEaF)AwQSoGeASw@*7!-C{$2em)*};C^v@^RDZ2+z5DrB_$={ zkH7m}q>Cfp<#8y}s3J^DIjIRI^{0$5iLiBWhd!PLef0<>EO}RGhcjc8n43B%Ta^7p zO)9*mBf9sTNT6MIFLx`cuo%&YgRE82XQ672ZA*KGbwzOi-+&New*NlmYMyNn? zZ5N__boek%ojQ&E7kt>h+=Jv;gdM1m^TtjT3>;nsNx;U-G>f#*SntE0RX0TnRh>{HK0Y4X@3>w0 z2Is0B$~n(W^od#&UVTuRQ0EGo@}V09VDsJ(rC5j0*+^NGrjQBU2kP22m72gsn4h1A zMT-`V`TGn^oj7pxp8EIOn`( zr`v|}wRW+&5q4l|$*4(&ToWP8B(_8yV#fuSL_j^hLA$={NokI9(cEoQk;&NDSgaHo zGb(EABJXqO&*P0Z-a=(nrRez!WkLE?G&htu{PD+f%{S53){g4x8hqimKChz469IjK zoSb=RZEZzalUrm;Cz%Uf^+LK-}^gam4eNvs1c9ey>9MnN@VGQl6wjSdd1 z_R7wV!}4X{^5_0;MnnFasu?JAXI#O0#>hDiRfsd-Q~+yaJjx4EnVSP zqQ?BGZZ}iIp_-Nr0ly5PU}6mkgavUiB!Mx6LqXLHgq{RGpOLV}v}A|Vfu!W5t3Nw- z>^REG%Ve=-DETrrHU`DT7gf-S1R%P)x^e09C1n;ZS-cpnZEa$%R0~;pkTo|8>(>>G z`?Yj+b>U)33F_+VMLwN_xpU{L6!V6L29%eVU;RC=*NcyZh*W!$WLGCCs%vW1_wz+w zUAAoLmiBNL!BFZZ&hdf6~$tC>f z^Din>s->j`M~)s-e!>DF&Y%C;pJLv;>zgeU1}@6;{OiyE4P|BJq8`mbLBU!%C2c6a zSgc;pV0?7w5c>N1grI4tsHl*@+ZFlRt@4!~OZ^=o;M_5<8iTlCf>{U~_YNb0)@H_TOcE@Z7mpJcn^9h8UC|78&qP`9BtcDWts(%?+1ZKr z-rG0ozoRK~_Uu`88;p`mmlQ$9M*_dH^-D|3lu5*lP~JvEPfrgHe)!>t@7KzSP+wPf zT@r*fWXW~*7$jiViH!JQ{z~XHoT1OG>+LWBPNxlva||=&^yOC3?E?}(vsu=PkM@6R zN(xd_Q!p9u-{<7!jQjWF;$oGZKT(jx31S|lrlw&!!=s9rY-kq}u(RI$U{1R&bViFM z5-BUl^7|)IcK7;FDW^d|qhx3e2^i6(@^Z_~6K}dl$#cu*%~&kz(Ri=9U_m~XE?t6& zf-!)F3l|_aH*|S5W`M;sEGpt2IM8up1T?cw0-y{gK#?FTLG>9TSZ3Mh<74Yo3z{Tp zX%pX3?RJ}5lr*iz3s$R9zn>_Qlap1EParV82LQ4|b$y4XT3ON@nv*o_?;!y~SY|nl z1ez)3Tr8tZNph)T8sfmodi45TmYG9bMBQR@zx~c$OcYd)J~(g?4UOZQs!18NUR0ps z;$ln`b>hcdxKNCaj!rW)g^+-+n-z7O@jN$4M_y_$LNk&Ux?GQ8xkLUovn-^TD7$L5 z_3_z8oG)t==}t!)oJt)rt7knOT;}?}x9?vi4)BSJ5lj?30a!fq-~Z&#uy*YlRqaK! zXt;FAYaTs*9B;k#Hj0W)!tI{8{_U3MD%`(c5oybo&3NRIhgBWKbOKXY&Quvq%UB=1 zGHAPdEu_u3hOKy;X@$LPuky%_1?n;DjbHz$0zH9*kR?e41Ir)(=70VK`#(4^DFO@z ziLiI?yZGC`{fR_-N4}jbfBfYypH;g5WC$<-rc+c_Rblt;J@~u7drGND(+SLOWkxU8 zISXl4k01dFAeyOb;sV0;Fq8y#M;S~4O(I5(Sy@ILztD`{K%A*0;Ohq1< z)p})-hGL=m#iVn4ES&!}0nij;OPec=b}Y^`+SQC`6+_D)#Jx#}lE7n*V|?}ELWFNV zWTY*8a-j()Dx=ZkHLpiKol2G>YE$fs@cDM^*p9gPk@X2V^K&qN{`@JuCZCH^>!ytx zucmTL2OPTOR3(*cFvgNfmVl0UTUb^Zm4Q%V$hNDk-_@p{`hJ^PDb>X7>*uP|;CyKt zeqGpx#Sds$m`ZMj-Y?+7`N~(mga_`wPqj<=<+H!SWWn;x+qd4P7J7V;BAvyH7UA39 z`a=oKRbt=1_mwF&kOwpoP};rsp1V~-AJZ--TNiB>cna+P#OO-RX2t9Be8@@;;twbi zOik(OXb9GZu}n4PH3@9B^5uIL;wR6ZM$x5C9J=U5x?DZcqz#P=m5Yb%OUlbDap2%V zOa#>ZnKwj-I7I?)qb0WS_eeff#U=}(t-S+Bj~>NDz~CIyJ3f8iy-J>)$`Z{`<5ZnBy@V>W08?LF(jiE@XU)^qb>ubKiH6|Abv zE~jPO_#*I=!N`@S1GUKI7mvH{V1xyr7Yrb-& zR1sl3pdV0OU9GY~Ckj@dF-A}}DD66&!DY@qNY5XMQd4?1E%0H-3ZI(mHUhS2;}i(7 zKcFr(;yZpjq6=TVYav!INI`SA18<*lr~wXY^0^7n#Qq$d@<0K zE)>_=R2%yT3M4otvZy22UdP~A%)F2$&JAG16+|H_Gg~1Vz~)uy_`=-_(Ad_C3$@}O z9MKg^ImjWDt;QMEr9VJr=j5qVDxardZGlLfu{eM3JdS_z2^t!%r9*J>ZxM%d>C&Yt z$adz;SrzzVx4A{*OrT>W*^(uTap#>oR0Ci75)1kZc~}AV+Usu&`F&P~QO;#O0RwWZ zK_F=h3f8Cs{%}V}kA|lYM5#{SOc`T4${j1bqn`p%bL3`DdiW?b(~IPP+hGCj+?0*W zRh{_F`=vNgY)p9JxKd>|hKLBN=2>?9M;?AiEkyPNV!;fZ&6UfSqouVKO-;>e=jD#Q za6!JPKs%9_my2Erwk=<_OjVZ66UUe;&3M4);k7>VzylIkt5Hrh3B+r#a_pl+hgHGO z0B*T?i&BBo(o$8u1Bv7H`V@In!#GufO-1_L8eTo=!iz^;s*d>HH6GkArvL|w1O=1j z*m2Gg`feQRazVeVi$bJXLxT7i2fiedsox*K^Y4{n-+AU4>G9AC?M4L^H3T6LDYZHW)xzQ?Vmd^&@Tno?t2v*l)9dU$XWXn`Ut zyRmSF@%^F}U9RrH2SxQbS8Ys>4>bu!!&+J7l@*mLM~5cNx*Mn?o+x%~->%FerbFBz z!8f*snNBk30H^@{;y|=&e4LXOz<=G|rv`Hb^#d3eaEXrM7KeiT;QN1}d=2^w(jRs}%)*IqP@PF)o9}u*(~xloC}{q`}If8`}D`z0DxN z0C>HutgLBE078+#ZG3JVTQ%xm!oXPkB8dy+!(8ZlMt^s8Z4WF)Qi2N!u?_@mu?R4g z)*gijrWe@RqpLqrm!qSCR!K5*m~v=ru8}rvCj5?~(Mh185Edgk$_|(4X)T>P>Uz>- zmspGlrVrR$w{cLTFOHfGy5L9vj%$rFxnY3#0}Kg_P6EH95Eg?0G^SLr8%3{Qc8H`^ zax*QrZ$?2M^nbJ9_iLzY>tABRg?Xs~iOCFm4Y7IhL2ncyWWjXUu-~{F1%_W>?P-vb z5Upk$cXWHu*xHLe9}}vkP80Wd<$0Sz+xtFT(A3x@j=k4Z*NQWrFEtoTj5E`6L>3+4 z6f+*+np~@!NnkhsH@3%Rv0uOe9;u0jRMy$!MO`bC(Z6q)!b3B zR)OsznIn}JCx5$1v&-0KmYJf&;>=O%Ls&0hMS}%hE7R8exR4LWCPBcy8x|rp$%XXf zXt-qiXln1nm6~otMVJJbv!2XdDVe2}y(;oL)4@EYippwLN}87*2;SFc$}eg-#h2@i zN`c%ImuO3oRz6Af&|USTZM|T9q6- zb__Ee%r>p6sz4w6r3wks<3nGy=Lr~t%1awwQ{a6K)iw^YP=KAe3Oo=~rKU9WT828@&43 zYk2;J7t{{j6T+%6o&xXf+lTV<3L$|HcdznZog5!Z&=lf`S{Bg6I(6J7*L4PKBH|RK z&u(4>{wg&6nZaL<^DGKH1B<{m?o0EMuzFDnn%mtdD(OID&*US=3E~{yzSN7%c&{wb zTDqAnPrxIM~>~MGN_;Iv0)j{`lqoKYQAAWR54f~kPJhIV10&vm|C*Cmix**qw zjSGC@4~5P+fW8VoD)lX3g{ zERi+sIA7k456<)&(%K}z(_qbfKYnYo2QHgiwMKk-_a1b1bxmo5TM~df{=WC$M{9F~ zDk*$qlLsraJh)O?s@gH0K64gR309ji1NE2BKBuPaBu07gU+!>Y>73D$*QO30KNTUH z8dx4Jr@+>wzTnCbi|3sQ<~zn3o*e$IalIwVB+~Vt!6Gnf%&gMY3scb8?!gDAJJ8ZQ z`5Y6P2A|vL#n#2LQw2PD>+N^&?z``)s;#Nmox8fbapcGmyt8+&DyUzS?p7s*U%l0X zPp|bMBd%A~DZKv18?tMkpOS8PboTjNue|!2I(cGcqy3baBU_hvRlq9LXztWhLoN0e zWzo#G<)fSeBmhkzvmIlR%q#=V{H`o^7Yum!#ei@@HcJ$*jauCb}jEyS>6sp+qlk)6Gdmx(bb8Vm{`@5h=ngV+AYp21gfs8R?TwXeCsW>E9a)T z@nu>3T#)lq11h7ExLhlX_EIfM%gR)ZF~=&!1!>xKJs5@iH8^wj9Cq({1s@zZpa`&Y zg9l&V?p9@tp^izhP0q(x9Qfs-C^Z}IrbT}I_7;yi5k?>`4~WSzIVn)8E@JpVIrV2n?9*KT(Ijep;MKZ?Cegzjb%tlpXVI@$y%%#Gts=j_NiI zeX>B8EM1C%fqzD#wXP$$EXw@p`zkpw6eGm0~hIR(@0?n82H0IOsX{O&e4Hstwa zXCC=FNjw&xzjo4vDtX-6<3M6k61Hx=P1Q29_Bb{sc0^49XP$AULTzmwPKtAV@#00) z*3~K%W=W z#0GW*`@s$G5BjO^kp$ae5$c+I@xPxtgI5n!ASKq1AMET^eeI`G`+n(|3%@!Xr5b>> zc4?|Ggt0A-du2O@r`0R3 z|APw-JbTEcWYOg!KmYNk`*6$RAg_UMQ0lGyC6s2$quS%z+8;d~^e4DMSbZ9B^y#Tf zt@z=;9LI(7He`rN@ejY#t&|>{Hg!bcslaY{FCBB@OqD|-pqfeuV`k*=U@xr|4x#2P zSIU9n=HIhlKS_A7#HpN2UXR}&eoa0v15r_O%SbZ%`fpqA!>!@~ zo3;BB0o@p~@el7s3xORfF!tqJ-1x1VMk$GPCIeab8z~cJfwE}9j~0yf;|W=c`pNH? zO28o>7NMuthok2j@wE5sirqN4tCq+$D_e|f`UfeuyyilQ058urt{Lq#Z{ZI{i=31{-ye-<4o0b3fzONN z{Kxl=VTL8GHtGjVl}1ND1=LS50qCc`|Cs#W(n9>MUN3&W=OX^^3+L3=4~q@@rw{gt zLpZ&M*i9#p06!HU;PsP+sYb{DiFT8-1Kln|I?Ap_}D1ADivE8N!@X86NYN*9c=$m);jZOd}WrO*3;z5FA!!hBo z>#jezgQ=H~!9q|rWi*-6Y0<@I)XE3LK+RH7N752?Q)I!}1}<@`SU-6)8V4_m6ED6J zm8h>t3}j)ZfAm-cyGy66H+39W|0(eJ^?q%_+h%|MMIkH(qsf2tg_U^h!KJV}TsT^4 z$9H}mhofRoQ{s$Z>OklGO_6f{{KZ)8mskK>sW2AsM|bsN#XNuTO-I###EW9E&RhZz zHvPH;ASRW76Aq^V!4qL&PNF&yE>(7_?i3e9*=ZAJl7pd>L^_PnVRGn^1^>n=mpH*u zxFB*a1p)d1Uy&1lDcUakC}t2-rBlTbj-6+6iiAXm*Zz21sXmil8~VxbJtfcbZG-`; z8hh~0fnvORuo5LTZWXLrpYO;0YdxZy8^Njw8Ey<}!ldl_>?qBmd3KLriRM=&7ID`~ zFS1j{kbzZXc$HxWnVl%-cP!|yjJz%;Pl6M>l419kTG7fq7+TxAQGD?-b{Ag8N5x*1 z*2}z^jrl%2Sl~s0L~bcBM#wNWIDPiC=>M;a`9l(vH`!FskTnUPml(i?eB*r_l>nSI z7B7B4azRL^(FcW&C$)kf?;7u~Psv)4xWN+=H~1;S1n%B0lwUcA_m9=!txx*Y4i+Wm z=;Ard5n@2ehZUmhGp7a`B7}h9@CE`J8rn6S7jx%KwOz$27`$r|DRg0mUq$Bc6epMw z@G(qWsC3t)z*6$CKw(BS&v@nGsmaAH@!m_;YT#Vk_rw!_<2jGC$nAwoA!ihO#$#wH)Q z174q;)S_u;Ckq+mRG_}ip84G27;s}-5=Nj0Qnh1TMov(aMUmNwg5$25CF0FGAv(8A z!C;qYiUu?lIYOzv!=}ugYFYR!i{xLJCz}Jabl2tjuvrMeS;J$)W(2|FWD`zUY<6;7 zKj;i!UlJYhuP}uOH?v5=+X3{|!rgiajZKZXQm^BaG6ycpG0)tf`VLJEk|3DcJV1iP zVI*LimfIHlLOwcbD!~y+&mE3ZX&1~vA_1Q$KBAy72PPS&wVOr1qy zHZs;iKWc9BI3n-^1Gm{xnoV_`i7*{v1|eYIF^|;7l`J$WO!uz!;-QUhWG7kcF#C0}@4H#xZpZT9vJT$9QFbehmGH%2u145DwIe`NYEcSmi`(rY7yt zSK&!jDdx|?Vh8?dUo?)1(@&>wfeWCW(-KWMS(cj0RmyrQSwyp6g_F)vH(o0$#(PAR**_pvUGfKXl@w z5}PWNr z7Y6uxlwVO^@5Y`ZJ^0n3C>3m?luAdFT_qmg=)oM37M&s3EJ*+okBk24gHbqo#i1N| zCbV(H?YHmgRSmDM3#vMf{@yOR*JFxc%Hb{k!7jPd z4>6M-qFY>(_FkJx?cnz*%LYX5^vlPU zD^BdR^z2Ha!bl;ujc>u2q`;WZ-v@07aN$m`ehtUE6%`%T;IA z2ueE6ZgHqPFT&Se49>@6kg7%$q~qldoG7#7T#a1?;=KJnHWw|)Fj!4e{fz>evinuE zT7H%huVb~CJBu>>*e*LhPmy>zU6{+{8qeYaq3Wb?moWy_Y3fGQGW4U9Xq6{$Fc+pDWqDQu?2G>k5{O*zrEZ0aStK67|{vgqAD zs2~P{X zvG~I!s5McTKmfwhvvI}~fuM=xX;Im$a5u=~RwD?fPr-B=)yW~&u=Q#8bJ4TSAp>30 zdGQk_5rDAVK%5msASkD*pj(HLtK{o6$iUzmBh@N0eVvm+C9g5K71y86kYFr$rhPET z<*;D>S14d20f?~hl4cDN1~A}6DfzObr{UV8+U)*fjZqE3Ks$p(5umhbqPyMOA-)~Q(+oF!_VMz z>=N@QtW~~gOM(GJPKB@pZU66Bsr}ywracJ=<5cjG438oL3n9vn9(dC1+@Hx}Mv!0t zYQC~Ar$WR;G9S~#^a+L;MS=lD$Y3hMQue$N%t#UpAVP+aqL72K!&&tiFJ?3e1`r{` zlw!s#{sGJi5)2?hhKWL@I_#GB?U|Xh_y;hnNH74SKdSa^d9)J|i~*`W`p*z>JT)C1 z-tl5ql3)P+0sa61|I+GX@-{pgIUR;z#+f{0VOEo1Fx2S~z+>{3Y@4NoD3sH24+8e5 zXY#He3=t9p!7L)gtX=qn5h1~K&`*f%@=k5Tv~MQd@8H6}AAZ;F*}U)vBSL~3fa-|h z@U6Q>3T<6@PvOza0GsUgI4QgR?&%!R3MC>Wm?VT4>tOfg%R(bD3gkW+nzk5bLI*o| z)yQ>=)PlF^MesR_B0K%~5FtT`pr7593%@%S0b4q3_B45?(}6&&EYetc+vQ#!6Ph;4 zv zJ75B?%(z!4OE+e+7cy}t2#LQS5#2`@qC_Qg7rJ#K2rf)A5m9`Ri4TzYy63Cg)wido zpVigvz1$Bv{jT&^=hQi;PE`$2hFDx&G!_;XX6NVU$8rAr`STJV^W}dvX2B!Sp$%?Rc+`oT+lAA?|35s(*7JDXMx_9qhZ-0OPh}V0m z8m&0s4>h7b%Y?>3HsF!+-Me?op8v;rGCMn)|Ni}ZiT`;o7r4~X(J|H6*HLS_C|l1{32=-6+xQ7Ws2?V z*RS;X^Jn_<_sI!!N zmX?;_dkY}x_hDRqqzZ*lxEzxrg0%+Tq0)2>e;zz|FzQ2A0QbCVD-88|oxXkh7DQH{ zy}f-jiWYIj#QlGUJeq*>f*>5`GQ@*iTX9vJ$(j)#6}BVnA+GpdiV1E4rt@63;X;IW z^Kqrjl@z61iBl1tiET?@fSu<#IB$xGxKfTO5i_W4>t37+l;6;-(rmg7ijKHaj`e}8 z)&-S&AuyaLITm>=HHj)^>zP<(vn??LZmSZ`JGD3$WSxKg3gFrf?arx4ge&v7-@Q1I zm>X->tg*iZMoT5AD8na)Jfk8J-*;3jwBubv9;--LfPG@1loch?;x`>oRq1BJ{9&D> z0EC}GQdX6S+iwC^B`AltO@xya6e49MiFg?%}=TmLETUq}Q)s)AI5%WdZo&)Cq&={{8y}NhdaM-YmA=yLSu1 zPoF*&soOMxWJjth4Wb7R9&91&MpsuC9X)!Kwrtr#X#z2MYJ@=+TU0>Rj~qFYDrxSR z8-`?c868MicUwlZ)xlz}lcxC<2rR;Y0k&$jDvnLlB*QR# zpGEU{@!|#P0(yp8t1zDr?j((jjL^iyMALt@a=A?7zY}nv=9co;uRD9p-?(U{WqqW}AhIO~&Ogayct{(;m z2Lmeugu@2ZW1!KIM&RLwG*VuG^s$MrVJR01S~5DGV6F|VZJ0;=TdskGB;lUR6ZoUnUwsP7CfBN*Pob(2OU6_vExV7-0&mUIFJTE^1a)OulIp~a1q zN~K8e9zXuiI2tN0jg*fd%*^LV6YzhLAnnBP@NlSFMc~-Vx407JHDLo105) z?E_G=rw{We9je$Q%|MzKn==c7$P4}%B+*3#vPjjkCja3ij3LjcQ*&bhWVe59+a|Ih z&K?jXieLrpHH&0?e}8|Q-Fd)daBKdRj?u&>Kx(kM(q&0$N0H|I{5;*baf8mBIg>Q) zQ^g-U#RGrLB2PD%wE&_~$i8{=M)b5EJ$fXFCjoO4o~S9O#qMc}6v0hGY`Oq~=g*%P zq*)ckmITaAc%qhtTB^qD^yz=on9eUg4C=RQ*Dg{8toilp*F||K_u|EiqK&Kei;=e* z7#Qfmal8BG*|TStcvqsBfI)ip>=`|I@MAKwQ>L!p*V zI91(R)ncD-+O$ci@P!K(MD&G4STA3`q|VMxu>mV9EA-*R2Z{o;+Y={F6q~O3Jse|w zkS{<+N)ATI%hG}*Bnf{_U`dE`NK{Hywp*FZLtBpGvstp&xV)14df@8PG=dRGUjpqL z1l`~)4DH#orzK-4yPsjk%dN&vgf6FL(iPriw!T*aWVdhMP8&CF6z6ES@87=Q$C% zCCbCGR)}L3OnZBKg-M^Ie+R1Eo`=Gu>V(pgcx%EZRNSQBgDU;qR;v^fiGBkB634V$ zEakISfTcHVK*FyUxjR`c7K_Ts3avkSz#(OxT@Cy!ToGv?zWGr|d$!}=l00_zrJsnWU$o1}ou2y0l&y000O{MNUMnLSTZ@*RYNN diff --git a/src/components/Common/SectionHeader/sectionHeader.css.ts b/src/components/Common/SectionHeader/sectionHeader.css.ts index 0219e4a67..4ded7ab18 100644 --- a/src/components/Common/SectionHeader/sectionHeader.css.ts +++ b/src/components/Common/SectionHeader/sectionHeader.css.ts @@ -3,7 +3,6 @@ import { style } from '@vanilla-extract/css'; export const container = style({ display: 'flex', justifyContent: 'space-between', - padding: '0 20px', }); export const title = style({ diff --git a/src/components/Common/StarRating/StarRating.stories.tsx b/src/components/Common/StarRating/StarRating.stories.tsx new file mode 100644 index 000000000..cfe92333c --- /dev/null +++ b/src/components/Common/StarRating/StarRating.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import StarRating from './StarRating'; + +const meta: Meta = { + title: 'common/StarRating', + component: StarRating, + args: { + rating: 4.5, + createdAt: '2021-09-01T00:00:00.000Z', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/components/Common/StarRating/StarRating.tsx b/src/components/Common/StarRating/StarRating.tsx new file mode 100644 index 000000000..c773bf2c0 --- /dev/null +++ b/src/components/Common/StarRating/StarRating.tsx @@ -0,0 +1,37 @@ +import { date, ratingInfo, ratingNumber, ratingWrapper } from './starRating.css'; +import SvgIcon from '../Svg/SvgIcon'; +import Text from '../Text/Text'; + +import { vars } from '@/styles/theme.css'; +import { getRelativeDate } from '@/utils/date'; + +interface StarRatingProps { + rating: number; + createdAt: string; +} + +const StarRating = ({ rating, createdAt }: StarRatingProps) => { + return ( +

+
+ + {rating.toFixed(1)} + + {Array.from({ length: 5 }, (_, index) => ( + + ))} +
+ + {getRelativeDate(createdAt)} + +
+ ); +}; + +export default StarRating; diff --git a/src/components/Common/StarRating/starRating.css.ts b/src/components/Common/StarRating/starRating.css.ts new file mode 100644 index 000000000..17692480c --- /dev/null +++ b/src/components/Common/StarRating/starRating.css.ts @@ -0,0 +1,23 @@ +import { vars } from '@/styles/theme.css'; +import { style } from '@vanilla-extract/css'; + +export const ratingWrapper = style({ + display: 'flex', + alignItems: 'center', + gap: 8, +}); + +export const ratingInfo = style({ + display: 'flex', + alignItems: 'center', + gap: 4, +}); + +export const ratingNumber = style({ + paddingTop: 4, + color: vars.colors.gray5, +}); + +export const date = style({ + paddingTop: 2, +}); diff --git a/src/components/Common/Svg/SvgSprite.tsx b/src/components/Common/Svg/SvgSprite.tsx index a7f67c9b7..e98fafb7c 100644 --- a/src/components/Common/Svg/SvgSprite.tsx +++ b/src/components/Common/Svg/SvgSprite.tsx @@ -40,19 +40,19 @@ const SvgSprite = () => {
- - - + + + + + + + + + { return ( - + ); }; diff --git a/src/components/Common/TopBar/topBar.css.ts b/src/components/Common/TopBar/topBar.css.ts index c743e3365..22f0a61f4 100644 --- a/src/components/Common/TopBar/topBar.css.ts +++ b/src/components/Common/TopBar/topBar.css.ts @@ -11,7 +11,6 @@ export const container = style({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', - padding: '0 20px', backgroundColor: vars.colors.white, transform: 'translateX(-50%)', zIndex: 1001, diff --git a/src/components/Common/index.ts b/src/components/Common/index.ts index 6c66972c6..942836c46 100644 --- a/src/components/Common/index.ts +++ b/src/components/Common/index.ts @@ -27,4 +27,5 @@ export { default as WriteButton } from './WriteButton/WriteButton'; export { default as Text } from './Text/Text'; export { default as Indicator } from './Indicator/Indicator'; export { default as TopBar } from './TopBar/TopBar'; +export { default as StarRating } from './StarRating/StarRating'; export { default as ShowAllButton } from './ShowAllButton/ShowAllButton'; diff --git a/src/components/Members/MemberImage/MemberImage.tsx b/src/components/Members/MemberImage/MemberImage.tsx index c3dd9f98e..5dc0e5df6 100644 --- a/src/components/Members/MemberImage/MemberImage.tsx +++ b/src/components/Members/MemberImage/MemberImage.tsx @@ -1,18 +1,16 @@ import { useState } from 'react'; -import type { CSSProp } from 'styled-components'; -import styled from 'styled-components'; + +import { container } from './memberImage.css'; import DefaultMemberImage from '@/assets/defaultProfile.png'; interface MemberImageProps { src: string; - alt: string; width?: number; height?: number; - css?: CSSProp; } -const MemberImage = ({ src, alt, width = 45, height = 45, css }: MemberImageProps) => { +const MemberImage = ({ src, width = 48, height = 48 }: MemberImageProps) => { const [isError, setIsError] = useState(false); const handleImageError = () => { @@ -20,23 +18,15 @@ const MemberImage = ({ src, alt, width = 45, height = 45, css }: MemberImageProp }; return ( - ); }; export default MemberImage; - -const StyledMemberImage = styled.img` - border: 2px solid ${({ theme }) => theme.colors.primary}; - border-radius: 50%; - background: ${({ theme }) => theme.backgroundColors.default}; - object-fit: cover; - ${({ css }) => css}; -`; diff --git a/src/components/Members/MemberImage/memberImage.css.ts b/src/components/Members/MemberImage/memberImage.css.ts new file mode 100644 index 000000000..d36c252e9 --- /dev/null +++ b/src/components/Members/MemberImage/memberImage.css.ts @@ -0,0 +1,6 @@ +import { style } from '@vanilla-extract/css'; + +export const container = style({ + borderRadius: '50%', + objectFit: 'cover', +}); diff --git a/src/components/Members/MemberModifyInput/MemberModifyInput.stories.tsx b/src/components/Members/MemberModifyInput/MemberModifyInput.stories.tsx new file mode 100644 index 000000000..620b8e62e --- /dev/null +++ b/src/components/Members/MemberModifyInput/MemberModifyInput.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import MemberModifyInput from './MemberModifyInput'; + +const meta: Meta = { + title: 'members/ MemberModifyInput', + component: MemberModifyInput, + args: { + nickname: '펀잇', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/components/Members/MemberModifyInput/MemberModifyInput.tsx b/src/components/Members/MemberModifyInput/MemberModifyInput.tsx index 6a03e4507..be7cfb1f2 100644 --- a/src/components/Members/MemberModifyInput/MemberModifyInput.tsx +++ b/src/components/Members/MemberModifyInput/MemberModifyInput.tsx @@ -1,6 +1,8 @@ -import { Heading, Spacing, Text, Input, useTheme } from '@fun-eat/design-system'; import type { ChangeEventHandler } from 'react'; -import styled from 'styled-components'; + +import { container, inputWrapper, letterCount } from './memberModifyInput.css'; + +import { Text } from '@/components/Common'; const MIN_LENGTH = 1; const MAX_LENGTH = 10; @@ -11,36 +13,26 @@ interface MemberModifyInputProps { } const MemberModifyInput = ({ nickname, modifyNickname }: MemberModifyInputProps) => { - const theme = useTheme(); - return ( - - + <> + 닉네임 - - - {nickname.length}자 / {MAX_LENGTH}자 - - - - + +
+
+ + {nickname.length} / {MAX_LENGTH} + + +
+ ); }; export default MemberModifyInput; - -const MemberModifyInputContainer = styled.div` - position: relative; -`; - -const NicknameStatusText = styled(Text)` - position: absolute; - top: 0; - right: 0; -`; diff --git a/src/components/Members/MemberModifyInput/memberModifyInput.css.ts b/src/components/Members/MemberModifyInput/memberModifyInput.css.ts new file mode 100644 index 000000000..dbed2e00e --- /dev/null +++ b/src/components/Members/MemberModifyInput/memberModifyInput.css.ts @@ -0,0 +1,34 @@ +import { vars } from '@/styles/theme.css'; +import { style } from '@vanilla-extract/css'; + +export const container = style({ + position: 'relative', + width: '100%', + border: `1px solid ${vars.colors.border.default}`, + borderRadius: 6, + boxSizing: 'border-box', + + selectors: { + '&:focus-within': { + outline: `1px solid ${vars.colors.primary}`, + border: `1px solid transparent`, + }, + }, +}); + +export const inputWrapper = style({ + width: '90%', + height: 44, + paddingLeft: 16, + outline: 'none', +}); + +export const letterCount = style({ + position: 'absolute', + width: '10%', + top: 14.5, + right: 16, + display: 'flex', + alignItems: 'center', + background: vars.colors.white, +}); diff --git a/src/components/Members/MemberRecipeList/MemberRecipeList.tsx b/src/components/Members/MemberRecipeList/MemberRecipeList.tsx index 74cf2da96..a2a7205ef 100644 --- a/src/components/Members/MemberRecipeList/MemberRecipeList.tsx +++ b/src/components/Members/MemberRecipeList/MemberRecipeList.tsx @@ -1,90 +1,46 @@ -import { Link, Spacing, Text, theme } from '@fun-eat/design-system'; import { useRef } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; -import styled from 'styled-components'; -import { PATH } from '@/constants/path'; +import { container } from './memberRecipeList.css'; + +import { DefaultRecipeItem } from '@/components/Recipe'; import { useIntersectionObserver } from '@/hooks/common'; import { useInfiniteMemberRecipeQuery } from '@/hooks/queries/members'; -import displaySlice from '@/utils/displaySlice'; - -interface MemberRecipeListProps { - isPreview?: boolean; -} -const MemberRecipeList = ({ isPreview = false }: MemberRecipeListProps) => { +const MemberRecipeList = () => { const scrollRef = useRef(null); const { fetchNextPage, hasNextPage, data } = useInfiniteMemberRecipeQuery(); const memberRecipes = data?.pages.flatMap((page) => page.recipes); - const recipeToDisplay = displaySlice(isPreview, memberRecipes); useIntersectionObserver(fetchNextPage, scrollRef, hasNextPage); - const totalRecipeCount = data?.pages[0].page.totalDataCount; - - if (totalRecipeCount === 0) { - return ( - - - 앗, 작성한 꿀조합이 없네요 🥲 - - - - 꿀조합 작성하러 가기 - - - ); - } + // 추후 디자인 추가에 따라 변경 예정 + // if (totalRecipeCount === 0) { + // return ( + // + // + // 앗, 작성한 꿀조합이 없네요 🥲 + // + // + // + // 꿀조합 작성하러 가기 + // + // + // ); + // } return ( - - {!isPreview && ( - - 총 {totalRecipeCount}개의 꿀조합을 남겼어요! - - )} - - - {recipeToDisplay?.map((recipe) => ( + <> +
    + {memberRecipes.map((recipe) => (
  • - - {/* */} - +
  • ))} - +
- + ); }; export default MemberRecipeList; - -const MemberRecipeListContainer = styled.section` - display: flex; - flex-direction: column; -`; - -const MemberRecipeListWrapper = styled.ul` - display: flex; - flex-direction: column; - gap: 20px; -`; - -const TotalRecipeCount = styled(Text)` - text-align: right; -`; - -const ErrorContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-top: 20px; -`; - -const RecipeLink = styled(Link)` - padding: 12px 12px; - border: 1px solid ${({ theme }) => theme.colors.gray4}; - border-radius: 8px; -`; diff --git a/src/components/Members/MemberRecipeList/memberRecipeList.css.ts b/src/components/Members/MemberRecipeList/memberRecipeList.css.ts new file mode 100644 index 000000000..5de3d0593 --- /dev/null +++ b/src/components/Members/MemberRecipeList/memberRecipeList.css.ts @@ -0,0 +1,9 @@ +import { style } from '@vanilla-extract/css'; + +export const container = style({ + display: 'grid', + gridTemplateColumns: 'repeat(2, 1fr)', + gridAutoRows: 'auto', + columnGap: 10, + rowGap: 20, +}); diff --git a/src/components/Members/MemberReviewItem/MemberReviewItem.stories.tsx b/src/components/Members/MemberReviewItem/MemberReviewItem.stories.tsx index 3856648f5..b86b4c5c8 100644 --- a/src/components/Members/MemberReviewItem/MemberReviewItem.stories.tsx +++ b/src/components/Members/MemberReviewItem/MemberReviewItem.stories.tsx @@ -8,15 +8,27 @@ const meta: Meta = { args: { review: { reviewId: 1, - productId: 5, - productName: '구운감자슬림명란마요', + productId: 1, + productName: '새우깡', + image: + 'https://i.namu.wiki/i/9wnvUaEa1EkDqG-M0Pbwfdf19FJQQXV_-bnlU2SYaNcG05y2wbabiIrfrGES1M4xSgDjY39RwOvLNggDd3Huuw.webp', content: '할머니가 먹을 거 같은 맛입니다. 1960년 전쟁 때 맛 보고 싶었는데 그때는 너무 가난해서 먹을 수 없었는데요 이것보다 긴 리뷰도 잘려 보인답니다', rating: 4.0, - favoriteCount: 1256, - categoryType: 'food', + createdAt: '2023-08-09T10:10:10', + tags: [ + { + id: 5, + name: '단짠단짠', + tagType: 'TASTE', + }, + { + id: 1, + name: '망고망고', + tagType: 'TASTE', + }, + ], }, - isPreview: true, }, }; diff --git a/src/components/Members/MemberReviewItem/MemberReviewItem.tsx b/src/components/Members/MemberReviewItem/MemberReviewItem.tsx index 4320f967d..52efee7b1 100644 --- a/src/components/Members/MemberReviewItem/MemberReviewItem.tsx +++ b/src/components/Members/MemberReviewItem/MemberReviewItem.tsx @@ -1,24 +1,26 @@ -import { useTheme, Spacing, Text, Button, useToastActionContext } from '@fun-eat/design-system'; +import { useToastActionContext } from '@fun-eat/design-system'; import type { MouseEventHandler } from 'react'; -import styled from 'styled-components'; +import { Link } from 'react-router-dom'; -import { SvgIcon } from '@/components/Common'; +import { titleWrapper } from './memberReviewItem.css'; + +import { SvgIcon, Text } from '@/components/Common'; +import { ReviewItemInfo } from '@/components/Review'; +import { PATH } from '@/constants/path'; import { useDeleteReview } from '@/hooks/queries/members'; +import { vars } from '@/styles/theme.css'; import type { MemberReview } from '@/types/review'; interface MemberReviewItemProps { review: MemberReview; - isPreview: boolean; } -const MemberReviewItem = ({ review, isPreview }: MemberReviewItemProps) => { - const theme = useTheme(); - +const MemberReviewItem = ({ review }: MemberReviewItemProps) => { const { mutate } = useDeleteReview(); const { toast } = useToastActionContext(); - const { reviewId, productName, content, rating, favoriteCount } = review; + const { reviewId, productId, productName, rating, createdAt, image, content, tags } = review; const handleReviewDelete: MouseEventHandler = (e) => { e.preventDefault(); @@ -44,79 +46,25 @@ const MemberReviewItem = ({ review, isPreview }: MemberReviewItemProps) => { }; return ( - - - - {productName} - - {!isPreview && ( - - )} - - - {content} - - - - - - - {favoriteCount} + <> +
+ + + {productName} + - - - - - {rating.toFixed(1)} + + +
+
+ + + ); }; export default MemberReviewItem; - -const ReviewRankingItemContainer = styled.div` - display: flex; - flex-direction: column; - gap: 4px; - padding: 12px 0; - border-bottom: ${({ theme }) => `1px solid ${theme.borderColors.disabled}`}; -`; - -const ProductNameIconWrapper = styled.div` - display: flex; - justify-content: space-between; -`; - -const ReviewText = styled(Text)` - display: -webkit-inline-box; - text-overflow: ellipsis; - overflow: hidden; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; -`; - -const FavoriteStarWrapper = styled.div` - display: flex; - gap: 4px; -`; - -const FavoriteIconWrapper = styled.div` - display: flex; - gap: 4px; - align-items: center; -`; - -const RatingIconWrapper = styled.div` - display: flex; - gap: 2px; - align-items: center; - - & > svg { - padding-bottom: 2px; - } -`; diff --git a/src/components/Members/MemberReviewItem/memberReviewItem.css.ts b/src/components/Members/MemberReviewItem/memberReviewItem.css.ts new file mode 100644 index 000000000..efed1a142 --- /dev/null +++ b/src/components/Members/MemberReviewItem/memberReviewItem.css.ts @@ -0,0 +1,13 @@ +import { style } from '@vanilla-extract/css'; + +export const titleWrapper = style({ + display: 'flex', + justifyContent: 'space-between', +}); + +export const reviewImage = style({ + width: 164, + height: 90, + borderRadius: 6, + objectFit: 'cover', +}); diff --git a/src/components/Members/MemberReviewList/MemberReviewList.tsx b/src/components/Members/MemberReviewList/MemberReviewList.tsx index b150e1000..8f37f3be4 100644 --- a/src/components/Members/MemberReviewList/MemberReviewList.tsx +++ b/src/components/Members/MemberReviewList/MemberReviewList.tsx @@ -1,11 +1,7 @@ -import { Link, Spacing, Text, theme } from '@fun-eat/design-system'; import { useRef } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; -import styled from 'styled-components'; import MemberReviewItem from '../MemberReviewItem/MemberReviewItem'; -import { PATH } from '@/constants/path'; import { useIntersectionObserver } from '@/hooks/common'; import { useInfiniteMemberReviewQuery } from '@/hooks/queries/members'; import displaySlice from '@/utils/displaySlice'; @@ -22,70 +18,36 @@ const MemberReviewList = ({ isPreview = false }: MemberReviewListProps) => { useIntersectionObserver(fetchNextPage, scrollRef, hasNextPage); - const totalReviewCount = data.pages[0].page.totalDataCount; - - if (totalReviewCount === 0) { - return ( - - - 앗, 작성한 리뷰가 없네요 🥲 - - - - 리뷰 작성하러 가기 - - - ); - } + // 추후 디자인 추가에 따라 변경 예정 + // if (totalReviewCount === 0) { + // return ( + // + // + // 앗, 작성한 리뷰가 없네요 🥲 + // + // + // + // 리뷰 작성하러 가기 + // + // + // ); + // } return ( - - {!isPreview && ( - - 총 {totalReviewCount}개의 리뷰를 남겼어요! - - )} - - + <> +
    {reviewsToDisplay.map((review) => ( -
  • - - - -
  • + <> +
  • + +
  • +
    + ))} - +
- + ); }; export default MemberReviewList; - -const MemberReviewListContainer = styled.section` - display: flex; - flex-direction: column; -`; - -const MemberReviewListWrapper = styled.ul` - display: flex; - flex-direction: column; - gap: 20px; -`; - -const TotalReviewCount = styled(Text)` - text-align: right; -`; - -const ErrorContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-top: 20px; -`; - -const ReviewLink = styled(Link)` - padding: 12px 12px; - border: 1px solid ${({ theme }) => theme.colors.gray4}; - border-radius: 8px; -`; diff --git a/src/components/Members/MembersInfo/MyPageInfo.stories.tsx b/src/components/Members/MembersInfo/MemberInfo.stories.tsx similarity index 100% rename from src/components/Members/MembersInfo/MyPageInfo.stories.tsx rename to src/components/Members/MembersInfo/MemberInfo.stories.tsx diff --git a/src/components/Members/MembersInfo/MembersInfo.tsx b/src/components/Members/MembersInfo/MembersInfo.tsx index 3387d60e9..2fc7de304 100644 --- a/src/components/Members/MembersInfo/MembersInfo.tsx +++ b/src/components/Members/MembersInfo/MembersInfo.tsx @@ -1,12 +1,13 @@ -import { Button, Heading, Link, theme } from '@fun-eat/design-system'; -import { Link as RouterLink } from 'react-router-dom'; -import styled from 'styled-components'; +import { Link } from 'react-router-dom'; +import { logoutButton, modifyButton, wrapper } from './memberInfo.css'; import MemberImage from '../MemberImage/MemberImage'; +import PostCounterBox from '../PostCounterBox/PostCounterBox'; -import { SvgIcon } from '@/components/Common'; +import { SvgIcon, Text } from '@/components/Common'; import { PATH } from '@/constants/path'; import { useLogoutMutation, useMemberQuery } from '@/hooks/queries/members'; +import { vars } from '@/styles/theme.css'; const MembersInfo = () => { const { data: member } = useMemberQuery(); @@ -16,53 +17,43 @@ const MembersInfo = () => { return null; } - const { nickname, profileImage } = member; + const { nickname, profileImage, recipeCount, reviewCount } = member; const handleLogout = () => { mutate(); }; return ( - - + <> + + +
- - {nickname} 님 - - - - - - - +
+ + {nickname} + + + + +
+
+ + + ); }; export default MembersInfo; - -const MembersInfoContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const MemberInfoWrapper = styled.div` - display: flex; - align-items: center; -`; - -const MemberModifyLink = styled(Link)` - margin-left: 5px; - transform: translateY(1px); -`; diff --git a/src/components/Members/MembersInfo/memberInfo.css.ts b/src/components/Members/MembersInfo/memberInfo.css.ts new file mode 100644 index 000000000..c3d1c2701 --- /dev/null +++ b/src/components/Members/MembersInfo/memberInfo.css.ts @@ -0,0 +1,22 @@ +import { vars } from '@/styles/theme.css'; +import { style } from '@vanilla-extract/css'; + +export const logoutButton = style({ + float: 'right', +}); + +export const wrapper = style({ + display: 'flex', + alignItems: 'center', +}); + +export const modifyButton = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: 17, + height: 17, + marginLeft: 5, + background: vars.colors.icon.default, + borderRadius: '50%', +}); diff --git a/src/components/Members/PostCounterBox/PostCounterBox.stories.tsx b/src/components/Members/PostCounterBox/PostCounterBox.stories.tsx new file mode 100644 index 000000000..60bc8ccdc --- /dev/null +++ b/src/components/Members/PostCounterBox/PostCounterBox.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import PostCounterBox from './PostCounterBox'; + +const meta: Meta = { + title: 'members/PostCounterBox', + component: PostCounterBox, + args: { + recipeCount: 5, + reviewCount: 10, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/components/Members/PostCounterBox/PostCounterBox.tsx b/src/components/Members/PostCounterBox/PostCounterBox.tsx new file mode 100644 index 000000000..301bb44db --- /dev/null +++ b/src/components/Members/PostCounterBox/PostCounterBox.tsx @@ -0,0 +1,41 @@ +import { Link } from 'react-router-dom'; + +import { border, box, container } from './postCounterBox.css'; + +import { Text } from '@/components/Common'; +import { PATH } from '@/constants/path'; + +interface PostCounterBoxProps { + recipeCount: number; + reviewCount: number; +} + +const PostCounterBox = ({ recipeCount, reviewCount }: PostCounterBoxProps) => { + return ( +
+ +
+ + 작성한 꿀조합 + + + {recipeCount}개 + +
+ +
+ +
+ + 작성한 리뷰 + + + {reviewCount}개 + +
+ +
+ ); +}; + +export default PostCounterBox; diff --git a/src/components/Members/PostCounterBox/postCounterBox.css.ts b/src/components/Members/PostCounterBox/postCounterBox.css.ts new file mode 100644 index 000000000..79015cfa2 --- /dev/null +++ b/src/components/Members/PostCounterBox/postCounterBox.css.ts @@ -0,0 +1,25 @@ +import { vars } from '@/styles/theme.css'; +import { style } from '@vanilla-extract/css'; + +export const container = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-evenly', + width: '100%', + height: 80, + background: vars.colors.border.light, + borderRadius: 6, +}); + +export const box = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', +}); + +export const border = style({ + width: 1, + height: 53, + background: vars.colors.border.default, +}); diff --git a/src/components/Members/index.ts b/src/components/Members/index.ts index 2080b25c6..7e5608e44 100644 --- a/src/components/Members/index.ts +++ b/src/components/Members/index.ts @@ -4,3 +4,4 @@ export { default as MemberRecipeList } from './MemberRecipeList/MemberRecipeList export { default as MemberModifyInput } from './MemberModifyInput/MemberModifyInput'; export { default as MemberReviewItem } from './MemberReviewItem/MemberReviewItem'; export { default as MemberImage } from './MemberImage/MemberImage'; +export { default as PostCounterBox } from './PostCounterBox/PostCounterBox'; diff --git a/src/components/Recipe/CommentForm/CommentForm.tsx b/src/components/Recipe/CommentForm/CommentForm.tsx index c0dcf52ce..24fc6ffa6 100644 --- a/src/components/Recipe/CommentForm/CommentForm.tsx +++ b/src/components/Recipe/CommentForm/CommentForm.tsx @@ -67,7 +67,7 @@ const CommentForm = ({ recipeId, scrollTargetRef }: CommentFormProps) => { return (
- + <>