[feat] solution/frontend: 히어로 제목의 앞말이 돈다 — '홈페이지' 는 고정
"SEO · AEO 되는 웹사이트" 는 규격 이름이지 문구가 아니었다. 아임웹처럼 [형용사절] + [명사] 구조로 바꾸고, 명사를 고정한 채 앞말만 갈아 끼운다. - AI가 먼저 찾는 / 챗GPT가 인용하는 / 검색에 바로 걸리는 / 손님이 먼저 만나는 - CSS 만으로 돈다(마퀴와 같은 이유 — 타이머는 백그라운드 탭에서 밀린다) - 문구를 다섯 줄 쌓고 마지막을 첫 줄의 복제로 둔다. -80% 에서 0% 로 되감을 때 글자가 안 튄다 - 줄 높이를 1.25em 으로 못 박는다 — 창 1줄 · 트랙 5줄이라 한 칸이 정확히 20% 여야 한다 - 복제분은 aria-hidden. SEO·AEO 는 제목에서 빼 보조 문구로 내렸다 tsc·eslint·vite build 통과
This commit is contained in:
parent
4ef8e7d232
commit
d5e9b87e3f
@ -76,6 +76,34 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 히어로 제목의 앞말만 갈아 끼운다 — '홈페이지' 는 고정이고 수식어가 돈다.
|
||||||
|
★ CSS 만으로 돈다(마퀴와 같은 이유). 그리고 **문구를 다섯 줄 쌓는다** — 마지막 줄이
|
||||||
|
첫 줄의 복제라 -80% 에서 0% 로 되감을 때 글자가 튀지 않는다.
|
||||||
|
★ 줄 높이를 1.25em 으로 못 박는다. 창이 1줄이고 트랙이 5줄이라 한 칸이 정확히 20% 여야 한다. */
|
||||||
|
@keyframes o2o-rotate-5 {
|
||||||
|
0%, 18% { transform: translateY(0); }
|
||||||
|
20%, 38% { transform: translateY(-20%); }
|
||||||
|
40%, 58% { transform: translateY(-40%); }
|
||||||
|
60%, 78% { transform: translateY(-60%); }
|
||||||
|
80%, 100% { transform: translateY(-80%); }
|
||||||
|
}
|
||||||
|
.o2o-rotator {
|
||||||
|
display: block;
|
||||||
|
height: 1.25em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.o2o-rotator-track {
|
||||||
|
animation: o2o-rotate-5 11s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
||||||
|
}
|
||||||
|
.o2o-rotator-track > span {
|
||||||
|
display: block;
|
||||||
|
height: 1.25em;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.o2o-rotator-track { animation: none; }
|
||||||
|
}
|
||||||
|
|
||||||
/* 랜딩 히어로의 발행 사이트 마퀴. **CSS 만으로 돈다** — 타이머를 쓰면 탭이 백그라운드일 때
|
/* 랜딩 히어로의 발행 사이트 마퀴. **CSS 만으로 돈다** — 타이머를 쓰면 탭이 백그라운드일 때
|
||||||
프레임이 밀려 끊긴 것처럼 보인다. 트랙에 같은 목록을 두 벌 넣고 -50% 까지 밀면 이음매가 없다. */
|
프레임이 밀려 끊긴 것처럼 보인다. 트랙에 같은 목록을 두 벌 넣고 -50% 까지 밀면 이음매가 없다. */
|
||||||
@keyframes o2o-marquee {
|
@keyframes o2o-marquee {
|
||||||
|
|||||||
@ -6,6 +6,12 @@ import {MarketingShell, Section, SectionHead} from '@/components/layout/Marketin
|
|||||||
import {ShowcaseGrid, ShowcasePeeks} from '@/features/marketing/ShowcaseGrid';
|
import {ShowcaseGrid, ShowcasePeeks} from '@/features/marketing/ShowcaseGrid';
|
||||||
import {Button} from '@/components/ui/button';
|
import {Button} from '@/components/ui/button';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 히어로 제목의 앞말. '홈페이지' 는 고정이고 이 넷이 돌아간다.
|
||||||
|
* ★ 넷을 넘기지 않는다 — 다섯째부터는 한 바퀴 도는 데 걸리는 시간이 체류 시간을 넘긴다.
|
||||||
|
*/
|
||||||
|
const HEADLINES = ['AI가 먼저 찾는', '챗GPT가 인용하는', '검색에 바로 걸리는', '손님이 먼저 만나는'];
|
||||||
|
|
||||||
const INDUSTRIES: {id: IndustryType; label: string; icon: typeof Building2}[] = [
|
const INDUSTRIES: {id: IndustryType; label: string; icon: typeof Building2}[] = [
|
||||||
{id: 'stay', label: '숙박', icon: Building2},
|
{id: 'stay', label: '숙박', icon: Building2},
|
||||||
{id: 'cafe', label: '카페', icon: Coffee},
|
{id: 'cafe', label: '카페', icon: Coffee},
|
||||||
@ -43,13 +49,21 @@ export function LandingPage() {
|
|||||||
{/* ── 상단 ─────────────────────────────────────── */}
|
{/* ── 상단 ─────────────────────────────────────── */}
|
||||||
<section className="border-b border-border">
|
<section className="border-b border-border">
|
||||||
<div className="mx-auto w-full max-w-6xl px-5 py-20 text-center sm:py-28">
|
<div className="mx-auto w-full max-w-6xl px-5 py-20 text-center sm:py-28">
|
||||||
<h1 className="mx-auto max-w-3xl text-3xl leading-[1.25] font-bold tracking-tight text-balance sm:text-5xl">
|
<h1 className="mx-auto max-w-3xl text-3xl leading-[1.25] font-bold tracking-tight sm:text-5xl">
|
||||||
SEO · AEO 되는
|
{/* 앞말만 돈다. 마지막 항목은 첫 항목의 복제다 — 되감을 때 글자가 튀지 않게(index.css). */}
|
||||||
<br />
|
<span className="o2o-rotator">
|
||||||
웹사이트
|
<span className="o2o-rotator-track">
|
||||||
|
{[...HEADLINES, HEADLINES[0]].map((line, index) => (
|
||||||
|
<span key={index} aria-hidden={index > 0}>
|
||||||
|
{line}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
홈페이지
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto mt-5 max-w-xl text-sm leading-relaxed text-muted-foreground sm:text-base">
|
<p className="mx-auto mt-5 max-w-xl text-sm leading-relaxed text-muted-foreground sm:text-base">
|
||||||
가게 이름 한 줄이면 만들어 드립니다
|
가게 이름 한 줄로 시작해 보세요
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form onSubmit={submit} className="mx-auto mt-9 flex max-w-lg gap-2">
|
<form onSubmit={submit} className="mx-auto mt-9 flex max-w-lg gap-2">
|
||||||
@ -87,9 +101,9 @@ export function LandingPage() {
|
|||||||
|
|
||||||
<ul className="mt-8 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-xs text-muted-foreground">
|
<ul className="mt-8 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-xs text-muted-foreground">
|
||||||
{[
|
{[
|
||||||
|
'SEO · AEO 자동 적용',
|
||||||
'가입 없이 만들어 봅니다',
|
'가입 없이 만들어 봅니다',
|
||||||
'검색엔진에 바로 알립니다',
|
'5분이면 끝납니다',
|
||||||
'AI가 읽는 형태로 나갑니다',
|
|
||||||
].map((line) => (
|
].map((line) => (
|
||||||
<li key={line} className="flex items-center gap-1.5">
|
<li key={line} className="flex items-center gap-1.5">
|
||||||
<Check className="size-3.5 text-success" aria-hidden />
|
<Check className="size-3.5 text-success" aria-hidden />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user