- 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.
72 lines
3.1 KiB
TypeScript
72 lines
3.1 KiB
TypeScript
import { Container } from '../components/Container'
|
|
import { SectionHeading } from '../components/SectionHeading'
|
|
import { DownloadIcon, ExternalIcon } from '../components/icons'
|
|
import { fmt, useI18n } from '../i18n'
|
|
import {
|
|
DESKTOP_FEED_URL,
|
|
DESKTOP_RELEASE_DATE,
|
|
DESKTOP_RELEASE_HUB_URL,
|
|
DESKTOP_VERSION,
|
|
DESKTOP_WINDOWS_INSTALLER_URL,
|
|
} from '../release'
|
|
|
|
export function Download() {
|
|
const { t, bcp47 } = useI18n()
|
|
|
|
const date = new Intl.DateTimeFormat(bcp47, { dateStyle: 'long', timeZone: 'UTC' }).format(
|
|
new Date(`${DESKTOP_RELEASE_DATE}T00:00:00Z`),
|
|
)
|
|
const details = fmt(t.download.details, { date })
|
|
|
|
return (
|
|
<section id="download" aria-labelledby="download-title" className="section border-t border-white/10">
|
|
<Container>
|
|
<SectionHeading id="download-title" title={t.download.title} subtitle={t.download.subtitle} />
|
|
|
|
<div className="mt-14 grid grid-cols-1 gap-5 lg:grid-cols-12">
|
|
<div className="rounded-2xl border border-brand-blue/50 bg-surface-800 p-6 md:p-9 lg:col-span-8">
|
|
<div className="flex flex-wrap items-baseline justify-between gap-3">
|
|
<h3 className="text-h3 font-medium text-neutral-50">
|
|
{t.download.windowsName}{' '}
|
|
<span className="font-mono text-base font-normal text-neutral-300">v{DESKTOP_VERSION}</span>
|
|
</h3>
|
|
<p className="text-sm text-neutral-300">{t.download.windowsMeta}</p>
|
|
</div>
|
|
|
|
<a href={DESKTOP_WINDOWS_INSTALLER_URL} className="btn btn-primary btn-lg mt-7 w-full sm:w-auto">
|
|
<DownloadIcon />
|
|
{t.download.cta}
|
|
</a>
|
|
|
|
<p className="mt-5 keep-ko text-sm leading-relaxed text-neutral-400">{details}</p>
|
|
|
|
<p className="mt-3 flex flex-wrap gap-x-6 text-sm">
|
|
<a href={DESKTOP_RELEASE_HUB_URL} target="_blank" rel="noopener" className="link inline-flex min-h-[44px] items-center gap-1">
|
|
{t.download.releaseNotes}
|
|
<ExternalIcon />
|
|
<span className="sr-only">({t.a11y.opensInNewTab})</span>
|
|
</a>
|
|
<a href={`${DESKTOP_FEED_URL}/latest.yml`} target="_blank" rel="noopener" className="link inline-flex min-h-[44px] items-center gap-1">
|
|
{t.download.checksum}
|
|
<ExternalIcon />
|
|
<span className="sr-only">({t.a11y.opensInNewTab})</span>
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div className="rounded-2xl border border-white/10 p-6 md:p-7 lg:col-span-4">
|
|
<h3 className="text-sm font-medium text-neutral-300">{t.download.soonTitle}</h3>
|
|
<ul className="mt-4 divide-y divide-white/10">
|
|
{t.download.soon.map((item) => (
|
|
<li key={item.title} className="py-4 first:pt-0 last:pb-0">
|
|
<p className="text-base text-neutral-100">{item.title}</p>
|
|
<p className="mt-1 keep-ko text-sm leading-relaxed text-neutral-400">{item.body}</p>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</Container>
|
|
</section>
|
|
)
|
|
}
|