diff --git a/.storybook/preview.js b/.storybook/preview.jsx similarity index 52% rename from .storybook/preview.js rename to .storybook/preview.jsx index 1f1fcd68..14fb4db0 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.jsx @@ -1,3 +1,9 @@ +import React from 'react'; +import { Global } from '@emotion/react'; +import { globalStyle } from '../packages/ui/src/styles/GlobalStyles'; +import { ThemeProvider } from '@emotion/react'; +import { theme } from '../packages/ui/src/styles/theme'; + /** @type { import('@storybook/react').Preview } */ const preview = { parameters: { @@ -17,6 +23,14 @@ const preview = { ], }, }, + decorators: [ + (Story) => ( + + + + + ), + ], }; export default preview; diff --git a/apps/salon/src/pages/Home.tsx b/apps/salon/src/pages/Home.tsx index c64c8bb4..3b252445 100644 --- a/apps/salon/src/pages/Home.tsx +++ b/apps/salon/src/pages/Home.tsx @@ -1,16 +1,69 @@ -import { DuriNavbar, MobileLayout } from '@duri-fe/ui'; +import { DuriNavbar, Flex, Header, HeightFitFlex, MobileLayout, Pencil, Text, theme } from '@duri-fe/ui'; +import styled from '@emotion/styled'; const Home = () => { return ( - <> - -

Home

-

Home

-

Home

- -
- + + +
+ + + + 댕댕샵 + + + 경기도 성남시 + + + + + 댕댕샵 점주님 안녕하세용용용용용용용용 + + + + + + ); }; +const HomeHeaderContainer = styled(Flex)` + position: relative; + background-size: cover; + background-position: center; + + &::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 70%; + background: linear-gradient(180deg, rgba(217, 217, 217, 0.00) 0%, #111 100%); + } +`; + +const TextContainer = styled(Flex)` + height: fit-content; + width: fit-content; + z-index: 2; +`; + +const ShopNotice = styled(HeightFitFlex)` + width: calc(100% - 40px); + border-radius: 0 12px 12px 12px; + position: absolute; + bottom: -25px; + left: 20px; + overflow: hidden; +`; + +const ShopNoticeText = styled(Text)` + width: 100%; + justify-content: start; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +`; + export default Home; diff --git a/packages/ui/src/assets/Doori.tsx b/packages/ui/src/assets/Doori.tsx index 7879a326..2b56ab63 100644 --- a/packages/ui/src/assets/Doori.tsx +++ b/packages/ui/src/assets/Doori.tsx @@ -2,14 +2,13 @@ import * as React from 'react'; const SvgDoori = (props: React.SVGProps) => ( - ); diff --git a/packages/ui/src/assets/Magnifier.tsx b/packages/ui/src/assets/Magnifier.tsx index 640835c3..d2fed3a5 100644 --- a/packages/ui/src/assets/Magnifier.tsx +++ b/packages/ui/src/assets/Magnifier.tsx @@ -2,13 +2,13 @@ import * as React from 'react'; const SvgMagnifier = (props: React.SVGProps) => ( diff --git a/packages/ui/src/assets/Notification.tsx b/packages/ui/src/assets/Notification.tsx index 3d0fdbe6..4a3ae069 100644 --- a/packages/ui/src/assets/Notification.tsx +++ b/packages/ui/src/assets/Notification.tsx @@ -2,14 +2,16 @@ import * as React from 'react'; const SvgNotification = (props: React.SVGProps) => ( + + ); export default SvgNotification; diff --git a/packages/ui/src/assets/Pencil.tsx b/packages/ui/src/assets/Pencil.tsx new file mode 100644 index 00000000..e51954b4 --- /dev/null +++ b/packages/ui/src/assets/Pencil.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +const SvgPencil = (props: React.SVGProps) => ( + + + +); +export default SvgPencil; diff --git a/packages/ui/src/assets/index.tsx b/packages/ui/src/assets/index.tsx index 7204f9ed..30e78d1f 100644 --- a/packages/ui/src/assets/index.tsx +++ b/packages/ui/src/assets/index.tsx @@ -55,6 +55,7 @@ export { default as AiStyleBanner } from './AiStyleBanner'; export { default as AlertStar } from './AlertStar'; export { default as NaverLogo } from './NaverLogo'; export { default as SpeechBallon } from './SpeechBallon'; +export { default as Pencil } from './Pencil'; import Add from './Add'; import AddNew from './AddNew'; diff --git a/packages/ui/src/components/Card/Card.tsx b/packages/ui/src/components/Card/Card.tsx new file mode 100644 index 00000000..dc5eb770 --- /dev/null +++ b/packages/ui/src/components/Card/Card.tsx @@ -0,0 +1,31 @@ +import { Flex, theme } from "@duri-fe/ui" +import styled from "@emotion/styled" + +interface CardProps { + height: string, + borderRadius: number, + shadow?: 'small' | 'large', + children: React.ReactNode, +} + +export const Card = ({ + height, + borderRadius, + shadow = 'small', + children, +}: CardProps) => { + return ( + + {children} + + ) +} + +const CardContainer = styled(Flex)` + box-shadow: ${({ shadow }) => ( + shadow === 'small' + ? '0px 0px 4px 0px rgba(0, 0, 0, 0.10)' + : '0px 0px 10px 0px rgba(0, 0, 0, 0.10)' + )}; + background-color: ${theme.palette.White}; +`; \ No newline at end of file diff --git a/packages/ui/src/components/Card/index.tsx b/packages/ui/src/components/Card/index.tsx new file mode 100644 index 00000000..9aa55b4b --- /dev/null +++ b/packages/ui/src/components/Card/index.tsx @@ -0,0 +1 @@ +export { Card } from "./Card"; \ No newline at end of file diff --git a/packages/ui/src/components/Header/Header.tsx b/packages/ui/src/components/Header/Header.tsx new file mode 100644 index 00000000..d6985397 --- /dev/null +++ b/packages/ui/src/components/Header/Header.tsx @@ -0,0 +1,59 @@ +import { Doori, Flex, Magnifier, Notification, theme } from "@duri-fe/ui"; +import styled from "@emotion/styled"; + +import { HeightFitFlex } from "../FlexBox/Flex"; + +interface HeaderProps { + logoColor: string; + iconColor: string; + searchIcon?: boolean; + badge?: boolean; + + onClickLogo?: () => void; + onClickSearch?: () => void; + onClickNotification?: () => void; +} + +export const Header = ({ + logoColor, + iconColor, + searchIcon, + badge, + onClickLogo, + onClickSearch, + onClickNotification, +}: HeaderProps) => { + return ( + + + + + {searchIcon && onClickSearch && + + } + + + {badge && } + + + + ) +} + +const IconContainer = styled(Flex)` + width: fit-content; +` + +const NotificationContainer = styled.button` + position: relative; +` + +const NotificationBadge = styled(Flex)` + position: absolute; + top: 0px; + right: 0px; +`; \ No newline at end of file diff --git a/packages/ui/src/components/Header/index.tsx b/packages/ui/src/components/Header/index.tsx new file mode 100644 index 00000000..826fbb9c --- /dev/null +++ b/packages/ui/src/components/Header/index.tsx @@ -0,0 +1 @@ +export { Header } from './Header'; \ No newline at end of file diff --git a/packages/ui/src/components/index.tsx b/packages/ui/src/components/index.tsx index 2e7c3be2..eeb4e586 100644 --- a/packages/ui/src/components/index.tsx +++ b/packages/ui/src/components/index.tsx @@ -11,3 +11,5 @@ export * from './Image'; export * from './Hr'; export * from './Tag'; +export * from './Header'; +export * from './Card'; diff --git a/packages/ui/src/stories/components/Card.stories.tsx b/packages/ui/src/stories/components/Card.stories.tsx new file mode 100644 index 00000000..1fec8851 --- /dev/null +++ b/packages/ui/src/stories/components/Card.stories.tsx @@ -0,0 +1,50 @@ +import { Card, Flex } from '@duri-fe/ui'; +import type { Meta, StoryFn } from '@storybook/react'; + +/** + * `Card` 컴포넌트의 스토리북 정의입니다. + */ +const meta: Meta = { + title: 'components/Card', + component: Card, + tags: ['autodocs'], + argTypes: { + height: { control: 'number' }, + borderRadius: { control: 'number' }, + shadow: { control: 'select', options: ['small', 'large'] }, + }, +}; + +export default meta; + +const DuriDefaultTemplate: StoryFn = (args) => ( + + 내부 요소 + +) + +/** + * `DuriDefaultCard`는 고객 메인홈에 쓰이는 `Card` 스토리입니다. + */ +export const DuriDefaultCard = DuriDefaultTemplate; +DuriDefaultCard.args = { + height: 172, + borderRadius: 12, + shadow: 'small', +}; + + +const SalonDefaultTemplate: StoryFn = (args) => ( + + 내부 요소 + +) +/** + * `SalonDefaultCard`는 미용사 메인홈에 쓰이는 `Card` 스토리입니다. + */ +export const SalonDefaultCard = SalonDefaultTemplate; +SalonDefaultCard.args = { + height: 200, + borderRadius: 16, + shadow: 'large', +}; \ No newline at end of file diff --git a/packages/ui/src/stories/components/Header.stories.tsx b/packages/ui/src/stories/components/Header.stories.tsx new file mode 100644 index 00000000..f6656ed3 --- /dev/null +++ b/packages/ui/src/stories/components/Header.stories.tsx @@ -0,0 +1,50 @@ +import { Header, theme } from '@duri-fe/ui'; +import type { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +/** + * `Header` 컴포넌트의 스토리북 정의입니다. + */ +const meta: Meta = { + title: 'components/Header', + component: Header, + tags: ['autodocs'], + argTypes: { + logoColor: { control: 'color' }, + iconColor: { control: 'color' }, + searchIcon: { control: 'boolean' }, + badge: { control: 'boolean' }, + onClickLogo: { action: 'onClickLogo' }, + onClickSearch: { action: 'onClickSearch' }, + onClickNotification: { action: 'onClickNotification' }, + }, +}; + +export default meta; + +/** + * `DuriDefaultHeader`는 `Header` 컴포넌트의 고객 스토리입니다. + */ +export const DuriDefaultHeader: Story = { + args: { + logoColor: theme.palette.Black, + iconColor: theme.palette.Normal700, + searchIcon: true, + onClickLogo: () => console.log('홈화면 라우팅'), + onClickSearch: () => console.log('검색창 열기'), + onClickNotification: () => console.log('알림창 열기'), + } +}; + +/** + * `SalonDefaultHeader`는 `Header` 컴포넌트의 미용사 스토리입니다. + */ +export const SalonDefaultHeader: Story = { + args: { + logoColor: theme.palette.Black, + iconColor: theme.palette.White, + onClickLogo: () => console.log('홈화면 라우팅'), + onClickNotification: () => console.log('알림창 열기'), + } +}; \ No newline at end of file