Skip to content

Commit 4bd52ac

Browse files
authored
[#204] ✨ 포트폴리오 페이지 개발 (#205)
* [#201] ♻️ margin layout to flex flex layout * [#201] ✨ add community page * [#204] 💄 select trigger to flex row * [#204] 💄 add white space in param of join * [#204] ✨ add portfolio page
1 parent f6ce1d7 commit 4bd52ac

File tree

3 files changed

+208
-4
lines changed

3 files changed

+208
-4
lines changed

src/app/(pages)/portfolio/page.tsx

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
5+
import { IcPencil, IcSearch } from '@/assets/IconList'
6+
import { cn } from '@/lib/utils'
7+
import { PortfolioListItem } from '@/types/api/Portfolio.types'
8+
import clsx from 'clsx'
9+
10+
import { Button, Link } from '@/components/common/button'
11+
import { Box, Container, Grid } from '@/components/common/containers'
12+
import { TextInput } from '@/components/common/input'
13+
import { Text } from '@/components/common/text'
14+
import { PortfolioCard } from '@/components/portfolio/PortfolioCard'
15+
import { Pagination } from '@/components/shared/pagination'
16+
import { Select } from '@/components/shared/select'
17+
18+
import { usePagination } from '@/hooks/usePagination'
19+
import { useToggle } from '@/hooks/useToggle'
20+
21+
const MOCK_DATA: PortfolioListItem[] = [
22+
{
23+
id: 1,
24+
portTitle: 'Frontend Developer 모집1',
25+
portPosition: '프론트엔드',
26+
portImageUrl: 'https://picsum.photos/250/250',
27+
tags: ['React', 'TypeScript', 'Tailwind'],
28+
writer: {
29+
id: 1,
30+
nickname: 'John Doe',
31+
imageUrl: 'https://picsum.photos/250/250',
32+
},
33+
answers: 5,
34+
likes: 10,
35+
createdAt: '2023-12-01T12:00:00Z',
36+
views: 10,
37+
},
38+
]
39+
40+
const stackOptions = [
41+
{ label: '자바스크립트', value: 'Javascript' },
42+
{ label: 'Css', value: 'Css' },
43+
{ label: 'HTML', value: 'HTML' },
44+
{ label: '타입스크립트', value: 'Typescript' },
45+
]
46+
const positionOptions = [
47+
{ label: '프론트엔드', value: 'frontend' },
48+
{ label: '백엔드', value: 'backend' },
49+
{ label: '풀스택', value: 'fullstack' },
50+
]
51+
52+
export default function PortfolioPage(): JSX.Element {
53+
const [position, setPosition] = useState<string[]>([])
54+
const [order, setOrder] = useState<'recent' | 'like' | 'view'>('recent')
55+
const {
56+
currentPage,
57+
pageButtons,
58+
hasNextPageGroup,
59+
hasPreviousPageGroup,
60+
goToPage,
61+
goToNextPageGroup,
62+
goToPreviousPageGroup,
63+
} = usePagination({ totalItems: 20, itemsPerPage: 10, buttonsPerPage: 10 })
64+
65+
const handlePositionChange = (values: string[]) => {
66+
setPosition(() => values)
67+
}
68+
69+
return (
70+
<Container className='mx-auto my-80 flex gap-30'>
71+
<div className='flex w-216 flex-col gap-20'>
72+
<Box className='h-194 items-start justify-start p-16 text-center'>
73+
<div className='mb-10'>
74+
<Text.Title variant='title2' color='gray700' weight='700'>
75+
다른 사람들의
76+
<br />
77+
포트폴리오를 구경해보세요
78+
</Text.Title>
79+
</div>
80+
<div className='mb-20'>
81+
<Text.Body variant='body3' color='gray600'>
82+
본인의 포트폴리오를 등록하고
83+
<br />
84+
조회가 가능합니다.
85+
</Text.Body>
86+
</div>
87+
<Link href='mypage' fullWidth size='sm'>
88+
포트폴리오 등록 및 관리
89+
</Link>
90+
</Box>
91+
<Box
92+
variant='contained'
93+
color='secondary'
94+
className='h-380 gap-12'
95+
padding={20}
96+
>
97+
<Text.Title
98+
variant='title1'
99+
weight='700'
100+
className='text-common-black'
101+
>
102+
AD
103+
</Text.Title>
104+
</Box>
105+
</div>
106+
<main className='flex-grow'>
107+
<div className='mb-20 flex justify-between gap-12'>
108+
<TextInput
109+
className='h-48'
110+
placeholder='제목, 내용, 작성자를 검색해보세요!'
111+
startAdornment={<IcSearch width={24} height={24} />}
112+
/>
113+
<div className='flex-shrink-0'>
114+
<Button size='lg' className='font-semibold'>
115+
검색
116+
</Button>
117+
</div>
118+
</div>
119+
<div className='mb-20 flex justify-between gap-12'>
120+
<Text.Heading as='h2' variant='heading2'>
121+
포트폴리오
122+
</Text.Heading>
123+
<div>
124+
<Link href={'/team/add'} size='lg' className='w-118 font-semibold'>
125+
<IcPencil width={24} height={24} />
126+
작성하기
127+
</Link>
128+
</div>
129+
</div>
130+
<div className='mb-20 flex items-center justify-between'>
131+
<div className='flex gap-12'>
132+
<Select
133+
options={positionOptions}
134+
isMulti={true}
135+
isSearchable={false}
136+
onChange={handlePositionChange}
137+
>
138+
<Select.Trigger placeholder='포지션' />
139+
<Select.Menu className='w-216' />
140+
</Select>
141+
</div>
142+
<div className='flex gap-20'>
143+
<div className='flex gap-40'>
144+
<Button
145+
onClick={() => {
146+
setOrder('recent')
147+
}}
148+
variant='text'
149+
className={clsx('h-auto p-0 text-gray-500', {
150+
'text-gray-800': order === 'recent',
151+
})}
152+
>
153+
최신순
154+
</Button>
155+
<Button
156+
onClick={() => {
157+
setOrder('like')
158+
}}
159+
variant='text'
160+
className={clsx('h-auto p-0 text-gray-500', {
161+
'text-gray-800': order === 'like',
162+
})}
163+
>
164+
좋아요순
165+
</Button>
166+
<Button
167+
onClick={() => {
168+
setOrder('view')
169+
}}
170+
variant='text'
171+
className={cn('h-auto p-0 text-gray-500', {
172+
'text-gray-800': order === 'view',
173+
})}
174+
>
175+
조회순
176+
</Button>
177+
</div>
178+
</div>
179+
</div>
180+
<div className='mb-40 flex h-718 flex-col gap-12 overflow-hidden'>
181+
{MOCK_DATA.map(portfolioItem => (
182+
<PortfolioCard
183+
key={portfolioItem.id}
184+
portfolioItem={portfolioItem}
185+
/>
186+
))}
187+
</div>
188+
<Pagination
189+
currentPage={currentPage}
190+
pageButtons={pageButtons}
191+
hasNextPageGroup={hasNextPageGroup}
192+
hasPreviousPageGroup={hasPreviousPageGroup}
193+
goToPage={goToPage}
194+
goToNextPageGroup={goToNextPageGroup}
195+
goToPreviousPageGroup={goToPreviousPageGroup}
196+
/>
197+
</main>
198+
</Container>
199+
)
200+
}

src/components/shared/select/Select.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ const Trigger = ({
118118
'pointer-events-none cursor-not-allowed': disabled,
119119
})
120120
const triggerBoxClass = cn(
121-
'h-48 w-210 justify-between p-12 text-body1 font-medium text-gray-500 focus:border-primary-normal',
121+
'h-48 w-210 flex-row justify-between p-12 text-body1 font-medium text-gray-500 focus:border-primary-normal',
122122
{ 'text-gray-800': selectedValues.size },
123123
{ 'bg-gray-200 text-gray-400': disabled },
124124
className
@@ -128,7 +128,11 @@ const Trigger = ({
128128
<Dropdown.Trigger className={triggerStyle}>
129129
<Box className={triggerBoxClass} rounded={8}>
130130
{selectedLabel || placeholder}
131-
{isOpen ? <IcCaretUp /> : <IcCaretDown />}
131+
{isOpen ? (
132+
<IcCaretUp width={24} height={24} />
133+
) : (
134+
<IcCaretDown width={24} height={24} />
135+
)}
132136
</Box>
133137
</Dropdown.Trigger>
134138
)
@@ -145,7 +149,7 @@ const Menu = ({
145149

146150
return (
147151
<Dropdown.Menu className={className}>
148-
{children}{' '}
152+
{children}
149153
{options.map(option => (
150154
<Option key={option.value} value={option.value} label={option.label} />
151155
))}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export const joinWithHash = (items: string[]): string => {
2-
return items.map(item => `#${item}`).join('')
2+
return items.map(item => `#${item}`).join(' ')
33
}

0 commit comments

Comments
 (0)