diff --git a/src/App.module.scss b/src/App.module.scss index 674c893..dd8252f 100644 --- a/src/App.module.scss +++ b/src/App.module.scss @@ -16,8 +16,9 @@ } .Test3 { - width: 99px; + width: 216px; display: flex; flex-direction: column; - gap: 16px; + align-items: center; + gap: 8px; } diff --git a/src/App.tsx b/src/App.tsx index 1a8ea41..7d79321 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import styles from "./App.module.scss"; import Button from "@/components/ui/Button/Button"; import IconButton from "@/components/ui/IconButton/IconButton"; +import Text from "@/components/ui/Text/Text"; const App = () => { return ( @@ -16,6 +17,17 @@ const App = () => {
+
+ + 영수증으로 + + + AI 음식 리뷰 남겨요 + + + 손쉬운 음식 리뷰 작성 + +
); }; diff --git a/src/components/ui/Button/Button.module.scss b/src/components/ui/Button/Button.module.scss index 723d0b7..703099c 100644 --- a/src/components/ui/Button/Button.module.scss +++ b/src/components/ui/Button/Button.module.scss @@ -4,7 +4,7 @@ @include buttonSecondary; &.style-primary { - background-color: var(--color-text01); + background-color: var(--color-text-primary); color: var(--color-white); } @@ -15,12 +15,12 @@ &.style-tertiary { background-color: var(--color-gray200); - color: var(--color-text02); + color: var(--color-text-secondary); } &:disabled { background-color: var(--color-gray350); - color: var(--color-text03); + color: var(--color-text-tertiary); cursor: not-allowed; } } diff --git a/src/components/ui/IconButton/IconButton.module.scss b/src/components/ui/IconButton/IconButton.module.scss index f1f51d8..b135f57 100644 --- a/src/components/ui/IconButton/IconButton.module.scss +++ b/src/components/ui/IconButton/IconButton.module.scss @@ -16,7 +16,7 @@ gap: 0.125rem; height: 2.375rem; padding: 0.5rem 0.875rem; - background-color: var(--color-text01); + background-color: var(--color-text-primary); color: var(--color-white); border-radius: 0.75rem; @include buttonTertiary; diff --git a/src/components/ui/Text/Text.module.scss b/src/components/ui/Text/Text.module.scss new file mode 100644 index 0000000..9f077d7 --- /dev/null +++ b/src/components/ui/Text/Text.module.scss @@ -0,0 +1,67 @@ +.Text { + line-height: 1.5; + + @each $color-name + in ("white", "black", "primary", "secondary", "tertiary", "quarternary", "gradient") + { + @if $color-name == "gradient" { + &.color-#{$color-name} { + background: var(--color-text-gradient); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + } + } @else { + &.color-#{$color-name} { + color: var(--color-text-#{$color-name}); + } + } + } + + @each $size-name in ("xxs", "xs", "sm", "default", "md", "lg", "xl") { + &.size-#{"#{$size-name}"} { + font-size: var(--font-size-#{$size-name}); + } + } + + @each $weight-name in ("regular", "medium", "semi-bold", "bold") { + &.weight-#{"#{$weight-name}"} { + font-weight: var(--font-weight-#{$weight-name}); + } + } + + @each $align-name in ("left", "center", "right") { + &.align-#{"#{$align-name}"} { + text-align: #{$align-name}; + } + } + + &.truncated { + overflow: hidden; + display: block; + text-overflow: ellipsis; + white-space: nowrap; + } + + &.multi-line-truncated { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + line-clamp: 2; + } +} + +.TextStory { + display: flex; + flex-direction: column; + gap: 1rem; + width: 200px; + + .Wrapper { + display: flex; + gap: 1rem; + justify-content: center; + } +} diff --git a/src/components/ui/Text/Text.stories.tsx b/src/components/ui/Text/Text.stories.tsx new file mode 100644 index 0000000..8a9a9dd --- /dev/null +++ b/src/components/ui/Text/Text.stories.tsx @@ -0,0 +1,109 @@ +import Text from "@/components/ui/Text/Text"; +import styles from "@/components/ui/Text/Text.module.scss"; +import type { TextProps } from "@/components/ui/Text/Text.types"; + +import type { Meta, StoryObj, StoryFn } from "@storybook/react"; + +const meta: Meta = { + title: "Example/Text", + component: Text, + parameters: { + layout: "centered", + }, + tags: ["!autodocs"], +}; + +export default meta; + +const Template: StoryFn = ({ children, ...props }) => ( +
+ {children} +
+); + +export const Primary: StoryObj = { + render: Template, + args: { + size: "default", + color: "black", + weight: "regular", + align: "left", + truncated: false, + children: "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + }, +}; + +export const SizeProps: StoryObj = { + render: () => ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ), +}; + +export const WeightProps: StoryObj = { + render: () => ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ), +}; + +export const ColorPorps: StoryObj = { + render: () => ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ), +}; diff --git a/src/components/ui/Text/Text.tsx b/src/components/ui/Text/Text.tsx new file mode 100644 index 0000000..9fc1325 --- /dev/null +++ b/src/components/ui/Text/Text.tsx @@ -0,0 +1,47 @@ +import React from "react"; + +import classNames from "classnames"; + +import styles from "@/components/ui/Text/Text.module.scss"; +import type { TextProps } from "@/components/ui/Text/Text.types"; + +const Text = React.forwardRef( + ( + { + as: Comp = "span", + children, + color = "black", + size = "default", + className, + weight = "regular", + align = "left", + truncated, + ...props + }, + ref, + ) => { + const isMultiLineTruncated = typeof truncated === "number" && truncated >= 1; + + return ( + + {children} + + ); + }, +); + +export default Text; diff --git a/src/components/ui/Text/Text.types.ts b/src/components/ui/Text/Text.types.ts new file mode 100644 index 0000000..fc51701 --- /dev/null +++ b/src/components/ui/Text/Text.types.ts @@ -0,0 +1,23 @@ +type TextSize = "xxs" | "xs" | "sm" | "default" | "md" | "lg" | "xl"; + +type TextWeight = "regular" | "medium" | "semi-bold" | "bold"; + +type TextAlign = "left" | "center" | "right"; + +type TextColor = + | "white" + | "black" + | "primary" + | "secondary" + | "tertiary" + | "quarternary" + | "gradient"; + +export interface TextProps extends React.HTMLAttributes { + as?: React.ElementType; + color?: TextColor; + size?: TextSize; + weight?: TextWeight; + align?: TextAlign; + truncated?: boolean | number; +} diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index 0b0e75d..d1287c8 100644 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -12,13 +12,16 @@ --font-size-xs: 0.875rem; --font-size-xxs: 0.8125rem; - --color-white: #fff; - --color-black: #000; - --color-text01: #363642; - --color-text02: #68696e; - --color-text03: #a6a6ad; - --color-text04: #e0e0e0; - --color-text-gradient: linear-gradient(#d444ba, #443fb6); + --color-text-white: #fff; + --color-text-black: #000; + --color-text-primary: #363642; + --color-text-secondary: #68696e; + --color-text-tertiary: #a6a6ad; + --color-text-quarternary: #e0e0e0; + --color-text-gradient: linear-gradient(90deg, #d444ba, #443fb6); + + --color-white: #ffffff; + --color-black: #000000; --color-gray100: #f8f8f8; --color-gray200: #ebecf0; --color-gray300: #e1e2e8;