From a24ddffe560aab50326d51a782fe8e3d42bf2f07 Mon Sep 17 00:00:00 2001 From: Kang Date: Wed, 6 May 2026 10:50:11 +0800 Subject: [PATCH] feat: Enhance download platform management with architecture support and dynamic fetching This commit introduces a more robust download platform management system by defining specific types for download platforms and their keys, including support for ARM architectures. It updates the download button component to dynamically fetch the latest download manifest, allowing for real-time updates to available download links. Additionally, the platform detection logic is improved to better handle different operating systems and architectures, enhancing the user experience when selecting download options. --- docs-site/src/pages/index.tsx | 105 ++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 10 deletions(-) diff --git a/docs-site/src/pages/index.tsx b/docs-site/src/pages/index.tsx index 887ae220..1e649bba 100644 --- a/docs-site/src/pages/index.tsx +++ b/docs-site/src/pages/index.tsx @@ -24,20 +24,42 @@ type SummaryCard = { description: string; }; +type DownloadPlatformKey = + | 'windows-x86_64' + | 'windows-aarch64' + | 'linux-x86_64' + | 'linux-aarch64' + | 'darwin-x86_64' + | 'darwin-aarch64'; + type DownloadPlatform = { - key: string; + key: DownloadPlatformKey; href: string; }; +type LatestDownloadManifest = { + platforms?: Partial>; +}; + +const latestDownloadManifestUrl = 'https://downloads.nyaterm.app/latest.json'; + const downloadPlatforms: DownloadPlatform[] = [ { key: 'windows-x86_64', href: 'https://nyaterm.app/download/windows-x86_64', }, + { + key: 'windows-aarch64', + href: 'https://nyaterm.app/download/windows-aarch64', + }, { key: 'linux-x86_64', href: 'https://nyaterm.app/download/linux-x86_64', }, + { + key: 'linux-aarch64', + href: 'https://nyaterm.app/download/linux-aarch64', + }, { key: 'darwin-x86_64', href: 'https://nyaterm.app/download/darwin-x86_64', @@ -70,12 +92,51 @@ function detectDownloadPlatform(): DownloadPlatform { return downloadPlatforms[0]; } -function getDownloadPlatformLabel(key: DownloadPlatform['key']) { +function getDownloadPlatformByKey(key: DownloadPlatformKey, platforms: DownloadPlatform[] = downloadPlatforms) { + return platforms.find((item) => item.key === key) ?? platforms[0]; +} + +function isArmArchitecture(architecture: string) { + return architecture.includes('arm') || architecture.includes('aarch64'); +} + +function getPlatformKeyFromHints(os: string, architecture: string): DownloadPlatformKey { + const normalizedOs = os.toLowerCase(); + const normalizedArchitecture = architecture.toLowerCase(); + const isArm = isArmArchitecture(normalizedArchitecture); + + if (normalizedOs.includes('mac')) { + return isArm ? 'darwin-aarch64' : 'darwin-x86_64'; + } + + if (normalizedOs.includes('linux')) { + return isArm ? 'linux-aarch64' : 'linux-x86_64'; + } + + if (normalizedOs.includes('win')) { + return isArm ? 'windows-aarch64' : 'windows-x86_64'; + } + + return 'windows-x86_64'; +} + +function getDownloadPlatformsFromManifest(manifest: LatestDownloadManifest): DownloadPlatform[] { + return downloadPlatforms.map((platform) => { + const href = manifest.platforms?.[platform.key]?.url; + return href ? {...platform, href} : platform; + }); +} + +function getDownloadPlatformLabel(key: DownloadPlatformKey) { switch (key) { case 'windows-x86_64': return translate({message: 'Windows x86_64'}); + case 'windows-aarch64': + return translate({message: 'Windows ARM64'}); case 'linux-x86_64': return translate({message: 'Linux x86_64'}); + case 'linux-aarch64': + return translate({message: 'Linux ARM64'}); case 'darwin-x86_64': return translate({message: 'macOS Intel'}); case 'darwin-aarch64': @@ -86,11 +147,13 @@ function getDownloadPlatformLabel(key: DownloadPlatform['key']) { } function DownloadButton() { - const [platform, setPlatform] = useState(downloadPlatforms[0]); + const [platforms, setPlatforms] = useState(downloadPlatforms); + const [platformKey, setPlatformKey] = useState(downloadPlatforms[0].key); + const platform = getDownloadPlatformByKey(platformKey, platforms); useEffect(() => { const detectedPlatform = detectDownloadPlatform(); - setPlatform(detectedPlatform); + setPlatformKey(detectedPlatform.key); const userAgentData = ( navigator as Navigator & { @@ -108,11 +171,8 @@ function DownloadButton() { const detectedOs = values.platform?.toLowerCase() ?? userAgentData.platform?.toLowerCase() ?? ''; const architecture = values.architecture?.toLowerCase() ?? ''; - if (detectedOs.includes('mac') && ['arm', 'arm64', 'aarch64'].includes(architecture)) { - const appleSilicon = downloadPlatforms.find((item) => item.key === 'darwin-aarch64'); - if (appleSilicon) { - setPlatform(appleSilicon); - } + if (detectedOs) { + setPlatformKey(getPlatformKeyFromHints(detectedOs, architecture)); } }) .catch(() => { @@ -120,6 +180,31 @@ function DownloadButton() { }); }, []); + useEffect(() => { + const controller = new AbortController(); + + fetch(latestDownloadManifestUrl, {signal: controller.signal}) + .then((response) => { + if (!response.ok) { + throw new Error(`Failed to fetch latest download manifest: ${response.status}`); + } + + return response.json() as Promise; + }) + .then((manifest) => { + setPlatforms(getDownloadPlatformsFromManifest(manifest)); + }) + .catch((error: unknown) => { + if (error instanceof DOMException && error.name === 'AbortError') { + return; + } + + console.warn('Failed to load latest download manifest.', error); + }); + + return () => controller.abort(); + }, []); + return (