feat(site): implement dynamic client OS negotiation for Hero and CTA download buttons
This commit is contained in:
parent
4865387d7f
commit
55d03baf6b
5 changed files with 280 additions and 16 deletions
|
|
@ -3,9 +3,11 @@ import { Crosshair } from '../components/Crosshair'
|
|||
import { WaveBars } from '../components/WaveBars'
|
||||
import { GlowButton } from '../components/GlowButton'
|
||||
import { useI18n } from '../i18n'
|
||||
import { useClientOS } from '../hooks/useClientOS'
|
||||
|
||||
export function CTA() {
|
||||
const { t } = useI18n()
|
||||
const { t, locale } = useI18n()
|
||||
const clientOS = useClientOS()
|
||||
|
||||
return (
|
||||
<section className="relative py-28 md:py-36 overflow-hidden">
|
||||
|
|
@ -47,15 +49,23 @@ export function CTA() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<GlowButton
|
||||
href="#download"
|
||||
href={clientOS.downloadUrl}
|
||||
download={clientOS.downloadFilename || undefined}
|
||||
variant="primary"
|
||||
size="lg"
|
||||
className="shadow-glow-md hover:shadow-glow-lg"
|
||||
>
|
||||
{t.cta.downloadBtn}
|
||||
{locale === 'ko' ? clientOS.buttonLabelKo : clientOS.buttonLabelEn}
|
||||
</GlowButton>
|
||||
<div className="flex items-center gap-2 font-mono text-xs text-neutral-400">
|
||||
<span>{locale === 'ko' ? clientOS.subtextKo : clientOS.subtextEn}</span>
|
||||
<span>·</span>
|
||||
<a href="#download" className="underline hover:text-brand-amber transition-colors">
|
||||
{locale === 'ko' ? '다른 OS 다운로드' : 'Other Platforms'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="font-mono text-nano text-neutral-500 mt-8 uppercase tracking-widest">
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import { DataPoint } from '../components/DataPoint'
|
|||
import { Container } from '../components/Container'
|
||||
import { Led } from '../components/Led'
|
||||
import { useI18n } from '../i18n'
|
||||
import { useClientOS } from '../hooks/useClientOS'
|
||||
|
||||
export function Hero() {
|
||||
const { t, locale } = useI18n()
|
||||
const clientOS = useClientOS()
|
||||
|
||||
// Interactive Live Simulator State
|
||||
const [simState, setSimState] = useState<'idle' | 'recording' | 'processing' | 'done'>('idle')
|
||||
|
|
@ -125,15 +127,22 @@ export function Hero() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Action Buttons */}
|
||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-4 mb-3.5">
|
||||
{/* CTA Action Buttons with OS Negotiation */}
|
||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-4 mb-3">
|
||||
<a
|
||||
href="#download"
|
||||
href={clientOS.downloadUrl}
|
||||
download={clientOS.downloadFilename || undefined}
|
||||
className="glow-btn inline-flex items-center justify-center gap-2.5 px-8 py-4 font-mono text-sm font-semibold uppercase tracking-wider text-white bg-brand-amber rounded-panel shadow-glow-sm hover:shadow-glow-md"
|
||||
>
|
||||
<span className="relative z-10 flex items-center gap-2">
|
||||
<DownloadIcon />
|
||||
{t.hero.downloadBtn}
|
||||
<span className="relative z-10 flex items-center gap-2.5">
|
||||
{clientOS.os === 'android' ? (
|
||||
<AndroidIcon />
|
||||
) : clientOS.os === 'ios' || clientOS.os === 'macos' ? (
|
||||
<AppleIcon />
|
||||
) : (
|
||||
<WindowsIcon />
|
||||
)}
|
||||
{locale === 'ko' ? clientOS.buttonLabelKo : clientOS.buttonLabelEn}
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
|
|
@ -145,6 +154,20 @@ export function Hero() {
|
|||
</a>
|
||||
</div>
|
||||
|
||||
{/* Platform Subtext & Other OS Navigator */}
|
||||
<div className="flex flex-wrap items-center gap-y-2 gap-x-4 mb-3 font-mono text-xs">
|
||||
<span className="text-brand-amber font-medium flex items-center gap-1.5">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-brand-amber animate-pulse" />
|
||||
{locale === 'ko' ? clientOS.subtextKo : clientOS.subtextEn}
|
||||
</span>
|
||||
<a
|
||||
href="#download"
|
||||
className="text-neutral-400 hover:text-neutral-200 underline decoration-neutral-600 underline-offset-4 transition-colors"
|
||||
>
|
||||
{locale === 'ko' ? '다른 OS 다운로드 (Win / Mac / Android / iOS) →' : 'Other Platforms (Win / Mac / Android / iOS) →'}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Friction-Reduction Trust Microcopy */}
|
||||
<div className="flex items-center gap-2 font-mono text-nano text-neutral-500">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
|
||||
|
|
@ -274,12 +297,27 @@ export function Hero() {
|
|||
)
|
||||
}
|
||||
|
||||
function DownloadIcon() {
|
||||
|
||||
function AndroidIcon() {
|
||||
return (
|
||||
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" 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 className="w-4 h-4 text-emerald-400" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M17.523 15.3414c-.5511 0-.9993-.4486-.9993-.9997s.4482-.9993.9993-.9993c.551 0 .9993.4482.9993.9993.0001.5511-.4483.9997-.9993.9997m-11.046 0c-.5511 0-.9993-.4486-.9993-.9997s.4482-.9993.9993-.9993c.5511 0 .9993.4482.9993.9993 0 .5511-.4482.9997-.9993.9997m11.4045-6.02l1.996-3.4572a.416.416 0 0 0-.1521-.5676.416.416 0 0 0-.5676.1521l-2.0223 3.503C15.5902 8.411 13.856 8.125 12 8.125s-3.5902.286-5.1315.8267L4.8462 5.4487a.4161.4161 0 0 0-.5677-.1521.4157.4157 0 0 0-.1521.5676l1.996 3.4572C2.6889 11.1867.3432 14.6589 0 18.775h24c-.3432-4.1161-2.6889-7.5883-6.1185-9.4536" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function AppleIcon() {
|
||||
return (
|
||||
<svg className="w-4 h-4 text-neutral-200" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M15.97 6.37c.61-.75 1.04-1.8 1.01-2.87-.96.04-2.13.64-2.79 1.43-.58.68-.99 1.74-.94 2.82 1.08.08 2.11-.63 2.72-1.38z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function WindowsIcon() {
|
||||
return (
|
||||
<svg className="w-4 h-4 text-sky-400" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.551H10.949M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-13.051-1.851" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
|
@ -302,3 +340,4 @@ function MicIcon() {
|
|||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue