diff --git a/src/App.tsx b/src/App.tsx index d35d944..9a2e2eb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,7 @@ +import MainPage from '@pages/MainPage'; + function App() { - return
; + return ; } export default App; diff --git a/src/components/base/Button/index.tsx b/src/components/base/Button/index.tsx deleted file mode 100644 index f6bd284..0000000 --- a/src/components/base/Button/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Button } from '@mui/material'; - -interface Props { - children: string; -} - -export default function CustomButton({ children }: Props) { - return ; -} diff --git a/src/components/base/Card.tsx b/src/components/base/Card.tsx new file mode 100644 index 0000000..ba2c171 --- /dev/null +++ b/src/components/base/Card.tsx @@ -0,0 +1,88 @@ +import { + Card, + CardContent, + CardMedia, + Chip, + styled, + Typography, +} from '@mui/material'; +import Avatar from '@mui/material/Avatar'; + +interface Props { + author: { + name: string; + imgSrc: string; + url: string; + }; + thumbnail: string; + title: string; + description: string; + team: string; + date: string; +} + +const CardInfo = styled('div')` + display: flex; + gap: 16px; + align-items: center; + padding: 16px; + + div { + display: flex; + flex-wrap: wrap; + gap: 8px 16px; + + a { + display: lock; + font-size: 16px; + line-height: 1.43; + color: inherit; + text-decoration: none; + } + + span:last-child { + display: block; + width: 100%; + font-size: 14px; + } + } +`; + +const ClampTypography = styled(Typography)` + /* stylelint-disable-next-line value-no-vendor-prefix */ + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + white-space: normal; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; +`; + +export default function CustomCard({ + author, + thumbnail, + title, + description, + team, + date, +}: Props) { + return ( + + + +
+ {author.name} + + {date} +
+
+ + + + {title} + + {description} + +
+ ); +} diff --git a/src/components/base/Card/index.tsx b/src/components/base/Card/index.tsx deleted file mode 100644 index 52d2eef..0000000 --- a/src/components/base/Card/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { Card } from '@mui/material'; - -export default function CustomCard() { - return ; -} diff --git a/src/components/base/Chip.tsx b/src/components/base/Chip.tsx new file mode 100644 index 0000000..f97b886 --- /dev/null +++ b/src/components/base/Chip.tsx @@ -0,0 +1,18 @@ +import { Chip } from '@mui/material'; + +interface Props { + label: string; + onClick: () => void; + variant: 'filled' | 'outlined'; +} + +export default function CustomChip({ label, onClick, variant }: Props) { + return ( + + ); +} diff --git a/src/components/base/Chip/index.tsx b/src/components/base/Chip/index.tsx deleted file mode 100644 index b4007e7..0000000 --- a/src/components/base/Chip/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Chip } from '@mui/material'; - -interface Props { - label: string; - onClick: () => void; -} - -export default function CustomChip({ label, onClick }: Props) { - return ; -} diff --git a/src/components/base/Container.tsx b/src/components/base/Container.tsx new file mode 100644 index 0000000..2efb7f0 --- /dev/null +++ b/src/components/base/Container.tsx @@ -0,0 +1,15 @@ +import { Container } from '@mui/material'; +import { ReactNode } from 'react'; + +interface Props { + children: ReactNode; + sx?: { mb: string }; +} + +export default function CustomContainer({ children, sx }: Props) { + return {children}; +} + +CustomContainer.defaultProps = { + sx: {}, +}; diff --git a/src/components/base/LinkButton.tsx b/src/components/base/LinkButton.tsx new file mode 100644 index 0000000..d5ac029 --- /dev/null +++ b/src/components/base/LinkButton.tsx @@ -0,0 +1,19 @@ +import { Button } from '@mui/material'; + +interface Props { + children: string; +} + +export default function CustomButton({ children }: Props) { + return ( + + ); +} diff --git a/src/components/base/Logo/index.tsx b/src/components/base/Logo.tsx similarity index 51% rename from src/components/base/Logo/index.tsx rename to src/components/base/Logo.tsx index 5f0b088..b68b6b1 100644 --- a/src/components/base/Logo/index.tsx +++ b/src/components/base/Logo.tsx @@ -1,3 +1,3 @@ export default function Logo() { - return

Til-Store

; + return Til-Store; } diff --git a/src/components/base/Pagination.tsx b/src/components/base/Pagination.tsx new file mode 100644 index 0000000..b40fc93 --- /dev/null +++ b/src/components/base/Pagination.tsx @@ -0,0 +1,16 @@ +import { Pagination } from '@mui/material'; + +interface Props { + count: number; +} + +export default function CustomPagination({ count }: Props) { + return ( + + ); +} diff --git a/src/components/base/Pagination/index.tsx b/src/components/base/Pagination/index.tsx deleted file mode 100644 index 789573a..0000000 --- a/src/components/base/Pagination/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { Pagination } from '@mui/material'; - -export default function CustomPagination() { - return ; -} diff --git a/src/components/base/Select.tsx b/src/components/base/Select.tsx new file mode 100644 index 0000000..045d3da --- /dev/null +++ b/src/components/base/Select.tsx @@ -0,0 +1,42 @@ +import { + FormControl, + InputLabel, + MenuItem, + Select, + SelectChangeEvent, +} from '@mui/material'; +import { useState } from 'react'; + +interface Props { + options: number[]; + label: string; + onChange: (value: string) => void; +} + +export default function CustomSelect({ label, options, onChange }: Props) { + const [value, setValue] = useState(''); + + const handleChange = (e: SelectChangeEvent) => { + setValue(e.target.value); + onChange(e.target.value); + }; + + return ( + + {label} + + + ); +} diff --git a/src/components/base/Select/index.tsx b/src/components/base/Select/index.tsx deleted file mode 100644 index 762dbdf..0000000 --- a/src/components/base/Select/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { Select } from '@mui/material'; - -export default function CustomSelect() { - return + + ); +} diff --git a/src/components/layouts/Footer/Footer.style.ts b/src/components/layouts/Footer/Footer.style.ts new file mode 100644 index 0000000..11f9ed6 --- /dev/null +++ b/src/components/layouts/Footer/Footer.style.ts @@ -0,0 +1,22 @@ +import { styled } from '@mui/material'; + +const Footer = styled('footer')` + display: flex; + align-items: center; + justify-content: center; + width: 100%; + text-align: center; + background-color: #efefef; + + address { + font-size: 0.75rem; + font-style: normal; + } + + a { + color: inherit; + text-decoration: none; + } +`; + +export default Footer; diff --git a/src/components/layouts/Footer/index.tsx b/src/components/layouts/Footer/index.tsx new file mode 100644 index 0000000..82e18cb --- /dev/null +++ b/src/components/layouts/Footer/index.tsx @@ -0,0 +1,20 @@ +import { Container } from '@components/base'; +import StyledFooter from './Footer.style'; + +export default function Footer() { + return ( + + +
+ + https://github.com/TIL-store + +
+
+
+ ); +} diff --git a/src/components/layouts/Header/Header.style.ts b/src/components/layouts/Header/Header.style.ts new file mode 100644 index 0000000..9156eeb --- /dev/null +++ b/src/components/layouts/Header/Header.style.ts @@ -0,0 +1,17 @@ +import { styled } from '@mui/material'; + +export const BetweenWrapper = styled('div')` + display: flex; + align-items: center; + justify-content: space-between; +`; + +export const TitleLink = styled('a')` + display: block; + font-size: 1rem; + ${({ theme }) => ` + color: ${theme.palette.primary.main}; + `} + + text-decoration: none; +`; diff --git a/src/components/layouts/Header/index.tsx b/src/components/layouts/Header/index.tsx index a980254..5de1292 100644 --- a/src/components/layouts/Header/index.tsx +++ b/src/components/layouts/Header/index.tsx @@ -1,3 +1,19 @@ +import { LinkButton, Container, Logo } from '@components/base'; +import * as S from './Header.style'; + export default function Header() { - return
헤더
; + return ( +
+ + +

+ + + +

+ 관리자 페이지로 이동 +
+
+
+ ); } diff --git a/src/components/layouts/PageContainer/index.tsx b/src/components/layouts/PageContainer/index.tsx new file mode 100644 index 0000000..4f0d2eb --- /dev/null +++ b/src/components/layouts/PageContainer/index.tsx @@ -0,0 +1,26 @@ +import { styled } from '@mui/material'; + +const PageContainer = styled('div')` + position: relative; + min-height: 100vh; + + & main { + margin-bottom: 80px; + } + + & footer { + position: absolute; + bottom: 0; + left: 0; + } + + ${({ theme }) => ` + padding-bottom: ${theme.dimensions.footerHeight}px; + + footer { + height: ${theme.dimensions.footerHeight}px; + } + `} +`; + +export default PageContainer; diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 39563b0..ce0e65e 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,21 +1,23 @@ import { rest } from 'msw'; const handlers = [ - rest.get('/movies', (req, res, ctx) => { + rest.get('/teams', (req, res, ctx) => { return res( ctx.status(200), ctx.json({ data: [ - { - id: 1, - title: 'Spider Man', - rate: 4.5, - }, - { - id: 2, - title: 'Kings Man', - rate: 4.5, - }, + { id: 1, name: '동영' }, + { id: 2, name: '기동' }, + { id: 3, name: '달리' }, + { id: 4, name: '동근' }, + { id: 5, name: '나영' }, + { id: 6, name: '요한' }, + { id: 7, name: '찬희' }, + { id: 8, name: '화랑' }, + { id: 9, name: '지은' }, + { id: 10, name: '재호' }, + { id: 11, name: '루카스' }, + { id: 12, name: '오프' }, ], }) ); diff --git a/src/pages/MainPage/index.tsx b/src/pages/MainPage/index.tsx new file mode 100644 index 0000000..ea9d492 --- /dev/null +++ b/src/pages/MainPage/index.tsx @@ -0,0 +1,133 @@ +import Header from '@components/layouts/Header'; +import CardList from '@components/layouts/CardList'; +import Footer from '@components/layouts/Footer'; +import PageContainer from '@components/layouts/PageContainer'; +import FilterChips from '@components/layouts/FilterChips'; +import { useState } from 'react'; +import FilterSelect from '@components/layouts/FilterSelect'; + +const teams = [ + { id: 1, name: '동영' }, + { id: 2, name: '기동' }, + { id: 3, name: '달리' }, + { id: 4, name: '동근' }, + { id: 5, name: '나영' }, + { id: 6, name: '요한' }, + { id: 7, name: '찬희' }, + { id: 8, name: '화랑' }, + { id: 9, name: '지은' }, + { id: 10, name: '재호' }, + { id: 11, name: '루카스' }, + { id: 12, name: '오프' }, +]; + +const generations = [1, 2]; + +const tils = [ + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, + { + author: { + name: 'rekong', + imgSrc: '', + }, + team: '동영', + date: '2022-04-27', + thumbnail: 'image', + title: '글의 제목 입니다.', + description: + '간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다간단 요약입니다 간단 요약입니다 간단 요약입니다', + }, +]; + +export default function MainPage() { + const [selectedTeam, setSelectedTeam] = useState(teams[0].name); + + const handleClickTeam = (name: string) => { + setSelectedTeam(name); + // TODO : 팀별 TIL card 불러오기 + }; + + const handleChangeGeneration = (generation: string) => { + console.log('Change', generation); + // TODO : 기수별 TIL card 불러오기 + }; + + return ( + +
+ + +
+ +
+ +