"use client"; import { incrementDownloadCount } from "@/lib/db"; import { useState, useEffect, useCallback } from "react"; import styled, { keyframes } from "styled-components"; import { ny } from "@/lib/utils"; import { Checkbox } from "./ui/checkbox"; import { ChevronLeft } from "lucide-react"; import { Button } from "./ui/button"; import Particles from "./ui/particles"; import confetti from "canvas-confetti"; import type { Architecture, LinuxDownloadType, Platform, WindowsDownloadType, } from "@/lib/releases"; import { releases, releaseTree } from "@/lib/releases"; import { InfoCircledIcon } from "@radix-ui/react-icons"; import Link from "next/link"; import SparklesText from "./ui/sparkles-text"; import { useRouter } from "next/navigation"; const BASE_URL = "https://github.com/zen-browser/desktop/releases/latest/download"; const field_enter = keyframes` 0% { opacity: 0; transform: scale(0.9); filter: blur(10px); } 1% { max-height: 100%; } 100% { opacity: 1; transform: scale(1); filter: blur(0); } `; const field_exit = keyframes` from { display: flex; opacity: 1; transform: scale(1); filter: blur(0); } 99% { opacity: 0; transform: scale(0.9); filter: blur(10px); } 100% { display: none; } `; const FormField = styled.div<{ enter: boolean; out: boolean }>` max-height: 0; flex-direction: column; opacity: 0; width: 100%; animation: 0.2s ease-in-out forwards ${({ enter, out }) => (enter ? field_enter : out ? field_exit : "")} !important; animation-delay: ${({ enter }) => (enter ? "0.4s" : "0s")}; `; const FieldTitle = ({ children, className, }: React.PropsWithChildren & React.HTMLAttributes) => (

{children}

); const FieldDescription = ({ children, className, }: React.PropsWithChildren & React.HTMLAttributes) => (

{children}

); const platforms = { Windows: { color: "blue", icon: "windows8" }, Linux: { color: "yellow", icon: "linux" }, MacOS: { color: "purple", icon: "apple" }, }; export default function DownloadPage() { const router = useRouter(); const [platform, setPlatform] = useState(null); const [selectedPlatform, setSelectedPlatform] = useState( null ); const [selectedArchitecture, setSelectedArchitecture] = useState("specific"); const [selectedWindowsDownloadType, setSelectedWindowsDownloadType] = useState("installer"); const [selectedLinuxDownloadType, setSelectedLinuxDownloadType] = useState("portable"); const [hasDownloaded, setHasDownloaded] = useState(false); const [flowIndex, setFlowIndex] = useState(0); const detectPlatform = useCallback(() => { if (typeof window === "undefined") return; const userAgent = window.navigator.userAgent.toLowerCase(); if (userAgent.includes("win")) { setSelectedPlatform("Windows"); } else if (userAgent.includes("mac")) { setSelectedPlatform("MacOS"); } else if (userAgent.includes("linux")) { setSelectedPlatform("Linux"); } }, []); const throwConfetti = useCallback(() => { const end = Date.now() + 3 * 1000; // 3 seconds const colors = ["#a786ff", "#fd8bbc", "#eca184", "#f8deb1"]; const frame = () => { if (Date.now() > end) return; confetti({ particleCount: 2, angle: 60, spread: 55, startVelocity: 60, origin: { x: 0, y: 0.5 }, colors, }); confetti({ particleCount: 2, angle: 120, spread: 55, startVelocity: 60, origin: { x: 1, y: 0.5 }, colors, }); requestAnimationFrame(frame); }; frame(); }, []); const getReleaseTarget = useCallback((): | keyof typeof releases | undefined => { if (selectedLinuxDownloadType === "flatpak") { router.push( "https://dl.flathub.org/repo/appstream/io.github.zen_browser.zen.flatpakref" ); return; } if (!selectedPlatform) return; const platformReleases = releaseTree[selectedPlatform.toLowerCase()]; if (selectedPlatform === "MacOS") return platformReleases[selectedArchitecture]; return platformReleases[selectedArchitecture][ selectedPlatform === "Windows" ? selectedWindowsDownloadType : selectedLinuxDownloadType ]; }, [ router, selectedArchitecture, selectedLinuxDownloadType, selectedPlatform, selectedWindowsDownloadType, ]); const startDownload = useCallback(() => { const releaseTarget = getReleaseTarget(); if (!releaseTarget) return; router.push(`${BASE_URL}/${releases[releaseTarget]}`); setHasDownloaded(true); incrementDownloadCount(releaseTarget); throwConfetti(); }, [getReleaseTarget, router, throwConfetti]); const continueFlow = useCallback(() => { if (flowIndex === 0) setPlatform(selectedPlatform); if (flowIndex === 2 || (flowIndex === 1 && platform === "MacOS")) { startDownload(); } setFlowIndex(flowIndex + 1); }, [flowIndex, platform, selectedPlatform, startDownload]); const goBackFlow = useCallback(() => { if (flowIndex === 1) setPlatform(null); else if (flowIndex === 3) { setSelectedWindowsDownloadType("installer"); setSelectedLinuxDownloadType("portable"); } if (flowIndex > 0) setFlowIndex(flowIndex - 1); }, [flowIndex]); const changeToFlatpak = useCallback(() => { if (selectedArchitecture !== "specific") return; setSelectedLinuxDownloadType("flatpak"); }, [selectedArchitecture]); useEffect(() => { detectPlatform(); }, [detectPlatform]); return ( <>
{(hasDownloaded && (

Downloaded! ❤️

Zen Browser has been downloaded successfully. Enjoy browsing the web with Zen!

Source Code Donate Release Notes
{selectedPlatform === "MacOS" && (

Installation Instructions

To install Zen on MacOS, the process is a bit different. Please follow the instructions below:

)}
)) || ( <>

Download

We're thrilled for you to experience Zen Browser. First, let us know which device you're using. This will only take a moment, we promise.

)}
{/* Platform */} {!platform && ( Platform Choose the platform you want to download Zen for. {Object.entries(platforms).map(([plat, { color, icon }]) => (
setSelectedPlatform(plat as Platform)} className={ny( "select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", selectedPlatform === plat && `border-${color}-400` )} >
{plat}
))}
)} {/* Architecture */} {(platform === "Windows" || platform === "Linux") && flowIndex === 1 && ( = 1 } > Select Architecture Choose the architecture of your device, either optimized or generic.
setSelectedArchitecture("specific")} className={ny( "select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", selectedArchitecture === "specific" && "border-blue-400" )} >

🚀

Optimized

Blazing fast and compatible with modern devices

setSelectedArchitecture("generic")} className={ny( "select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", selectedArchitecture === "generic" && "border-blue-400" )} >

👴

Generic

Slow but compatible with older devices.

)} {platform === "MacOS" && flowIndex === 1 && ( Download Zen for MacOS Click the button below to download Zen for MacOS.
)} {flowIndex === 2 && platform === "Windows" && ( = 2} > Download Zen for Windows {selectedArchitecture} Choose the type of download you want for Zen for Windows.
)} {flowIndex === 2 && platform === "Linux" && ( = 2} > Download Zen for Linux {selectedArchitecture} Choose the type of download you want for Zen for Linux.
setSelectedLinuxDownloadType("appimage")} className={ny( "select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border space-y-2", selectedLinuxDownloadType === "appimage" && "border-blue-400" )} >

🚀

AppImage

Install Zen with a setup wizard

setSelectedLinuxDownloadType("portable")} className={ny( "select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border space-y-2", selectedLinuxDownloadType === "portable" && "border-blue-400" )} >

📦

Portable

Download Zen as a ZIP file

🧑‍💻

Flatpak

Install Zen from the Flatpak repository.

)}
{!hasDownloaded && (
)} {(platform === "Linux" || platform === "Windows") && flowIndex === 1 && (

Confused about which build to choose?{" "} System requirements .

)}
); }