diff --git a/.husky/pre-commit b/.husky/pre-commit index 61c8331..2312dc5 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1 @@ npx lint-staged -npx lint-staged diff --git a/README.md b/README.md index 786927a..459c645 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,4 @@ -# Team18_FE -18조 프론트엔드 +# 🍪 내가 먹은 쿠키 - 18조 FE -### 코드리뷰 질문 -**Week3** -- 현재 vite로 프로젝트 세팅을 마쳤는데, 더 추천해주실 라이브러리나 프레임워크 등 이 있을까요? -- 협업을 하면서 알면 좋은 사소한 팁이 있을까요? -- 현재 팀원들간 설정한 프로젝트 세팅은 아래 노션과 같습니다. 조언해주실 부분이 있나요? - https://kibong.notion.site/11100da872ea4854bf0f91908f029037?pvs=4 +## 🙋‍♂️ 4주차 코드리뷰 질문 +- `Modal` 컴포넌트를 구현하면서 텍스트 부분과 버튼 부분에 들어갈 내용은 개발할 때 코드를 작성하는 사람이 자유롭게 작성하여 구성할 수 있도록 `textChildren`과 `buttonChildren`만으로 구성하였는데, 더 적합하거나 지향하는 방식이 있을까요? \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 410442f..a5c7824 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@tanstack/react-query": "^5.56.2", + "csstype": "^3.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^4.5.5" @@ -2753,7 +2754,7 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true + "dev": true }, "node_modules/@types/qs": { "version": "6.9.16", @@ -2771,7 +2772,7 @@ "version": "18.3.5", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", - "devOptional": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" diff --git a/package.json b/package.json index bc6f6bf..b48b6c0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint --cache 'src/**/*.{ts,tsx}'", + "tsc": "tsc --noEmit", "format": "prettier --write --cache 'src/**/*.{ts,tsx}'", "lint-staged": "lint-staged", "preview": "vite preview", @@ -18,23 +19,22 @@ "lint-staged": { "**/*.{tsx,ts,jsx,js}": [ "eslint --fix --cache", - "prettier --write --cache" - ], - "*.js": "eslint --cache --fix", - "*.{ts,tsx}": "prettier --write" + "prettier --write --cache" + ] }, "dependencies": { "@emotion/babel-plugin": "^11.12.0", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", + "@emotion/css": "^11.13.0", "@tanstack/react-query": "^5.56.2", + "csstype": "^3.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^4.5.5" }, "devDependencies": { "@chromatic-com/storybook": "^2.0.2", - "@emotion/css": "^11.13.0", "@eslint/js": "^9.9.0", "@storybook/addon-essentials": "^8.3.0", "@storybook/addon-interactions": "^8.3.0", diff --git a/src/App.tsx b/src/App.tsx index 6ed5121..f85be72 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,5 @@ -import GlobalStyles from './assets/styles'; - function App() { - return ( - <> - -

hello world!

- - ); + return

helloWorld!

; } export default App; diff --git a/src/assets/images/hirehigher-logo.svg b/src/assets/images/hirehigher-logo.svg new file mode 100644 index 0000000..80c4bf4 --- /dev/null +++ b/src/assets/images/hirehigher-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/styles/emotion.d.ts b/src/assets/styles/emotion.d.ts new file mode 100644 index 0000000..0685ded --- /dev/null +++ b/src/assets/styles/emotion.d.ts @@ -0,0 +1,8 @@ +import '@emotion/react'; +import { PalettesTypes } from './global/palettes'; + +declare module '@emotion/react' { + export interface Theme { + palettes: PalettesTypes; + } +} diff --git a/src/assets/styles/global/palettes.ts b/src/assets/styles/global/palettes.ts new file mode 100644 index 0000000..f001c5e --- /dev/null +++ b/src/assets/styles/global/palettes.ts @@ -0,0 +1,6 @@ +export const palettes = { + white: '#fff', + borderGray: '#e4e5e8', +}; + +export type PalettesTypes = typeof palettes; diff --git a/src/assets/styles/images/features/layout/footer/facebook_Icon.svg b/src/assets/styles/images/features/layout/footer/facebook_Icon.svg new file mode 100644 index 0000000..cd3d1e2 --- /dev/null +++ b/src/assets/styles/images/features/layout/footer/facebook_Icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/styles/images/features/layout/footer/hire_higher_Icon.svg b/src/assets/styles/images/features/layout/footer/hire_higher_Icon.svg new file mode 100644 index 0000000..80c4bf4 --- /dev/null +++ b/src/assets/styles/images/features/layout/footer/hire_higher_Icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/styles/images/features/layout/footer/instagram_Icon.svg b/src/assets/styles/images/features/layout/footer/instagram_Icon.svg new file mode 100644 index 0000000..d2eb91c --- /dev/null +++ b/src/assets/styles/images/features/layout/footer/instagram_Icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/styles/images/features/layout/footer/twitter_Icon.svg b/src/assets/styles/images/features/layout/footer/twitter_Icon.svg new file mode 100644 index 0000000..0dc2e48 --- /dev/null +++ b/src/assets/styles/images/features/layout/footer/twitter_Icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/styles/images/features/layout/footer/youtube_Icon.svg b/src/assets/styles/images/features/layout/footer/youtube_Icon.svg new file mode 100644 index 0000000..5a2a447 --- /dev/null +++ b/src/assets/styles/images/features/layout/footer/youtube_Icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/styles/theme.ts b/src/assets/styles/theme.ts new file mode 100644 index 0000000..e02dbfa --- /dev/null +++ b/src/assets/styles/theme.ts @@ -0,0 +1,8 @@ +import { Theme } from '@emotion/react'; +import { palettes } from './global/palettes'; + +const theme: Theme = { + palettes, +}; + +export default theme; diff --git a/src/components/common/Button/index.stories.tsx b/src/components/common/Button/index.stories.tsx index 28e8305..e908acd 100644 --- a/src/components/common/Button/index.stories.tsx +++ b/src/components/common/Button/index.stories.tsx @@ -1,14 +1,20 @@ -import { Meta, StoryObj } from '@storybook/react'; -import Button from '.'; +import type { Meta, StoryObj } from '@storybook/react'; -const meta: Meta = { +import Button from './index'; + +const meta = { title: 'common/Button', - component: Button, tags: ['autodocs'], -}; + args: { + children: '버튼', + theme: 'default', + }, + render: (props) => , + }, + render: (props) => , +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/components/common/Modal/index.tsx b/src/components/common/Modal/index.tsx new file mode 100644 index 0000000..cdee1b1 --- /dev/null +++ b/src/components/common/Modal/index.tsx @@ -0,0 +1,53 @@ +import styled from '@emotion/styled'; +import { ReactNode } from 'react'; + +export type Props = { + textChildren: ReactNode; + buttonChildren: ReactNode; + borderRadius?: string; +} & React.HTMLAttributes; + +export const Modal = ({ textChildren, buttonChildren, borderRadius = '12px', ...props }: Props) => { + return ( + + + {textChildren} + {buttonChildren} + + + ); +}; + +const Card = styled.div<{ borderRadius: string }>` + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + backgroundcolor: #fff; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +`; + +const Wrapper = styled.div` + width: 100%; + padding: 20px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +`; + +const TextWrapper = styled.p` + width: 100%; + font-size: 16px; + font-weight: bold; + margin-bottom: 20px; +`; + +const ButtonWrapper = styled.div` + width: 100%; + margin: 0 auto; + display: flex; + justify-content: center; + align-items: center; +`; diff --git a/src/assets/styles/index.tsx b/src/components/providers/GlobalStylesProvider/GlobalStyles.tsx similarity index 100% rename from src/assets/styles/index.tsx rename to src/components/providers/GlobalStylesProvider/GlobalStyles.tsx diff --git a/src/components/providers/GlobalStylesProvider/index.provider.tsx b/src/components/providers/GlobalStylesProvider/index.provider.tsx new file mode 100644 index 0000000..9422bfe --- /dev/null +++ b/src/components/providers/GlobalStylesProvider/index.provider.tsx @@ -0,0 +1,19 @@ +import { ReactNode } from 'react'; +import { ThemeProvider } from '@emotion/react'; +import GlobalStyles from './GlobalStyles'; +import theme from '@assets/styles/theme'; + +interface Props { + children: ReactNode; +} + +const GlobalStylesProvider = ({ children }: Props) => { + return ( + + + {children} + + ); +}; + +export default GlobalStylesProvider; diff --git a/src/components/providers/index.tsx b/src/components/providers/index.tsx new file mode 100644 index 0000000..4b12809 --- /dev/null +++ b/src/components/providers/index.tsx @@ -0,0 +1,6 @@ +import { ReactNode } from 'react'; +import GlobalStylesProvider from './GlobalStylesProvider/index.provider'; + +export default function AppProviders({ children }: { children: ReactNode }) { + return {children}; +} diff --git a/src/features/layout/Header/index.stories.tsx b/src/features/layout/Header/index.stories.tsx new file mode 100644 index 0000000..82fd609 --- /dev/null +++ b/src/features/layout/Header/index.stories.tsx @@ -0,0 +1,16 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Header from '.'; + +const meta: Meta = { + title: 'features/layout/Header', + component: Header, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: () =>
, +}; diff --git a/src/features/layout/Header/index.tsx b/src/features/layout/Header/index.tsx new file mode 100644 index 0000000..63e2cf6 --- /dev/null +++ b/src/features/layout/Header/index.tsx @@ -0,0 +1,131 @@ +import styled from '@emotion/styled'; +import LogoImg from '@/assets/images/hirehigher-logo.svg'; + +const Header = () => { + return ( + + + + + ); +}; + +const HeaderContainer = styled.header` + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 20px; + background-color: #fff; + height: 88px; + + @media (max-width: 1200px) { + padding: 0 15px; + } + + @media (max-width: 768px) { + flex-direction: column; + height: auto; + padding: 10px; + } + + @media (max-width: 480px) { + flex-direction: column; + padding: 5px; + } +`; + +const Logo = styled.img` + height: 70px; + width: auto; + + @media (max-width: 768px) { + height: 60px; + } + + @media (max-width: 480px) { + height: 50px; + } +`; + +const Nav = styled.nav` + display: flex; + align-items: center; + gap: 15px; + + @media (max-width: 768px) { + width: 100%; + justify-content: center; + margin-top: 10px; + } + + @media (max-width: 480px) { + flex-direction: column; + width: 100%; + align-items: stretch; + } +`; + +const ButtonStyle = styled.button` + padding: 10px 20px; + width: 100%; + background-color: #fff; + color: #0a65cc; + border: 1px solid #cee0f5; + border-radius: 3px; + cursor: pointer; + text-align: center; + white-space: nowrap; + font-size: 16px; + + @media (max-width: 768px) { + font-size: 15px; + } + + @media (max-width: 480px) { + padding: 8px 10px; + font-size: 14px; + } +`; + +const PrimaryButton = styled(ButtonStyle)` + background-color: #0a65cc; + color: #fff; + border: none; +`; + +const OutlinedButton = styled(ButtonStyle)``; + +const TextButton = styled(ButtonStyle)` + background-color: none; + border: none; +`; + +const Dropdown = styled.select` + padding: 10px 20px; + width: 100%; + color: #0a65cc; + cursor: pointer; + text-align: center; + font-size: 16px; + border: none; + + @media (max-width: 768px) { + padding: 8px 10px; + font-size: 15px; + } + + @media (max-width: 480px) { + margin-top: 10px; + font-size: 14px; + } +`; + +export default Header; diff --git a/src/features/layout/footer/Footer.stories.tsx b/src/features/layout/footer/Footer.stories.tsx new file mode 100644 index 0000000..3c2126f --- /dev/null +++ b/src/features/layout/footer/Footer.stories.tsx @@ -0,0 +1,25 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Footer from '.'; +import GlobalStyles from '@/assets/styles/index'; + +const meta: Meta = { + title: 'features/layout/Footer', + decorators: [ + (Story) => ( + <> + + + + ), + ], + component: Footer, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: () =>