From 701480c11c147e06e5e7b14a02a4b3f89b2d7882 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 25 Mar 2026 23:06:35 +0700 Subject: [PATCH] Add /download page and link in nav Desktop (macOS, Windows, Linux with AppImage/DEB/RPM), Mobile (Android/iOS), and Web & CLI sections. Simplify homepage download button to a single link with "All download options" text link below. --- .../website/src/components/landing-page.tsx | 87 +-- packages/website/src/routeTree.gen.ts | 589 +++++++++--------- packages/website/src/routes/download.tsx | 419 +++++++++++++ 3 files changed, 748 insertions(+), 347 deletions(-) create mode 100644 packages/website/src/routes/download.tsx diff --git a/packages/website/src/components/landing-page.tsx b/packages/website/src/components/landing-page.tsx index b0d69e36b..357d22f5e 100644 --- a/packages/website/src/components/landing-page.tsx +++ b/packages/website/src/components/landing-page.tsx @@ -255,6 +255,12 @@ function Nav() { > Changelog + + Download + -
+
+ + All download options + +
+
Supports
} /> @@ -529,72 +543,19 @@ function GetStarted() { function DownloadButton() { const detectedPlatform = useDetectedPlatform(); - const [open, setOpen] = React.useState(false); - const ref = React.useRef(null); - - React.useEffect(() => { - function handleClickOutside(e: MouseEvent) { - if (ref.current && !ref.current.contains(e.target as Node)) { - setOpen(false); - } - } - document.addEventListener("mousedown", handleClickOutside); - return () => document.removeEventListener("mousedown", handleClickOutside); - }, []); - const primary = downloadOptions.find((o) => o.platform === detectedPlatform)!; - const secondaryOptions = downloadOptions.filter((o) => o.platform !== detectedPlatform); const PrimaryIcon = primary.icon; return ( -
-
- - - Download for {primary.label} - - -
- - {open && ( - - {secondaryOptions.map((option) => { - const Icon = option.icon; - return ( - setOpen(false)} - className="flex items-center gap-2 px-4 py-2 text-sm text-white/80 hover:bg-white/10 transition-colors" - > - - {option.label} - - ); - })} - - )} - -
+ + + Download for {primary.label} + ); } diff --git a/packages/website/src/routeTree.gen.ts b/packages/website/src/routeTree.gen.ts index 153985f2d..d12dcc7eb 100644 --- a/packages/website/src/routeTree.gen.ts +++ b/packages/website/src/routeTree.gen.ts @@ -8,332 +8,352 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { Route as rootRouteImport } from "./routes/__root"; -import { Route as PrivacyRouteImport } from "./routes/privacy"; -import { Route as OpencodeRouteImport } from "./routes/opencode"; -import { Route as DocsRouteImport } from "./routes/docs"; -import { Route as CodexRouteImport } from "./routes/codex"; -import { Route as ClaudeCodeRouteImport } from "./routes/claude-code"; -import { Route as ChangelogRouteImport } from "./routes/changelog"; -import { Route as IndexRouteImport } from "./routes/index"; -import { Route as DocsIndexRouteImport } from "./routes/docs/index"; -import { Route as DocsWorktreesRouteImport } from "./routes/docs/worktrees"; -import { Route as DocsVoiceRouteImport } from "./routes/docs/voice"; -import { Route as DocsUpdatesRouteImport } from "./routes/docs/updates"; -import { Route as DocsSecurityRouteImport } from "./routes/docs/security"; -import { Route as DocsConfigurationRouteImport } from "./routes/docs/configuration"; -import { Route as DocsCliRouteImport } from "./routes/docs/cli"; -import { Route as DocsBestPracticesRouteImport } from "./routes/docs/best-practices"; +import { Route as rootRouteImport } from './routes/__root' +import { Route as PrivacyRouteImport } from './routes/privacy' +import { Route as OpencodeRouteImport } from './routes/opencode' +import { Route as DownloadRouteImport } from './routes/download' +import { Route as DocsRouteImport } from './routes/docs' +import { Route as CodexRouteImport } from './routes/codex' +import { Route as ClaudeCodeRouteImport } from './routes/claude-code' +import { Route as ChangelogRouteImport } from './routes/changelog' +import { Route as IndexRouteImport } from './routes/index' +import { Route as DocsIndexRouteImport } from './routes/docs/index' +import { Route as DocsWorktreesRouteImport } from './routes/docs/worktrees' +import { Route as DocsVoiceRouteImport } from './routes/docs/voice' +import { Route as DocsUpdatesRouteImport } from './routes/docs/updates' +import { Route as DocsSecurityRouteImport } from './routes/docs/security' +import { Route as DocsConfigurationRouteImport } from './routes/docs/configuration' +import { Route as DocsCliRouteImport } from './routes/docs/cli' +import { Route as DocsBestPracticesRouteImport } from './routes/docs/best-practices' const PrivacyRoute = PrivacyRouteImport.update({ - id: "/privacy", - path: "/privacy", + id: '/privacy', + path: '/privacy', getParentRoute: () => rootRouteImport, -} as any); +} as any) const OpencodeRoute = OpencodeRouteImport.update({ - id: "/opencode", - path: "/opencode", + id: '/opencode', + path: '/opencode', getParentRoute: () => rootRouteImport, -} as any); +} as any) +const DownloadRoute = DownloadRouteImport.update({ + id: '/download', + path: '/download', + getParentRoute: () => rootRouteImport, +} as any) const DocsRoute = DocsRouteImport.update({ - id: "/docs", - path: "/docs", + id: '/docs', + path: '/docs', getParentRoute: () => rootRouteImport, -} as any); +} as any) const CodexRoute = CodexRouteImport.update({ - id: "/codex", - path: "/codex", + id: '/codex', + path: '/codex', getParentRoute: () => rootRouteImport, -} as any); +} as any) const ClaudeCodeRoute = ClaudeCodeRouteImport.update({ - id: "/claude-code", - path: "/claude-code", + id: '/claude-code', + path: '/claude-code', getParentRoute: () => rootRouteImport, -} as any); +} as any) const ChangelogRoute = ChangelogRouteImport.update({ - id: "/changelog", - path: "/changelog", + id: '/changelog', + path: '/changelog', getParentRoute: () => rootRouteImport, -} as any); +} as any) const IndexRoute = IndexRouteImport.update({ - id: "/", - path: "/", + id: '/', + path: '/', getParentRoute: () => rootRouteImport, -} as any); +} as any) const DocsIndexRoute = DocsIndexRouteImport.update({ - id: "/", - path: "/", + id: '/', + path: '/', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsWorktreesRoute = DocsWorktreesRouteImport.update({ - id: "/worktrees", - path: "/worktrees", + id: '/worktrees', + path: '/worktrees', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsVoiceRoute = DocsVoiceRouteImport.update({ - id: "/voice", - path: "/voice", + id: '/voice', + path: '/voice', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsUpdatesRoute = DocsUpdatesRouteImport.update({ - id: "/updates", - path: "/updates", + id: '/updates', + path: '/updates', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsSecurityRoute = DocsSecurityRouteImport.update({ - id: "/security", - path: "/security", + id: '/security', + path: '/security', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsConfigurationRoute = DocsConfigurationRouteImport.update({ - id: "/configuration", - path: "/configuration", + id: '/configuration', + path: '/configuration', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsCliRoute = DocsCliRouteImport.update({ - id: "/cli", - path: "/cli", + id: '/cli', + path: '/cli', getParentRoute: () => DocsRoute, -} as any); +} as any) const DocsBestPracticesRoute = DocsBestPracticesRouteImport.update({ - id: "/best-practices", - path: "/best-practices", + id: '/best-practices', + path: '/best-practices', getParentRoute: () => DocsRoute, -} as any); +} as any) export interface FileRoutesByFullPath { - "/": typeof IndexRoute; - "/changelog": typeof ChangelogRoute; - "/claude-code": typeof ClaudeCodeRoute; - "/codex": typeof CodexRoute; - "/docs": typeof DocsRouteWithChildren; - "/opencode": typeof OpencodeRoute; - "/privacy": typeof PrivacyRoute; - "/docs/best-practices": typeof DocsBestPracticesRoute; - "/docs/cli": typeof DocsCliRoute; - "/docs/configuration": typeof DocsConfigurationRoute; - "/docs/security": typeof DocsSecurityRoute; - "/docs/updates": typeof DocsUpdatesRoute; - "/docs/voice": typeof DocsVoiceRoute; - "/docs/worktrees": typeof DocsWorktreesRoute; - "/docs/": typeof DocsIndexRoute; + '/': typeof IndexRoute + '/changelog': typeof ChangelogRoute + '/claude-code': typeof ClaudeCodeRoute + '/codex': typeof CodexRoute + '/docs': typeof DocsRouteWithChildren + '/download': typeof DownloadRoute + '/opencode': typeof OpencodeRoute + '/privacy': typeof PrivacyRoute + '/docs/best-practices': typeof DocsBestPracticesRoute + '/docs/cli': typeof DocsCliRoute + '/docs/configuration': typeof DocsConfigurationRoute + '/docs/security': typeof DocsSecurityRoute + '/docs/updates': typeof DocsUpdatesRoute + '/docs/voice': typeof DocsVoiceRoute + '/docs/worktrees': typeof DocsWorktreesRoute + '/docs/': typeof DocsIndexRoute } export interface FileRoutesByTo { - "/": typeof IndexRoute; - "/changelog": typeof ChangelogRoute; - "/claude-code": typeof ClaudeCodeRoute; - "/codex": typeof CodexRoute; - "/opencode": typeof OpencodeRoute; - "/privacy": typeof PrivacyRoute; - "/docs/best-practices": typeof DocsBestPracticesRoute; - "/docs/cli": typeof DocsCliRoute; - "/docs/configuration": typeof DocsConfigurationRoute; - "/docs/security": typeof DocsSecurityRoute; - "/docs/updates": typeof DocsUpdatesRoute; - "/docs/voice": typeof DocsVoiceRoute; - "/docs/worktrees": typeof DocsWorktreesRoute; - "/docs": typeof DocsIndexRoute; + '/': typeof IndexRoute + '/changelog': typeof ChangelogRoute + '/claude-code': typeof ClaudeCodeRoute + '/codex': typeof CodexRoute + '/download': typeof DownloadRoute + '/opencode': typeof OpencodeRoute + '/privacy': typeof PrivacyRoute + '/docs/best-practices': typeof DocsBestPracticesRoute + '/docs/cli': typeof DocsCliRoute + '/docs/configuration': typeof DocsConfigurationRoute + '/docs/security': typeof DocsSecurityRoute + '/docs/updates': typeof DocsUpdatesRoute + '/docs/voice': typeof DocsVoiceRoute + '/docs/worktrees': typeof DocsWorktreesRoute + '/docs': typeof DocsIndexRoute } export interface FileRoutesById { - __root__: typeof rootRouteImport; - "/": typeof IndexRoute; - "/changelog": typeof ChangelogRoute; - "/claude-code": typeof ClaudeCodeRoute; - "/codex": typeof CodexRoute; - "/docs": typeof DocsRouteWithChildren; - "/opencode": typeof OpencodeRoute; - "/privacy": typeof PrivacyRoute; - "/docs/best-practices": typeof DocsBestPracticesRoute; - "/docs/cli": typeof DocsCliRoute; - "/docs/configuration": typeof DocsConfigurationRoute; - "/docs/security": typeof DocsSecurityRoute; - "/docs/updates": typeof DocsUpdatesRoute; - "/docs/voice": typeof DocsVoiceRoute; - "/docs/worktrees": typeof DocsWorktreesRoute; - "/docs/": typeof DocsIndexRoute; + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/changelog': typeof ChangelogRoute + '/claude-code': typeof ClaudeCodeRoute + '/codex': typeof CodexRoute + '/docs': typeof DocsRouteWithChildren + '/download': typeof DownloadRoute + '/opencode': typeof OpencodeRoute + '/privacy': typeof PrivacyRoute + '/docs/best-practices': typeof DocsBestPracticesRoute + '/docs/cli': typeof DocsCliRoute + '/docs/configuration': typeof DocsConfigurationRoute + '/docs/security': typeof DocsSecurityRoute + '/docs/updates': typeof DocsUpdatesRoute + '/docs/voice': typeof DocsVoiceRoute + '/docs/worktrees': typeof DocsWorktreesRoute + '/docs/': typeof DocsIndexRoute } export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath; + fileRoutesByFullPath: FileRoutesByFullPath fullPaths: - | "/" - | "/changelog" - | "/claude-code" - | "/codex" - | "/docs" - | "/opencode" - | "/privacy" - | "/docs/best-practices" - | "/docs/cli" - | "/docs/configuration" - | "/docs/security" - | "/docs/updates" - | "/docs/voice" - | "/docs/worktrees" - | "/docs/"; - fileRoutesByTo: FileRoutesByTo; + | '/' + | '/changelog' + | '/claude-code' + | '/codex' + | '/docs' + | '/download' + | '/opencode' + | '/privacy' + | '/docs/best-practices' + | '/docs/cli' + | '/docs/configuration' + | '/docs/security' + | '/docs/updates' + | '/docs/voice' + | '/docs/worktrees' + | '/docs/' + fileRoutesByTo: FileRoutesByTo to: - | "/" - | "/changelog" - | "/claude-code" - | "/codex" - | "/opencode" - | "/privacy" - | "/docs/best-practices" - | "/docs/cli" - | "/docs/configuration" - | "/docs/security" - | "/docs/updates" - | "/docs/voice" - | "/docs/worktrees" - | "/docs"; + | '/' + | '/changelog' + | '/claude-code' + | '/codex' + | '/download' + | '/opencode' + | '/privacy' + | '/docs/best-practices' + | '/docs/cli' + | '/docs/configuration' + | '/docs/security' + | '/docs/updates' + | '/docs/voice' + | '/docs/worktrees' + | '/docs' id: - | "__root__" - | "/" - | "/changelog" - | "/claude-code" - | "/codex" - | "/docs" - | "/opencode" - | "/privacy" - | "/docs/best-practices" - | "/docs/cli" - | "/docs/configuration" - | "/docs/security" - | "/docs/updates" - | "/docs/voice" - | "/docs/worktrees" - | "/docs/"; - fileRoutesById: FileRoutesById; + | '__root__' + | '/' + | '/changelog' + | '/claude-code' + | '/codex' + | '/docs' + | '/download' + | '/opencode' + | '/privacy' + | '/docs/best-practices' + | '/docs/cli' + | '/docs/configuration' + | '/docs/security' + | '/docs/updates' + | '/docs/voice' + | '/docs/worktrees' + | '/docs/' + fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute; - ChangelogRoute: typeof ChangelogRoute; - ClaudeCodeRoute: typeof ClaudeCodeRoute; - CodexRoute: typeof CodexRoute; - DocsRoute: typeof DocsRouteWithChildren; - OpencodeRoute: typeof OpencodeRoute; - PrivacyRoute: typeof PrivacyRoute; + IndexRoute: typeof IndexRoute + ChangelogRoute: typeof ChangelogRoute + ClaudeCodeRoute: typeof ClaudeCodeRoute + CodexRoute: typeof CodexRoute + DocsRoute: typeof DocsRouteWithChildren + DownloadRoute: typeof DownloadRoute + OpencodeRoute: typeof OpencodeRoute + PrivacyRoute: typeof PrivacyRoute } -declare module "@tanstack/react-router" { +declare module '@tanstack/react-router' { interface FileRoutesByPath { - "/privacy": { - id: "/privacy"; - path: "/privacy"; - fullPath: "/privacy"; - preLoaderRoute: typeof PrivacyRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/opencode": { - id: "/opencode"; - path: "/opencode"; - fullPath: "/opencode"; - preLoaderRoute: typeof OpencodeRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/docs": { - id: "/docs"; - path: "/docs"; - fullPath: "/docs"; - preLoaderRoute: typeof DocsRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/codex": { - id: "/codex"; - path: "/codex"; - fullPath: "/codex"; - preLoaderRoute: typeof CodexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/claude-code": { - id: "/claude-code"; - path: "/claude-code"; - fullPath: "/claude-code"; - preLoaderRoute: typeof ClaudeCodeRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/changelog": { - id: "/changelog"; - path: "/changelog"; - fullPath: "/changelog"; - preLoaderRoute: typeof ChangelogRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/": { - id: "/"; - path: "/"; - fullPath: "/"; - preLoaderRoute: typeof IndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/docs/": { - id: "/docs/"; - path: "/"; - fullPath: "/docs/"; - preLoaderRoute: typeof DocsIndexRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/worktrees": { - id: "/docs/worktrees"; - path: "/worktrees"; - fullPath: "/docs/worktrees"; - preLoaderRoute: typeof DocsWorktreesRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/voice": { - id: "/docs/voice"; - path: "/voice"; - fullPath: "/docs/voice"; - preLoaderRoute: typeof DocsVoiceRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/updates": { - id: "/docs/updates"; - path: "/updates"; - fullPath: "/docs/updates"; - preLoaderRoute: typeof DocsUpdatesRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/security": { - id: "/docs/security"; - path: "/security"; - fullPath: "/docs/security"; - preLoaderRoute: typeof DocsSecurityRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/configuration": { - id: "/docs/configuration"; - path: "/configuration"; - fullPath: "/docs/configuration"; - preLoaderRoute: typeof DocsConfigurationRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/cli": { - id: "/docs/cli"; - path: "/cli"; - fullPath: "/docs/cli"; - preLoaderRoute: typeof DocsCliRouteImport; - parentRoute: typeof DocsRoute; - }; - "/docs/best-practices": { - id: "/docs/best-practices"; - path: "/best-practices"; - fullPath: "/docs/best-practices"; - preLoaderRoute: typeof DocsBestPracticesRouteImport; - parentRoute: typeof DocsRoute; - }; + '/privacy': { + id: '/privacy' + path: '/privacy' + fullPath: '/privacy' + preLoaderRoute: typeof PrivacyRouteImport + parentRoute: typeof rootRouteImport + } + '/opencode': { + id: '/opencode' + path: '/opencode' + fullPath: '/opencode' + preLoaderRoute: typeof OpencodeRouteImport + parentRoute: typeof rootRouteImport + } + '/download': { + id: '/download' + path: '/download' + fullPath: '/download' + preLoaderRoute: typeof DownloadRouteImport + parentRoute: typeof rootRouteImport + } + '/docs': { + id: '/docs' + path: '/docs' + fullPath: '/docs' + preLoaderRoute: typeof DocsRouteImport + parentRoute: typeof rootRouteImport + } + '/codex': { + id: '/codex' + path: '/codex' + fullPath: '/codex' + preLoaderRoute: typeof CodexRouteImport + parentRoute: typeof rootRouteImport + } + '/claude-code': { + id: '/claude-code' + path: '/claude-code' + fullPath: '/claude-code' + preLoaderRoute: typeof ClaudeCodeRouteImport + parentRoute: typeof rootRouteImport + } + '/changelog': { + id: '/changelog' + path: '/changelog' + fullPath: '/changelog' + preLoaderRoute: typeof ChangelogRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/docs/': { + id: '/docs/' + path: '/' + fullPath: '/docs/' + preLoaderRoute: typeof DocsIndexRouteImport + parentRoute: typeof DocsRoute + } + '/docs/worktrees': { + id: '/docs/worktrees' + path: '/worktrees' + fullPath: '/docs/worktrees' + preLoaderRoute: typeof DocsWorktreesRouteImport + parentRoute: typeof DocsRoute + } + '/docs/voice': { + id: '/docs/voice' + path: '/voice' + fullPath: '/docs/voice' + preLoaderRoute: typeof DocsVoiceRouteImport + parentRoute: typeof DocsRoute + } + '/docs/updates': { + id: '/docs/updates' + path: '/updates' + fullPath: '/docs/updates' + preLoaderRoute: typeof DocsUpdatesRouteImport + parentRoute: typeof DocsRoute + } + '/docs/security': { + id: '/docs/security' + path: '/security' + fullPath: '/docs/security' + preLoaderRoute: typeof DocsSecurityRouteImport + parentRoute: typeof DocsRoute + } + '/docs/configuration': { + id: '/docs/configuration' + path: '/configuration' + fullPath: '/docs/configuration' + preLoaderRoute: typeof DocsConfigurationRouteImport + parentRoute: typeof DocsRoute + } + '/docs/cli': { + id: '/docs/cli' + path: '/cli' + fullPath: '/docs/cli' + preLoaderRoute: typeof DocsCliRouteImport + parentRoute: typeof DocsRoute + } + '/docs/best-practices': { + id: '/docs/best-practices' + path: '/best-practices' + fullPath: '/docs/best-practices' + preLoaderRoute: typeof DocsBestPracticesRouteImport + parentRoute: typeof DocsRoute + } } } interface DocsRouteChildren { - DocsBestPracticesRoute: typeof DocsBestPracticesRoute; - DocsCliRoute: typeof DocsCliRoute; - DocsConfigurationRoute: typeof DocsConfigurationRoute; - DocsSecurityRoute: typeof DocsSecurityRoute; - DocsUpdatesRoute: typeof DocsUpdatesRoute; - DocsVoiceRoute: typeof DocsVoiceRoute; - DocsWorktreesRoute: typeof DocsWorktreesRoute; - DocsIndexRoute: typeof DocsIndexRoute; + DocsBestPracticesRoute: typeof DocsBestPracticesRoute + DocsCliRoute: typeof DocsCliRoute + DocsConfigurationRoute: typeof DocsConfigurationRoute + DocsSecurityRoute: typeof DocsSecurityRoute + DocsUpdatesRoute: typeof DocsUpdatesRoute + DocsVoiceRoute: typeof DocsVoiceRoute + DocsWorktreesRoute: typeof DocsWorktreesRoute + DocsIndexRoute: typeof DocsIndexRoute } const DocsRouteChildren: DocsRouteChildren = { @@ -345,9 +365,9 @@ const DocsRouteChildren: DocsRouteChildren = { DocsVoiceRoute: DocsVoiceRoute, DocsWorktreesRoute: DocsWorktreesRoute, DocsIndexRoute: DocsIndexRoute, -}; +} -const DocsRouteWithChildren = DocsRoute._addFileChildren(DocsRouteChildren); +const DocsRouteWithChildren = DocsRoute._addFileChildren(DocsRouteChildren) const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, @@ -355,18 +375,19 @@ const rootRouteChildren: RootRouteChildren = { ClaudeCodeRoute: ClaudeCodeRoute, CodexRoute: CodexRoute, DocsRoute: DocsRouteWithChildren, + DownloadRoute: DownloadRoute, OpencodeRoute: OpencodeRoute, PrivacyRoute: PrivacyRoute, -}; +} export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) - ._addFileTypes(); + ._addFileTypes() -import type { getRouter } from "./router.tsx"; -import type { createStart } from "@tanstack/react-start"; -declare module "@tanstack/react-start" { +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { interface Register { - ssr: true; - router: Awaited>; + ssr: true + router: Awaited> } } diff --git a/packages/website/src/routes/download.tsx b/packages/website/src/routes/download.tsx new file mode 100644 index 000000000..304aeb800 --- /dev/null +++ b/packages/website/src/routes/download.tsx @@ -0,0 +1,419 @@ +import { Link, createFileRoute } from "@tanstack/react-router"; +import { pageMeta } from "~/meta"; +import websitePackage from "../../package.json"; +import "~/styles.css"; + +const desktopVersion = websitePackage.version; +const releaseBase = `https://github.com/getpaseo/paseo/releases/download/v${desktopVersion}`; + +export const Route = createFileRoute("/download")({ + head: () => ({ + meta: pageMeta( + "Download - Paseo", + "Download Paseo for macOS, Windows, Linux, iOS, and Android. Your dev environment, in your pocket.", + ), + }), + component: Download, +}); + +function Download() { + return ( +
+
+
+ + Paseo + Paseo + +
+ + Docs + + + Changelog + + + + + + + + + + + +
+
+ +

Download

+

+ v{desktopVersion} +

+ + {/* Desktop */} +
+
+

Desktop

+ +
+ +
+ {/* macOS */} +
+
+ + macOS +
+
+ + +
+
+ + {/* Windows */} +
+
+ + Windows +
+
+ +
+
+ + {/* Linux */} +
+
+ + Linux +
+
+ + + +
+
+
+
+ + {/* Mobile */} +
+
+

Mobile

+ +
+ +
+ {/* Android */} +
+
+ + Android +
+
+ + +
+
+ + {/* iOS */} +
+
+ + iOS +
+
+ +
+
+
+
+ + {/* Web & CLI */} +
+
+

Web & CLI

+ +
+ +
+
+
+ + Web App +
+
+ +
+
+ +
+
+ + CLI +
+
+ + npx paseo + +
+
+
+
+ +

+ All releases are available on{" "} + + GitHub + + . +

+
+
+ ); +} + +function DownloadPill({ + href, + label, + external, +}: { + href: string; + label: string; + external?: boolean; +}) { + return ( + + {label} + {external && ( + + )} + + ); +} + +function AppleIcon(props: React.SVGProps) { + return ( + + ); +} + +function AndroidIcon(props: React.SVGProps) { + return ( + + ); +} + +function WindowsIcon(props: React.SVGProps) { + return ( + + ); +} + +function LinuxIcon(props: React.SVGProps) { + return ( + + ); +} + +function MonitorIcon(props: React.SVGProps) { + return ( + + ); +} + +function PhoneIcon(props: React.SVGProps) { + return ( + + ); +} + +function TerminalIcon(props: React.SVGProps) { + return ( + + ); +} + +function GlobeIcon(props: React.SVGProps) { + return ( + + ); +}