diff --git a/package.json b/package.json index 6d323520a..5dcd006b3 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", + "analyze": "vite-bundle-visualizer", "svgr": "npx @svgr/cli -d src/shared/assets/svg --no-prettier --ignore-existing --typescript --no-dimensions --no-index --jsx-runtime automatic public/svg" }, "dependencies": { diff --git a/src/pages/class/components/TabWrapper/TabLevel/TabLevel.tsx b/src/pages/class/components/TabWrapper/TabLevel/TabLevel.tsx index 380c6b705..ec0b06836 100644 --- a/src/pages/class/components/TabWrapper/TabLevel/TabLevel.tsx +++ b/src/pages/class/components/TabWrapper/TabLevel/TabLevel.tsx @@ -1,13 +1,22 @@ import { lazy, Suspense } from 'react'; import Card from '@/pages/class/components/Card/Card'; -import * as styles from '@/pages/class/components/TabWrapper/TabLevel/tabLevel.css'; +import { + cardStyle, + levelStyle, + recommendClassStyle, + sectionStyle, + headerWrapperStyle, + cardContentStyle, + infoWrapperStyle, + recommendationSectionStyle, + recommendationHeaderStyle, +} from '@/pages/class/components/TabWrapper/TabLevel/tabLevel.css'; import type { LessonDetailResponseTypes } from '@/pages/class/types/api'; import IcQuesitonmark from '@/shared/assets/svg/IcQuesitonmark'; import Head from '@/shared/components/Head/Head'; import Text from '@/shared/components/Text/Text'; import { notify } from '@/shared/components/Toast/Toast'; import { LEVEL, levelMapping } from '@/shared/constants/index'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const IcSparkleMain20 = lazy(() => import('@/shared/assets/svg/IcSparkleMain20')); const IcLevelStarter = lazy(() => import('@/shared/assets/svg/IcLevelStarter')); @@ -18,19 +27,12 @@ const TabLevel = ({ lessonData }: { lessonData: LessonDetailResponseTypes }) => const levelData = LEVEL.find((item) => item.title === levelMapping[level]); return ( -
-
- -
+
+
+ +
{levelData?.icon || } - + {levelMapping[level]} @@ -38,21 +40,15 @@ const TabLevel = ({ lessonData }: { lessonData: LessonDetailResponseTypes }) =>
-
+
클래스 난이도는 이렇게 설정되어있어요! notify({ message: '해당 기능은 추후 구현 예정이에요' })} />
-
-
+
+
}> @@ -61,7 +57,7 @@ const TabLevel = ({ lessonData }: { lessonData: LessonDetailResponseTypes }) =>
- + {recommendation}
diff --git a/src/pages/class/components/TabWrapper/TabLevel/tabLevel.css.ts b/src/pages/class/components/TabWrapper/TabLevel/tabLevel.css.ts index 42a769ef9..7adcddf6c 100644 --- a/src/pages/class/components/TabWrapper/TabLevel/tabLevel.css.ts +++ b/src/pages/class/components/TabWrapper/TabLevel/tabLevel.css.ts @@ -20,3 +20,43 @@ export const levelStyle = style({ export const cardStyle = style({ border: `1px solid ${vars.colors.gray03}`, }); + +export const sectionStyle = style({ + display: 'flex', + flexDirection: 'column', + gap: '3.6rem', +}); + +export const headerWrapperStyle = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-end', + width: '100%', + gap: '0.8rem', +}); + +export const cardContentStyle = style({ + display: 'flex', + alignItems: 'center', + gap: '0.8rem', +}); + +export const infoWrapperStyle = style({ + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + gap: '0.6rem', +}); + +export const recommendationSectionStyle = style({ + display: 'flex', + flexDirection: 'column', + gap: '1.7rem', +}); + +export const recommendationHeaderStyle = style({ + display: 'flex', + justifyContent: 'flex-start', + alignItems: 'center', + gap: '0.4rem', +}); diff --git a/src/pages/class/components/TabWrapper/TabPeriod/TabPeriod.tsx b/src/pages/class/components/TabWrapper/TabPeriod/TabPeriod.tsx index 6c7da6dee..d45bfc82c 100644 --- a/src/pages/class/components/TabWrapper/TabPeriod/TabPeriod.tsx +++ b/src/pages/class/components/TabWrapper/TabPeriod/TabPeriod.tsx @@ -1,8 +1,13 @@ import Card from '@/pages/class/components/Card/Card'; -import * as styles from '@/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css'; +import { + cardStyle, + roundBoxStyle, + sectionStyle, + cardContentStyle, + periodInfoStyle, +} from '@/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css'; import type { LessonDetailResponseTypes } from '@/pages/class/types/api'; import Text from '@/shared/components/Text/Text'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; import { calculatePeriod, formatDate } from '@/shared/utils/dateCalculate'; const TabPeriod = ({ lessonData }: { lessonData: LessonDetailResponseTypes }) => { @@ -10,19 +15,19 @@ const TabPeriod = ({ lessonData }: { lessonData: LessonDetailResponseTypes }) => const lessonRounds = lessonRound.lessonRounds; return ( -
+
{lessonRounds.map((item, id) => { const { startDateTime, endDateTime } = item; const { startTime, formattedEndTime, durationString } = calculatePeriod(startDateTime, endDateTime); return ( - -
-
+ +
+
{id + 1}회차
-
+
{formatDate(startDateTime)} diff --git a/src/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css.ts b/src/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css.ts index 349fbd30d..4f41cbc69 100644 --- a/src/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css.ts +++ b/src/pages/class/components/TabWrapper/TabPeriod/tabPeriod.css.ts @@ -16,3 +16,22 @@ export const roundBoxStyle = style({ export const cardStyle = style({ border: `0.5px solid ${vars.colors.gray02}`, }); + +export const sectionStyle = style({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + gap: '1.2rem', +}); + +export const cardContentStyle = style({ + display: 'flex', + alignItems: 'center', + width: '100%', +}); + +export const periodInfoStyle = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.4rem', +}); diff --git a/src/pages/class/components/TabWrapper/TabReview/tabReview.css.ts b/src/pages/class/components/TabWrapper/TabReview/tabReview.css.ts index e69de29bb..12358007d 100644 --- a/src/pages/class/components/TabWrapper/TabReview/tabReview.css.ts +++ b/src/pages/class/components/TabWrapper/TabReview/tabReview.css.ts @@ -0,0 +1,5 @@ +import { style } from '@vanilla-extract/css'; + +export const reviewSectionStyle = style({ + height: '100%', +}); diff --git a/src/pages/class/components/TabWrapper/TabReview/tabReview.tsx b/src/pages/class/components/TabWrapper/TabReview/tabReview.tsx index 74e6ffd5b..6a2cd963d 100644 --- a/src/pages/class/components/TabWrapper/TabReview/tabReview.tsx +++ b/src/pages/class/components/TabWrapper/TabReview/tabReview.tsx @@ -1,7 +1,7 @@ -import { sprinkles } from '@/shared/styles/sprinkles.css'; +import { reviewSectionStyle } from '@/pages/class/components/TabWrapper/TabReview/tabReview.css'; const TabReview = () => { - return
; + return
; }; export default TabReview; diff --git a/src/pages/class/components/TabWrapper/TabWrapper.tsx b/src/pages/class/components/TabWrapper/TabWrapper.tsx index 38b412702..c56b18f0e 100644 --- a/src/pages/class/components/TabWrapper/TabWrapper.tsx +++ b/src/pages/class/components/TabWrapper/TabWrapper.tsx @@ -1,10 +1,9 @@ import { useState } from 'react'; -import * as styles from '@/pages/class/components/TabWrapper/tabWrapper.css'; +import { tabPanelStyle, tabListWrapperStyle } from '@/pages/class/components/TabWrapper/tabWrapper.css'; import type { LessonDetailResponseTypes } from '@/pages/class/types/api'; import { TabButton, TabList, TabPanel, TabRoot } from '@/shared/components/Tab'; import { notify } from '@/shared/components/Toast/Toast'; import { CLASS_TABS } from '@/shared/constants'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; interface TabWrapperPropTypes { colorScheme: 'tertiary'; @@ -24,7 +23,7 @@ const TabWrapper = ({ colorScheme, lessonData }: TabWrapperPropTypes) => { return ( -
+
{CLASS_TABS.map((tab) => ( {
-
+
{CLASS_TABS.map((tab) => ( {tab.isImplemented && tab.component(lessonData)} diff --git a/src/pages/class/components/TabWrapper/tabWrapper.css.ts b/src/pages/class/components/TabWrapper/tabWrapper.css.ts index 65dcca353..2bf61d336 100644 --- a/src/pages/class/components/TabWrapper/tabWrapper.css.ts +++ b/src/pages/class/components/TabWrapper/tabWrapper.css.ts @@ -10,3 +10,9 @@ export const tabPanelStyle = style({ borderColor: vars.colors.gray01, }); + +export const tabListWrapperStyle = style({ + display: 'flex', + paddingTop: '2.4rem', + justifyContent: 'center', +}); diff --git a/src/pages/dancer/components/DancerInfo/DancerClassItem/DancerClassItem.tsx b/src/pages/dancer/components/DancerInfo/DancerClassItem/DancerClassItem.tsx index c8f55da23..5f1c57027 100644 --- a/src/pages/dancer/components/DancerInfo/DancerClassItem/DancerClassItem.tsx +++ b/src/pages/dancer/components/DancerInfo/DancerClassItem/DancerClassItem.tsx @@ -1,29 +1,34 @@ -import * as styles from '@/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css'; +import { + classImageStyle, + deadlineTagStyle, + lessonNameStyle, + sectionStyle, + tagWrapperStyle, +} from '@/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css'; import type { ClassItemPropTypes } from '@/pages/dancer/types/api'; import Head from '@/shared/components/Head/Head'; import Tag from '@/shared/components/Tag/Tag'; import { genreMapping, levelMapping } from '@/shared/constants/index'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const DancerClassItem = ({ imageUrl, remainingDays, genre, level, name }: ClassItemPropTypes) => { const renderDeadlineTag = () => { if (remainingDays < 0) { return ( - + 마감 ); } if (remainingDays === 0) { return ( - + D-DAY ); } if (remainingDays <= 4) { return ( - + 마감 D-{remainingDays} ); @@ -35,18 +40,11 @@ const DancerClassItem = ({ imageUrl, remainingDays, genre, level, name }: ClassI const translatedLevel = levelMapping[level] || level; return ( -
- 클래스 섬네일 +
+ 클래스 섬네일 {renderDeadlineTag()} -
+
{translatedGenre} @@ -54,7 +52,7 @@ const DancerClassItem = ({ imageUrl, remainingDays, genre, level, name }: ClassI {translatedLevel}
- + {name} diff --git a/src/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css.ts b/src/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css.ts index 796d66be5..ab1b78877 100644 --- a/src/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css.ts +++ b/src/pages/dancer/components/DancerInfo/DancerClassItem/dancerClassItem.css.ts @@ -19,3 +19,16 @@ export const lessonNameStyle = style({ overflowWrap: 'break-word', wordBreak: 'break-all', }); + +export const sectionStyle = style({ + display: 'flex', + position: 'relative', + flexDirection: 'column', + width: '16.4rem', + gap: '0.8rem', +}); + +export const tagWrapperStyle = style({ + display: 'flex', + gap: '0.4rem', +}); diff --git a/src/pages/dancer/components/DancerInfo/DancerInfo.tsx b/src/pages/dancer/components/DancerInfo/DancerInfo.tsx index 4bac1c4fa..19ad214f0 100644 --- a/src/pages/dancer/components/DancerInfo/DancerInfo.tsx +++ b/src/pages/dancer/components/DancerInfo/DancerInfo.tsx @@ -1,6 +1,19 @@ import { useNavigate } from 'react-router-dom'; import DancerClassItem from '@/pages/dancer/components/DancerInfo/DancerClassItem/DancerClassItem'; -import * as styles from '@/pages/dancer/components/DancerInfo/dancerInfo.css'; +import { + rowScrollStyle, + classItemStyle, + firstClassItemStyle, + lastClassItemStyle, + detailStyle, + linkStyle, + infoSectionStyle, + socialLinksStyle, + socialLinkStyle, + classSectionStyle, + classTitleStyle, + emptyClassMessageStyle, +} from '@/pages/dancer/components/DancerInfo/dancerInfo.css'; import type { DancerDetailResponseTypes } from '@/pages/dancer/types/api'; import { expandInstagramUrl, expandYouTubeUrl } from '@/pages/dancer/utils/url'; import { ROUTES_CONFIG } from '@/routes/routesConfig'; @@ -9,7 +22,6 @@ import IcYoutube20 from '@/shared/assets/svg/IcYoutube20'; import Divider from '@/shared/components/Divider/Divider'; import Head from '@/shared/components/Head/Head'; import Text from '@/shared/components/Text/Text'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const DancerInfo = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) => { const { instagram, youtube, detail, nickname, lessons } = dancerData; @@ -23,15 +35,14 @@ const DancerInfo = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) = return ( <> -
+
{(instagram || youtube) && ( -
-
- +
+ {nickname}님의 클래스 {/* 개설한 클래스 없을 때 */} {lessons.length === 0 ? ( - + 아직 개설한 클래스가 없어요 ) : ( -
+
{lessons.map((data, id) => { const isFirst = id === 0; const isLast = id === lessons.length - 1; @@ -79,9 +86,9 @@ const DancerInfo = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) =
{ const { educations } = dancerData; return ( -
+
{educations?.length === 0 || educations?.every((exp) => exp === '') ? ( - + 아직 등록된 학력이 없어요 ) : ( diff --git a/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css.ts b/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css.ts index 0a13ebae1..56dcf3c0f 100644 --- a/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css.ts +++ b/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css.ts @@ -4,3 +4,15 @@ export const textStyle = style({ overflowWrap: 'break-word', wordBreak: 'break-all', }); + +export const sectionStyle = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.8rem', +}); + +export const emptyMessageStyle = style({ + display: 'flex', + justifyContent: 'center', + paddingBottom: '1.4rem', +}); \ No newline at end of file diff --git a/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.tsx b/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.tsx index d3f9b10cf..5ea85b108 100644 --- a/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.tsx +++ b/src/pages/dancer/components/TabWrapper/TabExperience/TabExperience.tsx @@ -1,20 +1,15 @@ -import { textStyle } from '@/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css'; +import { textStyle, sectionStyle, emptyMessageStyle } from '@/pages/dancer/components/TabWrapper/TabExperience/TabExperience.css'; import type { DancerDetailResponseTypes } from '@/pages/dancer/types/api'; import Head from '@/shared/components/Head/Head'; import Text from '@/shared/components/Text/Text'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const TabExperience = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) => { const { experiences } = dancerData; return ( -
+
{experiences?.length === 0 || experiences?.every((exp) => exp === '') ? ( - + 아직 등록된 경력이 없어요 ) : ( diff --git a/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css.ts b/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css.ts index 0a13ebae1..56dcf3c0f 100644 --- a/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css.ts +++ b/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css.ts @@ -4,3 +4,15 @@ export const textStyle = style({ overflowWrap: 'break-word', wordBreak: 'break-all', }); + +export const sectionStyle = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.8rem', +}); + +export const emptyMessageStyle = style({ + display: 'flex', + justifyContent: 'center', + paddingBottom: '1.4rem', +}); \ No newline at end of file diff --git a/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.tsx b/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.tsx index a5784664f..f217a08b1 100644 --- a/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.tsx +++ b/src/pages/dancer/components/TabWrapper/TabPrize/TabPrize.tsx @@ -1,20 +1,15 @@ -import { textStyle } from '@/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css'; +import { textStyle, sectionStyle, emptyMessageStyle } from '@/pages/dancer/components/TabWrapper/TabPrize/TabPrize.css'; import type { DancerDetailResponseTypes } from '@/pages/dancer/types/api'; import Head from '@/shared/components/Head/Head'; import Text from '@/shared/components/Text/Text'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const TabPrize = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) => { const { prizes } = dancerData; return ( -
+
{prizes?.length === 0 || prizes?.every((prize) => prize === '') ? ( - + 아직 등록된 수상 이력이 없어요 ) : ( diff --git a/src/pages/dancer/components/TabWrapper/TabVideo/TabVideo.tsx b/src/pages/dancer/components/TabWrapper/TabVideo/TabVideo.tsx index 1f7a99c99..d6296adcd 100644 --- a/src/pages/dancer/components/TabWrapper/TabVideo/TabVideo.tsx +++ b/src/pages/dancer/components/TabWrapper/TabVideo/TabVideo.tsx @@ -1,8 +1,7 @@ -import * as styles from '@/pages/dancer/components/TabWrapper/TabVideo/tabVideo.css'; +import { iframeStyle, sectionStyle, emptyMessageStyle, videoWrapperStyle } from '@/pages/dancer/components/TabWrapper/TabVideo/tabVideo.css'; import type { DancerDetailResponseTypes } from '@/pages/dancer/types/api'; import Head from '@/shared/components/Head/Head'; import { getYoutubeEmbedUrl } from '@/shared/constants/regex'; -import { sprinkles } from '@/shared/styles/sprinkles.css'; const TabVideo = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) => { const { videoUrls } = dancerData; @@ -10,21 +9,17 @@ const TabVideo = ({ dancerData }: { dancerData: DancerDetailResponseTypes }) => const validVideoUrls = videoUrls.map(getYoutubeEmbedUrl).filter((url): url is string => url !== null); return ( -
+
{validVideoUrls.length === 0 ? ( - + 아직 등록된 영상이 없어요 ) : ( validVideoUrls.map((embedUrl, id) => ( -
+