import {useState} from 'react'; import type {LocalPlace} from '@o2o/shared'; import {useSite} from '@site/lib/site-context'; import {naverMapSearchUrl} from '@site/lib/format'; import {PhotoCard} from '../kit/Card'; import {Sheet} from '../paper/Sheet'; const WALK = 80; const RANGES = [ {id: 'all', label: '전체', test: () => true}, {id: 'w5', label: '걸어서 5분 이내', test: (m: number) => m <= 5 * WALK}, {id: 'w10', label: '걸어서 10분 이내', test: (m: number) => m <= 10 * WALK}, {id: 'far', label: '걸어서 10분 이상', test: (m: number) => m > 10 * WALK}, ] as const; const FIRST_SPOTS = 6; const FIRST_EATS = 5; const HOME_ROWS = 3; function meters(place: LocalPlace): number { if (place.distanceMeters != null) return place.distanceMeters; const m = /^([\d.]+)\s*(km|m)$/i.exec((place.distanceText ?? '').trim()); return m ? Number(m[1]) * (m[2].toLowerCase() === 'km' ? 1000 : 1) : Infinity; } const byDistance = (a: LocalPlace, b: LocalPlace) => meters(a) - meters(b); const inRange = (id: string) => RANGES.find((r) => r.id === id)?.test ?? (() => true); function RangeTabs({places, value, onChange}: {places: LocalPlace[]; value: string; onChange: (id: string) => void}) { const tabs = RANGES.filter((r, i) => { const n = places.filter((p) => r.test(meters(p))).length; return i === 0 || (n > 0 && n < places.length); }); if (tabs.length < 2) return null; return (
{tabs.map((r) => ( ))}
); } export function Around() { const payload = useSite(); const {local} = payload; const spots = [...local.attractions].sort(byDistance); const eats = [...local.restaurants].sort(byDistance); const rail = [...spots, ...eats].filter((place) => place.imageUrl).sort(byDistance); const [open, setOpen] = useState(null); const [spotRange, setSpotRange] = useState('all'); const [eatRange, setEatRange] = useState('all'); const firstSpots = FIRST_SPOTS; if (rail.length === 0 && eats.length === 0) return null; const shownSpots = spots.filter((p) => inRange(spotRange)(meters(p))); const shownEats = eats.filter((p) => inRange(eatRange)(meters(p))); const place = (item: LocalPlace, withText = true) => ( ); const spot = (item: LocalPlace) => ( setOpen(item)} /> ); return ( <> {rail.length > 0 && (

AROUND

주변 안내

걸어서 닿는 명소와 맛집입니다.

{rail.slice(0, HOME_ROWS).map(spot)}
지역 소개에서 모두 보기
)}
{spots.length > 0 && (

AROUND

주변 명소 {spots.length}곳

걸어서 닿는 곳부터 차로 가는 곳까지 묶었습니다.

{shownSpots.slice(0, firstSpots).map(spot)}
{shownSpots.length > firstSpots && (
{shownSpots.length - firstSpots}곳 더 보기
{shownSpots.slice(firstSpots).map(spot)}
)}
)} {eats.length > 0 && (

EAT

주변 맛집 {eats.length}곳

{shownEats.slice(0, FIRST_EATS).map((item) => place(item, false))}
{shownEats.length > FIRST_EATS && (
{shownEats.length - FIRST_EATS}곳 더 보기
{shownEats.slice(FIRST_EATS).map((item) => place(item, false))}
)}
)}
setOpen(null)} label={open?.name ?? ''}> {open && ( <> {open.imageUrl && {open.name}}

{open.name}

{[open.distanceText, open.category].filter(Boolean).join(' · ')}

{open.description &&

{open.description}

} 네이버에서 보기 )}
); }