diff --git a/apps/web/package.json b/apps/web/package.json index cd9253667..f7522c579 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -38,6 +38,7 @@ "react-error-boundary": "6.0.0", "react-hook-form": "^7.54.2", "react-router-dom": "^7.1.5", + "tailwind-merge": "^3.6.0", "tailwindcss": "^4.0.0", "zod": "^3.24.2", "zustand": "^5.0.3" diff --git a/apps/web/src/components/common/typography/Hero.tsx b/apps/web/src/components/common/typography/Hero.tsx new file mode 100644 index 000000000..bf1024ece --- /dev/null +++ b/apps/web/src/components/common/typography/Hero.tsx @@ -0,0 +1,50 @@ +import type { HTMLAttributes, ReactNode } from "react"; + +import { cn } from "@/utils/cn"; + +type HeroSize = "lg" | "md" | "sm" | "xs"; +type HeroAlign = "center" | "left" | "right"; + +interface HeroProps extends Omit, "style"> { + size?: HeroSize; + textAlign?: HeroAlign; + children: ReactNode; +} + +const sizeClassName: Record = { + lg: "semantic-textStyle-title-4", + md: "semantic-textStyle-title-3", + sm: "semantic-textStyle-title-2", + xs: "semantic-textStyle-title-1", +}; + +const alignClassName: Record = { + center: "justify-center text-center", + left: "justify-start text-left", + right: "justify-end text-right", +}; + +function Hero({ + size = "lg", + textAlign = "center", + className, + children, + ...props +}: HeroProps) { + return ( +
+ {children} +
+ ); +} + +export default Hero; diff --git a/apps/web/src/components/common/typography/Label.tsx b/apps/web/src/components/common/typography/Label.tsx new file mode 100644 index 000000000..10b458033 --- /dev/null +++ b/apps/web/src/components/common/typography/Label.tsx @@ -0,0 +1,78 @@ +import type { ElementType, HTMLAttributes, ReactNode } from "react"; + +import { cn } from "@/utils/cn"; + +type LabelSize = "lg" | "md" | "sm" | "xs"; +type LabelAlign = "center" | "left" | "right"; +type LabelWeight = "bold" | "normal" | "subtle"; +type LabelCursor = "pointer" | "default"; + +interface LabelProps extends Omit, "style"> { + as?: ElementType; + size?: LabelSize; + textAlign?: LabelAlign; + weight?: LabelWeight; + cursor?: LabelCursor; + htmlFor?: string; + children: ReactNode; +} + +const sizeWeightClassName: Record> = { + lg: { + bold: "semantic-textStyle-label-lg-bold", + normal: "semantic-textStyle-label-lg-normal", + subtle: "semantic-textStyle-label-lg-subtle", + }, + md: { + bold: "semantic-textStyle-label-md-bold", + normal: "semantic-textStyle-label-md-normal", + subtle: "semantic-textStyle-label-md-subtle", + }, + sm: { + bold: "semantic-textStyle-label-sm-bold", + normal: "semantic-textStyle-label-sm-normal", + subtle: "semantic-textStyle-label-sm-subtle", + }, + xs: { + bold: "semantic-textStyle-label-xs-bold", + normal: "semantic-textStyle-label-xs-normal", + subtle: "semantic-textStyle-label-xs-subtle", + }, +}; + +const alignClassName: Record = { + center: "justify-center text-center", + left: "justify-start text-left", + right: "justify-end text-right", +}; + +function Label({ + as, + size = "md", + textAlign = "left", + weight = "normal", + cursor = "default", + className, + children, + ...props +}: LabelProps) { + const Component = as ?? "label"; + + return ( + + {children} + + ); +} + +export default Label; diff --git a/apps/web/src/components/common/typography/Title.tsx b/apps/web/src/components/common/typography/Title.tsx new file mode 100644 index 000000000..bec163d70 --- /dev/null +++ b/apps/web/src/components/common/typography/Title.tsx @@ -0,0 +1,50 @@ +import type { HTMLAttributes, ReactNode } from "react"; + +import { cn } from "@/utils/cn"; + +type TitleSize = "lg" | "md" | "sm" | "xs"; +type TitleTextAlign = "center" | "left" | "right"; + +interface TitleProps extends Omit, "style"> { + size?: TitleSize; + textAlign?: TitleTextAlign; + children: ReactNode; +} + +const sizeClassName: Record = { + lg: "semantic-textStyle-title-4", + md: "semantic-textStyle-title-3", + sm: "semantic-textStyle-title-2", + xs: "semantic-textStyle-title-1", +}; + +const alignClassName: Record = { + center: "justify-center text-center", + left: "justify-start text-left", + right: "justify-end text-right", +}; + +function Title({ + size = "md", + textAlign = "left", + className, + children, + ...props +}: TitleProps) { + return ( +
+ {children} +
+ ); +} + +export default Title; diff --git a/apps/web/src/components/common/typography/index.ts b/apps/web/src/components/common/typography/index.ts new file mode 100644 index 000000000..b3485c14c --- /dev/null +++ b/apps/web/src/components/common/typography/index.ts @@ -0,0 +1,3 @@ +export { default as Hero } from "./Hero"; +export { default as Label } from "./Label"; +export { default as Title } from "./Title"; diff --git a/apps/web/src/components/curriculum/sections/CurriculumTabSection.tsx b/apps/web/src/components/curriculum/sections/CurriculumTabSection.tsx index e63ed0f4d..e63a474e6 100644 --- a/apps/web/src/components/curriculum/sections/CurriculumTabSection.tsx +++ b/apps/web/src/components/curriculum/sections/CurriculumTabSection.tsx @@ -1,5 +1,6 @@ -import { ContentBadge, EmptyState, Tab, Title } from "@jects/jds"; +import { ContentBadge, EmptyState, Tab } from "@jects/jds"; +import { Title } from "@/components/common/typography"; import { figmaGuideCurriculumData, teamProjectScheduleData } from "@/constants/curriculumData"; import type { FigmaGuideItem, TeamProjectItem } from "@/types/ui/curriculum"; @@ -63,11 +64,11 @@ const CurriculumTabSection = () => { -
+
{teamProjectScheduleData.map(item => ( ))} -
+
{ -
+
{figmaGuideCurriculumData.map(item => ( ))} diff --git a/apps/web/src/components/gnb/Sidebar.tsx b/apps/web/src/components/gnb/Sidebar.tsx index ba7d6c6e2..5da168052 100644 --- a/apps/web/src/components/gnb/Sidebar.tsx +++ b/apps/web/src/components/gnb/Sidebar.tsx @@ -1,9 +1,10 @@ -import { Divider, IconButton, Label, MenuItem } from "@jects/jds"; +import { Divider, IconButton, MenuItem } from "@jects/jds"; import type { Dispatch, MouseEvent, SetStateAction } from "react"; import { useEffect } from "react"; import { createPortal } from "react-dom"; import { useNavigate } from "react-router-dom"; +import { Label } from "@/components/common/typography"; import { PATH } from "@/constants/path"; interface SidebarMenusProps { diff --git a/apps/web/src/components/main/sections/HeroSection.tsx b/apps/web/src/components/main/sections/HeroSection.tsx index df9093d07..d4562e245 100644 --- a/apps/web/src/components/main/sections/HeroSection.tsx +++ b/apps/web/src/components/main/sections/HeroSection.tsx @@ -1,7 +1,8 @@ -import { Hero, Icon, Label } from "@jects/jds"; +import { Icon } from "@jects/jds"; import { useEffect, useState } from "react"; import heroBackground from "@/assets/images/hero-background.png"; +import { Hero, Label } from "@/components/common/typography"; const ANIMATION_DELAY_MS = 800; const ANIMATION_DURATION_MS = 500; @@ -100,7 +101,7 @@ const HeroSection = () => { background: "radial-gradient(33.77% 43.9% at 50% 50%, #191B2480 0%, #191B2400 100%)", }} > - + 젝트에서 @@ -110,7 +111,7 @@ const HeroSection = () => {
-
-
@@ -107,9 +103,9 @@ const IntroSection = () => { >
- + {title} - </JdsTitle> +

{description} diff --git a/apps/web/src/components/main/sections/JoinSection.tsx b/apps/web/src/components/main/sections/JoinSection.tsx index 7ec7f9d1c..2f753fc01 100644 --- a/apps/web/src/components/main/sections/JoinSection.tsx +++ b/apps/web/src/components/main/sections/JoinSection.tsx @@ -1,7 +1,8 @@ -import { BlockButton, Hero, Image, Label } from "@jects/jds"; +import { BlockButton, Image } from "@jects/jds"; import { useNavigate } from "react-router-dom"; import joinTeamMeetingImage from "@/assets/images/join-team-meeting.png"; +import { Hero, Label } from "@/components/common/typography"; import { PATH } from "@/constants/path"; import { trackApplyStart } from "@/utils/analytics"; @@ -20,7 +21,7 @@ const JoinSection = () => {

- + {"젝트의 구성원으로\n함께해주세요"}
@@ -28,7 +29,7 @@ const JoinSection = () => { size='lg' textAlign='left' weight='bold' - color='var(--semantic-object-static-inverse-normal)' + className='text-(--semantic-object-static-inverse-normal)' > 모든 구성원들의 몰입과 성장을 위해. diff --git a/apps/web/src/components/vision/sections/GoalSection.tsx b/apps/web/src/components/vision/sections/GoalSection.tsx index 744ba8b30..ad3bd65dc 100644 --- a/apps/web/src/components/vision/sections/GoalSection.tsx +++ b/apps/web/src/components/vision/sections/GoalSection.tsx @@ -1,4 +1,4 @@ -import { Title } from "@jects/jds"; +import { Title } from "@/components/common/typography"; const GoalSection = () => { return ( @@ -8,7 +8,7 @@ const GoalSection = () => { 젝트의 목표 - + <Title size='md' textAlign='left' className='text-(--semantic-object-boldest)'> 우리는 IT 생태계의 선순환을 목표로 활동하고 있습니다. diff --git a/apps/web/src/components/vision/sections/GrowthStorySection.tsx b/apps/web/src/components/vision/sections/GrowthStorySection.tsx index a1c28c34e..93f14b901 100644 --- a/apps/web/src/components/vision/sections/GrowthStorySection.tsx +++ b/apps/web/src/components/vision/sections/GrowthStorySection.tsx @@ -1,4 +1,4 @@ -import { Title } from "@jects/jds"; +import { Title } from "@/components/common/typography"; const GrowthStorySection = () => { return ( diff --git a/apps/web/src/components/vision/sections/MemberSection.tsx b/apps/web/src/components/vision/sections/MemberSection.tsx index 72d112327..6ff49125e 100644 --- a/apps/web/src/components/vision/sections/MemberSection.tsx +++ b/apps/web/src/components/vision/sections/MemberSection.tsx @@ -1,6 +1,7 @@ -import { ContentBadge, Icon, Image, Tab, Title } from "@jects/jds"; +import { ContentBadge, Icon, Image, Tab } from "@jects/jds"; import { useState } from "react"; +import { Title } from "@/components/common/typography"; import { roleBadgeVariantMap, roleIconMap, @@ -135,7 +136,7 @@ const MemberSection = () => { 젝트를 만드는 사람들 - + <Title size='md' textAlign='left' className='text-(--semantic-object-boldest)'> 열정 넘치는 구성원들이 젝트에 직접 기여하며 많은 가치를 창출하고 있습니다.
diff --git a/apps/web/src/components/vision/sections/ProjectStartSection.tsx b/apps/web/src/components/vision/sections/ProjectStartSection.tsx index 109204046..1ae463d72 100644 --- a/apps/web/src/components/vision/sections/ProjectStartSection.tsx +++ b/apps/web/src/components/vision/sections/ProjectStartSection.tsx @@ -1,4 +1,4 @@ -import { Title } from "@jects/jds"; +import { Title } from "@/components/common/typography"; const ProjectStartSection = () => { return ( @@ -8,7 +8,7 @@ const ProjectStartSection = () => { 프로젝트 시작 - + <Title size='md' textAlign='left' className='text-(--semantic-object-boldest)'> 젝트는 개발자들의 소규모 사이드 프로젝트 모임으로 시작했습니다. diff --git a/apps/web/src/components/vision/sections/VisionHeroSection.tsx b/apps/web/src/components/vision/sections/VisionHeroSection.tsx index 5d26e7037..6c21afe2a 100644 --- a/apps/web/src/components/vision/sections/VisionHeroSection.tsx +++ b/apps/web/src/components/vision/sections/VisionHeroSection.tsx @@ -1,12 +1,13 @@ -import { Hero, Image, Title } from "@jects/jds"; +import { Image } from "@jects/jds"; import visionBannerImage from "@/assets/images/vision-banner.png"; +import { Hero, Title } from "@/components/common/typography"; const VisionHeroSection = () => { return (
- + <Title size='xs' textAlign='left' className='text-(--semantic-object-neutral)'> IT 생태계의 선순환을 목표로 활동하는 diff --git a/apps/web/src/features/apply/steps/CompleteStep.tsx b/apps/web/src/features/apply/steps/CompleteStep.tsx index 95ea63bc3..accaccfee 100644 --- a/apps/web/src/features/apply/steps/CompleteStep.tsx +++ b/apps/web/src/features/apply/steps/CompleteStep.tsx @@ -1,8 +1,9 @@ -import { BlockButton, Image, LocalNavigation, Title } from "@jects/jds"; +import { BlockButton, Image, LocalNavigation } from "@jects/jds"; import { useNavigate } from "react-router-dom"; import type { JobFamily } from "@/apis/apply"; import completeImage from "@/assets/images/complete.png"; +import { Title } from "@/components/common/typography"; import { APPLY_TITLE, findJobFamilyOption } from "@/constants/applyPageData"; import { PATH } from "@/constants/path"; diff --git a/apps/web/src/features/apply/steps/applicationInfo/ApplicantInfoStep.tsx b/apps/web/src/features/apply/steps/applicationInfo/ApplicantInfoStep.tsx index c31a44451..70159a75c 100644 --- a/apps/web/src/features/apply/steps/applicationInfo/ApplicantInfoStep.tsx +++ b/apps/web/src/features/apply/steps/applicationInfo/ApplicantInfoStep.tsx @@ -1,16 +1,9 @@ -import { - BlockButton, - Checkbox, - Icon, - Label, - TextField, - toastController, - Tooltip, -} from "@jects/jds"; +import { BlockButton, Checkbox, Icon, TextField, toastController, Tooltip } from "@jects/jds"; import { Controller } from "react-hook-form"; import { SelectController } from "./components/SelectController"; +import { Label } from "@/components/common/typography"; import { APPLY_MESSAGE } from "@/constants/applyMessages"; import { APPLY_TITLE } from "@/constants/applyPageData"; import { ApplyStepLayout } from "@/features/shared/components"; diff --git a/apps/web/src/features/apply/steps/registration/components/QuestionFieldWrapper.tsx b/apps/web/src/features/apply/steps/registration/components/QuestionFieldWrapper.tsx index 719be2f9e..e3430a2f0 100644 --- a/apps/web/src/features/apply/steps/registration/components/QuestionFieldWrapper.tsx +++ b/apps/web/src/features/apply/steps/registration/components/QuestionFieldWrapper.tsx @@ -1,6 +1,7 @@ -import { Title } from "@jects/jds"; import type { ReactNode } from "react"; +import { Title } from "@/components/common/typography"; + interface QuestionFieldWrapperProps { title: string; subtitle?: string | null; diff --git a/apps/web/src/features/shared/components/ApplyStepLayout.tsx b/apps/web/src/features/shared/components/ApplyStepLayout.tsx index 2794ec0a2..41340d25c 100644 --- a/apps/web/src/features/shared/components/ApplyStepLayout.tsx +++ b/apps/web/src/features/shared/components/ApplyStepLayout.tsx @@ -1,7 +1,8 @@ -import { LocalNavigation, Step, Title } from "@jects/jds"; +import { LocalNavigation, Step } from "@jects/jds"; import type { ReactNode } from "react"; import type { JobFamily } from "@/apis/apply"; +import { Title } from "@/components/common/typography"; import { findJobFamilyOption } from "@/constants/applyPageData"; import { STEP_LABELS } from "@/types/funnel"; diff --git a/apps/web/src/pages/ApplyGuidePage.tsx b/apps/web/src/pages/ApplyGuidePage.tsx index 3c43a5f3c..c52d47ba2 100644 --- a/apps/web/src/pages/ApplyGuidePage.tsx +++ b/apps/web/src/pages/ApplyGuidePage.tsx @@ -4,18 +4,17 @@ import { Accordion, BlockButton, Divider, - Hero, IconButton, Label, LocalNavigation, Tab, - Title, toastController, } from "@jects/jds"; import { theme } from "@jects/jds/tokens"; import { useNavigate, useParams, useSearchParams, Navigate } from "react-router-dom"; import type { JobFamily } from "@/apis/apply"; +import { Hero, Title } from "@/components/common/typography"; import PageModule from "@/components/layout/PageModule"; import { findJobFamilyOption, diff --git a/apps/web/src/pages/ApplyListPage.tsx b/apps/web/src/pages/ApplyListPage.tsx index b8fe56fca..fdd5b243f 100644 --- a/apps/web/src/pages/ApplyListPage.tsx +++ b/apps/web/src/pages/ApplyListPage.tsx @@ -1,10 +1,11 @@ -import { Card, Divider, Hero, Select, SelectField, Title } from "@jects/jds"; +import { Card, Divider, Select, SelectField } from "@jects/jds"; import { Fragment, useState } from "react"; import backendImage from "@/assets/images/backend.png"; import frontendImage from "@/assets/images/frontend.png"; import productDesignerImage from "@/assets/images/product-designer.png"; import productManagerImage from "@/assets/images/product-manager.png"; +import { Hero, Title } from "@/components/common/typography"; import PageHeroContainer from "@/components/layout/PageHeroContainer"; import PageModule from "@/components/layout/PageModule"; import { PATH } from "@/constants/path"; diff --git a/apps/web/src/pages/Curriculum.tsx b/apps/web/src/pages/Curriculum.tsx index 55fd43bdd..80e60d13e 100644 --- a/apps/web/src/pages/Curriculum.tsx +++ b/apps/web/src/pages/Curriculum.tsx @@ -1,5 +1,4 @@ -import { Hero, Title } from "@jects/jds"; - +import { Hero, Title } from "@/components/common/typography"; import CurriculumTabSection from "@/components/curriculum/sections/CurriculumTabSection"; import PageModule from "@/components/layout/PageModule"; diff --git a/apps/web/src/pages/Faq.tsx b/apps/web/src/pages/Faq.tsx index 3298ceea1..3c7f8a119 100644 --- a/apps/web/src/pages/Faq.tsx +++ b/apps/web/src/pages/Faq.tsx @@ -1,6 +1,7 @@ -import { Accordion, Hero, Tab, Title } from "@jects/jds"; +import { Accordion, Tab } from "@jects/jds"; import { useMediaQueryFlags } from "@jects/jds/hooks"; +import { Hero, Title } from "@/components/common/typography"; import PageHeroContainer from "@/components/layout/PageHeroContainer"; import PageModule from "@/components/layout/PageModule"; import { faqActivity, faqApply, faqJect, faqProject } from "@/constants/faqPageData"; @@ -13,102 +14,102 @@ function Faq() { return ( - -
- - FAQ - - - 젝트에 대해 자주 묻는 질문들이 정리되어 있어요. - -
-
+ +
+ + FAQ + + + 젝트에 대해 자주 묻는 질문들이 정리되어 있어요. + +
+
-
- - - 지원 - 프로젝트 - 활동 - 젝트 - +
+ + + 지원 + 프로젝트 + 활동 + 젝트 + - -
- - {faqApply.map(({ id, title, content }) => ( - - {title} - {content} - - ))} - -
-
- -
- - {faqProject.map(({ id, title, content }) => ( - - {title} - {content} - - ))} - -
-
- -
- - {faqActivity.map(({ id, title, content }) => ( - - {title} - {content} - - ))} - -
-
- -
- - {faqJect.map(({ id, title, content }) => ( - - {title} - {content} - - ))} - -
-
-
-
- + +
+ + {faqApply.map(({ id, title, content }) => ( + + {title} + {content} + + ))} + +
+
+ +
+ + {faqProject.map(({ id, title, content }) => ( + + {title} + {content} + + ))} + +
+
+ +
+ + {faqActivity.map(({ id, title, content }) => ( + + {title} + {content} + + ))} + +
+
+ +
+ + {faqJect.map(({ id, title, content }) => ( + + {title} + {content} + + ))} + +
+
+
+
+
); } diff --git a/apps/web/src/pages/LiveSession.tsx b/apps/web/src/pages/LiveSession.tsx index af816f3a8..29578c5ae 100644 --- a/apps/web/src/pages/LiveSession.tsx +++ b/apps/web/src/pages/LiveSession.tsx @@ -1,7 +1,8 @@ -import { Card, Hero, Title } from "@jects/jds"; +import { Card } from "@jects/jds"; import EmptyData from "@/components/common/emptyState/EmptyData"; import Label from "@/components/common/label/Label"; +import { Hero, Title } from "@/components/common/typography"; import PageHeroContainer from "@/components/layout/PageHeroContainer"; import PageModule from "@/components/layout/PageModule"; import useJectalksQuery from "@/hooks/useJectalksQuery"; @@ -11,63 +12,63 @@ const LiveSession = () => { return ( - -
- - 라이브 세션 - - - 온/오프라인에서 구성원이 자신의 경험과 기술에 대해 발표하는 콘텐츠입니다. - -
-
- -
- {isError ? ( - - ) : isPending ? ( -
- -
- ) : !jectalks || jectalks.length === 0 ? ( -
- -
- ) : ( -
- {jectalks.map(session => ( - - ))} -
- )} + +
+ + 라이브 세션 + + + 온/오프라인에서 구성원이 자신의 경험과 기술에 대해 발표하는 콘텐츠입니다. +
- +
+ +
+ {isError ? ( + + ) : isPending ? ( +
+ +
+ ) : !jectalks || jectalks.length === 0 ? ( +
+ +
+ ) : ( +
+ {jectalks.map(session => ( + + ))} +
+ )} +
+ ); }; diff --git a/apps/web/src/pages/Maintenance.tsx b/apps/web/src/pages/Maintenance.tsx index 32bd4477b..5a22706b0 100644 --- a/apps/web/src/pages/Maintenance.tsx +++ b/apps/web/src/pages/Maintenance.tsx @@ -1,6 +1,7 @@ -import { Icon, Title } from "@jects/jds"; +import { Icon } from "@jects/jds"; import Footer from "@/components/common/footer/Footer"; +import { Title } from "@/components/common/typography"; import PagesContainer from "@/components/layout/PagesContainer"; function Maintenance() { diff --git a/apps/web/src/pages/MiniStudy.tsx b/apps/web/src/pages/MiniStudy.tsx index 8d5b25ab7..cfa9b1532 100644 --- a/apps/web/src/pages/MiniStudy.tsx +++ b/apps/web/src/pages/MiniStudy.tsx @@ -1,7 +1,8 @@ -import { Card, Hero, Title } from "@jects/jds"; +import { Card } from "@jects/jds"; import EmptyData from "@/components/common/emptyState/EmptyData"; import Label from "@/components/common/label/Label"; +import { Hero, Title } from "@/components/common/typography"; import PageHeroContainer from "@/components/layout/PageHeroContainer"; import PageModule from "@/components/layout/PageModule"; import useMiniStudiesQuery from "@/hooks/useMiniStudiesQuery"; @@ -11,55 +12,55 @@ const MiniStudy = () => { return ( - -
- - 미니 스터디 - - - 활동 중 팀 프로젝트와 병행할 수 있는, 성장을 위한 스터디입니다. - -
-
- -
- {isError ? ( - - ) : isPending ? ( -
- -
- ) : !miniStudies || miniStudies.length === 0 ? ( -
- -
- ) : ( -
- {miniStudies.map(study => ( - - ))} -
- )} + +
+ + 미니 스터디 + + + 활동 중 팀 프로젝트와 병행할 수 있는, 성장을 위한 스터디입니다. +
- +
+ +
+ {isError ? ( + + ) : isPending ? ( +
+ +
+ ) : !miniStudies || miniStudies.length === 0 ? ( +
+ +
+ ) : ( +
+ {miniStudies.map(study => ( + + ))} +
+ )} +
+ ); }; diff --git a/apps/web/src/pages/NonSpecificError.tsx b/apps/web/src/pages/NonSpecificError.tsx index 8f509df01..73f416e63 100644 --- a/apps/web/src/pages/NonSpecificError.tsx +++ b/apps/web/src/pages/NonSpecificError.tsx @@ -1,9 +1,10 @@ -import { BlockButton, Icon, Title } from "@jects/jds"; +import { BlockButton, Icon } from "@jects/jds"; import { captureException } from "@sentry/react"; import { useEffect } from "react"; import { useNavigate, useRouteError } from "react-router-dom"; import Footer from "@/components/common/footer/Footer"; +import { Title } from "@/components/common/typography"; import GlobalNavigationBar from "@/components/gnb/GlobalNavigationBar"; import PageBoard from "@/components/layout/PageBoard"; import PageModule from "@/components/layout/PageModule"; diff --git a/apps/web/src/pages/NotFoundError.tsx b/apps/web/src/pages/NotFoundError.tsx index 0e06dcb29..4ce40ceaf 100644 --- a/apps/web/src/pages/NotFoundError.tsx +++ b/apps/web/src/pages/NotFoundError.tsx @@ -1,7 +1,8 @@ -import { BlockButton, Hero, Title } from "@jects/jds"; +import { BlockButton } from "@jects/jds"; import { useNavigate } from "react-router-dom"; import Footer from "@/components/common/footer/Footer"; +import { Hero, Title } from "@/components/common/typography"; import GlobalNavigationBar from "@/components/gnb/GlobalNavigationBar"; import PageBoard from "@/components/layout/PageBoard"; import PageModule from "@/components/layout/PageModule"; @@ -17,7 +18,7 @@ function NotFoundError() {
- + 404
diff --git a/apps/web/src/pages/TeamProject.tsx b/apps/web/src/pages/TeamProject.tsx index 2c56c7644..5b2a929b0 100644 --- a/apps/web/src/pages/TeamProject.tsx +++ b/apps/web/src/pages/TeamProject.tsx @@ -1,8 +1,9 @@ -import { Card, Hero, Select, SelectField, Title } from "@jects/jds"; +import { Card, Select, SelectField } from "@jects/jds"; import Lottie from "lottie-react"; import { useState, useRef } from "react"; import loadingSpinner from "@/assets/lottie/ject-loadingSpinner.json"; +import { Hero, Title } from "@/components/common/typography"; import PageHeroContainer from "@/components/layout/PageHeroContainer"; import PageModule from "@/components/layout/PageModule"; import useCloseOutside from "@/hooks/useCloseOutside"; @@ -46,70 +47,70 @@ const TeamProject = () => { return ( - -
- - 팀 프로젝트 - - - 젝트에서 진행한 팀 프로젝트들을 소개합니다. - -
-
- setIsOpen(!isOpen)} /> - {isOpen && ( -
- -
- )} -
-
- -
- {isLoading && ( -
- + +
+ + 팀 프로젝트 + + + 젝트에서 진행한 팀 프로젝트들을 소개합니다. + +
+
+ setIsOpen(!isOpen)} /> + {isOpen && ( +
+
)} +
+
- {!isLoading && ( - <> -
- {allProjects.map(project => ( -
- -
- ))} -
+
+ {isLoading && ( +
+ +
+ )} - {!isError && allProjects.length > 0 && ( -
- {isFetchingNextPage && } + {!isLoading && ( + <> +
+ {allProjects.map(project => ( +
+
- )} - - )} -
- + ))} +
+ + {!isError && allProjects.length > 0 && ( +
+ {isFetchingNextPage && } +
+ )} + + )} +
+ ); }; diff --git a/apps/web/src/pages/TeamProjectDetail.tsx b/apps/web/src/pages/TeamProjectDetail.tsx index f7660f435..1d789cc64 100644 --- a/apps/web/src/pages/TeamProjectDetail.tsx +++ b/apps/web/src/pages/TeamProjectDetail.tsx @@ -1,13 +1,5 @@ import type { ImgRatio } from "@jects/jds"; -import { - BlockButton, - ContentBadge, - Hero, - IconButton, - Image, - Label, - LocalNavigation, -} from "@jects/jds"; +import { BlockButton, ContentBadge, IconButton, Image, LocalNavigation } from "@jects/jds"; import { useEffect } from "react"; import { Navigate, useNavigate, useParams } from "react-router-dom"; @@ -15,6 +7,7 @@ import positionBe from "@/assets/images/position-be.png"; import positionFe from "@/assets/images/position-fe.png"; import positionPd from "@/assets/images/position-pd.png"; import positionPm from "@/assets/images/position-pm.png"; +import { Hero, Label } from "@/components/common/typography"; import PageModule from "@/components/layout/PageModule"; import { PATH } from "@/constants/path"; import { useProjectDetailQuery } from "@/hooks/useProjectDetailQuery"; @@ -128,149 +121,149 @@ const TeamProjectDetail = () => { return ( - - void navigate(PATH.teamProject)} /> - 팀 프로젝트 - + + void navigate(PATH.teamProject)} /> + 팀 프로젝트 + -
- {/* 썸네일 */} - {project.name +
+ {/* 썸네일 */} + {project.name - {/* 서비스 샘플 이미지 */} - {project.sampleImageUrls && ( -
- {project.sampleImageUrls.map(img => ( - {project.name + {/* 서비스 샘플 이미지 */} + {project.sampleImageUrls && ( +
+ {project.sampleImageUrls.map(img => ( + {project.name + ))} +
+ )} + + {/* 타이틀 정보 */} +
+
+
+ {project.badges.map(badge => ( + + {badge} + ))}
- )} - - {/* 타이틀 정보 */} -
-
-
- {project.badges.map(badge => ( - - {badge} - - ))} -
-
- - {project.name} - - - - -
- - {project.description} - +
+ + {project.name} + + + +
+ + {project.description} + +
- {/* 프로젝트 정보 - 진행 기간 및 사용 기술 */} -
-
-
-
- -
-
- - - -
+ {/* 프로젝트 정보 - 진행 기간 및 사용 기술 */} +
+
+
+
+
- -
-
- -
-
- {project.techStack.map(stack => ( - - ))} -
+
+ + +
- {/* 프로젝트 정보 - 팀원 */} -
- - - - +
+
+ +
+
+ {project.techStack.map(stack => ( + + ))} +
- {/* 버튼 */} - - - 서비스 바로가기 - - + {/* 프로젝트 정보 - 팀원 */} +
+ + + + +
-
- {/* 서비스 소개 */} -
- {project.descriptionImageUrls.map(img => ( - {project.name - ))} + {/* 버튼 */} + + + 서비스 바로가기 + +
- +
+ + {/* 서비스 소개 */} +
+ {project.descriptionImageUrls.map(img => ( + {project.name + ))} +
+ ); }; diff --git a/apps/web/src/utils/cn.ts b/apps/web/src/utils/cn.ts new file mode 100644 index 000000000..a5ef19350 --- /dev/null +++ b/apps/web/src/utils/cn.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/package-lock.json b/package-lock.json index 7dfe822bd..49cc200a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "react-error-boundary": "6.0.0", "react-hook-form": "^7.54.2", "react-router-dom": "^7.1.5", + "tailwind-merge": "^3.6.0", "tailwindcss": "^4.0.0", "zod": "^3.24.2", "zustand": "^5.0.3" @@ -1639,7 +1640,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -1657,7 +1657,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -1675,7 +1674,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -1693,7 +1691,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -1711,7 +1708,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -1729,7 +1725,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -1747,7 +1742,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1765,7 +1759,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1783,7 +1776,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1801,7 +1793,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1819,7 +1810,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1837,7 +1827,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1855,7 +1844,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1873,7 +1861,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1891,7 +1878,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1909,7 +1895,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1927,7 +1912,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1945,7 +1929,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1963,7 +1946,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1981,7 +1963,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1999,7 +1980,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -2017,7 +1997,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } @@ -2035,7 +2014,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -2053,7 +2031,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -2071,7 +2048,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -2089,7 +2065,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -5031,8 +5006,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.54.0", @@ -5045,8 +5019,7 @@ "optional": true, "os": [ "android" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.54.0", @@ -5072,8 +5045,7 @@ "optional": true, "os": [ "darwin" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.54.0", @@ -5086,8 +5058,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.54.0", @@ -5100,8 +5071,7 @@ "optional": true, "os": [ "freebsd" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.54.0", @@ -5114,8 +5084,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.54.0", @@ -5128,8 +5097,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.54.0", @@ -5142,8 +5110,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.54.0", @@ -5156,8 +5123,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.54.0", @@ -5170,8 +5136,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.54.0", @@ -5184,8 +5149,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.54.0", @@ -5198,8 +5162,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.54.0", @@ -5212,8 +5175,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.54.0", @@ -5226,8 +5188,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.53.2", @@ -5253,8 +5214,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.54.0", @@ -5267,8 +5227,7 @@ "optional": true, "os": [ "openharmony" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.54.0", @@ -5281,8 +5240,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.54.0", @@ -5295,8 +5253,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.54.0", @@ -5309,8 +5266,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.54.0", @@ -5323,8 +5279,7 @@ "optional": true, "os": [ "win32" - ], - "peer": true + ] }, "node_modules/@rtsao/scc": { "version": "1.1.0", @@ -14845,8 +14800,7 @@ "optional": true, "os": [ "linux" - ], - "peer": true + ] }, "node_modules/run-applescript": { "version": "7.1.0", @@ -15689,6 +15643,16 @@ "node": ">= 10" } }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", diff --git a/packages/jds/package.json b/packages/jds/package.json index eb9a6088e..fe1ebdb9d 100644 --- a/packages/jds/package.json +++ b/packages/jds/package.json @@ -22,7 +22,8 @@ "README.md" ], "sideEffects": [ - "**/*.css" + "**/*.css", + "**/*.css.ts" ], "exports": { ".": { diff --git a/packages/jds/src/components/Accordion/Accordion.tsx b/packages/jds/src/components/Accordion/Accordion.tsx index 1489db368..07abdb506 100644 --- a/packages/jds/src/components/Accordion/Accordion.tsx +++ b/packages/jds/src/components/Accordion/Accordion.tsx @@ -20,6 +20,8 @@ import type { } from "./accordion.types"; import { AccordionContext, useAccordionContext } from "./accordionContext"; +import { getLabelClassName } from "@/utils/typography"; + /** * Accordion.Root * - Radix UI Accordion의 루트 컨테이너입니다. @@ -70,9 +72,7 @@ const AccordionTrigger = forwardRef( {withPrefixIcon && } - - {children} - + {children} diff --git a/packages/jds/src/components/Accordion/accordion.styles.ts b/packages/jds/src/components/Accordion/accordion.styles.ts index f68ba4079..ead187729 100644 --- a/packages/jds/src/components/Accordion/accordion.styles.ts +++ b/packages/jds/src/components/Accordion/accordion.styles.ts @@ -9,8 +9,9 @@ import type { StyledAccordionTriggerProps, } from "./accordion.types"; import type { IconSize } from "../Icon/Icon.types"; -import { Label } from "../Label"; -import type { LabelSize } from "../Label/Label.style"; + +import { shouldForwardTypographyProp } from "@/utils/typography"; +import type { LabelSize } from "@/utils/typography"; export const accordionSizeMap: Record< AccordionSize, @@ -121,12 +122,16 @@ export const StyledAccordionChevron = styled("div")(({ theme }) => ({ transition: `transform ${theme.environment.semantic.duration[300]} ${theme.environment.semantic.motion.fluent}`, })); -export const StyleLabel = styled(Label)(() => ({ - color: "inherit", - textAlign: "left" as const, - textWrap: "wrap" as const, - cursor: "pointer", -})); +export const StyleLabel = styled("span", { shouldForwardProp: shouldForwardTypographyProp })( + () => ({ + "&&": { + color: "inherit", + cursor: "pointer", + }, + textAlign: "left" as const, + textWrap: "wrap" as const, + }), +); const slideUp = keyframes` from { height: var(--radix-accordion-content-height); } diff --git a/packages/jds/src/components/Badge/contentBadge/ContentBadge.style.ts b/packages/jds/src/components/Badge/contentBadge/ContentBadge.style.ts index 8295e59d6..7f78bad35 100644 --- a/packages/jds/src/components/Badge/contentBadge/ContentBadge.style.ts +++ b/packages/jds/src/components/Badge/contentBadge/ContentBadge.style.ts @@ -20,7 +20,7 @@ import { } from "./contentBadge.variants"; import { Icon } from "@/components/Icon"; -import { Label } from "@/components/Label"; +import { shouldForwardTypographyProp } from "@/utils/typography"; interface ContentBasicBadgeDivProps { hierarchy: BasicHierarchy; @@ -59,18 +59,18 @@ interface ContentBadgeBasicLabelProps { isMuted: boolean; } -export const ContentBadgeBasicLabel = styled(Label)(({ - theme, - hierarchy, - badgeStyle, - isMuted, -}) => { +export const ContentBadgeBasicLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, +})(({ theme, hierarchy, badgeStyle, isMuted }) => { const color = isMuted ? contentBadgeBasicMutedStylesMap(theme)[badgeStyle].color : contentBadgeBasicStylesMap(theme)[badgeStyle][hierarchy].color; return { - color, + "&&": { + color, + cursor: "inherit", + }, }; }); @@ -131,18 +131,18 @@ interface ContentBadgeFeedbackLabelProps { isMuted: boolean; } -export const ContentBadgeFeedbackLabel = styled(Label)(({ - theme, - variant, - badgeStyle, - isMuted, -}) => { +export const ContentBadgeFeedbackLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, +})(({ theme, variant, badgeStyle, isMuted }) => { const color = isMuted ? contentBadgeFeedbackMutedStylesMap(theme)[badgeStyle][variant].color : contentBadgeFeedbackStylesMap(theme)[badgeStyle][variant].color; return { - color, + "&&": { + color, + cursor: "inherit", + }, }; }); @@ -182,17 +182,17 @@ interface ContentBadgeThemeLabelProps { isMuted: boolean; } -export const ContentBadgeThemeLabel = styled(Label)(({ - theme, - variant, - badgeStyle, - isMuted, -}) => { +export const ContentBadgeThemeLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, +})(({ theme, variant, badgeStyle, isMuted }) => { const color = isMuted ? contentBadgeThemeMutedStylesMap(theme)[badgeStyle][variant].color : contentBadgeThemeStylesMap(theme)[badgeStyle][variant].color; return { - color, + "&&": { + color, + cursor: "inherit", + }, }; }); diff --git a/packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx b/packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx index 87b84dfdd..f02646a75 100644 --- a/packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx +++ b/packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx @@ -18,6 +18,8 @@ import type { } from "../badge.types"; import { iconSizeMap } from "./contentBadge.variants"; +import { getLabelClassName } from "@/utils/typography"; + export interface ContentBadgeBasicProps { hierarchy?: BasicHierarchy; size?: BadgeSize; @@ -48,10 +50,7 @@ const ContentBadgeBasic = ({ withIcon={withIcon} > (({ - theme, - hierarchy, - badgeStyle, - isMuted, -}) => { +export const NumericBadgeBasicLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, +})(({ theme, hierarchy, badgeStyle, isMuted }) => { const color = isMuted ? numericBadgeBasicMutedStylesMap(theme)[badgeStyle].color : numericBadgeBasicStylesMap(theme)[badgeStyle][hierarchy].color; return { - color, + "&&": { + color, + cursor: "inherit", + }, }; }); @@ -95,17 +95,17 @@ interface NumericBadgeFeedbackLabelProps { isMuted: boolean; } -export const NumericBadgeFeedbackLabel = styled(Label)(({ - theme, - variant, - badgeStyle, - isMuted, -}) => { +export const NumericBadgeFeedbackLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, +})(({ theme, variant, badgeStyle, isMuted }) => { const color = isMuted ? numericBadgeFeedbacksMutedStylesMap(theme)[badgeStyle][variant].color : numericBadgeFeedbackStylesMap(theme)[badgeStyle][variant].color; return { - color, + "&&": { + color, + cursor: "inherit", + }, }; }); diff --git a/packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx b/packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx index 3ca5daafe..d39fbb07f 100644 --- a/packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx +++ b/packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx @@ -8,6 +8,8 @@ import { NumericBadgeFeedbackLabel, } from "./NumericBadge.style"; +import { getLabelClassName } from "@/utils/typography"; + export interface NumericBadgeBasicProps { hierarchy?: BasicHierarchy; size?: BadgeSize; @@ -31,10 +33,7 @@ const NumericBadgeBasic = ({ isMuted={isMuted} > ( ( { @@ -176,9 +178,7 @@ const CheckboxContent = forwardRef( @@ -186,9 +186,7 @@ const CheckboxContent = forwardRef( {subLabel && ( diff --git a/packages/jds/src/components/Checkbox/checkbox.styles.ts b/packages/jds/src/components/Checkbox/checkbox.styles.ts index 1f27e4966..4f36df05d 100644 --- a/packages/jds/src/components/Checkbox/checkbox.styles.ts +++ b/packages/jds/src/components/Checkbox/checkbox.styles.ts @@ -4,12 +4,14 @@ import styled from "@emotion/styled"; import type { CheckboxAlign, CheckboxSize, CheckboxVariant } from "./checkbox.types"; import type { IconSize } from "../Icon/Icon.types"; -import type { LabelOwnProps } from "../Label"; -import { Label } from "../Label/Label"; -import type { LabelSize } from "../Label/Label.style"; import type { Variant } from "@/types"; import { InteractionLayer, pxToRem } from "@/utils"; +import { + shouldForwardTypographyProp, + type LabelOwnProps, + type LabelSize, +} from "@/utils/typography"; const checkboxSizeMap: Record = { lg: 20, @@ -583,8 +585,8 @@ const labelColorParams = { }, }; -export const StyledMainLabel = styled(Label, { - shouldForwardProp: prop => !prop.startsWith("$"), +export const StyledMainLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, })< LabelOwnProps & { $disabled: boolean; @@ -595,12 +597,15 @@ export const StyledMainLabel = styled(Label, { const availability = $disabled ? "disabled" : "normal"; const colors = labelColorParams[validity][availability](theme); return { - color: colors.main, + "&&": { + color: colors.main, + cursor: "inherit", + }, }; }); -export const StyledSubLabel = styled(Label, { - shouldForwardProp: prop => !prop.startsWith("$"), +export const StyledSubLabel = styled("span", { + shouldForwardProp: shouldForwardTypographyProp, })< LabelOwnProps & { $disabled: boolean; @@ -611,6 +616,9 @@ export const StyledSubLabel = styled(Label, { const availability = $disabled ? "disabled" : "normal"; const colors = labelColorParams[validity][availability](theme); return { - color: colors.sub, + "&&": { + color: colors.sub, + cursor: "inherit", + }, }; }); diff --git a/packages/jds/src/components/Dialog/Dialog.styles.ts b/packages/jds/src/components/Dialog/Dialog.styles.ts index ce8714a7c..0865eb092 100644 --- a/packages/jds/src/components/Dialog/Dialog.styles.ts +++ b/packages/jds/src/components/Dialog/Dialog.styles.ts @@ -3,7 +3,7 @@ import styled from "@emotion/styled"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { pxToRem, shadow } from "utils"; -import { Title } from "../Title"; +import { shouldForwardTypographyProp } from "@/utils/typography"; const dialogOverlayFadeIn = keyframes` from { opacity: 0 } @@ -100,7 +100,7 @@ export const DialogContentDiv = styled.div(({ theme }) => ({ gap: theme.scheme.semantic.spacing[16], })); -export const DialogTitle = styled(Title)({ +export const DialogTitle = styled("h2", { shouldForwardProp: shouldForwardTypographyProp })({ alignSelf: "stretch", }); diff --git a/packages/jds/src/components/Dialog/Dialog.tsx b/packages/jds/src/components/Dialog/Dialog.tsx index 0fe6ff4bd..70e780db1 100644 --- a/packages/jds/src/components/Dialog/Dialog.tsx +++ b/packages/jds/src/components/Dialog/Dialog.tsx @@ -15,6 +15,8 @@ import type { DialogProps } from "./Dialog.types"; import { BlockButton } from "../Button/BlockButton"; import { Checkbox } from "../Checkbox"; +import { getTitleClassName } from "@/utils/typography"; + export const Dialog = forwardRef( ( { @@ -76,9 +78,7 @@ export const Dialog = forwardRef( - - {header} - + {header} {body} {checkboxAction && } diff --git a/packages/jds/src/components/EmptyState/EmptyState.tsx b/packages/jds/src/components/EmptyState/EmptyState.tsx index d1f15cb58..878c1a100 100644 --- a/packages/jds/src/components/EmptyState/EmptyState.tsx +++ b/packages/jds/src/components/EmptyState/EmptyState.tsx @@ -11,6 +11,8 @@ import type { EmptyStateProps } from "./emptyState.types"; import { BlockButton } from "../Button/BlockButton"; import { Icon } from "../Icon"; +import { getLabelClassName } from "@/utils/typography"; + export const EmptyState = forwardRef( ( { @@ -50,7 +52,7 @@ export const EmptyState = forwardRef( {icon &&