[feat] solution/frontend: 히어로를 첫 화면 높이로 · 검색창 pill · 쇼케이스 카드 축소

콘텐츠가 세로로 퍼져서 첫 화면에 임팩트가 없었다.

- 히어로 min-h-[calc(100dvh-3.5rem)] + 세로 가운데. 헤더(h-14)를 빼야 스크롤바가 안 생기고,
  vh 가 아니라 dvh 인 이유는 모바일에서 주소창이 접혔다 펴져 vh 가 흔들리기 때문
- 검색창·버튼을 rounded-full h-13 로. 아이콘 여백도 같이 밀었다
- 마퀴 카드 w-52 → w-40, 간격·글자 축소. 히어로 안에 들어와야 한 화면에 다 담긴다
This commit is contained in:
Mina Choi 2026-09-03 10:58:02 +09:00
parent d8ed0766d6
commit 0c3f8dd3b0
2 changed files with 14 additions and 14 deletions

View File

@ -130,11 +130,11 @@ export function ShowcasePeeks({limit = 10}: {limit?: number}) {
return ( return (
<div <div
className="o2o-marquee relative mt-10 overflow-hidden [mask-image:linear-gradient(90deg,transparent,#000_8%,#000_92%,transparent)]" className="o2o-marquee relative mt-8 overflow-hidden [mask-image:linear-gradient(90deg,transparent,#000_8%,#000_92%,transparent)]"
aria-label="발행된 홈페이지" aria-label="발행된 홈페이지"
> >
<div <div
className="o2o-marquee-track flex w-max gap-4 py-1" className="o2o-marquee-track flex w-max gap-3 py-1"
style={{'--marquee-duration': duration} as CSSProperties} style={{'--marquee-duration': duration} as CSSProperties}
> >
{[...items, ...items].map((item, index) => ( {[...items, ...items].map((item, index) => (
@ -146,7 +146,7 @@ export function ShowcasePeeks({limit = 10}: {limit?: number}) {
// 두 벌째는 첫 벌의 복제다 — 스크린리더가 같은 목록을 두 번 읽지 않게 한다. // 두 벌째는 첫 벌의 복제다 — 스크린리더가 같은 목록을 두 번 읽지 않게 한다.
aria-hidden={index >= items.length} aria-hidden={index >= items.length}
tabIndex={index >= items.length ? -1 : undefined} tabIndex={index >= items.length ? -1 : undefined}
className="w-52 shrink-0 overflow-hidden rounded-xl border border-border bg-card text-left transition-transform hover:-translate-y-0.5" className="w-40 shrink-0 overflow-hidden rounded-lg border border-border bg-card text-left transition-transform hover:-translate-y-0.5"
> >
<div className="flex aspect-[16/10] items-center justify-center overflow-hidden bg-muted"> <div className="flex aspect-[16/10] items-center justify-center overflow-hidden bg-muted">
{item.thumbnailUrl ? ( {item.thumbnailUrl ? (
@ -160,9 +160,9 @@ export function ShowcasePeeks({limit = 10}: {limit?: number}) {
<ImageOff className="size-5 text-muted-foreground/40" aria-hidden /> <ImageOff className="size-5 text-muted-foreground/40" aria-hidden />
)} )}
</div> </div>
<div className="px-3 py-2.5"> <div className="px-2.5 py-2">
<p className="truncate text-xs font-semibold tracking-tight">{item.name}</p> <p className="truncate text-[11px] font-semibold tracking-tight">{item.name}</p>
<p className="truncate text-[11px] text-muted-foreground"> <p className="truncate text-[10px] text-muted-foreground">
{[item.region, CATEGORY_LABEL[item.category]].filter(Boolean).join(' · ')} {[item.region, CATEGORY_LABEL[item.category]].filter(Boolean).join(' · ')}
</p> </p>
</div> </div>

View File

@ -55,8 +55,8 @@ export function LandingPage() {
return ( return (
<MarketingShell> <MarketingShell>
{/* ── 상단 ─────────────────────────────────────── */} {/* ── 상단 ─────────────────────────────────────── */}
<section className="border-b border-border"> <section className="flex min-h-[calc(100dvh-3.5rem)] items-center border-b border-border">
<div className="mx-auto w-full max-w-6xl px-5 py-16 text-center sm:py-20"> <div className="mx-auto w-full max-w-6xl px-5 py-12 text-center">
<h1 className="mx-auto max-w-4xl text-4xl leading-[1.25] font-bold tracking-[-0.04em] sm:text-6xl"> <h1 className="mx-auto max-w-4xl text-4xl leading-[1.25] font-bold tracking-[-0.04em] sm:text-6xl">
{/* 앞말만 돈다. 마지막 항목은 첫 항목의 복제다 — 되감을 때 글자가 튀지 않게(index.css). */} {/* 앞말만 돈다. 마지막 항목은 첫 항목의 복제다 — 되감을 때 글자가 튀지 않게(index.css). */}
<span className="o2o-rotator"> <span className="o2o-rotator">
@ -70,14 +70,14 @@ export function LandingPage() {
</span> </span>
홈페이지 홈페이지
</h1> </h1>
<p className="mx-auto mt-4 max-w-xl text-sm text-muted-foreground sm:text-base"> <p className="mx-auto mt-3 max-w-xl text-sm text-muted-foreground sm:text-base">
가게 이름 한 줄로 시작해 보세요 가게 이름 한 줄로 시작해 보세요
</p> </p>
<form onSubmit={submit} className="mx-auto mt-8 flex max-w-lg gap-2"> <form onSubmit={submit} className="mx-auto mt-6 flex max-w-lg gap-2">
<div className="relative flex-1"> <div className="relative flex-1">
<Search <Search
className="pointer-events-none absolute top-1/2 left-4 size-4 -translate-y-1/2 text-muted-foreground" className="pointer-events-none absolute top-1/2 left-5 size-4 -translate-y-1/2 text-muted-foreground"
aria-hidden aria-hidden
/> />
<input <input
@ -85,16 +85,16 @@ export function LandingPage() {
onChange={(e) => setQuery(e.target.value)} onChange={(e) => setQuery(e.target.value)}
placeholder="가게 이름을 입력하세요" placeholder="가게 이름을 입력하세요"
aria-label="가게 이름" aria-label="가게 이름"
className="h-12 w-full rounded-lg border border-border bg-card pr-4 pl-11 text-sm shadow-sm transition-colors outline-none placeholder:text-muted-foreground focus:border-ring focus:ring-1 focus:ring-ring" className="h-13 w-full rounded-full border border-border bg-card pr-5 pl-12 text-sm shadow-sm transition-colors outline-none placeholder:text-muted-foreground focus:border-ring focus:ring-1 focus:ring-ring"
/> />
</div> </div>
<Button type="submit" variant="primary" size="lg" className="shrink-0"> <Button type="submit" variant="primary" size="lg" className="h-13 shrink-0 rounded-full px-7">
확인하기 확인하기
</Button> </Button>
</form> </form>
{/* 업종은 고르지 않아도 된다 — 여기 있는 건 "누구를 위한 서비스인가" 를 말하기 위한 것이다. */} {/* 업종은 고르지 않아도 된다 — 여기 있는 건 "누구를 위한 서비스인가" 를 말하기 위한 것이다. */}
<div className="mt-4 flex flex-wrap items-center justify-center gap-2"> <div className="mt-3 flex flex-wrap items-center justify-center gap-2">
{INDUSTRIES.map(({id, label, icon: Icon}) => ( {INDUSTRIES.map(({id, label, icon: Icon}) => (
<Link <Link
key={id} key={id}