From 217e5d57b08b51ae1f929ff022744250c4710b38 Mon Sep 17 00:00:00 2001 From: Bharath Lakshman Kumar <108531789+BharathxD@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:28:00 +0530 Subject: [PATCH] refactor: Improved Platform Detection and UI Enhancements --- src/components/download.tsx | 471 ++++++++++++++++-------------------- 1 file changed, 212 insertions(+), 259 deletions(-) diff --git a/src/components/download.tsx b/src/components/download.tsx index 2ab7f6e..3a80113 100644 --- a/src/components/download.tsx +++ b/src/components/download.tsx @@ -1,6 +1,7 @@ "use client"; -import { addDownload } from "@/lib/db"; -import { useState, useEffect } from "react"; + +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"; @@ -8,50 +9,36 @@ 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"; -import SparklesText from "./ui/sparkles-text"; 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); - } + 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; - } + 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; - margin-top: 3rem; opacity: 0; width: 100%; animation: 0.2s ease-in-out forwards @@ -59,53 +46,59 @@ const FormField = styled.div<{ enter: boolean; out: boolean }>` animation-delay: ${({ enter }) => (enter ? "0.4s" : "0s")}; `; -const FieldTitle = styled.div` - font-size: 1.35rem; - font-weight: 500; -`; +const FieldTitle = ({ + children, + className, +}: React.PropsWithChildren & React.HTMLAttributes) => ( +

{children}

+); -const FieldDescription = styled.div` - font-size: 1rem; - color: #666; - margin-bottom: 1rem; -`; +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 [platform, setPlatform] = useState(null); - const [architecture, setArchitecture] = useState(null); - const [windowsDownloadType, setWindowsDownloadType] = useState( - null - ); - const [linuxDownloadType, setLinuxDownloadType] = useState( + const router = useRouter(); + + const [platform, setPlatform] = useState(null); + const [selectedPlatform, setSelectedPlatform] = useState( null ); - const [selectedPlatform, setSelectedPlatform] = useState(""); - const [selectedArchitecture, setSelectedArchitecture] = useState("specific"); + const [selectedArchitecture, setSelectedArchitecture] = + useState("specific"); const [selectedWindowsDownloadType, setSelectedWindowsDownloadType] = - useState("installer"); + useState("installer"); const [selectedLinuxDownloadType, setSelectedLinuxDownloadType] = - useState("portable"); + useState("portable"); - const [hasDownloaded, setHasDownloaded] = useState(false); + const [hasDownloaded, setHasDownloaded] = useState(false); + const [flowIndex, setFlowIndex] = useState(0); - const [flowIndex, setFlowIndex] = useState(0); - useEffect(() => { - let userAgent: string = ""; - if (typeof window !== "undefined") { - userAgent = window.navigator.userAgent; - } - if (userAgent.includes("Win")) { + const detectPlatform = useCallback(() => { + if (typeof window === "undefined") return; + + const userAgent = window.navigator.userAgent.toLowerCase(); + + if (userAgent.includes("win")) { setSelectedPlatform("Windows"); - } - if (userAgent.includes("Mac")) { + } else if (userAgent.includes("mac")) { setSelectedPlatform("MacOS"); - } - if (userAgent.includes("Linux")) { + } else if (userAgent.includes("linux")) { setSelectedPlatform("Linux"); } }, []); - const throwConfetti = () => { + + const throwConfetti = useCallback(() => { const end = Date.now() + 3 * 1000; // 3 seconds const colors = ["#a786ff", "#fd8bbc", "#eca184", "#f8deb1"]; const frame = () => { @@ -130,68 +123,75 @@ export default function DownloadPage() { requestAnimationFrame(frame); }; frame(); - }; + }, []); - const startDownload = () => { - let releaseTarget: string; + const getReleaseTarget = useCallback((): + | keyof typeof releases + | undefined => { if (selectedLinuxDownloadType === "flatpak") { - window.open( + router.push( "https://dl.flathub.org/repo/appstream/io.github.zen_browser.zen.flatpakref" ); - releaseTarget = "flatpak"; - } else { - const platform = releaseTree[selectedPlatform.toLowerCase()]; - let arch: string = selectedArchitecture; - if (selectedPlatform === "MacOS") { - releaseTarget = platform[arch]; - } else { - releaseTarget = - platform[arch][ - selectedPlatform === "Windows" - ? (selectedWindowsDownloadType as string) - : (selectedLinuxDownloadType as string) - ]; - } - console.log("Downloading: "); - console.log("platform: ", selectedPlatform); - console.log("compat: ", arch); - window.location.replace(`${BASE_URL}/${releases[releaseTarget]}`); + return; } - setHasDownloaded(true); - addDownload(releaseTarget); - throwConfetti(); - }; - const continueFlow = () => { + 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 === 1) setArchitecture(selectedArchitecture); if (flowIndex === 2 || (flowIndex === 1 && platform === "MacOS")) { - setWindowsDownloadType(selectedWindowsDownloadType); - setLinuxDownloadType(selectedLinuxDownloadType); startDownload(); } setFlowIndex(flowIndex + 1); - }; + }, [flowIndex, platform, selectedPlatform, startDownload]); - const goBackFlow = () => { - if (flowIndex === 1) { - setPlatform(null); - } else if (flowIndex === 2) { - setArchitecture(null); - } else if (flowIndex === 3) { - setWindowsDownloadType(null); + const goBackFlow = useCallback(() => { + if (flowIndex === 1) setPlatform(null); + else if (flowIndex === 3) { setSelectedWindowsDownloadType("installer"); - setLinuxDownloadType(null); setSelectedLinuxDownloadType("portable"); } if (flowIndex > 0) setFlowIndex(flowIndex - 1); - }; + }, [flowIndex]); - const changeToFlatpak = () => { - if (selectedArchitecture === "specific") { - setSelectedLinuxDownloadType("flatpak"); - } - }; + const changeToFlatpak = useCallback(() => { + if (selectedArchitecture !== "specific") return; + setSelectedLinuxDownloadType("flatpak"); + }, [selectedArchitecture]); + + useEffect(() => { + detectPlatform(); + }, [detectPlatform]); return ( <> @@ -244,63 +244,52 @@ export default function DownloadPage() { )} )) || ( <> -

Download

+

+ 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. + 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 === null && ( - +
+ {/* Platform */} + {!platform && ( + Platform Choose the platform you want to download Zen for. -
setSelectedPlatform("Windows")} - className={ny( - "select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", - selectedPlatform === "Windows" ? "border-blue-400" : "" - )} - > - - -
Windows
-
-
setSelectedPlatform("Linux")} - className={ny( - "select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", - selectedPlatform === "Linux" ? "border-yellow-400" : "" - )} - > - - -
Linux
-
-
setSelectedPlatform("MacOS")} - className={ny( - "select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", - selectedPlatform === "MacOS" ? "border-purple-400" : "" - )} - > - - -
MacOS
-
+ {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 */} @@ -322,38 +311,30 @@ export default function DownloadPage() { 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" - : "" + selectedArchitecture === "specific" && "border-blue-400" )} > -

- 🚀 -

-

Optimized

-

+

🚀

+

Optimized

+

Blazing fast and compatible with modern devices

setSelectedArchitecture("generic")} className={ny( - "select-none w-full h-full mb-2 ml-10 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", - selectedArchitecture === "generic" - ? "border-blue-400" - : "" + "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

-

+

👴

+

Generic

+

Slow but compatible with older devices.

@@ -369,39 +350,33 @@ export default function DownloadPage() { Click the button below to download Zen for MacOS. -
-
+
-
🍏 +

aarch64

+

+ 64-bit ARM architecture, for Apple's M Series Chips +

+ +
+
)} @@ -416,41 +391,35 @@ export default function DownloadPage() { Choose the type of download you want for Zen for Windows. -
-
+
-
+
+
)} @@ -465,61 +434,51 @@ export default function DownloadPage() { 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", - selectedLinuxDownloadType === "appimage" - ? "border-blue-400" - : "" + "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

-

+

🚀

+

AppImage

+

Install Zen with a setup wizard

-
-
+
setSelectedLinuxDownloadType("portable")} className={ny( - "select-none w-full h-full mb-2 ml-5 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", - selectedLinuxDownloadType === "portable" - ? "border-blue-400" - : "" + "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

-

+

📦

+

Portable

+

Download Zen as a ZIP file

-
-
changeToFlatpak()} + +
-

- 🧑‍💻 -

-

Flatpak

-

+

🧑‍💻

+

Flatpak

+

Install Zen from the Flatpak repository.

-
+
)} @@ -528,19 +487,13 @@ export default function DownloadPage() {
-