import {useSite} from '@site/lib/site-context'; import {primaryImage} from '@site/seo/meta'; import { bookingActionLabel, bookingLinks, contactLinks, channelLabel, heroFacts, lowestPrice, unitSpec, unitViews, } from '@site/lib/derive'; import {GRAIN} from './SectionHead'; /** * 편집(잡지)형 첫 화면 — 표지. * * ★ 사진은 오른쪽에 크게 걸고, 상호는 그 경계를 넘어 왼쪽 여백까지 흘러나온다. * 겹침은 12칸 격자 위에서 만든다 — 사진과 상호 띠를 **같은 행 같은 칸**에 놓고 * 띠만 아래로 붙였다(absolute 를 쓰지 않아 모바일에서 자동으로 위아래로 풀린다). * ★ 상호를 사진에 맨몸으로 얹지 않는다. 어느 사진의 어느 쪽이 밝은지 우리는 모른다 — * 어두운 띠를 한 겹 깔고 그 위에 얹으면 어떤 사진에서도 대비가 남는다(88% 기준 * 흰 사진 위 최악값이 약 3.9:1, 큰 글자 기준 3:1 을 넘긴다). * ★ 태그라인·요금·이용 정보는 사진 위가 아니라 **왼쪽 종이 면**에 둔다. 작은 글자는 * 3:1 로 부족하고(4.5:1 이 기준이다), 무엇보다 인용되는 문장을 사진에 태우면 안 된다. */ export function Hero() { const payload = useSite(); const {place, narrative} = payload; const image = primaryImage(payload); const spec = unitSpec(payload); const units = unitViews(payload); const facts = heroFacts(payload); const price = lowestPrice(payload); const booking = bookingLinks(payload)[0]; const contact = contactLinks(payload)[0]; const tagline = narrative.tagline ?? narrative.heroSubline; // 검색창에 치는 이름을 먼저 쓴다 — "제주시" 보다 "애월" 이다. const locality = place.addressSubLocality ?? place.addressLocality ?? place.addressRegion; // 메타 한 줄 — 지역 · 객실 수 · 최저가. 확인된 값만 · 로 잇는다. const meta = [ locality, units.length > 0 ? `${spec.label} ${units.length}개` : undefined, price, ].filter((part): part is string => Boolean(part)); return (
{image && (
{image.alt}
)} {/* 상호 띠 — 데스크톱에서는 격자 1~12칸 같은 행에 놓고 아래에 붙인다(self-end). 사진이 5~12칸이므로 왼쪽 4칸은 종이 위, 나머지는 사진 위를 지난다. ★ z-10: 격자에서 뒤에 오는 형제(왼쪽 칸)가 이 띠를 덮지 않게 한다. */}
{/* h1 은 페이지에 하나. 가게 이름이 들어가야 "○○ 홈페이지" 질의에 잡힌다. */}

{place.name}

{/* 왼쪽 종이 면 — 읽는 값이 전부 여기 있다. 아래는 상호 띠가 지나가는 자리다. */} {/* pb-56 은 상호 띠 높이(제목 5.5rem + 여백)에서 나온 값이다 — 줄이면 글자가 겹친다. */}
{tagline && (

{tagline}

)} {meta.length > 0 && (

{meta.join(' · ')}

)} {/* 버튼을 세우지 않는다 — 잡지의 규칙은 밑줄 링크다. 대신 .tap 으로 높이를 지킨다. */} {(booking || place.phone || contact) && (
{booking && ( {bookingActionLabel(booking)} )} {place.phone && ( {place.phone} )} {contact && ( {channelLabel(contact)} 문의 )}
)} {/* 확인된 값만. 없는 업종에서는 칸 자체가 안 생긴다. */} {facts.length > 0 && (
{facts.map((row) => (
{row.label}
{row.value}
))}
)}
); }