diff --git a/app/i18n.ts b/app/i18n.ts index b29c6e2..44fa179 100644 --- a/app/i18n.ts +++ b/app/i18n.ts @@ -1,5 +1,4 @@ import i18n from "i18next"; -import LanguageDetector from "i18next-browser-languagedetector"; import { initReactI18next } from "react-i18next"; import supportedByEN from "../public/locales/en/supportedBy.json"; import supportedByES from "../public/locales/es/supportedBy.json"; @@ -21,8 +20,8 @@ import footerES from "../public/locales/es/footer.json"; i18n .use(initReactI18next) - .use(LanguageDetector) .init({ + lng: "en", resources: { en: { navbar: navbarEN, diff --git a/app/page.tsx b/app/page.tsx index a276797..27d43db 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,7 @@ "use client" +import { useEffect } from "react" +import i18n from "i18next" import { Navbar } from "@/components/navbar" import { HeroSection } from "@/components/hero-section" import { FeaturesSection } from "@/components/features-section" @@ -11,7 +13,15 @@ import { ContactSection } from "@/components/contact-section" import { Footer } from "@/components/footer" import "./i18n" +const SUPPORTED_LANGS = ["en", "es"] + export default function Home() { + useEffect(() => { + const detected = navigator.language ?? "en" + const match = SUPPORTED_LANGS.find((l) => detected.startsWith(l)) ?? "en" + if (match !== i18n.language) i18n.changeLanguage(match) + }, []) + return (
diff --git a/components/download-section.tsx b/components/download-section.tsx index f9ef716..5f9127c 100644 --- a/components/download-section.tsx +++ b/components/download-section.tsx @@ -3,38 +3,53 @@ import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" import { Download, Package } from "lucide-react" +import { useEffect, useState } from "react" import { useTranslation } from "react-i18next" +import { findAsset, formatBytes, getLatestRelease } from "@/lib/github" -const downloads = [ +const SOURCEFORGE_URL = "https://sourceforge.net/projects/dashai/files/latest/download" + +type DownloadEntry = { + id: "mac_intel" | "mac_arm" | "windows" + icon: typeof Package + key: string + defaultPlatform: string + version: string + size: string + defaultFormat: string + link: string +} + +const FALLBACK_DOWNLOADS: DownloadEntry[] = [ { id: "mac_intel", icon: Package, key: "macIntel", defaultPlatform: "macOS Intel processors", - version: "v0.1.15", - size: "487 MB", - defaultFormat: "binary", - link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-x86_64", + version: "", + size: "", + defaultFormat: ".dmg", + link: SOURCEFORGE_URL, }, { id: "mac_arm", icon: Package, key: "macArm", defaultPlatform: "macOS ARM processors", - version: "v0.1.15", - size: "381 MB", - defaultFormat: "binary", - link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu-arm64", + version: "", + size: "", + defaultFormat: ".dmg", + link: SOURCEFORGE_URL, }, { id: "windows", icon: Package, key: "windows", defaultPlatform: "Windows", - version: "v0.1.15", - size: "434 MB", + version: "", + size: "", defaultFormat: ".exe", - link: "https://dashai.nyc3.cdn.digitaloceanspaces.com/executables/DashAI-launcher-cpu.exe", + link: SOURCEFORGE_URL, }, ] @@ -53,6 +68,26 @@ async function trackClick(buttonId: string) { export function DownloadSection() { const { t } = useTranslation() + const [downloads, setDownloads] = useState(FALLBACK_DOWNLOADS) + + useEffect(() => { + getLatestRelease().then((release) => { + if (!release) return + setDownloads( + FALLBACK_DOWNLOADS.map((entry) => { + const asset = findAsset(release.assets, entry.id) + if (!asset) return entry + return { + ...entry, + version: release.tag_name, + size: formatBytes(asset.size), + link: asset.browser_download_url, + } + }) + ) + }) + }, []) + return (
@@ -66,7 +101,7 @@ export function DownloadSection() {

{t("download:description", { defaultValue: - "This early version lets you explore DashAI’s main features. We appreciate your feedback to help us improve before the official release.", + "This early version lets you explore DashAI's main features. We appreciate your feedback to help us improve before the official release.", })}

@@ -92,9 +127,11 @@ export function DownloadSection() {

{platform}

-

- {download.version} • {download.size} -

+ {download.version && ( +

+ {download.version} • {download.size} +

+ )}

{format}

) -} \ No newline at end of file +} diff --git a/lib/github.ts b/lib/github.ts new file mode 100644 index 0000000..46829b9 --- /dev/null +++ b/lib/github.ts @@ -0,0 +1,51 @@ +export interface ReleaseAsset { + name: string + browser_download_url: string + size: number +} + +export interface LatestRelease { + tag_name: string + assets: ReleaseAsset[] +} + +export async function getLatestRelease(): Promise { + try { + const res = await fetch( + "https://api.github.com/repos/DashAISoftware/DashAI/releases/latest", + { headers: { Accept: "application/vnd.github+json" } } + ) + if (!res.ok) return null + return res.json() + } catch { + return null + } +} + +export function formatBytes(bytes: number): string { + const mb = bytes / (1024 * 1024) + return `${Math.round(mb)} MB` +} + +export function findAsset( + assets: ReleaseAsset[], + platform: "windows" | "mac_intel" | "mac_arm" +): ReleaseAsset | undefined { + return assets.find(({ name }) => { + const n = name.toLowerCase() + switch (platform) { + case "windows": + return n.includes("windows") + case "mac_intel": + return ( + (n.includes("x64") || n.includes("intel")) && + (n.includes("osx") || n.includes("mac") || n.includes("darwin")) + ) + case "mac_arm": + return ( + (n.includes("arm") || n.includes("aarch")) && + (n.includes("osx") || n.includes("mac") || n.includes("darwin")) + ) + } + }) +}