From 5b724bf39babf18083910ee29238f1f7b941a659 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 00:19:08 +0900 Subject: [PATCH 01/21] =?UTF-8?q?feat:=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/src/components/Toast/index.tsx | 61 ++ packages/ui/src/components/index.ts | 1 + packages/ui/src/styles.css | 847 +-------------------- 3 files changed, 63 insertions(+), 846 deletions(-) create mode 100644 packages/ui/src/components/Toast/index.tsx diff --git a/packages/ui/src/components/Toast/index.tsx b/packages/ui/src/components/Toast/index.tsx new file mode 100644 index 00000000..06ed6b88 --- /dev/null +++ b/packages/ui/src/components/Toast/index.tsx @@ -0,0 +1,61 @@ +"use client"; + +import { css } from "@styled-system/css"; +import { Flex, styled } from "@styled-system/jsx"; +import type { CSSProperties } from "react"; +import { forwardRef } from "react"; + +import Text from "../Text"; + +/** + * @description 토스트 컴포넌트입니다. + * + * @param {string} text - 토스트 컴포넌트의 메인 텍스트. + * @param {string} [subText] - 토스트 컴포넌트의 보조 텍스트. + * @param {CSSProperties} [style] - 커스텀 스타일을 적용하기 위한 객체. + * @param {string} [className] - 커스텀 클래스를 적용하기 위한 문자열. + */ + +export interface ToastProps { + text: string; + subText?: string; + style?: CSSProperties; + className?: string; +} + +const Toast = forwardRef(({ text, subText, ...rest }: ToastProps) => { + return ( + + + {text} + + + {subText} + + + ); +}); + +const toastContainerStyle = css({ + width: "22.375rem", + padding: "0.75rem 1rem", + + borderRadius: "md", + + position: "absolute", + top: 24, + left: "50%", + translateX: "-50%", + zIndex: 9999, + + background: "backgroundDimmer", + backdropFilter: "blur(30px)", + boxShadow: "mono", +}); + +export default Toast; diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index f30b81fb..e1442d7f 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -4,3 +4,4 @@ export { default as NavItem } from "./NavItem"; export { default as Space } from "./Space"; export { default as Table } from "./Table"; export { default as Text } from "./Text"; +export { default as Toast } from "./Toast"; diff --git a/packages/ui/src/styles.css b/packages/ui/src/styles.css index 8a3a60aa..770a7f03 100644 --- a/packages/ui/src/styles.css +++ b/packages/ui/src/styles.css @@ -1,846 +1 @@ -:host, -html { - --font-fallback: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - -webkit-text-size-adjust: 100%; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -moz-tab-size: 4; - tab-size: 4; - -webkit-tap-highlight-color: transparent; - line-height: 1.5; - font-family: var(--global-font-body, var(--font-fallback)); -} -*, -::backdrop, -::file-selector-button, -:after, -:before { - margin: 0px; - padding: 0px; - box-sizing: border-box; - border-width: 0px; - border-style: solid; - border-color: var(--global-color-border, currentColor); -} -hr { - height: 0px; - color: inherit; - border-top-width: 1px; -} -body { - height: 100%; - line-height: inherit; -} -img { - border-style: none; -} -audio, -canvas, -embed, -iframe, -img, -object, -svg, -video { - display: block; - vertical-align: middle; -} -img, -video { - max-width: 100%; - height: auto; -} -h1, -h2, -h3, -h4, -h5, -h6 { - text-wrap: balance; - font-size: inherit; - font-weight: inherit; -} -h1, -h2, -h3, -h4, -h5, -h6, -p { - overflow-wrap: break-word; -} -menu, -ol, -ul { - list-style: none; -} -::file-selector-button, -button, -input:where([type="button"], [type="reset"], [type="submit"]) { - appearance: button; - -webkit-appearance: button; -} -::file-selector-button, -button, -input, -optgroup, -select, -textarea { - font: inherit; - font-feature-settings: inherit; - font-variation-settings: inherit; - letter-spacing: inherit; - color: inherit; - background: transparent; -} -::placeholder { - opacity: 1; - --placeholder-fallback: color-mix(in srgb, currentColor 50%, transparent); - color: var(--global-color-placeholder, var(--placeholder-fallback)); -} -textarea { - resize: vertical; -} -table { - text-indent: 0px; - border-collapse: collapse; - border-color: inherit; -} -summary { - display: list-item; -} -small { - font-size: 80%; -} -sub, -sup { - position: relative; - vertical-align: baseline; - font-size: 75%; - line-height: 0; -} -sub { - bottom: -0.25em; -} -sup { - top: -0.5em; -} -dialog { - padding: 0px; -} -a { - color: inherit; - text-decoration: inherit; -} -abbr:where([title]) { - text-decoration: underline dotted; -} -b, -strong { - font-weight: bolder; -} -code, -kbd, -pre, -samp { - --font-mono-fallback: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New"; - font-feature-settings: normal; - font-variation-settings: normal; - font-family: var(--global-font-mono, var(--font-mono-fallback)); - font-size: 1em; -} -progress { - vertical-align: baseline; -} -::-webkit-search-cancel-button, -::-webkit-search-decoration { - -webkit-appearance: none; -} -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} -:-moz-ui-invalid { - box-shadow: none; -} -:-moz-focusring { - outline: auto; -} -[hidden]:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - display: none !important; -} -:where(:root, :host):not(#\#):not(#\#) { - --colors-red-50: #fdeceb; - --colors-red-100: #fbd9d7; - --colors-red-150: #f9c7c2; - --colors-red-200: #f7b4ae; - --colors-red-300: #f28e86; - --colors-red-400: #ee695d; - --colors-red-500: #ea4335; - --colors-red-600: #bb362a; - --colors-red-700: #8c2820; - --colors-red-800: #5e1b15; - --colors-red-850: #461410; - --colors-red-900: #2f0d0b; - --colors-red-950: #170705; - --colors-blue-50: #ebf4fe; - --colors-blue-100: #d7e9fd; - --colors-blue-150: #c3ddfd; - --colors-blue-200: #afd2fc; - --colors-blue-300: #86bcfa; - --colors-blue-400: #5ea5f9; - --colors-blue-500: #368ff7; - --colors-blue-600: #2b72c6; - --colors-blue-700: #205694; - --colors-blue-800: #163963; - --colors-blue-850: #102b4a; - --colors-blue-900: #0b1d31; - --colors-blue-950: #050e19; - --colors-yellow-50: #fef7e6; - --colors-yellow-100: #feeecc; - --colors-yellow-150: #fde6b3; - --colors-yellow-200: #fddd99; - --colors-yellow-300: #fbcd66; - --colors-yellow-400: #fabc33; - --colors-yellow-500: #f9ab00; - --colors-yellow-600: #c78900; - --colors-yellow-700: #956700; - --colors-yellow-800: #644400; - --colors-yellow-850: #4b3300; - --colors-yellow-900: #322200; - --colors-yellow-950: #191100; - --colors-green-50: #ebf6ee; - --colors-green-100: #d6eedd; - --colors-green-150: #c2e5cb; - --colors-green-200: #aedcba; - --colors-green-300: #85cb98; - --colors-green-400: #5db975; - --colors-green-500: #34a853; - --colors-green-600: #2a8642; - --colors-green-700: #1f6532; - --colors-green-800: #154321; - --colors-green-850: #103219; - --colors-green-900: #0a2211; - --colors-green-950: #051108; - --colors-mono-50: #f7f7f7; - --colors-mono-100: #f0f0f0; - --colors-mono-150: #e8e8e8; - --colors-mono-200: #e1e1e1; - --colors-mono-300: #d1d1d1; - --colors-mono-400: #c2c2c2; - --colors-mono-500: #b3b3b3; - --colors-mono-600: #8f8f8f; - --colors-mono-700: #6b6b6b; - --colors-mono-800: #484848; - --colors-mono-900: #242424; - --colors-mono-950: #121212; - --colors-white: #ffffff; - --colors-black: #000000; - --spacing-xl: 1.5rem; - --radii-md: 0.5rem; - --border-widths-button: 1px; - --shadows-mono: 0px 4px 8px 0px rgba(0, 0, 0, 0.2); - --colors-primary: #368ff7; - --colors-success: #2a8642; - --colors-error: #bb362a; - --colors-background-normal: #ffffff; - --colors-background-alternative: #f7f7f7; - --colors-background-dimmer: rgba(0, 0, 0, 0.8); - --colors-sub: #6b6b6b; - --colors-outline: #c2c2c2; - --colors-text-black: #121212; - --colors-text-white: #ffffff; - --colors-dark-disabled: #c2c2c2; - --colors-light-disabled: #e1e1e1; - --colors-blue-hover: #2b72c6; - --colors-mono-hover: #121212; - --colors-elevated-hover: rgba(16, 43, 74, 0.2); - --colors-blue-pressed: #5ea5f9; - --colors-blue-background-pressed: #ebf4fe; - --colors-mono-background-pressed: #f7f7f7; - --colors-shadow-small: rgba(0, 0, 0, 0.1); - --colors-shadow-medium: rgba(0, 0, 0, 0.2); - --colors-blue-shadow: rgba(16, 43, 74, 0.2); - --colors-discord: #5566fb; - --colors-github: #000000; - --colors-secondary-yellow: #f9ab00; - --colors-secondary-green: #34a853; - --colors-secondary-red: #ea4335; - --colors-error-background: #fbd9d7; - --colors-blue-disabled: #d7e9fd; - --colors-text-blue-disabled: #afd2fc; -} -.textStyle_body1:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01rem; - font-size: 1rem; - line-height: 160%; - font-weight: 500; -} -.textStyle_body0:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01125rem; - font-size: 1.125rem; - line-height: 160%; - font-weight: 500; -} -.textStyle_body2:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.00875rem; - font-size: 0.875rem; - line-height: 160%; - font-weight: 500; -} -.textStyle_body3:not(#\#):not(#\#):not(#\#):not(#\#) { - font-size: 0.75rem; - line-height: 140%; - font-weight: 500; -} -.textStyle_display1:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.025rem; - font-size: 2.5rem; - line-height: 130%; - font-weight: 700; -} -.textStyle_display2:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.02rem; - font-size: 2rem; - line-height: 130%; - font-weight: 700; -} -.textStyle_h1:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.015rem; - font-size: 1.5rem; - line-height: 130%; - font-weight: 600; -} -.textStyle_h2:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01125rem; - font-size: 1.125rem; - line-height: 130%; - font-weight: 600; -} -.textStyle_h3:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01rem; - font-size: 1rem; - line-height: 130%; - font-weight: 600; -} -.textStyle_label1:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01rem; - font-size: 1rem; - line-height: 100%; - font-weight: 600; -} -.textStyle_label2:not(#\#):not(#\#):not(#\#):not(#\#) { - letter-spacing: -0.01rem; - font-size: 0.875rem; - line-height: 100%; - font-weight: 600; -} -.textStyle_label3:not(#\#):not(#\#):not(#\#):not(#\#) { - font-size: 0.75rem; - line-height: 100%; - font-weight: 600; -} -.h_24:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 24px; -} -.w_49:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 49px; -} -.w_100vw:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 100vw; -} -.h_54px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 54px; -} -.d_flex:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - display: flex; -} -.gap_8px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - gap: 8px; -} -.w_956px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 956px; -} -.px_16px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - padding-inline: 16px; -} -.w_49px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 49px; -} -.h_24px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 24px; -} -.c_primary:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-primary); -} -.w_24:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 24px; -} -.w_40\.75rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 40.75rem; -} -.h_28\.125rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 28.125rem; -} -.pos_relative:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - position: relative; -} -.bdr_md:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - border-radius: var(--radii-md); -} -.bx-sh_mono:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - box-shadow: var(--shadows-mono); -} -.h_100vh:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 100vh; -} -.pos_fixed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - position: fixed; -} -.z_9999:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - z-index: 9999; -} -.bg_backgroundDimmer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - background: var(--colors-background-dimmer); -} -.pos_absolute:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - position: absolute; -} -.cursor_pointer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - cursor: pointer; -} -.li-s_none:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - list-style: none; -} -.h_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 20px; -} -.w_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 20px; -} -.gap_12px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - gap: 12px; -} -.p_11px_18px_11px_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - padding: 11px 18px 11px 20px; -} -.bg_monoBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - background: var(--colors-mono-background-pressed); -} -.bg_white:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - background: var(--colors-white); -} -.w_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 20px; -} -.h_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 20px; -} -.h_80px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 80px; -} -.w_100\%:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - width: 100%; -} -.c_textBlack:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-text-black); -} -.c_blue\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-50); -} -.c_blue\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-100); -} -.c_blue\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-150); -} -.c_blue\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-200); -} -.c_blue\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-300); -} -.c_blue\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-400); -} -.c_blue\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-500); -} -.c_blue\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-600); -} -.c_blue\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-700); -} -.c_blue\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-800); -} -.c_blue\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-850); -} -.c_blue\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-900); -} -.c_blue\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-950); -} -.c_yellow\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-50); -} -.c_yellow\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-100); -} -.c_yellow\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-150); -} -.c_yellow\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-200); -} -.c_yellow\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-300); -} -.c_yellow\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-400); -} -.c_yellow\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-500); -} -.c_yellow\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-600); -} -.c_yellow\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-700); -} -.c_yellow\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-800); -} -.c_yellow\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-850); -} -.c_yellow\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-900); -} -.c_yellow\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-yellow-950); -} -.c_green\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-50); -} -.c_green\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-100); -} -.c_green\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-150); -} -.c_green\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-200); -} -.c_green\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-300); -} -.c_green\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-400); -} -.c_green\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-500); -} -.c_green\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-600); -} -.c_green\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-700); -} -.c_green\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-800); -} -.c_green\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-850); -} -.c_green\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-900); -} -.c_green\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-green-950); -} -.c_red\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-50); -} -.c_red\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-100); -} -.c_red\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-150); -} -.c_red\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-200); -} -.c_red\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-300); -} -.c_red\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-400); -} -.c_red\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-500); -} -.c_red\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-600); -} -.c_red\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-700); -} -.c_red\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-800); -} -.c_red\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-850); -} -.c_red\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-900); -} -.c_red\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-red-950); -} -.c_mono\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-50); -} -.c_mono\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-100); -} -.c_mono\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-150); -} -.c_mono\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-200); -} -.c_mono\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-300); -} -.c_mono\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-400); -} -.c_mono\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-500); -} -.c_mono\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-600); -} -.c_mono\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-700); -} -.c_mono\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-800); -} -.c_mono\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: mono.850; -} -.c_mono\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-900); -} -.c_mono\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-950); -} -.c_white:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-white); -} -.c_black:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-black); -} -.c_whiteOpacity\.20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: whiteOpacity.20; -} -.c_whiteOpacity\.40:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: whiteOpacity.40; -} -.c_whiteOpacity\.60:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: whiteOpacity.60; -} -.c_whiteOpacity\.80:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: whiteOpacity.80; -} -.c_blackOpacity\.20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blackOpacity.20; -} -.c_blackOpacity\.40:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blackOpacity.40; -} -.c_blackOpacity\.60:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blackOpacity.60; -} -.c_blackOpacity\.80:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blackOpacity.80; -} -.c_success:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-success); -} -.c_error:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-error); -} -.c_backgroundNormal:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-background-normal); -} -.c_backgroundAlternative:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-background-alternative); -} -.c_backgroundDimmer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-background-dimmer); -} -.c_errorBackground:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-error-background); -} -.c_sub:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-sub); -} -.c_outline:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-outline); -} -.c_textWhite:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-text-white); -} -.c_darkDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-dark-disabled); -} -.c_lightDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-light-disabled); -} -.c_blueDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-disabled); -} -.c_textBlueDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-text-blue-disabled); -} -.c_blueHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-hover); -} -.c_monoHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-hover); -} -.c_elevatedHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-elevated-hover); -} -.c_bluePressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-pressed); -} -.c_blueBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-background-pressed); -} -.c_monoBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-mono-background-pressed); -} -.c_shadowSmall:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-shadow-small); -} -.c_shadowMedium:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-shadow-medium); -} -.c_blueShadow:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-blue-shadow); -} -.c_discord:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-discord); -} -.c_github:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-github); -} -.c_secondaryYellow:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-secondary-yellow); -} -.c_secondaryGreen:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-secondary-green); -} -.c_secondaryRed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: var(--colors-secondary-red); -} -.c_blueGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blueGradientDark; -} -.c_blueGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: blueGradientLight; -} -.c_redGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: redGradientDark; -} -.c_redGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: redGradientLight; -} -.c_greenGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: greenGradientDark; -} -.c_greenGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: greenGradientLight; -} -.c_yellowGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: yellowGradientDark; -} -.c_yellowGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - color: yellowGradientLight; -} -.bd-b-w_button:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - border-bottom-width: var(--border-widths-button); -} -.bd-b-c_mono\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - border-bottom-color: var(--colors-mono-400); -} -.border-bottom-style_solid:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - border-bottom-style: solid; -} -.ai_center:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - align-items: center; -} -.jc_center:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - justify-content: center; -} -.ff_Product_Sans:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - font-family: Product Sans; -} -.fw_700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - font-weight: 700; -} -.fs_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - font-size: 20px; -} -.lh_130\%:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - line-height: 130%; -} -.fw_400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - font-weight: 400; -} -.fs_14px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - font-size: 14px; -} -.flex-d_column:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - flex-direction: column; -} -.top_0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - top: 0; -} -.left_0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - left: 0; -} -.top_xl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - top: var(--spacing-xl); -} -.right_xl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - right: var(--spacing-xl); -} -.mr_8px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - margin-right: 8px; -} -.ml_auto:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - margin-left: auto; -} -.jc_space-between:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - justify-content: space-between; -} -.mb_12px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - margin-bottom: 12px; -} -.jc_flex-start:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - justify-content: flex-start; -} -.jc_flex-end:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - justify-content: flex-end; -} +:host,html{--font-fallback:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent;line-height:1.5;font-family:var(--global-font-body,var(--font-fallback))}*,::backdrop,::file-selector-button,:after,:before{margin:0px;padding:0px;box-sizing:border-box;border-width:0px;border-style:solid;border-color:var(--global-color-border,currentColor)}hr{height:0px;color:inherit;border-top-width:1px}body{height:100%;line-height:inherit}img{border-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}h1,h2,h3,h4,h5,h6{text-wrap:balance;font-size:inherit;font-weight:inherit}h1,h2,h3,h4,h5,h6,p{overflow-wrap:break-word}menu,ol,ul{list-style:none}::file-selector-button,button,input:where([type=button],[type=reset],[type=submit]){appearance:button;-webkit-appearance:button}::file-selector-button,button,input,optgroup,select,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;background:transparent}::placeholder{opacity:1;--placeholder-fallback:color-mix(in srgb,currentColor 50%,transparent);color:var(--global-color-placeholder,var(--placeholder-fallback))}textarea{resize:vertical}table{text-indent:0px;border-collapse:collapse;border-color:inherit}summary{display:list-item}small{font-size:80%}sub,sup{position:relative;vertical-align:baseline;font-size:75%;line-height:0}sub{bottom:-0.25em}sup{top:-0.5em}dialog{padding:0px}a{color:inherit;text-decoration:inherit}abbr:where([title]){text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{--font-mono-fallback:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New';font-feature-settings:normal;font-variation-settings:normal;font-family:var(--global-font-mono,var(--font-mono-fallback));font-size:1em}progress{vertical-align:baseline}::-webkit-search-cancel-button,::-webkit-search-decoration{-webkit-appearance:none}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}:-moz-ui-invalid{box-shadow:none}:-moz-focusring{outline:auto}[hidden]:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){display:none!important}:where(:root,:host):not(#\#):not(#\#){--colors-red-50:#FDECEB;--colors-red-100:#FBD9D7;--colors-red-150:#F9C7C2;--colors-red-200:#F7B4AE;--colors-red-300:#F28E86;--colors-red-400:#EE695D;--colors-red-500:#EA4335;--colors-red-600:#BB362A;--colors-red-700:#8C2820;--colors-red-800:#5E1B15;--colors-red-850:#461410;--colors-red-900:#2F0D0B;--colors-red-950:#170705;--colors-blue-50:#EBF4FE;--colors-blue-100:#D7E9FD;--colors-blue-150:#C3DDFD;--colors-blue-200:#AFD2FC;--colors-blue-300:#86BCFA;--colors-blue-400:#5EA5F9;--colors-blue-500:#368FF7;--colors-blue-600:#2B72C6;--colors-blue-700:#205694;--colors-blue-800:#163963;--colors-blue-850:#102B4A;--colors-blue-900:#0B1D31;--colors-blue-950:#050E19;--colors-yellow-50:#FEF7E6;--colors-yellow-100:#FEEECC;--colors-yellow-150:#FDE6B3;--colors-yellow-200:#FDDD99;--colors-yellow-300:#FBCD66;--colors-yellow-400:#FABC33;--colors-yellow-500:#F9AB00;--colors-yellow-600:#C78900;--colors-yellow-700:#956700;--colors-yellow-800:#644400;--colors-yellow-850:#4B3300;--colors-yellow-900:#322200;--colors-yellow-950:#191100;--colors-green-50:#EBF6EE;--colors-green-100:#D6EEDD;--colors-green-150:#C2E5CB;--colors-green-200:#AEDCBA;--colors-green-300:#85CB98;--colors-green-400:#5DB975;--colors-green-500:#34A853;--colors-green-600:#2A8642;--colors-green-700:#1F6532;--colors-green-800:#154321;--colors-green-850:#103219;--colors-green-900:#0A2211;--colors-green-950:#051108;--colors-mono-50:#F7F7F7;--colors-mono-100:#F0F0F0;--colors-mono-150:#E8E8E8;--colors-mono-200:#E1E1E1;--colors-mono-300:#D1D1D1;--colors-mono-400:#C2C2C2;--colors-mono-500:#B3B3B3;--colors-mono-600:#8F8F8F;--colors-mono-700:#6B6B6B;--colors-mono-800:#484848;--colors-mono-900:#242424;--colors-mono-950:#121212;--colors-white:#FFFFFF;--colors-black:#000000;--spacing-xl:1.5rem;--radii-md:0.5rem;--border-widths-button:1px;--shadows-mono:0px 4px 8px 0px rgba(0,0,0,0.2);--colors-primary:#368FF7;--colors-success:#2A8642;--colors-error:#BB362A;--colors-background-normal:#FFFFFF;--colors-background-alternative:#F7F7F7;--colors-background-dimmer:rgba(0,0,0,0.8);--colors-sub:#6B6B6B;--colors-outline:#C2C2C2;--colors-text-black:#121212;--colors-text-white:#FFFFFF;--colors-dark-disabled:#C2C2C2;--colors-light-disabled:#E1E1E1;--colors-blue-hover:#2B72C6;--colors-mono-hover:#121212;--colors-elevated-hover:rgba(16,43,74,0.2);--colors-blue-pressed:#5EA5F9;--colors-blue-background-pressed:#EBF4FE;--colors-mono-background-pressed:#F7F7F7;--colors-shadow-small:rgba(0,0,0,0.1);--colors-shadow-medium:rgba(0,0,0,0.2);--colors-blue-shadow:rgba(16,43,74,0.2);--colors-discord:#5566FB;--colors-github:#000000;--colors-secondary-yellow:#F9AB00;--colors-secondary-green:#34A853;--colors-secondary-red:#EA4335;--colors-error-background:#FBD9D7;--colors-blue-disabled:#D7E9FD;--colors-text-blue-disabled:#AFD2FC}.textStyle_body1:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01rem;font-size:1rem;line-height:160%;font-weight:500}.textStyle_body0:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01125rem;font-size:1.125rem;line-height:160%;font-weight:500}.textStyle_body2:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.00875rem;font-size:0.875rem;line-height:160%;font-weight:500}.textStyle_body3:not(#\#):not(#\#):not(#\#):not(#\#){font-size:0.75rem;line-height:140%;font-weight:500}.textStyle_display1:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.025rem;font-size:2.5rem;line-height:130%;font-weight:700}.textStyle_display2:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.02rem;font-size:2rem;line-height:130%;font-weight:700}.textStyle_h1:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.015rem;font-size:1.5rem;line-height:130%;font-weight:600}.textStyle_h2:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01125rem;font-size:1.125rem;line-height:130%;font-weight:600}.textStyle_h3:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01rem;font-size:1rem;line-height:130%;font-weight:600}.textStyle_label1:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01rem;font-size:1rem;line-height:100%;font-weight:600}.textStyle_label2:not(#\#):not(#\#):not(#\#):not(#\#){letter-spacing:-0.01rem;font-size:0.875rem;line-height:100%;font-weight:600}.textStyle_label3:not(#\#):not(#\#):not(#\#):not(#\#){font-size:0.75rem;line-height:100%;font-weight:600}.h_24:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:24px}.w_49:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:49px}.w_100vw:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:100vw}.h_54px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:54px}.d_flex:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){display:flex}.gap_8px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){gap:8px}.w_956px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:956px}.px_16px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){padding-inline:16px}.w_49px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:49px}.h_24px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:24px}.c_primary:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-primary)}.w_24:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:24px}.w_40\.75rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:40.75rem}.h_28\.125rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:28.125rem}.pos_relative:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){position:relative}.bdr_md:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){border-radius:var(--radii-md)}.bx-sh_mono:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){box-shadow:var(--shadows-mono)}.h_100vh:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:100vh}.pos_fixed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){position:fixed}.z_9999:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){z-index:9999}.bg_backgroundDimmer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){background:var(--colors-background-dimmer)}.pos_absolute:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){position:absolute}.cursor_pointer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){cursor:pointer}.li-s_none:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){list-style:none}.h_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:20px}.w_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:20px}.gap_12px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){gap:12px}.p_11px_18px_11px_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){padding:11px 18px 11px 20px}.bg_monoBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){background:var(--colors-mono-background-pressed)}.bg_white:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){background:var(--colors-white)}.w_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:20px}.h_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:20px}.h_80px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){height:80px}.w_100\%:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:100%}.c_textBlack:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-text-black)}.c_textWhite:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-text-white)}.c_outline:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-outline)}.w_22\.375rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){width:22.375rem}.p_0\.75rem_1rem:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){padding:0.75rem 1rem}.bkdp_blur\(30px\):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){backdrop-filter:blur(30px);-webkit-backdrop-filter:blur(30px)}.c_blue\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-50)}.c_blue\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-100)}.c_blue\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-150)}.c_blue\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-200)}.c_blue\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-300)}.c_blue\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-400)}.c_blue\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-500)}.c_blue\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-600)}.c_blue\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-700)}.c_blue\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-800)}.c_blue\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-850)}.c_blue\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-900)}.c_blue\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-950)}.c_yellow\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-50)}.c_yellow\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-100)}.c_yellow\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-150)}.c_yellow\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-200)}.c_yellow\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-300)}.c_yellow\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-400)}.c_yellow\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-500)}.c_yellow\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-600)}.c_yellow\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-700)}.c_yellow\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-800)}.c_yellow\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-850)}.c_yellow\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-900)}.c_yellow\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-yellow-950)}.c_green\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-50)}.c_green\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-100)}.c_green\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-150)}.c_green\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-200)}.c_green\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-300)}.c_green\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-400)}.c_green\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-500)}.c_green\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-600)}.c_green\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-700)}.c_green\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-800)}.c_green\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-850)}.c_green\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-900)}.c_green\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-green-950)}.c_red\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-50)}.c_red\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-100)}.c_red\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-150)}.c_red\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-200)}.c_red\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-300)}.c_red\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-400)}.c_red\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-500)}.c_red\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-600)}.c_red\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-700)}.c_red\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-800)}.c_red\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-850)}.c_red\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-900)}.c_red\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-red-950)}.c_mono\.50:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-50)}.c_mono\.100:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-100)}.c_mono\.150:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-150)}.c_mono\.200:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-200)}.c_mono\.300:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-300)}.c_mono\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-400)}.c_mono\.500:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-500)}.c_mono\.600:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-600)}.c_mono\.700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-700)}.c_mono\.800:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-800)}.c_mono\.850:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:mono.850}.c_mono\.900:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-900)}.c_mono\.950:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-950)}.c_white:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-white)}.c_black:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-black)}.c_whiteOpacity\.20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:whiteOpacity.20}.c_whiteOpacity\.40:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:whiteOpacity.40}.c_whiteOpacity\.60:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:whiteOpacity.60}.c_whiteOpacity\.80:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:whiteOpacity.80}.c_blackOpacity\.20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blackOpacity.20}.c_blackOpacity\.40:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blackOpacity.40}.c_blackOpacity\.60:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blackOpacity.60}.c_blackOpacity\.80:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blackOpacity.80}.c_success:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-success)}.c_error:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-error)}.c_backgroundNormal:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-background-normal)}.c_backgroundAlternative:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-background-alternative)}.c_backgroundDimmer:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-background-dimmer)}.c_errorBackground:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-error-background)}.c_sub:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-sub)}.c_darkDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-dark-disabled)}.c_lightDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-light-disabled)}.c_blueDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-disabled)}.c_textBlueDisabled:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-text-blue-disabled)}.c_blueHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-hover)}.c_monoHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-hover)}.c_elevatedHover:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-elevated-hover)}.c_bluePressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-pressed)}.c_blueBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-background-pressed)}.c_monoBackgroundPressed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-mono-background-pressed)}.c_shadowSmall:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-shadow-small)}.c_shadowMedium:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-shadow-medium)}.c_blueShadow:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-blue-shadow)}.c_discord:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-discord)}.c_github:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-github)}.c_secondaryYellow:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-secondary-yellow)}.c_secondaryGreen:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-secondary-green)}.c_secondaryRed:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:var(--colors-secondary-red)}.c_blueGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blueGradientDark}.c_blueGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:blueGradientLight}.c_redGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:redGradientDark}.c_redGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:redGradientLight}.c_greenGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:greenGradientDark}.c_greenGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:greenGradientLight}.c_yellowGradientDark:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:yellowGradientDark}.c_yellowGradientLight:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){color:yellowGradientLight}.bd-b-w_button:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-width:var(--border-widths-button)}.bd-b-c_mono\.400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-color:var(--colors-mono-400)}.border-bottom-style_solid:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-style:solid}.ai_center:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){align-items:center}.jc_center:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){justify-content:center}.ff_Product_Sans:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){font-family:Product Sans}.fw_700:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){font-weight:700}.fs_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){font-size:20px}.lh_130\%:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){line-height:130%}.fw_400:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){font-weight:400}.fs_14px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){font-size:14px}.flex-d_column:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){flex-direction:column}.top_0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){top:0}.left_0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){left:0}.top_xl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){top:var(--spacing-xl)}.right_xl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){right:var(--spacing-xl)}.mr_8px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){margin-right:8px}.ml_auto:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){margin-left:auto}.jc_space-between:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){justify-content:space-between}.mb_12px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:12px}.jc_flex-start:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){justify-content:flex-start}.jc_flex-end:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){justify-content:flex-end}.top_24:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){top:24px}.left_50\%:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){left:50%} \ No newline at end of file From a9b0134de33515f91f63843f25cfcc2a729e1c10 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 00:19:27 +0900 Subject: [PATCH 02/21] =?UTF-8?q?feat:=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/src/components/Toast/Toast.stories.tsx | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/ui/src/components/Toast/Toast.stories.tsx diff --git a/packages/ui/src/components/Toast/Toast.stories.tsx b/packages/ui/src/components/Toast/Toast.stories.tsx new file mode 100644 index 00000000..d2c5b8e9 --- /dev/null +++ b/packages/ui/src/components/Toast/Toast.stories.tsx @@ -0,0 +1,33 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Toast from "."; + +const meta: Meta = { + title: "Shared/Toast", + component: Toast, + tags: ["autodocs"], + parameters: { + componentSubtitle: "Toast 컴포넌트", + }, + argTypes: { + text: { + description: "Toast에 들어갈 메인 텍스트를 나타냅니다.", + control: { type: "text" }, + }, + subText: { + description: "Toast에 들어갈 보조 텍스트를 나타냅니다.", + control: { type: "text" }, + }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + text: "Text", + subText: "subtext", + }, +}; From 689b50e52a18c224f87242a75f5c27cde1e1f0e7 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 00:20:09 +0900 Subject: [PATCH 03/21] =?UTF-8?q?fix:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/src/components/Toast/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/Toast/index.tsx b/packages/ui/src/components/Toast/index.tsx index 06ed6b88..13f9f6db 100644 --- a/packages/ui/src/components/Toast/index.tsx +++ b/packages/ui/src/components/Toast/index.tsx @@ -1,7 +1,7 @@ "use client"; import { css } from "@styled-system/css"; -import { Flex, styled } from "@styled-system/jsx"; +import { Flex } from "@styled-system/jsx"; import type { CSSProperties } from "react"; import { forwardRef } from "react"; From b4a5f1482ea5d107e280b1a158d21c648f6952ea Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 04:13:57 +0900 Subject: [PATCH 04/21] =?UTF-8?q?fix:=20id=20=ED=95=84=EC=88=98=20prop?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98,=20export=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/src/components/Toast/index.tsx | 12 ++++-------- packages/ui/src/components/index.ts | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/ui/src/components/Toast/index.tsx b/packages/ui/src/components/Toast/index.tsx index 13f9f6db..ad436972 100644 --- a/packages/ui/src/components/Toast/index.tsx +++ b/packages/ui/src/components/Toast/index.tsx @@ -1,6 +1,7 @@ "use client"; import { css } from "@styled-system/css"; +import type { FlexProps } from "@styled-system/jsx"; import { Flex } from "@styled-system/jsx"; import type { CSSProperties } from "react"; import { forwardRef } from "react"; @@ -16,14 +17,15 @@ import Text from "../Text"; * @param {string} [className] - 커스텀 클래스를 적용하기 위한 문자열. */ -export interface ToastProps { +export interface ToastProps extends FlexProps { text: string; subText?: string; style?: CSSProperties; className?: string; + id: string; } -const Toast = forwardRef(({ text, subText, ...rest }: ToastProps) => { +export const Toast = forwardRef(({ text, subText, ...rest }: ToastProps) => { return ( Date: Mon, 2 Sep 2024 04:14:48 +0900 Subject: [PATCH 05/21] =?UTF-8?q?feat:=20toast=20atoms=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/store/actions/index.ts | 1 + apps/admin/store/actions/toastAtoms.ts | 26 ++++++++++++++++++++++++++ apps/admin/store/atoms/index.ts | 1 + apps/admin/store/atoms/toastAtoms.ts | 4 ++++ apps/admin/store/index.ts | 2 ++ 5 files changed, 34 insertions(+) create mode 100644 apps/admin/store/actions/index.ts create mode 100644 apps/admin/store/actions/toastAtoms.ts create mode 100644 apps/admin/store/atoms/index.ts create mode 100644 apps/admin/store/atoms/toastAtoms.ts create mode 100644 apps/admin/store/index.ts diff --git a/apps/admin/store/actions/index.ts b/apps/admin/store/actions/index.ts new file mode 100644 index 00000000..226399d8 --- /dev/null +++ b/apps/admin/store/actions/index.ts @@ -0,0 +1 @@ +export * from "./toastAtoms"; diff --git a/apps/admin/store/actions/toastAtoms.ts b/apps/admin/store/actions/toastAtoms.ts new file mode 100644 index 00000000..a7fc88e4 --- /dev/null +++ b/apps/admin/store/actions/toastAtoms.ts @@ -0,0 +1,26 @@ +import type { ToastProps } from "@wow-class/ui"; +import { atom } from "jotai"; + +import { toastsAtom } from "../atoms/toastAtoms"; + +export const toastAtom = atom( + null, + (get, set) => + (props: Omit & Partial>) => { + const prevAtom = get(toastsAtom); + const newToast = { + ...props, + id: props.id || Date.now().toString(), + }; + + set(toastsAtom, [...prevAtom, newToast]); + } +); + +export const removeToastAtom = atom(null, (get, set, id: string) => { + const prev = get(toastsAtom); + set( + toastsAtom, + prev.filter((toast) => toast.id !== id) + ); +}); diff --git a/apps/admin/store/atoms/index.ts b/apps/admin/store/atoms/index.ts new file mode 100644 index 00000000..226399d8 --- /dev/null +++ b/apps/admin/store/atoms/index.ts @@ -0,0 +1 @@ +export * from "./toastAtoms"; diff --git a/apps/admin/store/atoms/toastAtoms.ts b/apps/admin/store/atoms/toastAtoms.ts new file mode 100644 index 00000000..cae676f7 --- /dev/null +++ b/apps/admin/store/atoms/toastAtoms.ts @@ -0,0 +1,4 @@ +import type { ToastProps } from "@wow-class/ui"; +import { atom } from "jotai"; + +export const toastsAtom = atom([]); diff --git a/apps/admin/store/index.ts b/apps/admin/store/index.ts new file mode 100644 index 00000000..a9485524 --- /dev/null +++ b/apps/admin/store/index.ts @@ -0,0 +1,2 @@ +export * from "./actions"; +export * from "./atoms"; From 624128d42ac493636718bd506d1dd9dce1bcd471 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 04:15:23 +0900 Subject: [PATCH 06/21] feat: useToast hook --- apps/admin/hooks/useToast.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 apps/admin/hooks/useToast.ts diff --git a/apps/admin/hooks/useToast.ts b/apps/admin/hooks/useToast.ts new file mode 100644 index 00000000..df3d0992 --- /dev/null +++ b/apps/admin/hooks/useToast.ts @@ -0,0 +1,12 @@ +import { useSetAtom } from "jotai"; +import { toastAtom } from "store"; + +const useToast = () => { + const addToast = useSetAtom(toastAtom); + + return { + toast: addToast(), + }; +}; + +export default useToast; From e8c64339729f3a970ab645e5b984473297b7ddb4 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 04:15:54 +0900 Subject: [PATCH 07/21] feat: ToastProvider --- apps/admin/components/ToastProvider.tsx | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 apps/admin/components/ToastProvider.tsx diff --git a/apps/admin/components/ToastProvider.tsx b/apps/admin/components/ToastProvider.tsx new file mode 100644 index 00000000..bec0bc3c --- /dev/null +++ b/apps/admin/components/ToastProvider.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { Flex } from "@styled-system/jsx"; +import type { ToastProps } from "@wow-class/ui"; +import { useAtomValue } from "jotai"; +import type { ReactNode } from "react"; +import { toastsAtom } from "store"; + +import Toast from "./Toast"; + +const ToastProvider = ({ children }: { children: ReactNode }) => { + const toasts = useAtomValue(toastsAtom); + + return ( + <> + + {toasts?.map((toast: ToastProps) => ( + + ))} + + {children} + + ); +}; + +export default ToastProvider; From 3769a508d83896da51550ed3737cb9d58516d13a Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 04:16:25 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feat:=20admin=20Toast=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/components/Toast.tsx | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 apps/admin/components/Toast.tsx diff --git a/apps/admin/components/Toast.tsx b/apps/admin/components/Toast.tsx new file mode 100644 index 00000000..8af3df0c --- /dev/null +++ b/apps/admin/components/Toast.tsx @@ -0,0 +1,43 @@ +"use client"; +import type { ToastProps } from "@wow-class/ui"; +import { Toast as ToastUI } from "@wow-class/ui"; +import { useSetAtom } from "jotai"; +import { useEffect, useState } from "react"; +import { removeToastAtom } from "store"; + +const TOAST_DURATION = 2000; +const ANIMATION_DURATION = 200; + +const Toast = ({ id, ...rest }: ToastProps) => { + const [opacity, setOpacity] = useState(0.2); + const removeToastItem = useSetAtom(removeToastAtom); + + useEffect(() => { + setOpacity(1); + const timeoutForRemove = setTimeout(() => { + removeToastItem(id); + }, TOAST_DURATION); + + const timeoutForVisible = setTimeout(() => { + setOpacity(0); + }, TOAST_DURATION - ANIMATION_DURATION); + + return () => { + clearTimeout(timeoutForRemove); + clearTimeout(timeoutForVisible); + }; + }, [id, removeToastItem]); + + return ( + + ); +}; + +export default Toast; From a86c4ab4885cb48c912138880faf653d034e5a88 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:11:27 +0900 Subject: [PATCH 09/21] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=EB=A5=BC=20=EB=B0=9B=EA=B8=B0=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20fetcher=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/utils/src/fetcher/index.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/utils/src/fetcher/index.ts b/packages/utils/src/fetcher/index.ts index c91cc884..7f897cc6 100644 --- a/packages/utils/src/fetcher/index.ts +++ b/packages/utils/src/fetcher/index.ts @@ -68,14 +68,17 @@ class Fetcher { return response.text(); } - private async handleError(response: Response) { + private async handleError( + response: Response, + data: { + errorCodeName: string; + errorMessage: string; + } + ) { if (!response.ok) { - const text = await response.text(); - const error = new Error( - `HTTP Error: ${response.status} ${response.statusText}` - ); - (error as any).response = response; - (error as any).responseText = text; + const error = new Error(); + error.message = data.errorMessage; + error.name = data.errorCodeName; throw error; } @@ -96,10 +99,11 @@ class Fetcher { let response: ApiResponse = await fetch(fullUrl, fetchOptions); - await this.handleError(response); + const data = await this.parseJsonResponse(response); + await this.handleError(response, data); response = await this.interceptResponse(response); - response.data = await this.parseJsonResponse(response); + response.data = data; return response; } From c6fdb91a0289d6661757507507e470232d9770c3 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:13:10 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feat:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20Toa?= =?UTF-8?q?stProvider=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/app/layout.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/admin/app/layout.tsx b/apps/admin/app/layout.tsx index 42b0d62c..9d52451a 100644 --- a/apps/admin/app/layout.tsx +++ b/apps/admin/app/layout.tsx @@ -3,6 +3,7 @@ import "wowds-ui/styles.css"; import "@wow-class/ui/styles.css"; import { JotaiProvider } from "components/JotaiProvider"; +import ToastProvider from "components/ToastProvider"; import type { Metadata } from "next"; import type { ReactNode } from "react"; @@ -48,8 +49,10 @@ const RootLayout = ({ - {children} - {modal} + + {children} + {modal} + From cff50674ae47dbcb143948f802b43e502922e8b3 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:14:36 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feat:=20default=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/constants/messages/error.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/admin/constants/messages/error.ts diff --git a/apps/admin/constants/messages/error.ts b/apps/admin/constants/messages/error.ts new file mode 100644 index 00000000..26e06eb9 --- /dev/null +++ b/apps/admin/constants/messages/error.ts @@ -0,0 +1 @@ +export const DEFAULT_ERROR_MESSAGE = "에러가 발생했어요."; From 98c4326a1835d512d1d87325488fda8058b49881 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:16:00 +0900 Subject: [PATCH 12/21] =?UTF-8?q?feat:=20=EA=B3=BC=EC=A0=9C=20=ED=9C=B4?= =?UTF-8?q?=EA=B0=95=EC=B2=98=EB=A6=AC=20toast=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/assignment/AssignmentButtons.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx index 9d4b92df..284b4a1d 100644 --- a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx @@ -1,7 +1,9 @@ "use client"; import { Flex } from "@styled-system/jsx"; import { studyApi } from "apis/study/studyApi"; +import { DEFAULT_ERROR_MESSAGE } from "constants/messages/error"; import { routerPath } from "constants/router/routerPath"; +import useToast from "hooks/useToast"; import Link from "next/link"; import type { StudyAssignmentStatusType } from "types/entities/study"; import Button from "wowds-ui/Button"; @@ -13,12 +15,16 @@ const AssignmentButtons = ({ studyDetailId: number; assignmentStatus: StudyAssignmentStatusType; }) => { + const { toast } = useToast(); + const handleCancelAssignment = async () => { - const { success } = await studyApi.cancelAssignment(studyDetailId); - if (success) { - console.log("휴강 처리에 성공했어요."); - } else { - console.log("휴강 처리에 실패했어요."); + try { + await studyApi.cancelAssignment(studyDetailId); + toast({ text: "휴강 처리에 성공했어요." }); + } catch (error) { + if (error instanceof Error) { + toast({ text: error.message || DEFAULT_ERROR_MESSAGE }); + } } }; From ae0710582b42c6b93e69d2ccad4b31336e6975b0 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:25:43 +0900 Subject: [PATCH 13/21] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=A4=ED=8C=A8=20toast=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@modal/(.)created-study-check/page.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx index 4b2bcbbe..104f727b 100644 --- a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx +++ b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx @@ -5,9 +5,11 @@ import { Modal, Space, Text } from "@wow-class/ui"; import { useModalRoute } from "@wow-class/ui/hooks"; import { createStudyApi } from "apis/study/createStudyApi"; import ItemSeparator from "components/ItemSeparator"; +import { DEFAULT_ERROR_MESSAGE } from "constants/messages/error"; import { routerPath } from "constants/router/routerPath"; import { tags } from "constants/tags"; import useParseSearchParams from "hooks/useParseSearchParams"; +import useToast from "hooks/useToast"; import { useRouter, useSearchParams } from "next/navigation"; import type { CreateStudyApiRequestDto } from "types/dtos/createStudy"; import { revalidateTagByName } from "utils/revalidateTagByName"; @@ -26,15 +28,18 @@ const CreatedStudyCheckModal = () => { const studyName = data.title; const semester = `${data.academicYear}-${data.semesterType === "FIRST" ? "1" : "2"}`; - const handleClickSubmitButton = async () => { - const result = await createStudyApi.postCreateStudy(data); + const { toast } = useToast(); - if (result.success) { - await revalidateTagByName(tags.studyList); - window.alert("스터디 생성에 성공했어요."); + const handleClickSubmitButton = async () => { + try { + await createStudyApi.postCreateStudy(data); + revalidateTagByName(tags.studyList); + toast({ text: "스터디 생성에 성공했어요." }); router.push(`${routerPath.root.href}`); - } else { - window.alert("스터디 생성에 실패했어요."); + } catch (error) { + if (error instanceof Error) { + toast({ text: error.message || DEFAULT_ERROR_MESSAGE }); + } } }; From efea0198999bda4db52399aaf7a0498c9061a1bc Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:28:28 +0900 Subject: [PATCH 14/21] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=A4=ED=8C=A8=20toast=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../announcement/CreateStudyAnnouncement.tsx | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx b/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx index 006fe139..cf7b1dd7 100644 --- a/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx +++ b/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx @@ -5,6 +5,7 @@ import { Flex } from "@styled-system/jsx"; import { Text } from "@wow-class/ui"; import { studyApi } from "apis/study/studyApi"; import { tags } from "constants/tags"; +import useToast from "hooks/useToast"; import { useState } from "react"; import type { StudyAnnouncementType } from "types/entities/study"; import { revalidateTagByName } from "utils/revalidateTagByName"; @@ -18,19 +19,24 @@ const CreateStudyAnnouncement = ({ studyId }: { studyId: string }) => { link: "", }); + const { toast } = useToast(); + const handlePublishAnnouncement = async (studyId: string) => { - const { success } = await studyApi.publishStudyAnnouncement( - parseInt(studyId, 10), - studyAnnouncement - ); - if (success) { + try { + await studyApi.publishStudyAnnouncement( + parseInt(studyId, 10), + studyAnnouncement + ); + toast({ text: "공지 생성 성공" }); revalidateTagByName(tags.announcements); setStudyAnnouncement({ title: "", link: "", }); - } else { - console.log("공지 생성 실패"); + } catch (error) { + if (error instanceof Error) { + toast({ text: error.message }); + } } }; return ( From c0c42b3f0da709b6284420e01d5864ae14093c88 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:41:22 +0900 Subject: [PATCH 15/21] =?UTF-8?q?feat:=20toast=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/components/Toast.tsx | 5 ++- .../{ => status}/assignmentStatusMap.ts | 0 apps/admin/constants/status/toastStatusMap.ts | 6 +++ packages/ui/src/components/Toast/index.tsx | 41 +++++++++++-------- 4 files changed, 33 insertions(+), 19 deletions(-) rename apps/admin/constants/{ => status}/assignmentStatusMap.ts (100%) create mode 100644 apps/admin/constants/status/toastStatusMap.ts diff --git a/apps/admin/components/Toast.tsx b/apps/admin/components/Toast.tsx index 8af3df0c..b813458d 100644 --- a/apps/admin/components/Toast.tsx +++ b/apps/admin/components/Toast.tsx @@ -1,6 +1,7 @@ "use client"; import type { ToastProps } from "@wow-class/ui"; import { Toast as ToastUI } from "@wow-class/ui"; +import { toastStatusMap } from "constants/status/toastStatusMap"; import { useSetAtom } from "jotai"; import { useEffect, useState } from "react"; import { removeToastAtom } from "store"; @@ -8,7 +9,7 @@ import { removeToastAtom } from "store"; const TOAST_DURATION = 2000; const ANIMATION_DURATION = 200; -const Toast = ({ id, ...rest }: ToastProps) => { +const Toast = ({ id, type, text, ...rest }: ToastProps) => { const [opacity, setOpacity] = useState(0.2); const removeToastItem = useSetAtom(removeToastAtom); @@ -32,9 +33,11 @@ const Toast = ({ id, ...rest }: ToastProps) => { ); diff --git a/apps/admin/constants/assignmentStatusMap.ts b/apps/admin/constants/status/assignmentStatusMap.ts similarity index 100% rename from apps/admin/constants/assignmentStatusMap.ts rename to apps/admin/constants/status/assignmentStatusMap.ts diff --git a/apps/admin/constants/status/toastStatusMap.ts b/apps/admin/constants/status/toastStatusMap.ts new file mode 100644 index 00000000..6d5bbbcb --- /dev/null +++ b/apps/admin/constants/status/toastStatusMap.ts @@ -0,0 +1,6 @@ +import { DEFAULT_ERROR_MESSAGE } from "constants/messages/error"; + +export const toastStatusMap: Record<"error" | "success", string> = { + error: DEFAULT_ERROR_MESSAGE, + success: "", +}; diff --git a/packages/ui/src/components/Toast/index.tsx b/packages/ui/src/components/Toast/index.tsx index ad436972..2b5a08f7 100644 --- a/packages/ui/src/components/Toast/index.tsx +++ b/packages/ui/src/components/Toast/index.tsx @@ -11,6 +11,8 @@ import Text from "../Text"; /** * @description 토스트 컴포넌트입니다. * + * @param {string} id - 토스트 컴포넌트의 id. + * @param {"error" | "success"} type - 토스트 컴포넌트의 타입. * @param {string} text - 토스트 컴포넌트의 메인 텍스트. * @param {string} [subText] - 토스트 컴포넌트의 보조 텍스트. * @param {CSSProperties} [style] - 커스텀 스타일을 적용하기 위한 객체. @@ -18,30 +20,33 @@ import Text from "../Text"; */ export interface ToastProps extends FlexProps { + id: string; + type: "error" | "success"; text: string; subText?: string; style?: CSSProperties; className?: string; - id: string; } -export const Toast = forwardRef(({ text, subText, ...rest }: ToastProps) => { - return ( - - - {text} - - - {subText} - - - ); -}); +export const Toast = forwardRef( + ({ text, subText, type, ...rest }: ToastProps) => { + return ( + + + {text} + + + {subText} + + + ); + } +); const toastContainerStyle = css({ width: "22.375rem", From dbfc6587f2485cc58069b81f078354e708bdc49c Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:43:37 +0900 Subject: [PATCH 16/21] =?UTF-8?q?feat:=20toast=20default=20message=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20type=20=EA=B0=9C=EB=B3=84?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[studyId]/_components/assignment/AssignmentButtons.tsx | 5 ++--- .../create-study/@modal/(.)created-study-check/page.tsx | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx index 284b4a1d..a6208bcf 100644 --- a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx @@ -1,7 +1,6 @@ "use client"; import { Flex } from "@styled-system/jsx"; import { studyApi } from "apis/study/studyApi"; -import { DEFAULT_ERROR_MESSAGE } from "constants/messages/error"; import { routerPath } from "constants/router/routerPath"; import useToast from "hooks/useToast"; import Link from "next/link"; @@ -20,10 +19,10 @@ const AssignmentButtons = ({ const handleCancelAssignment = async () => { try { await studyApi.cancelAssignment(studyDetailId); - toast({ text: "휴강 처리에 성공했어요." }); + toast({ type: "success", text: "휴강 처리에 성공했어요." }); } catch (error) { if (error instanceof Error) { - toast({ text: error.message || DEFAULT_ERROR_MESSAGE }); + toast({ type: "error", text: error.message }); } } }; diff --git a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx index 104f727b..05230762 100644 --- a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx +++ b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx @@ -5,7 +5,6 @@ import { Modal, Space, Text } from "@wow-class/ui"; import { useModalRoute } from "@wow-class/ui/hooks"; import { createStudyApi } from "apis/study/createStudyApi"; import ItemSeparator from "components/ItemSeparator"; -import { DEFAULT_ERROR_MESSAGE } from "constants/messages/error"; import { routerPath } from "constants/router/routerPath"; import { tags } from "constants/tags"; import useParseSearchParams from "hooks/useParseSearchParams"; @@ -34,11 +33,11 @@ const CreatedStudyCheckModal = () => { try { await createStudyApi.postCreateStudy(data); revalidateTagByName(tags.studyList); - toast({ text: "스터디 생성에 성공했어요." }); + toast({ type: "success", text: "스터디 생성에 성공했어요." }); router.push(`${routerPath.root.href}`); } catch (error) { if (error instanceof Error) { - toast({ text: error.message || DEFAULT_ERROR_MESSAGE }); + toast({ type: "error", text: error.message }); } } }; From ac66a2733fdc6dc478181c0a1b982b1a1d68b7c2 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:48:35 +0900 Subject: [PATCH 17/21] =?UTF-8?q?feat:=20=EA=B3=BC=EC=A0=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A4=20toast=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[studyDetailId]/_components/AssignmentHeader.tsx | 11 ++++++++--- .../[studyDetailId]/edit-assignment/page.tsx | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx index f2803f10..9eac01a2 100644 --- a/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx +++ b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx @@ -5,6 +5,7 @@ import { Flex } from "@styled-system/jsx"; import { Text } from "@wow-class/ui"; import { studyApi } from "apis/study/studyApi"; import { tags } from "constants/tags"; +import useToast from "hooks/useToast"; import { useFormContext } from "react-hook-form"; import type { AssignmentApiRequestDto, @@ -25,9 +26,10 @@ const AssignmentHeader = ({ assignment, disabled }: AssignmentHeaderProps) => { onOpen: () => void; } >(); - const onOpen = methods.getValues("onOpen"); + const { toast } = useToast(); + const handleClickSubmit = async () => { if (assignmentStatus === "CANCELLED") return; @@ -37,14 +39,17 @@ const AssignmentHeader = ({ assignment, disabled }: AssignmentHeaderProps) => { deadLine: methods.getValues("deadLine"), }; - const { success } = + try { assignmentStatus === "NONE" ? await studyApi.createAssignment(studyDetailId, data) : await studyApi.patchAssignment(studyDetailId, data); - if (success) { revalidateTagByName(`${tags.assignments} ${studyDetailId}`); revalidateTagByName(tags.assignments); onOpen(); + } catch (error) { + if (error instanceof Error) { + toast({ type: "error", text: error.message }); + } } }; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx index 6be479aa..c952a24a 100644 --- a/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx +++ b/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx @@ -2,7 +2,7 @@ import { useOpenState } from "@wow-class/ui/hooks"; import { studyApi } from "apis/study/studyApi"; -import { assignmentStatusMap } from "constants/assignmentStatusMap"; +import { assignmentStatusMap } from "constants/status/assignmentStatusMap"; import { useEffect, useState } from "react"; import { FormProvider, useForm } from "react-hook-form"; import type { From 5a3e2425abc375667db9178aae7bc442b978de18 Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:51:37 +0900 Subject: [PATCH 18/21] =?UTF-8?q?fix:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EC=A0=95=EB=B3=B4=20=EC=9E=91=EC=84=B1=20try?= =?UTF-8?q?=20catch=EA=B5=AC=EB=AC=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_hooks/useSubmitStudyDetailInfo.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts index 9ee3a4d4..3fafdb14 100644 --- a/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts +++ b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts @@ -12,20 +12,19 @@ const useSubmitStudyDetailInfo = ( const router = useRouter(); const handleSubmitDetailInfo = async () => { - const data = await createStudyApi.postStudyDetailInfo( - studyDetailData, - studyId - ); - if (data.success) { + try { + await createStudyApi.postStudyDetailInfo(studyDetailData, studyId); setIsSuccess(true); const timerId = setTimeout(() => { router.push(`${routerPath.root.href}/${studyId}`); }, 500); return () => clearTimeout(timerId); - } else { - setIsSuccess(false); - window.alert("스터디 상세 정보 저장에 실패했어요."); - router.push(`${routerPath.root.href}`); + } catch (error) { + if (error instanceof Error) { + setIsSuccess(false); + window.alert(error.message); + router.push(`${routerPath.root.href}`); + } } }; From a9e9ed14fc3b3d2103ebbc8c18b985f4e7c90a9b Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 05:59:41 +0900 Subject: [PATCH 19/21] =?UTF-8?q?feat:=20=ED=81=B4=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EC=96=B8=ED=8A=B8=20Toast=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/app/layout.tsx | 5 ++- apps/client/components/Toast.tsx | 46 ++++++++++++++++++++++++ apps/client/components/ToastProvider.tsx | 33 +++++++++++++++++ apps/client/constants/toastStatusMap.ts | 6 ++++ apps/client/hooks/useToast.ts | 12 +++++++ apps/client/store/actions/index.ts | 1 + apps/client/store/actions/toastAtoms.ts | 26 ++++++++++++++ apps/client/store/atoms/index.ts | 1 + apps/client/store/atoms/toastAtoms.ts | 4 +++ apps/client/store/index.ts | 2 ++ 10 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 apps/client/components/Toast.tsx create mode 100644 apps/client/components/ToastProvider.tsx create mode 100644 apps/client/constants/toastStatusMap.ts create mode 100644 apps/client/hooks/useToast.ts create mode 100644 apps/client/store/actions/index.ts create mode 100644 apps/client/store/actions/toastAtoms.ts create mode 100644 apps/client/store/atoms/index.ts create mode 100644 apps/client/store/atoms/toastAtoms.ts create mode 100644 apps/client/store/index.ts diff --git a/apps/client/app/layout.tsx b/apps/client/app/layout.tsx index d4642870..450b897c 100644 --- a/apps/client/app/layout.tsx +++ b/apps/client/app/layout.tsx @@ -2,6 +2,7 @@ import "./global.css"; import "wowds-ui/styles.css"; import "@wow-class/ui/styles.css"; +import ToastProvider from "components/ToastProvider"; import type { Metadata } from "next"; import { JotaiProvider } from "../components/JotaiProvider"; @@ -53,7 +54,9 @@ const RootLayout = ({ return ( - {children} + + {children} + ); diff --git a/apps/client/components/Toast.tsx b/apps/client/components/Toast.tsx new file mode 100644 index 00000000..df69ac05 --- /dev/null +++ b/apps/client/components/Toast.tsx @@ -0,0 +1,46 @@ +"use client"; +import type { ToastProps } from "@wow-class/ui"; +import { Toast as ToastUI } from "@wow-class/ui"; +import { toastStatusMap } from "constants/toastStatusMap"; +import { useSetAtom } from "jotai"; +import { useEffect, useState } from "react"; +import { removeToastAtom } from "store"; + +const TOAST_DURATION = 2000; +const ANIMATION_DURATION = 200; + +const Toast = ({ id, type, text, ...rest }: ToastProps) => { + const [opacity, setOpacity] = useState(0.2); + const removeToastItem = useSetAtom(removeToastAtom); + + useEffect(() => { + setOpacity(1); + const timeoutForRemove = setTimeout(() => { + removeToastItem(id); + }, TOAST_DURATION); + + const timeoutForVisible = setTimeout(() => { + setOpacity(0); + }, TOAST_DURATION - ANIMATION_DURATION); + + return () => { + clearTimeout(timeoutForRemove); + clearTimeout(timeoutForVisible); + }; + }, [id, removeToastItem]); + + return ( + + ); +}; + +export default Toast; diff --git a/apps/client/components/ToastProvider.tsx b/apps/client/components/ToastProvider.tsx new file mode 100644 index 00000000..bec0bc3c --- /dev/null +++ b/apps/client/components/ToastProvider.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { Flex } from "@styled-system/jsx"; +import type { ToastProps } from "@wow-class/ui"; +import { useAtomValue } from "jotai"; +import type { ReactNode } from "react"; +import { toastsAtom } from "store"; + +import Toast from "./Toast"; + +const ToastProvider = ({ children }: { children: ReactNode }) => { + const toasts = useAtomValue(toastsAtom); + + return ( + <> + + {toasts?.map((toast: ToastProps) => ( + + ))} + + {children} + + ); +}; + +export default ToastProvider; diff --git a/apps/client/constants/toastStatusMap.ts b/apps/client/constants/toastStatusMap.ts new file mode 100644 index 00000000..bb3b88c7 --- /dev/null +++ b/apps/client/constants/toastStatusMap.ts @@ -0,0 +1,6 @@ +const DEFAULT_ERROR_MESSAGE = "에러가 발생했어요."; + +export const toastStatusMap: Record<"error" | "success", string> = { + error: DEFAULT_ERROR_MESSAGE, + success: "", +}; diff --git a/apps/client/hooks/useToast.ts b/apps/client/hooks/useToast.ts new file mode 100644 index 00000000..df3d0992 --- /dev/null +++ b/apps/client/hooks/useToast.ts @@ -0,0 +1,12 @@ +import { useSetAtom } from "jotai"; +import { toastAtom } from "store"; + +const useToast = () => { + const addToast = useSetAtom(toastAtom); + + return { + toast: addToast(), + }; +}; + +export default useToast; diff --git a/apps/client/store/actions/index.ts b/apps/client/store/actions/index.ts new file mode 100644 index 00000000..226399d8 --- /dev/null +++ b/apps/client/store/actions/index.ts @@ -0,0 +1 @@ +export * from "./toastAtoms"; diff --git a/apps/client/store/actions/toastAtoms.ts b/apps/client/store/actions/toastAtoms.ts new file mode 100644 index 00000000..a7fc88e4 --- /dev/null +++ b/apps/client/store/actions/toastAtoms.ts @@ -0,0 +1,26 @@ +import type { ToastProps } from "@wow-class/ui"; +import { atom } from "jotai"; + +import { toastsAtom } from "../atoms/toastAtoms"; + +export const toastAtom = atom( + null, + (get, set) => + (props: Omit & Partial>) => { + const prevAtom = get(toastsAtom); + const newToast = { + ...props, + id: props.id || Date.now().toString(), + }; + + set(toastsAtom, [...prevAtom, newToast]); + } +); + +export const removeToastAtom = atom(null, (get, set, id: string) => { + const prev = get(toastsAtom); + set( + toastsAtom, + prev.filter((toast) => toast.id !== id) + ); +}); diff --git a/apps/client/store/atoms/index.ts b/apps/client/store/atoms/index.ts new file mode 100644 index 00000000..226399d8 --- /dev/null +++ b/apps/client/store/atoms/index.ts @@ -0,0 +1 @@ +export * from "./toastAtoms"; diff --git a/apps/client/store/atoms/toastAtoms.ts b/apps/client/store/atoms/toastAtoms.ts new file mode 100644 index 00000000..cae676f7 --- /dev/null +++ b/apps/client/store/atoms/toastAtoms.ts @@ -0,0 +1,4 @@ +import type { ToastProps } from "@wow-class/ui"; +import { atom } from "jotai"; + +export const toastsAtom = atom([]); diff --git a/apps/client/store/index.ts b/apps/client/store/index.ts new file mode 100644 index 00000000..a9485524 --- /dev/null +++ b/apps/client/store/index.ts @@ -0,0 +1,2 @@ +export * from "./actions"; +export * from "./atoms"; From b56960ecb3bfd222abba9c908941843db32f2dfa Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 06:15:21 +0900 Subject: [PATCH 20/21] =?UTF-8?q?fix:=20=EB=88=84=EB=9D=BD=EB=90=9C=20type?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/announcement/CreateStudyAnnouncement.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx b/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx index cf7b1dd7..bbd10cdc 100644 --- a/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx +++ b/apps/admin/app/studies/[studyId]/_components/announcement/CreateStudyAnnouncement.tsx @@ -27,7 +27,7 @@ const CreateStudyAnnouncement = ({ studyId }: { studyId: string }) => { parseInt(studyId, 10), studyAnnouncement ); - toast({ text: "공지 생성 성공" }); + toast({ type: "success", text: "공지 생성 성공" }); revalidateTagByName(tags.announcements); setStudyAnnouncement({ title: "", @@ -35,7 +35,7 @@ const CreateStudyAnnouncement = ({ studyId }: { studyId: string }) => { }); } catch (error) { if (error instanceof Error) { - toast({ text: error.message }); + toast({ type: "error", text: error.message }); } } }; From ecca3816d267392787dbd2e6129c333b109abf8e Mon Sep 17 00:00:00 2001 From: hamo-o Date: Mon, 2 Sep 2024 06:22:48 +0900 Subject: [PATCH 21/21] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20impo?= =?UTF-8?q?rt=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/src/components/Toast/Toast.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/Toast/Toast.stories.tsx b/packages/ui/src/components/Toast/Toast.stories.tsx index d2c5b8e9..39a89590 100644 --- a/packages/ui/src/components/Toast/Toast.stories.tsx +++ b/packages/ui/src/components/Toast/Toast.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; -import Toast from "."; +import { Toast } from "."; const meta: Meta = { title: "Shared/Toast",