feat(site): rewrite the landing page around verified facts and accessible controls

- Replace claims that contradicted the app: the default hotkey is Right Alt
  (hold to talk), local features are free with no daily cap, there is no
  14-day trial, Team/SSO/SCIM/ZDR are not offered, and the repository is not
  public. Remove invented metrics, status badges, the competitor table, the
  ad-mediation changelog, the hash calculator and the duplicate demo.
- Seven sections: hero with one labelled example, features, how it works,
  privacy, pricing (Free / Pro 2,900 / Pro+ 8,900 KRW a month), download, FAQ.
  Footer links the privacy policy, terms and account deletion pages.
- All copy moves into i18n and every one of the 10 locales is translated.
  Pricing and cloud quotas come from site/src/pricing.ts.
- Accessibility: skip link, labelled sections, aria-expanded with Esc and
  focus return for the menu, language list and FAQ, live status for the
  example, reduced-motion support, 44px targets, AA contrast on the primary
  button. Korean keep-all line breaking is scoped to :lang(ko) because
  Tailwind's break-keep blocked wrapping in Japanese and Chinese.
- JS 111 -> 98 KB gzip, CSS 7.8 -> 5.2 KB gzip.
This commit is contained in:
Yun Chan 2026-09-26 15:04:43 +09:00
parent ad6bb70c20
commit e689683b72
44 changed files with 2198 additions and 3782 deletions

View file

@ -0,0 +1,49 @@
// 사이트 공용 아이콘. 모두 장식이므로 aria-hidden 이고, 의미는 옆 텍스트가 전달한다.
interface IconProps {
className?: string
}
export function DownloadIcon({ className = 'h-4 w-4' }: IconProps) {
return (
<svg aria-hidden="true" className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</svg>
)
}
export function ExternalIcon({ className = 'h-3.5 w-3.5' }: IconProps) {
return (
<svg aria-hidden="true" className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M7 17 17 7" />
<path d="M8 7h9v9" />
</svg>
)
}
export function CheckIcon({ className = 'h-4 w-4' }: IconProps) {
return (
<svg aria-hidden="true" className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
)
}
export function PlusIcon({ className = 'h-4 w-4' }: IconProps) {
return (
<svg aria-hidden="true" className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
)
}
export function PlayIcon({ className = 'h-3.5 w-3.5' }: IconProps) {
return (
<svg aria-hidden="true" className={className} viewBox="0 0 24 24" fill="currentColor">
<path d="M7 4.5v15l13-7.5z" />
</svg>
)
}