Skip to content

Commit

Permalink
feat: search map ui interface
Browse files Browse the repository at this point in the history
  • Loading branch information
poiu694 committed Sep 29, 2024
1 parent 855656a commit 15b0bf8
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,4 @@
"pnpm": "use npm instead of pnpm",
"bun": "use npm instead of bun"
}
}
}
111 changes: 111 additions & 0 deletions src/app/map/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'use client'

import AccessibleIconButton from '@/components/common/accessible-icon-button'
import SearchInput from '@/components/common/search-input'
import Tab from '@/components/common/tab/tab'
import TabLabels from '@/components/common/tab/tab-labels'
import TabPanel from '@/components/common/tab/tab-panel'
import Typography from '@/components/common/typography'
import useSafeRouter from '@/hooks/use-safe-router'
import { useState } from 'react'
import SearchMapCard from './search-map-card'
import Link from 'next/link'
import SearchMenuList from './search-menu-list'
import SearchCityList from './search-location-list'

const MapSearch = () => {
const [activeTab, setActiveTab] = useState<'인기 많은순' | '가까운 순'>(
'인기 많은순',
)
const router = useSafeRouter()

return (
<>
<div className="min-h-dvh bg-neutral-700">
<header className="relative flex items-center pt-4">
<AccessibleIconButton
icon={{ type: 'caretLeft', size: 'xl' }}
label="이전 페이지"
className="p-[10px]"
onClick={() => router.safeBack()}
/>
<Typography
className="absolute left-1/2 translate-x-[-50%]"
as="h1"
size="body0"
>
지도 둘러보기
</Typography>
</header>

<div className="flex flex-col gap-6">
<div className="mt-2 flex items-end px-5">
<SearchInput
value=""
placeholder="메뉴나 지역으로 지도를 검색해 주세요"
onChange={() => {}}
/>
</div>

<SearchMenuList className="px-5" onClickMenu={() => {}} />
<SearchCityList className="px-5" onClickLocation={() => {}} />

<Tab
activeTab={activeTab}
setActiveTab={setActiveTab}
className="px-5"
>
<TabLabels labels={['인기 많은순', '가까운 순']} />
<TabPanel tabId="인기 많은순">
<ul className="flex flex-col gap-4">
<Link href={`/map/search/123`}>
<SearchMapCard
map={{
name: '비타민C',
numOfCrews: 123,
numOfPins: 200,
id: '123',
description: 'Mash-Up 최고먹짱들의 지도',
categories: ['돈까스', '강남'],
}}
/>
</Link>
<Link href={`/map/search/123`}>
<SearchMapCard
map={{
name: '비타민C',
numOfCrews: 123,
numOfPins: 200,
id: '123',
description: 'Mash-Up 최고먹짱들의 지도',
categories: ['돈까스', '강남'],
}}
/>
</Link>
</ul>
</TabPanel>

<TabPanel tabId="가까운 순">
<ul className="flex flex-col gap-4">
<Link href={`/map/search/123`}>
<SearchMapCard
map={{
name: '비타민C',
numOfCrews: 123,
numOfPins: 200,
id: '123',
description: 'Mash-Up 최고먹짱들의 지도',
categories: ['돈까스', '강남'],
}}
/>
</Link>
</ul>
</TabPanel>
</Tab>
</div>
</div>
</>
)
}

export default MapSearch
30 changes: 30 additions & 0 deletions src/app/map/search/search-icon-chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { IconKey } from '@/components/common/icon'
import Icon from '@/components/common/icon'
import Typography from '@/components/common/typography'
import cn from '@/utils/cn'

const SearchIconChip = ({
label,
iconType,
className,
}: {
label: string
iconType?: IconKey
className?: string
}) => {
return (
<span
className={cn(
'flex w-fit items-center justify-center gap-1 rounded-full bg-neutral-500 px-[10px] py-[5.5px]',
className,
)}
>
{iconType && <Icon type={iconType} size="md" />}
<Typography size="body3" className="text-[#dcdcdc]">
{label}
</Typography>
</span>
)
}

export default SearchIconChip
49 changes: 49 additions & 0 deletions src/app/map/search/search-location-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Typography from '@/components/common/typography'
import type { ClassName } from '@/models/common'
import cn from '@/utils/cn'
import SearchIconChip from './search-icon-chip'

interface SearchLocationListProps extends ClassName {
onClickLocation: (location: string) => void
}

const locations: string[] = [
'종로',
'강남',
'여의도',
'가산',
'성수',
'판교',
'마곡',
'구로 디지털단지',
'문정',
' 상암',
'세종',
]

const SearchLocationList = ({
className,
onClickLocation,
}: SearchLocationListProps) => {
return (
<div className={cn('flex flex-col gap-3', className)}>
<Typography size="body3" color="neutral-300">
지역
</Typography>

<ul className="flex flex-wrap gap-[10px]">
{locations.map((location) => (
<button
type="button"
key={location}
onClick={() => onClickLocation(location)}
>
<SearchIconChip label={location} className="px-[10px] py-2" />
</button>
))}
</ul>
</div>
)
}

