Skip to content

Commit b57ba2d

Browse files
Merge pull request #6 from DashAISoftware/fix/download-links
Auto update download links from GitHub releases
2 parents feb694c + cdf3e70 commit b57ba2d

4 files changed

Lines changed: 117 additions & 20 deletions

File tree

app/i18n.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import i18n from "i18next";
2-
import LanguageDetector from "i18next-browser-languagedetector";
32
import { initReactI18next } from "react-i18next";
43
import supportedByEN from "../public/locales/en/supportedBy.json";
54
import supportedByES from "../public/locales/es/supportedBy.json";
@@ -21,8 +20,8 @@ import footerES from "../public/locales/es/footer.json";
2120

2221
i18n
2322
.use(initReactI18next)
24-
.use(LanguageDetector)
2523
.init({
24+
lng: "en",
2625
resources: {
2726
en: {
2827
navbar: navbarEN,

app/page.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"use client"
22

3+
import { useEffect } from "react"
4+
import i18n from "i18next"
35
import { Navbar } from "@/components/navbar"
46
import { HeroSection } from "@/components/hero-section"
57
import { FeaturesSection } from "@/components/features-section"
@@ -11,7 +13,15 @@ import { ContactSection } from "@/components/contact-section"
1113
import { Footer } from "@/components/footer"
1214
import "./i18n"
1315

16+
const SUPPORTED_LANGS = ["en", "es"]
17+
1418
export default function Home() {
19+
useEffect(() => {
20+
const detected = navigator.language ?? "en"
21+
const match = SUPPORTED_LANGS.find((l) => detected.startsWith(l)) ?? "en"
22+
if (match !== i18n.language) i18n.changeLanguage(match)
23+
}, [])
24+
1525
return (
1626
<main className="min-h-screen">
1727
<Navbar />

components/download-section.tsx

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,53 @@
33
import { Button } from "@/components/ui/button"
44
import { Card, CardContent } from "@/components/ui/card"
55
import { Download, Package } from "lucide-react"
6+
import { useEffect, useState } from "react"
67
import { useTranslation } from "react-i18next"
8+
import { findAsset, formatBytes, getLatestRelease } from "@/lib/github"
79

8-
const downloads = [
10+
const SOURCEFORGE_URL = "https://sourceforge.net/projects/dashai/files/latest/download"
11+
12+
type DownloadEntry = {
13+
id: "mac_intel" | "mac_arm" | "windows"
14+
icon: typeof Package
15+
key: string
16+
defaultPlatform: string
17+
version: string
18+
size: string
19+
defaultFormat: string
20+
link: string
21+
}
22+
23+
const FALLBACK_DOWNLOADS: DownloadEntry[] = [
924
{
1025
id: "mac_intel",
1126
icon: Package,
1227
key: "macIntel",
1328
defaultPlatform: "macOS Intel processors",
14-
version: "v0.1.15",
15-
size: "487 MB",
16-
defaultFormat: "binary",
17-
link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-x86_64",
29+
version: "",
30+
size: "",
31+
defaultFormat: ".dmg",
32+
link: SOURCEFORGE_URL,
1833
},
1934
{
2035
id: "mac_arm",
2136
icon: Package,
2237
key: "macArm",
2338
defaultPlatform: "macOS ARM processors",
24-
version: "v0.1.15",
25-
size: "381 MB",
26-
defaultFormat: "binary",
27-
link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-arm64",
39+
version: "",
40+
size: "",
41+
defaultFormat: ".dmg",
42+
link: SOURCEFORGE_URL,
2843
},
2944
{
3045
id: "windows",
3146
icon: Package,
3247
key: "windows",
3348
defaultPlatform: "Windows",
34-
version: "v0.1.15",
35-
size: "434 MB",
49+
version: "",
50+
size: "",
3651
defaultFormat: ".exe",
37-
link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu.exe",
52+
link: SOURCEFORGE_URL,
3853
},
3954
]
4055

@@ -53,6 +68,26 @@ async function trackClick(buttonId: string) {
5368

5469
export function DownloadSection() {
5570
const { t } = useTranslation()
71+
const [downloads, setDownloads] = useState<DownloadEntry[]>(FALLBACK_DOWNLOADS)
72+
73+
useEffect(() => {
74+
getLatestRelease().then((release) => {
75+
if (!release) return
76+
setDownloads(
77+
FALLBACK_DOWNLOADS.map((entry) => {
78+
const asset = findAsset(release.assets, entry.id)
79+
if (!asset) return entry
80+
return {
81+
...entry,
82+
version: release.tag_name,
83+
size: formatBytes(asset.size),
84+
link: asset.browser_download_url,
85+
}
86+
})
87+
)
88+
})
89+
}, [])
90+
5691
return (
5792
<section id="download" className="py-24 px-4 bg-secondary/30">
5893
<div className="container mx-auto">
@@ -66,7 +101,7 @@ export function DownloadSection() {
66101
<p className="text-lg text-muted-foreground max-w-2xl mx-auto leading-relaxed">
67102
{t("download:description", {
68103
defaultValue:
69-
"This early version lets you explore DashAIs main features. We appreciate your feedback to help us improve before the official release.",
104+
"This early version lets you explore DashAI's main features. We appreciate your feedback to help us improve before the official release.",
70105
})}
71106
</p>
72107
</div>
@@ -92,17 +127,19 @@ export function DownloadSection() {
92127
</div>
93128
<h3 className="text-xl font-semibold mb-2">{platform}</h3>
94129
<div className="space-y-1 mb-4">
95-
<p className="text-sm text-muted-foreground">
96-
{download.version}{download.size}
97-
</p>
130+
{download.version && (
131+
<p className="text-sm text-muted-foreground">
132+
{download.version}{download.size}
133+
</p>
134+
)}
98135
<p className="text-xs text-muted-foreground font-mono">{format}</p>
99136
</div>
100137
<Button
101138
className="w-full bg-primary hover:bg-primary/90 text-primary-foreground cursor-pointer"
102139
size="sm"
103140
asChild
104141
>
105-
<a href={download.link} download onClick={() => trackClick(download.id)}>
142+
<a href={download.link} onClick={() => trackClick(download.id)}>
106143
<Download className="mr-2 h-4 w-4" />
107144
{t("download:button", { defaultValue: "Download" })}
108145
</a>
@@ -140,4 +177,4 @@ export function DownloadSection() {
140177
</div>
141178
</section>
142179
)
143-
}
180+
}

lib/github.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export interface ReleaseAsset {
2+
name: string
3+
browser_download_url: string
4+
size: number
5+
}
6+
7+
export interface LatestRelease {
8+
tag_name: string
9+
assets: ReleaseAsset[]
10+
}
11+
12+
export async function getLatestRelease(): Promise<LatestRelease | null> {
13+
try {
14+
const res = await fetch(
15+
"https://api.github.com/repos/DashAISoftware/DashAI/releases/latest",
16+
{ headers: { Accept: "application/vnd.github+json" } }
17+
)
18+
if (!res.ok) return null
19+
return res.json()
20+
} catch {
21+
return null
22+
}
23+
}
24+
25+
export function formatBytes(bytes: number): string {
26+
const mb = bytes / (1024 * 1024)
27+
return `${Math.round(mb)} MB`
28+
}
29+
30+
export function findAsset(
31+
assets: ReleaseAsset[],
32+
platform: "windows" | "mac_intel" | "mac_arm"
33+
): ReleaseAsset | undefined {
34+
return assets.find(({ name }) => {
35+
const n = name.toLowerCase()
36+
switch (platform) {
37+
case "windows":
38+
return n.includes("windows")
39+
case "mac_intel":
40+
return (
41+
(n.includes("x64") || n.includes("intel")) &&
42+
(n.includes("osx") || n.includes("mac") || n.includes("darwin"))
43+
)
44+
case "mac_arm":
45+
return (
46+
(n.includes("arm") || n.includes("aarch")) &&
47+
(n.includes("osx") || n.includes("mac") || n.includes("darwin"))
48+
)
49+
}
50+
})
51+
}

0 commit comments

Comments
 (0)