From 2fa667973744ca6b10f4ca5f1bb7a42295aa9c9f Mon Sep 17 00:00:00 2001 From: CHAE Date: Tue, 23 Jan 2024 00:01:56 +0900 Subject: [PATCH] =?UTF-8?q?config:=20=EC=8A=A4=ED=86=A0=EB=A6=AC=EB=B6=81?= =?UTF-8?q?=20=EB=B0=B0=ED=8F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: 박유현 --- .github/workflows/chromatic.yml | 31 ++++++++ .gitignore | 1 + .nvmrc | 1 + package.json | 8 ++- src/components/Button/Button.css.ts | 92 ++++++++++++++++++++++++ src/components/Button/Button.stories.tsx | 37 ++++++++++ src/components/Button/Button.tsx | 47 ++++++++++++ src/components/Button/index.ts | 3 + src/tokens/color.ts | 72 +++++++++++++++++++ src/tokens/typography.ts | 25 +++++++ src/tokens/utils.css.ts | 78 ++++++++++++++++++++ src/utils/classnames.ts | 11 +++ yarn.lock | 12 ++++ 13 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/chromatic.yml create mode 100644 .nvmrc create mode 100644 src/components/Button/Button.css.ts create mode 100644 src/components/Button/Button.stories.tsx create mode 100644 src/components/Button/Button.tsx create mode 100644 src/components/Button/index.ts create mode 100644 src/tokens/color.ts create mode 100644 src/tokens/typography.ts create mode 100644 src/tokens/utils.css.ts create mode 100644 src/utils/classnames.ts diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml new file mode 100644 index 0000000..42a0268 --- /dev/null +++ b/.github/workflows/chromatic.yml @@ -0,0 +1,31 @@ + +# Workflow name +name: 'Chromatic Deployment' + +# Event for the workflow +on: + push: + branches: + - main + +# List of jobs +jobs: + test: + # Operating System + runs-on: ubuntu-latest + # Job steps + steps: + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc + cache: yarn + - name: Corepack Enable + run: corepack enable + - uses: actions/checkout@v1 + run: yarn + #👇 Adds Chromatic as a step in the workflow + - uses: chromaui/action@v1 + # Options required for Chromatic's GitHub Action + with: + #👇 Chromatic projectToken, see https://storybook.js.org/tutorials/intro-to-storybook/react/ko/deploy/ to obtain it + projectToken: ${{ secrets.CHROMATIC_PAGE_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index c6a1715..eca94f5 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ next-env.d.ts .idea .obsidian .vscode +build-storybook.log diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..f4801a0 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v21.1.0 diff --git a/package.json b/package.json index 3fe56b1..dcd60fe 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "start": "next start", "lint": "next lint", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "chromatic": "npx chromatic --project-token=chpt_2c58d8828cea154" }, "dependencies": { "@vanilla-extract/css": "^1.14.0", @@ -33,6 +34,7 @@ "@typescript-eslint/parser": "^6.19.0", "@vanilla-extract/next-plugin": "^2.3.3", "@vanilla-extract/webpack-plugin": "^2.3.2", + "chromatic": "^10.3.1", "css-loader": "^6.9.1", "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", @@ -50,5 +52,7 @@ "typescript": "^5", "webpack": "^5.89.0" }, - "packageManager": "yarn@4.0.2" + "packageManager": "yarn@4.0.2", + "readme": "ERROR: No README data found!", + "_id": "design-system@0.1.0" } diff --git a/src/components/Button/Button.css.ts b/src/components/Button/Button.css.ts new file mode 100644 index 0000000..d83cf5d --- /dev/null +++ b/src/components/Button/Button.css.ts @@ -0,0 +1,92 @@ +import { style, styleVariants } from "@vanilla-extract/css"; + +import color from "../../tokens/color"; +import typography from "../../tokens/typography"; +import { borderRadius } from "../../tokens/utils.css"; + +export const buttonBase = style([ + typography.$semantic.title4Regular, + borderRadius, + { + height: 42, + border: "1px solid transparent", + padding: "8px 13px", + + ":disabled": { + borderColor: color.$semantic.bgDisabled, + color: color.$semantic.textDisabled, + backgroundColor: color.$semantic.bgDisabled, + }, + }, +]); + +export const buttonVariants = styleVariants({ + primaryFill: { + color: color.$semantic.textWhite, + backgroundColor: color.$semantic.primary, + + selectors: { + "&:hover:not(:disabled)": { + backgroundColor: color.$semantic.primaryHover, + }, + }, + }, + + secondaryFill: { + color: color.$semantic.textWhite, + backgroundColor: color.$semantic.secondary, + + selectors: { + "&:hover:not(:disabled)": { + backgroundColor: color.$semantic.secondaryHover, + }, + }, + }, + + primaryLine: { + border: `1px solid ${color.$semantic.primary}`, + color: color.$semantic.primary, + backgroundColor: color.$semantic.bgWhite, + + selectors: { + "&:hover:not(:disabled)": { + backgroundColor: color.$semantic.primaryLow, + }, + }, + }, + + secondaryLine: { + border: `1px solid ${color.$semantic.secondary}`, + color: color.$semantic.secondary, + backgroundColor: color.$semantic.bgWhite, + + selectors: { + "&:hover:not(:disabled)": { + color: color.$semantic.secondary, + backgroundColor: color.$semantic.secondaryLow, + }, + }, + }, + + primaryLow: { + color: color.$semantic.primary, + backgroundColor: color.$semantic.primaryLow, + + selectors: { + "&:hover:not(:disabled)": { + backgroundColor: color.$semantic.primaryLowHover, + }, + }, + }, + + secondaryLow: { + color: color.$semantic.secondary, + backgroundColor: color.$semantic.secondaryLow, + + selectors: { + "&:hover:not(:disabled)": { + backgroundColor: color.$semantic.secondaryLowHover, + }, + }, + }, +}); diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx new file mode 100644 index 0000000..230080f --- /dev/null +++ b/src/components/Button/Button.stories.tsx @@ -0,0 +1,37 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { Button } from "./Button"; + +const meta: Meta = { + title: "Button", + component: Button, + argTypes: { + onClick: { action: "clicked" }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Variants: Story = { + args: { + variant: "primaryFill", + children: "variants", + }, +}; + +export const FullWidth: Story = { + args: { + variant: "primaryFill", + children: "full width", + full: true, + }, +}; + +export const Disabled: Story = { + args: { + variant: "primaryFill", + children: "disabled", + disabled: true, + }, +}; diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx new file mode 100644 index 0000000..52078e8 --- /dev/null +++ b/src/components/Button/Button.tsx @@ -0,0 +1,47 @@ +import type { ButtonHTMLAttributes, ReactNode } from "react"; + +import { widthFull } from "../../tokens/utils.css"; +import classnames from "../../utils/classnames"; + +import * as styles from "./Button.css"; + +export type ButtonVariantType = keyof typeof styles.buttonVariants; + +export interface ButtonProps + extends Pick< + ButtonHTMLAttributes, + "type" | "disabled" | "onClick" + > { + full?: boolean; + variant: ButtonVariantType; + children: ReactNode; + className?: string; +} + +export function Button({ + full = false, + variant, + children, + type = "button", + disabled = false, + onClick, + className = "", +}: ButtonProps) { + const buttonStyle = classnames( + styles.buttonBase, + styles.buttonVariants[variant], + full ? widthFull : "", + className, + ); + + return ( + + ); +} diff --git a/src/components/Button/index.ts b/src/components/Button/index.ts new file mode 100644 index 0000000..56dca6c --- /dev/null +++ b/src/components/Button/index.ts @@ -0,0 +1,3 @@ +import { Button } from "./Button"; + +export default Button; diff --git a/src/tokens/color.ts b/src/tokens/color.ts new file mode 100644 index 0000000..3ad6f92 --- /dev/null +++ b/src/tokens/color.ts @@ -0,0 +1,72 @@ +const $scale = { + grey00: "var(--mm-scale-color-grey-00)", + grey50: "var(--mm-scale-color-grey-50)", + grey100: "var(--mm-scale-color-grey-100)", + grey200: "var(--mm-scale-color-grey-200)", + grey300: "var(--mm-scale-color-grey-300)", + grey400: "var(--mm-scale-color-grey-400)", + grey500: "var(--mm-scale-color-grey-500)", + grey600: "var(--mm-scale-color-grey-600)", + grey700: "var(--mm-scale-color-grey-700)", + grey800: "var(--mm-scale-color-grey-800)", + grey900: "var(--mm-scale-color-grey-900)", + coral50: "var(--mm-scale-color-coral-50)", + coral100: "var(--mm-scale-color-coral-100)", + coral200: "var(--mm-scale-color-coral-200)", + coral300: "var(--mm-scale-color-coral-300)", + coral400: "var(--mm-scale-color-coral-400)", + coral500: "var(--mm-scale-color-coral-500)", + coral600: "var(--mm-scale-color-coral-600)", + coral700: "var(--mm-scale-color-coral-700)", + coral800: "var(--mm-scale-color-coral-800)", + coral900: "var(--mm-scale-color-coral-900)", + coral950: "var(--mm-scale-color-coral-950)", + brown50: "var(--mm-scale-color-brown-50)", + brown100: "var(--mm-scale-color-brown-100)", + brown200: "var(--mm-scale-color-brown-200)", + brown300: "var(--mm-scale-color-brown-300)", + brown400: "var(--mm-scale-color-brown-400)", + brown500: "var(--mm-scale-color-brown-500)", + brown600: "var(--mm-scale-color-brown-600)", + brown700: "var(--mm-scale-color-brown-700)", + brown800: "var(--mm-scale-color-brown-800)", + brown900: "var(--mm-scale-color-brown-900)", + brown950: "var(--mm-scale-color-brown-950)", +}; + +const $semantic = { + textWhite: "var(--mm-semantic-color-text-white)", + bgWhite: "var(--mm-semantic-color-background-white)", + bgDefault: "var(--mm-semantic-color-background-default)", + bgAlt: "var(--mm-semantic-color-background-alt)", + textDisabled: "var(--mm-semantic-color-text-disabled)", + bgDisabled: "var(--mm-semantic-color-background-disabled)", + primary: "var(--mm-semantic-color-primary)", + primaryHover: "var(--mm-semantic-color-primary-hover)", + primaryLow: "var(--mm-semantic-color-primary-low)", + primaryLowHover: "var(--mm-semantic-color-primary-low-hover)", + secondary: "var(--mm-semantic-color-secondary)", + secondaryHover: "var(--mm-semantic-color-secondary-hover)", + secondaryLow: "var(--mm-semantic-color-secondary-low)", + secondaryLowHover: "var(--mm-semantic-color-secondary-low-hover)", + border: "var(--mm-semantic-color-border)", + success: "var(--mm-semantic-color-success)", + danger: "var(--mm-semantic-color-danger)", + badgeBlue: "var(--mm-semantic-color-badge-blue)", + badgeBlueBg: "var(--mm-semantic-color-badge-blue-bg)", + badgeGreen: "var(--mm-semantic-color-badge-green)", + badgeGreenBg: "var(--mm-semantic-color-badge-green-bg)", + badgeOrange: "var(--mm-semantic-color-badge-orange)", + badgeOrangeBg: "var(--mm-semantic-color-badge-orange-bg)", + badgePurple: "var(--mm-semantic-color-badge-purple)", + badgePurpleBg: "var(--mm-semantic-color-badge-purple-bg)", + badgeRed: "var(--mm-semantic-color-badge-red)", + badgeRedBg: "var(--mm-semantic-color-badge-red-bg)", + badgeTeal: "var(--mm-semantic-color-badge-teal)", + badgeTealBg: "var(--mm-semantic-color-badge-teal-bg)", + badgeYellow: "var(--mm-semantic-color-badge-yellow)", + badgeYellowBg: "var(--mm-semantic-color-badge-yellow-bg)", +}; + +const color = { $scale, $semantic }; +export default color; diff --git a/src/tokens/typography.ts b/src/tokens/typography.ts new file mode 100644 index 0000000..4150e60 --- /dev/null +++ b/src/tokens/typography.ts @@ -0,0 +1,25 @@ +const $semantic = { + h1: "mm-semantic-typography-h1", + h2: "mm-semantic-typography-h2", + h3: "mm-semantic-typography-h3", + title1Regular: "mm-semantic-typography-title1-regular", + title1Bold: "mm-semantic-typography-title1-bold", + title2Regular: "mm-semantic-typography-title2-regular", + title2Bold: "mm-semantic-typography-title2-bold", + title3Regular: "mm-semantic-typography-title3-regular", + title3Bold: "mm-semantic-typography-title3-bold", + title4Regular: "mm-semantic-typography-title4-regular", + title4Bold: "mm-semantic-typography-title4-bold", + body1Regular: "mm-semantic-typography-body1-regular", + body1Bold: "mm-semantic-typography-body1-bold", + body2Regular: "mm-semantic-typography-body2-regular", + body2Bold: "mm-semantic-typography-body2-bold", + caption1Regular: "mm-semantic-typography-caption1-regular", + caption1Bold: "mm-semantic-typography-caption1-bold", + caption2Regular: "mm-semantic-typography-caption2-regular", + caption2Bold: "mm-semantic-typography-caption2-bold", + code: "mm-semantic-typography-code", +}; + +const typography = { $semantic }; +export default typography; diff --git a/src/tokens/utils.css.ts b/src/tokens/utils.css.ts new file mode 100644 index 0000000..42a7977 --- /dev/null +++ b/src/tokens/utils.css.ts @@ -0,0 +1,78 @@ +import { style } from "@vanilla-extract/css"; + +import color from "./color"; + +export const widthMax = style({ maxWidth: 1280 }); +export const widthFull = style({ width: "100%" }); +export const backLayer = style({ zIndex: -1 }); +export const baseLayer = style({ zIndex: 0 }); +export const middleLayer = style({ zIndex: 50 }); +export const topLayer = style({ zIndex: 100 }); +export const modalLayer = style({ zIndex: 1000 }); +export const coachmarkZIndex = 1000; +export const block = style({ + display: "block", +}); +export const flex = style({ + display: "flex", +}); +export const flexColumn = style([ + flex, + { + flexDirection: "column", + }, +]); +export const flexAlignCenter = style([ + flex, + { + alignItems: "center", + }, +]); +export const flexJustifyCenter = style([ + flex, + { + justifyContent: "center", + }, +]); +export const flexCenter = style([flex, flexAlignCenter, flexJustifyCenter]); +export const flexColumnCenter = style([ + flexCenter, + { + flexDirection: "column", + }, +]); + +export const boxShadow = style({ + boxShadow: "0 3px 10px rgba(0,0,0,0.1), 0 3px 3px rgba(0,0,0,0.05)", +}); + +export const scrollBarHidden = style({ + overflow: "scroll", + msOverflowStyle: "none", + scrollbarWidth: "none", + "::-webkit-scrollbar": { + display: "none", + }, +}); + +export const border = { + top: style({ borderTop: `1px solid ${color.$semantic.border}` }), + bottom: style({ borderBottom: `1px solid ${color.$semantic.border}` }), + verticalSide: style({ + border: `1px solid ${color.$semantic.border}`, + borderTop: "none", + borderBottom: "none", + }), + horizontalSide: style({ + border: `1px solid ${color.$semantic.border}`, + borderLeft: "none", + borderRight: "none", + }), + all: style({ + border: `1px solid ${color.$semantic.border}`, + }), +}; + +export const borderRadius = style({ + borderRadius: 8, +}); diff --git a/src/utils/classnames.ts b/src/utils/classnames.ts new file mode 100644 index 0000000..6c623d7 --- /dev/null +++ b/src/utils/classnames.ts @@ -0,0 +1,11 @@ +export default function classnames(...args: string[]) { + return args + .map((value) => value.trim()) + .filter(isTruthy) + .join(" ") + .trim(); +} + +function isTruthy(value: unknown) { + return !!value; +} diff --git a/yarn.lock b/yarn.lock index 29ce2ba..fa69ed2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6331,6 +6331,17 @@ __metadata: languageName: node linkType: hard +"chromatic@npm:^10.3.1": + version: 10.3.1 + resolution: "chromatic@npm:10.3.1" + bin: + chroma: dist/bin.js + chromatic: dist/bin.js + chromatic-cli: dist/bin.js + checksum: 51c664ef66b637eb5da00ec977c673ee61499b3ceac6236e13def2b9211b5ea7af6c274ee71c3d1d215c891d1dd9a7d3f91fd7b4f8c07eddc3f6cd8b36550800 + languageName: node + linkType: hard + "chrome-trace-event@npm:^1.0.2": version: 1.0.3 resolution: "chrome-trace-event@npm:1.0.3" @@ -7086,6 +7097,7 @@ __metadata: "@vanilla-extract/css": "npm:^1.14.0" "@vanilla-extract/next-plugin": "npm:^2.3.3" "@vanilla-extract/webpack-plugin": "npm:^2.3.2" + chromatic: "npm:^10.3.1" css-loader: "npm:^6.9.1" eslint: "npm:^8.56.0" eslint-config-airbnb: "npm:^19.0.4"