export default SearchLocationList
64 changes: 64 additions & 0 deletions src/app/map/search/search-map-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Icon from '@/components/common/icon'
import Typography from '@/components/common/typography'
import type { ClassName } from '@/models/common'
import type { MapInfo } from '@/models/map'
import cn from '@/utils/cn'
import SearchIconChip from './search-icon-chip'

interface SearchMapCardProps extends ClassName {
map: Pick<MapInfo, 'id' | 'name' | 'description'> & {
numOfCrews: number
numOfPins: number
categories?: string[]
}
}

const SearchMapCard = ({ map, className }: SearchMapCardProps) => {
return (
<li
className={cn(
'flex w-full flex-col gap-2 rounded-[20px] bg-neutral-600 p-5',
className,
)}
>
<div className="flex items-center justify-between">
<Typography size="h3">{map.name}</Typography>
{map.categories && (
<div className="flex items-center justify-center gap-2">
{map.categories.map((category) => (
<SearchIconChip key={category} label={category} />
))}
</div>
)}
</div>

<div className="flex items-center gap-2">
<div className="flex items-center gap-[2px]">
<Icon type="person" size="md" />
<Typography size="body3" color="neutral-300">
Crew
</Typography>
<Typography size="body3" color="neutral-100">
{map.numOfCrews.toLocaleString()}
</Typography>
</div>

<div className="flex items-center gap-[2px]">
<Icon type="pin" size="md" />
<Typography size="body3" color="neutral-300">
Pins
</Typography>
<Typography size="body3" color="neutral-100">
{map.numOfPins.toLocaleString()}
</Typography>
</div>
</div>

<Typography size="body2" color="neutral-200">
{map.description}
</Typography>
</li>
)
}

export default SearchMapCard
95 changes: 95 additions & 0 deletions src/app/map/search/search-menu-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import type { IconKey } from '@/components/common/icon'
import Typography from '@/components/common/typography'
import type { ClassName } from '@/models/common'
import cn from '@/utils/cn'
import SearchIconChip from './search-icon-chip'

interface SearchMenuListProps extends ClassName {
onClickMenu: (menu: string) => void
}

const menus: {
icon: IconKey
label: string
}[] = [
{
icon: '찜',
label: '찜, 탕, 찌개',
},
{
icon: '일식',
label: '돈까스, 회, 일식',
},
{
icon: '피자',
label: '피자',
},
{
icon: '고기',
label: '고기, 구이',
},
{
icon: '호프',
label: '호프/ 요리주점',
},
{
icon: '양식',
label: '양식',
},
{
icon: '치킨',
label: '치킨',
},
{
icon: '중식',
label: '중식',
},
{
icon: '아시안',
label: '아시안',
},
{
icon: '백반',
label: '백반, 죽, 국수',
},
{
icon: '분식',
label: '분식',
},
{
icon: '카페',
label: '카페, 디저트',
},
{
icon: '패스트푸드',
label: '패스트푸드',
},
]

const SearchMenuList = ({ className, onClickMenu }: SearchMenuListProps) => {
return (
<div className={cn('flex flex-col gap-3', className)}>
<Typography size="body3" color="neutral-300">
메뉴
</Typography>

<ul className="flex flex-wrap gap-[10px]">
{menus.map((menu) => (
<button
type="button"
key={menu.label}
onClick={() => onClickMenu(menu.label)}
>
<SearchIconChip
iconType={menu.icon}
label={menu.label}
className="px-[10px] py-2"
/>
</button>
))}
</ul>
</div>
)
}

export default SearchMenuList
14 changes: 12 additions & 2 deletions src/app/my-map/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,26 @@ const MyMap = () => {
{myMapList?.map((map) => <MyMapCard key={map.id} mapId={map.id} />)}
</div>

<div className="pb-5">
<div className="flex items-center justify-center gap-[10px] px-[11.5px] pb-5">
<Link
href="/map/create"
className="mx-auto mt-5 flex w-fit items-center justify-center gap-2 rounded-full border border-neutral-500 px-[24px] py-[12px]"
className="mt-5 flex w-fit items-center justify-center gap-2 rounded-full border border-neutral-500 px-[24px] py-[12px]"
>
<Icon type="plus" size="md" />
<Typography size="body1" color="neutral-000">
새로운 지도
</Typography>
</Link>

<Link
href="/map/search"
className="mt-5 flex w-fit items-center justify-center gap-2 rounded-full border border-neutral-500 px-[24px] py-[12px]"
>
<Icon type="search" size="md" fill="neutral-000" />
<Typography size="body1" color="neutral-000">
지도 둘러보기
</Typography>
</Link>
</div>
</div>
</>
Expand Down

0 comments on commit 15b0bf8

Please sign in to comment.