Skip to content

Commit 339c450

Browse files
feat: show arch in landing page (#697)
1 parent e8d526a commit 339c450

1 file changed

Lines changed: 89 additions & 15 deletions

File tree

apps/landing-page/src/app/(home)/page.client.tsx

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ export default function HomeClient({ release }: { release: Release }) {
124124
const [downloadOS, setDownloadOS] = useState<
125125
'auto' | 'windows' | 'macos' | 'linux'
126126
>('auto');
127+
const [downloadArch, setDownloadArch] = useState<
128+
'auto' | 'x86_64' | 'arm64' | 'armv7' | 'i386'
129+
>('auto');
127130

128131
function detectOS(): 'windows' | 'macos' | 'linux' | 'unknown' {
129132
if (typeof navigator === 'undefined') return 'unknown';
@@ -147,6 +150,25 @@ export default function HomeClient({ release }: { release: Release }) {
147150
return 'unknown';
148151
}
149152

153+
function detectArch():
154+
| 'x86_64'
155+
| 'arm64'
156+
| 'armv7'
157+
| 'i386'
158+
| 'unknown' {
159+
if (typeof navigator === 'undefined') return 'unknown';
160+
const ua =
161+
(navigator.userAgent || navigator.platform || '').toLowerCase();
162+
163+
if (ua.includes('aarch64') || ua.includes('arm64')) return 'arm64';
164+
if (ua.includes('armv7') || ua.includes('armv7l') || ua.includes('armhf'))
165+
return 'armv7';
166+
if (ua.includes('amd64') || ua.includes('x86_64') || ua.includes('wow64') || ua.includes('win64') || ua.includes('x64'))
167+
return 'x86_64';
168+
if (ua.includes('i386') || ua.includes('i686') || ua.includes('ia32')) return 'i386';
169+
return 'unknown';
170+
}
171+
150172
function findAssetForOS(rel: any, os: string) {
151173
if (!rel || !rel.assets) return null;
152174
const assets = rel.assets as {
@@ -162,20 +184,56 @@ export default function HomeClient({ release }: { release: Release }) {
162184
return null;
163185
};
164186

165-
if (os === 'windows') return tryKeywords(['windows', '.exe', 'win']);
166-
if (os === 'macos')
167-
return tryKeywords(['macos', 'darwin', 'mac', '.dmg', '.pkg']);
168-
if (os === 'linux')
169-
return tryKeywords([
170-
'linux',
171-
'.appimage',
172-
'.deb',
173-
'.rpm',
174-
'.tar.gz',
175-
'.tar',
176-
]);
177-
178-
// fallback: try to find any CLI binary
187+
// Accept an "os" string optionally containing an arch with the format "os:arch".
188+
const normalizedOs = (os || '').toLowerCase();
189+
190+
const osKeywordsMap: Record<string, string[]> = {
191+
windows: ['windows', '.exe', 'win'],
192+
macos: ['macos', 'darwin', 'mac', '.dmg', '.pkg'],
193+
linux: ['linux', '.appimage', '.deb', '.rpm', '.tar.gz', '.tar'],
194+
};
195+
196+
const archKeywordsMap: Record<string, string[]> = {
197+
x86_64: ['x86_64', 'amd64', 'x64', 'x86-64', '-amd64', '_amd64'],
198+
arm64: ['arm64', 'aarch64', 'arm64v8', '-arm64', '_arm64'],
199+
armv7: ['armv7', 'armv7l', 'armhf', '-armv7', '_armv7'],
200+
i386: ['i386', 'i686', 'ia32', 'x86'],
201+
};
202+
203+
let arch: string | undefined = undefined;
204+
if (normalizedOs.includes(':')) {
205+
const [o, a] = normalizedOs.split(':', 2);
206+
arch = a;
207+
}
208+
209+
const osKey = normalizedOs.includes(':') ? normalizedOs.split(':', 1)[0] : normalizedOs;
210+
const osKeywords = osKeywordsMap[osKey] || [];
211+
const archKeywords = arch ? archKeywordsMap[arch] || [] : [];
212+
213+
// Try to match both OS and arch in the filename
214+
if (archKeywords.length && osKeywords.length) {
215+
const found = assets.find((a) => {
216+
const n = name(a.name);
217+
const ok = osKeywords.some((k) => n.includes(k));
218+
const ak = archKeywords.some((k) => n.includes(k));
219+
return ok && ak;
220+
});
221+
if (found) return found.browser_download_url;
222+
}
223+
224+
// If no combined match, try arch-only (if provided)
225+
if (archKeywords.length) {
226+
const byArch = tryKeywords(archKeywords);
227+
if (byArch) return byArch;
228+
}
229+
230+
// Fallback to OS-only matching
231+
if (osKeywords.length) {
232+
const byOs = tryKeywords(osKeywords);
233+
if (byOs) return byOs;
234+
}
235+
236+
// Final fallback: try to find any CLI binary
179237
return tryKeywords(['cli', 'chithi', 'chithi-cli']);
180238
}
181239

@@ -185,7 +243,9 @@ export default function HomeClient({ release }: { release: Release }) {
185243
return;
186244
}
187245
const osToUse = downloadOS === 'auto' ? detectOS() : downloadOS;
188-
const asset = findAssetForOS(release, osToUse);
246+
const archToUse = downloadArch === 'auto' ? detectArch() : downloadArch;
247+
const osAndArch = archToUse && archToUse !== 'unknown' ? `${osToUse}:${archToUse}` : osToUse;
248+
const asset = findAssetForOS(release, osAndArch);
189249
if (asset) {
190250
// redirect to the asset (GitHub release file)
191251
window.location.href = asset;
@@ -271,6 +331,20 @@ export default function HomeClient({ release }: { release: Release }) {
271331
<option value="linux">Linux</option>
272332
</select>
273333

334+
<select
335+
value={downloadArch}
336+
onChange={(e) =>
337+
setDownloadArch(e.target.value as any)
338+
}
339+
className="select variant-form-material"
340+
>
341+
<option value="auto">Auto-detect</option>
342+
<option value="x86_64">x86_64 (amd64)</option>
343+
<option value="arm64">arm64 (aarch64)</option>
344+
<option value="armv7">armv7 (armhf)</option>
345+
<option value="i386">i386 (x86)</option>
346+
</select>
347+
274348
<button
275349
onClick={handleDownloadClick}
276350
className="btn preset-filled-primary-500 rounded-full px-6 py-3 font-bold"

0 commit comments

Comments
 (0)