refactor: Improve responsiveness of Features component layout

This commit is contained in:
Pratyay360
2024-08-12 21:33:45 +05:30
parent b4034ac07a
commit ff19d50cda
10 changed files with 612 additions and 298 deletions

View File

@@ -1,35 +1,18 @@
"use client";
import { addDownload } from "@/lib/db";
import { useState } from "react";
import { useState, useEffect } 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 confetti from "canvas-confetti";
import { releases, releaseTree } from "@/lib/releases";
import { InfoCircledIcon } from "@radix-ui/react-icons";
const BASE_URL = "https://github.com/zen-browser/desktop/releases/latest/download";
function getDefaultPlatformBasedOnUserAgent() {
let userAgent = "";
if (typeof window !== "undefined") {
userAgent = window.navigator.userAgent;
}
if (userAgent.includes("Win")) {
return "Windows";
}
if (userAgent.includes("Mac")) {
return "MacOS";
}
if (userAgent.includes("Linux")) {
return "Linux";
}
return "";
}
import Link from "next/link";
const BASE_URL =
"https://github.com/zen-browser/desktop/releases/latest/download";
const field_enter = keyframes`
0% {
@@ -64,14 +47,15 @@ const field_exit = keyframes`
}
`;
const FormField = styled.div<{ enter: boolean, out: boolean }>`
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 ${({ enter, out }) => enter ? field_enter : out ? field_exit : ""} !important;
animation-delay: ${({ enter }) => enter ? "0.4s" : "0s"};
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 = styled.div`
@@ -88,24 +72,43 @@ const FieldDescription = styled.div`
export default function DownloadPage() {
const [platform, setPlatform] = useState<string | null>(null);
const [architecture, setArchitecture] = useState<string | null>(null);
const [windowsDownloadType, setWindowsDownloadType] = useState<string | null>(null);
const [linuxDownloadType, setLinuxDownloadType] = useState<string | null>(null);
const [windowsDownloadType, setWindowsDownloadType] = useState<string | null>(
null
);
const [linuxDownloadType, setLinuxDownloadType] = useState<string | null>(
null
);
const [selectedPlatform, setSelectedPlatform] = useState(getDefaultPlatformBasedOnUserAgent());
const [selectedPlatform, setSelectedPlatform] = useState("");
const [selectedArchitecture, setSelectedArchitecture] = useState("specific");
const [selectedWindowsDownloadType, setSelectedWindowsDownloadType] = useState("installer");
const [selectedLinuxDownloadType, setSelectedLinuxDownloadType] = useState("portable");
const [selectedWindowsDownloadType, setSelectedWindowsDownloadType] =
useState("installer");
const [selectedLinuxDownloadType, setSelectedLinuxDownloadType] =
useState("portable");
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")) {
setSelectedPlatform("Windows");
}
if (userAgent.includes("Mac")) {
setSelectedPlatform("MacOS");
}
if (userAgent.includes("Linux")) {
setSelectedPlatform("Linux");
}
}, []);
const throwConfetti = () => {
const end = Date.now() + 3 * 1000 // 3 seconds
const colors = ['#a786ff', '#fd8bbc', '#eca184', '#f8deb1']
const end = Date.now() + 3 * 1000; // 3 seconds
const colors = ["#a786ff", "#fd8bbc", "#eca184", "#f8deb1"];
const frame = () => {
if (Date.now() > end)
return
if (Date.now() > end) return;
confetti({
particleCount: 2,
@@ -114,7 +117,7 @@ export default function DownloadPage() {
startVelocity: 60,
origin: { x: 0, y: 0.5 },
colors,
})
});
confetti({
particleCount: 2,
angle: 120,
@@ -122,16 +125,18 @@ export default function DownloadPage() {
startVelocity: 60,
origin: { x: 1, y: 0.5 },
colors,
})
requestAnimationFrame(frame)
}
frame()
}
});
requestAnimationFrame(frame);
};
frame();
};
const startDownload = () => {
let releaseTarget: string;
if (selectedLinuxDownloadType === "flatpak") {
window.open("https://dl.flathub.org/repo/appstream/io.github.zen_browser.zen.flatpakref");
window.open(
"https://dl.flathub.org/repo/appstream/io.github.zen_browser.zen.flatpakref"
);
releaseTarget = "flatpak";
} else {
const platform = releaseTree[selectedPlatform.toLowerCase()];
@@ -139,9 +144,12 @@ export default function DownloadPage() {
if (selectedPlatform === "MacOS") {
releaseTarget = platform[arch];
} else {
releaseTarget = platform[arch][selectedPlatform === "Windows"
? selectedWindowsDownloadType as string
: selectedLinuxDownloadType as string];
releaseTarget =
platform[arch][
selectedPlatform === "Windows"
? (selectedWindowsDownloadType as string)
: (selectedLinuxDownloadType as string)
];
}
console.log("Downloading: ");
console.log("platform: ", selectedPlatform);
@@ -154,10 +162,8 @@ export default function DownloadPage() {
};
const continueFlow = () => {
if (flowIndex === 0)
setPlatform(selectedPlatform);
if (flowIndex === 1)
setArchitecture(selectedArchitecture);
if (flowIndex === 0) setPlatform(selectedPlatform);
if (flowIndex === 1) setArchitecture(selectedArchitecture);
if (flowIndex === 2 || (flowIndex === 1 && platform === "MacOS")) {
setWindowsDownloadType(selectedWindowsDownloadType);
setLinuxDownloadType(selectedLinuxDownloadType);
@@ -168,7 +174,7 @@ export default function DownloadPage() {
const goBackFlow = () => {
if (flowIndex === 1) {
setPlatform(null);
setPlatform(null);
} else if (flowIndex === 2) {
setArchitecture(null);
} else if (flowIndex === 3) {
@@ -176,67 +182,122 @@ export default function DownloadPage() {
setSelectedWindowsDownloadType("installer");
setLinuxDownloadType(null);
setSelectedLinuxDownloadType("portable");
}
if (flowIndex > 0)
setFlowIndex(flowIndex - 1);
}
}
if (flowIndex > 0) setFlowIndex(flowIndex - 1);
};
const changeToFlatpak = () => {
if (selectedArchitecture === "specific") {
setSelectedLinuxDownloadType("flatpak");
}
}
};
return (
<>
<link rel="stylesheet" type='text/css' href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css" />
<link rel="stylesheet" type='text/css' href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css" />
<link rel="stylesheet" type='text/css' href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css" />
<link
rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
/>
<link
rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
/>
<link
rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
/>
<div className="w-full overflow-hidden relative h-screen flex items-center justify-center flex-col lg:flex-row">
<div className="flex flex-col justify-center w-full p-10 md:p-0 md:p-20 lg:p-0 lg:w-1/2 2xl:w-1/3 mx-auto">
{hasDownloaded && (
<div className="flex flex-col justify-center w-full p-10 md:p-20 lg:p-0 lg:w-1/2 2xl:w-1/3 mx-auto">
{(hasDownloaded && (
<div className="flex items-center justify-center flex-col">
<h1 className="text-6xl font-bold">Downloaded! </h1>
<p className="text-muted-foreground mt-3">Zen Browser has been downloaded successfully. Enjoy browsing the web with Zen!</p>
<p className="text-muted-foreground mt-3">
Zen Browser has been downloaded successfully. Enjoy browsing the
web with Zen!
</p>
<div className="flex font-bold mt-5 items-center justify-between mx-auto">
<a href="https://github.com/zen-browser">Source Code</a>
<a className="ml-5" href="https://patreon.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink">Donate</a>
<a className="ml-5" href="/release-notes/latest">Release Notes</a>
<Link href="https://github.com/zen-browser">Source Code</Link>
<Link
className="ml-5"
href="https://patreon.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink"
>
Donate
</Link>
<Link className="ml-5" href="/release-notes/latest">
Release Notes
</Link>
</div>
{selectedPlatform === "MacOS" && (
<div className="mt-12 flex flex-col items-start border justify-between rounded-md bg-background p-5">
<h3 className="text-xl font-semibold">Installation Instructions</h3>
<p className="text-muted-foreground text-sm ">To install Zen on MacOS, the process is a bit different. Please follow the instructions below:</p>
<Button className="mt-5" onClick={() => window.location.href = "https://github.com/zen-browser/desktop/issues/53"}>Download Zen for MacOS</Button>
<h3 className="text-xl font-semibold">
Installation Instructions
</h3>
<p className="text-muted-foreground text-sm ">
To install Zen on MacOS, the process is a bit different.
Please follow the instructions below:
</p>
<Button
className="mt-5"
onClick={() =>
(window.location.href =
"https://github.com/zen-browser/desktop/issues/53")
}
>
Download Zen for MacOS
</Button>
</div>
)}
</div>
) || (
)) || (
<>
<h1 className="text-6xl font-bold">Download Zen</h1>
<p className="text-muted-foreground mt-3">We are so excited for you to try Zen Browser. But first, we need to know what kind of device you are using. It will be fast, we promise.</p>
<p className="text-muted-foreground mt-3">
We are so excited for you to try Zen Browser. But first, we need
to know what kind of device you are using. It will be fast, we
promise.
</p>
</>
)}
<div className="relative w-full">
{platform === null && (
<FormField
enter={platform === null}
out={platform !== null}
>
<FormField enter={platform === null} out={platform !== null}>
<FieldTitle>Platform</FieldTitle>
<FieldDescription>Choose the platform you want to download Zen for.</FieldDescription>
<div onClick={() => 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" : "")}>
<FieldDescription>
Choose the platform you want to download Zen for.
</FieldDescription>
<div
onClick={() => 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" : ""
)}
>
<Checkbox checked={selectedPlatform === "Windows"} />
<i className="devicon-windows8-original ml-3 p-2 border border-blue-400 rounded-lg"></i>
<div className="ml-2">Windows</div>
</div>
<div onClick={() => 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" : "")}>
<Checkbox checked={selectedPlatform === "Linux"} />
<div
onClick={() => 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" : ""
)}
>
<Checkbox checked={selectedPlatform === "Linux"} />
<i className="devicon-linux-plain ml-3 p-2 border border-yellow-400 rounded-lg"></i>
<div className="ml-2">Linux</div>
</div>
<div onClick={() => 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" : "")}>
<div
onClick={() => 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" : ""
)}
>
<Checkbox checked={selectedPlatform === "MacOS"} />
<i className="devicon-apple-original p-2 border border-purple-400 ml-3 rounded-lg"></i>
<div className="ml-2 font-bold">MacOS</div>
@@ -244,94 +305,219 @@ export default function DownloadPage() {
</FormField>
)}
{/* Architecture */}
{((platform === "Windows" || platform === "Linux") && flowIndex === 1) && (
<FormField
enter={platform === "Windows" || platform === "Linux" && flowIndex === 1}
out={platform !== "Windows" && platform !== "Linux" && flowIndex >= 1}
>
<FieldTitle>Select Architecture</FieldTitle>
<FieldDescription>Choose the architecture of your device, either optimized or generic.</FieldDescription>
<div className="flex items-center justify-center">
<div onClick={() => 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" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">🚀</h1>
<h1 className="text-2xl font-semibold my-2">Optimized</h1>
<p className="text-muted-foreground mx-auto text-center">Blazing fast and compatible with modern devices</p>
{(platform === "Windows" || platform === "Linux") &&
flowIndex === 1 && (
<FormField
enter={
platform === "Windows" ||
(platform === "Linux" && flowIndex === 1)
}
out={
platform !== "Windows" &&
platform !== "Linux" &&
flowIndex >= 1
}
>
<FieldTitle>Select Architecture</FieldTitle>
<FieldDescription>
Choose the architecture of your device, either optimized or
generic.
</FieldDescription>
<div className="flex items-center justify-center">
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
🚀
</h1>
<h1 className="text-2xl font-semibold my-2">Optimized</h1>
<p className="text-muted-foreground mx-auto text-center">
Blazing fast and compatible with modern devices
</p>
</div>
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
👴
</h1>
<h1 className="text-2xl font-semibold my-2">Generic</h1>
<p className="text-muted-foreground mx-auto text-center">
Slow but compatible with older devices.
</p>
</div>
</div>
<div onClick={() => 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" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">👴</h1>
<h1 className="text-2xl font-semibold my-2">Generic</h1>
<p className="text-muted-foreground mx-auto text-center">Slow but compatible with older devices.</p>
</div>
</div>
</FormField>
)}
{(platform === "MacOS" && flowIndex === 1) && (
</FormField>
)}
{platform === "MacOS" && flowIndex === 1 && (
<FormField
enter={platform === "MacOS"}
out={platform !== "MacOS"}
>
<FieldTitle>Download Zen for MacOS</FieldTitle>
<FieldDescription>Click the button below to download Zen for MacOS.</FieldDescription>
<FieldDescription>
Click the button below to download Zen for MacOS.
</FieldDescription>
<div className="flex items-center justify-center">
<div onClick={() => 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" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">🍏</h1>
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
🍏
</h1>
<h1 className="text-2xl font-semibold my-2">aarch64</h1>
<p className="text-muted-foreground mx-auto text-center">64-bit ARM architecture, for Apple's M1 or M2 chips</p>
<p className="text-muted-foreground mx-auto text-center">
64-bit ARM architecture, for Apple's M1 or M2 chips
</p>
</div>
<div onClick={() => 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" : "")}>
<h1 className="text-5xl font-bold my-2 opacity-40 dark:opacity-20">x64</h1>
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl font-bold my-2 opacity-40 dark:opacity-20">
x64
</h1>
<h1 className="text-2xl font-semibold my-2">Intel</h1>
<p className="text-muted-foreground mx-auto text-center">64-bit Intel architecture, for older Macs</p>
<p className="text-muted-foreground mx-auto text-center">
64-bit Intel architecture, for older Macs
</p>
</div>
</div>
</FormField>
)}
{flowIndex === 2 && (platform === "Windows") && (
{flowIndex === 2 && platform === "Windows" && (
<FormField
enter={platform === "Windows" && flowIndex === 2}
out={platform !== "Windows" && flowIndex >= 2}
>
<FieldTitle
className="text-2xl"
>Download Zen for Windows {selectedArchitecture}</FieldTitle>
<FieldDescription>Choose the type of download you want for Zen for Windows.</FieldDescription>
<FieldTitle className="text-2xl">
Download Zen for Windows {selectedArchitecture}
</FieldTitle>
<FieldDescription>
Choose the type of download you want for Zen for Windows.
</FieldDescription>
<div className="flex items-center justify-center">
<div onClick={() => setSelectedWindowsDownloadType("installer")} className={ny("select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", selectedWindowsDownloadType === "installer" ? "border-blue-400" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">🚀</h1>
<div
onClick={() => setSelectedWindowsDownloadType("installer")}
className={ny(
"select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border",
selectedWindowsDownloadType === "installer"
? "border-blue-400"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
🚀
</h1>
<h1 className="text-2xl font-semibold my-2">Installer</h1>
<p className="text-muted-foreground mx-auto text-center">Install Zen with a setup wizard</p>
<p className="text-muted-foreground mx-auto text-center">
Install Zen with a setup wizard
</p>
</div>
<div onClick={() => setSelectedWindowsDownloadType("portable")} 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", selectedWindowsDownloadType === "portable" ? "border-blue-400" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">📦</h1>
<div
onClick={() => setSelectedWindowsDownloadType("portable")}
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",
selectedWindowsDownloadType === "portable"
? "border-blue-400"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
📦
</h1>
<h1 className="text-2xl font-semibold my-2">Portable</h1>
<p className="text-muted-foreground mx-auto text-center">Download Zen as a ZIP file</p>
<p className="text-muted-foreground mx-auto text-center">
Download Zen as a ZIP file
</p>
</div>
</div>
</FormField>
)}
{flowIndex === 2 && (platform === "Linux") && (
{flowIndex === 2 && platform === "Linux" && (
<FormField
enter={platform === "Linux" && flowIndex === 2}
out={platform !== "Linux" && flowIndex >= 2}
>
<FieldTitle
className="text-2xl"
>Download Zen for Linux {selectedArchitecture}</FieldTitle>
<FieldDescription>Choose the type of download you want for Zen for Linux.</FieldDescription>
<FieldTitle className="text-2xl">
Download Zen for Linux {selectedArchitecture}
</FieldTitle>
<FieldDescription>
Choose the type of download you want for Zen for Linux.
</FieldDescription>
<div className="flex items-center justify-center">
<div onClick={() => 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" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">🚀</h1>
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
🚀
</h1>
<h1 className="text-2xl font-semibold my-2">AppImage</h1>
<p className="text-muted-foreground mx-auto text-center">Install Zen with a setup wizard</p>
<p className="text-muted-foreground mx-auto text-center">
Install Zen with a setup wizard
</p>
</div>
<div onClick={() => 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" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">📦</h1>
<div
onClick={() => 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"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
📦
</h1>
<h1 className="text-2xl font-semibold my-2">Portable</h1>
<p className="text-muted-foreground mx-auto text-center">Download Zen as a ZIP file</p>
<p className="text-muted-foreground mx-auto text-center">
Download Zen as a ZIP file
</p>
</div>
<div onClick={() => changeToFlatpak()} 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 === "flatpak" ? "border-blue-400" : "",
selectedArchitecture === "generic" ? "opacity-50 cursor-not-allowed" : "")}>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">🧑💻</h1>
<div
onClick={() => changeToFlatpak()}
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 === "flatpak"
? "border-blue-400"
: "",
selectedArchitecture === "generic"
? "opacity-50 cursor-not-allowed"
: ""
)}
>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20">
🧑💻
</h1>
<h1 className="text-2xl font-semibold my-2">Flatpak</h1>
<p className="text-muted-foreground mx-auto text-center">
Install Zen from the Flatpak repository.
@@ -343,23 +529,44 @@ export default function DownloadPage() {
</div>
{!hasDownloaded && (
<div className="mt-5 flex items-center justify-between">
<Button variant="ghost" onClick={() => goBackFlow()} className={ny("opacity-70", platform === null ? "invisible" : "")}>
<Button
variant="ghost"
onClick={() => goBackFlow()}
className={ny(
"opacity-70",
platform === null ? "invisible" : ""
)}
>
<ChevronLeft className="size-4" />
Back
</Button>
<Button onClick={() => continueFlow()} disabled={
(selectedPlatform === null)
}>
{((flowIndex === 1 && platform === "MacOS") || flowIndex === 2) ? "Download 🥳" : "Continue"}
<Button
onClick={() => continueFlow()}
disabled={selectedPlatform === null}
>
{(flowIndex === 1 && platform === "MacOS") || flowIndex === 2
? "Download 🥳"
: "Continue"}
</Button>
</div>
)}
{((platform === "Linux" || platform === "Windows") && flowIndex === 1) && (
<div className="mt-5 flex items-center">
<InfoCircledIcon className="size-4 mr-2" />
<p className="text-muted-foreground">Confused about which build to choose? <a href="https://github.com/zen-browser/desktop/blob/main/docs/requirements.md#supported-cpus-for-optimized-builds-windows-and-linux" target="_blank" className="text-blue-400">System requirements</a>.</p>
</div>
)}
{(platform === "Linux" || platform === "Windows") &&
flowIndex === 1 && (
<div className="mt-5 flex items-center">
<InfoCircledIcon className="size-4 mr-2" />
<p className="text-muted-foreground">
Confused about which build to choose?{" "}
<Link
href="https://github.com/zen-browser/desktop/blob/main/docs/requirements.md#supported-cpus-for-optimized-builds-windows-and-linux"
target="_blank"
className="text-blue-400"
>
System requirements
</Link>
.
</p>
</div>
)}
</div>
</div>
<Particles

View File

@@ -3,6 +3,7 @@ import Feature, { FeatureCard } from "./feature";
import { Button } from "./ui/button";
import TextReveal from "./ui/text-reveal";
import styled, { css, keyframes } from "styled-components";
import Link from "next/link";
import {
Table,
TableBody,
@@ -13,10 +14,21 @@ import {
TableHeader,
TableRow,
} from "./ui/table";
import { CheckIcon, EyeIcon, EyeOffIcon, RabbitIcon, XIcon } from "lucide-react";
import { EyeClosedIcon, LockClosedIcon, QuestionMarkIcon } from "@radix-ui/react-icons";
import {
CheckIcon,
EyeIcon,
EyeOffIcon,
RabbitIcon,
XIcon,
} from "lucide-react";
import {
EyeClosedIcon,
LockClosedIcon,
QuestionMarkIcon,
} from "@radix-ui/react-icons";
import ShineBorder from "./ui/shine-border";
import SparklesText from "./ui/sparkles-text";
import Image from "next/image";
function Checkmark() {
return (
@@ -40,8 +52,14 @@ export default function Features() {
return (
<div className="relative">
{/*<TextReveal text="Zen will change the way you browse the web. 🌟" />*/}
<h1 className="text-5xl font-bold mt-20 text-center p-5 md:p-0 flex flex-col md:flex-row justify-center items-center mb-2">What does Zen offer to <SparklesText className="mx-2" text="YOU" />?</h1>
<p className="text-muted-foreground text-center mx-auto w-3/4 md:w-full p-5 lg:p-0 mb-24">Zen Browser is packed with features that will change the way you browse the web. Here are<br className="hidden md:block"/> some of the features that Zen offers.</p>
<h1 className="text-5xl font-bold mt-20 text-center p-5 md:p-0 flex flex-col md:flex-row justify-center items-center mb-2">
What does Zen offer to <SparklesText className="mx-2" text="YOU" />?
</h1>
<p className="text-muted-foreground text-center mx-auto w-3/4 md:w-full p-5 lg:p-0 mb-24">
Zen Browser is packed with features that will change the way you browse
the web. Here are
<br className="hidden md:block" /> some of the features that Zen offers.
</p>
<div className="flex flex-col lg:flex-row w-full mt-4 p-5 lg:p-0">
<div className="w-full flex mx-auto lg:mx-0 flex-col lg:mb-24 lg:ml-4 lg:mt-24">
<div className="hover:border-blue-500 transition-all duration-100 bg-background relative mx-auto lg:mx-0 flex flex-col max-w-lg justify-center rounded-xl md:border-2 p-20 md:shadow-xl">
@@ -50,7 +68,13 @@ export default function Features() {
Split your browser into multiple views to browse multiple websites
at once.
</p>
<img src="/split-view.png" className="mt-8 w-full h-full" />
<Image
height={500}
width={300}
src="/split-view.png"
className="mt-8 w-full h-full"
alt=""
/>
</div>
<div className="hover:border-blue-500 transition-all duration-100 bg-background mx-auto lg:mx-0 relative flex flex-col mt-8 max-w-lg justify-center rounded-xl md:border-2 p-20 md:shadow-xl">
<h1 className="text-5xl font-bold">Workspaces</h1>
@@ -58,7 +82,13 @@ export default function Features() {
Create workspaces to keep your tabs organized and your browsing
experience clutter-free.
</p>
<img src="/workspaces.png" className="mt-8 w-full h-full" />
<Image
height={500}
width={300}
src="/workspaces.png"
className="mt-8 w-full h-full"
alt=""
/>
</div>
</div>
<div className="w-full lg:mr-4 flex flex-col">
@@ -68,7 +98,13 @@ export default function Features() {
Switch between profiles to keep your work and personal browsing
separate.
</p>
<img src="/profiles.png" className="mt-8 w-full h-full" />
<Image
height={500}
width={300}
src="/profiles.png"
className="mt-8 w-full h-full"
alt=""
/>
</div>
<div className="hover:border-blue-500 transition-all duration-100 bg-background relative mx-auto lg:mx-0 mt-8 flex-col flex max-w-lg justify-center rounded-xl md:border-2 p-20 md:shadow-xl">
<h1 className="text-5xl font-bold">Side web panels</h1>
@@ -76,7 +112,13 @@ export default function Features() {
Access your favorite websites and services without leaving the
page you're on.
</p>
<img src="/sidebar.png" className="mt-8 w-full h-full" />
<Image
height={500}
width={300}
src="/sidebar.png"
className="mt-8 w-full h-full"
alt=""
/>
</div>
</div>
</div>
@@ -95,9 +137,36 @@ export default function Features() {
How Zen differs from other browsers
</span>
</TableHead>
<TableHead className="py-2 font-bold text-center"><img src="/favicon.ico" className="bg-black dark:bg-white rounded-md mx-auto mb-2 w-8 h-8" />Zen</TableHead>
<TableHead className="py-2 pl-4 pr-0 font-bold text-center opacity-60"><img src="/floorp.png" className="bg-black dark:bg-white rounded-md p-1 mx-auto mb-2 w-7 h-7" />Floorp</TableHead>
<TableHead className="py-2 pl-0 font-bold text-center opacity-60"><img src="/librewolf.png" className="bg-black dark:bg-white rounded-md mx-auto p-1 mb-2 w-7 h-7" />LibreWolf</TableHead>
<TableHead className="py-2 font-bold text-center">
<Image
height={32}
width={32}
src="/favicon.ico"
className="bg-black dark:bg-white rounded-md mx-auto mb-2 w-8 h-8"
alt="zen"
/>
Zen
</TableHead>
<TableHead className="py-2 pl-4 md:pr-0 pr-2 font-bold text-center opacity-60">
<Image
height={32}
width={32}
src="/floorp.png"
className="bg-black dark:bg-white rounded-md p-1 mx-auto mb-2 w-7 h-7"
alt="floorp"
/>
Floorp
</TableHead>
<TableHead className="py-2 pl-0 font-bold text-center opacity-60">
<Image
height={32}
width={32}
src="/librewolf.png"
className="bg-black dark:bg-white rounded-md mx-auto p-1 mb-2 w-7 h-7"
alt="librewolf"
/>
LibreWolf
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -162,31 +231,45 @@ export default function Features() {
</div>
</ShineBorder>
<div className="flex flex-col items-center justify-center w-full mt-40">
<div className="flex flex-col lg:flex-row w-full mt-4 p-5 justify-between items-center">
<div className="flex flex-wrap lg:flex-row w-full mt-4 p-5 justify-between items-center">
<RabbitIcon className="mx-auto hidden md:block w-32 h-32" />
<div className="flex flex-col max-w-lg text-center md:text-start">
<h1 className="text-5xl font-bold flex items-center flex-col md:flex-row">Built for <SparklesText className="md:mx-2" text="speed" /></h1>
<p className="text-muted-foreground mt-3">
Zen is built with speed in mind. Improving release after release, with new optimizations and technologies to make your browsing experience faster.<br /><br />
We have been working and benchmarking Zen to make it the fastest browser out there.
<h1 className="text-5xl font-bold flex items-center flex-col md:flex-row">
Built for <SparklesText className="md:mx-2" text="speed" />
</h1>
<p className="flex flex-wrap overflow-auto text-muted-foreground mt-3">
Zen is built with speed in mind. Improving release after release,
with new optimizations and technologies to make your browsing
experience faster.
<br className="hidden md:block" />
<br className="hidden md:block" />
We have been working and benchmarking Zen to make it the fastest
browser out there.
</p>
</div>
</div>
<div className="flex flex-col lg:flex-row w-full mt-52 p-5 justify-between items-center">
<div className="flex flex-col max-w-lg text-center md:text-start">
<h1 className="text-5xl font-bold flex flex-col md:flex-row items-center">Privacy is <SparklesText className="md:mx-2" text="key" /></h1>
<p className="text-muted-foreground mt-3">
Zen is designed with privacy in mind. We found the perfect balance between privacy and functionality, so you can browse the web without worrying about your data.
<div className="flex flex-wrap max-w-lg text-center md:text-start">
<h1 className="text-5xl font-bold flex flex-wrap md:flex-row items-center">
Privacy is <SparklesText className="md:mx-2" text="key" />
</h1>
<p className="text-muted-foreground mt-3 overflow-auto">
Zen is designed with privacy in mind. We found the perfect balance
between privacy and functionality, so you can browse the web
without worrying about your data.
</p>
</div>
<EyeClosedIcon className="mx-auto hidden md:block w-32 h-32" />
</div>
<div className="flex flex-col lg:flex-row w-full mt-52 p-5 justify-between items-center">
<div className="flex flex-wrap lg:flex-row w-full mt-52 p-5 justify-between items-center">
<LockClosedIcon className="mx-auto hidden md:block w-32 h-32" />
<div className="flex flex-col text-center md:text-start max-w-lg">
<h1 className="text-5xl font-bold items-center flex-col">Security is <SparklesText className="inline" text="important" /></h1>
<p className="text-muted-foreground mt-3">
Zen is built with security in mind. We use the latest technologies and security measures that no other firefox-based browser offers.
<div className="flex flex-wrap text-center md:text-start max-w-lg">
<h1 className="text-5xl font-bold items-center flex-col">
Security is <SparklesText className="inline" text="important" />
</h1>
<p className=" text-muted-foreground mt-3 overflow-auto">
Zen is built with security in mind. We use the latest technologies
and security measures that no other firefox-based browser offers.
</p>
</div>
</div>
@@ -199,26 +282,35 @@ export default function Features() {
the web.
</p>
<div className="grid gap-5 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-10">
<FeatureCard title="Beautifully designed"
description="Zen is designed to be easy to use and beautiful to look at." />
<FeatureCard title="Customizable"
description="Customize Zen to fit your needs. Change the theme, layout, and more." />
<FeatureCard title="Keyboard shortcuts"
description="Navigate Zen with ease using keyboard shortcuts." />
<FeatureCard title="Your browsing experience, your way"
description="Zen is designed to be customizable to fit your needs." />
<FeatureCard title="Tab groups"
description="Organize your tabs into groups to keep your browsing experience organized."
todo />
<FeatureCard title="Vertical tabs"
description="Keep your tabs organized with vertical tabs." />
<FeatureCard
title="Beautifully designed"
description="Zen is designed to be easy to use and beautiful to look at."
/>
<FeatureCard
title="Customizable"
description="Customize Zen to fit your needs. Change the theme, layout, and more."
/>
<FeatureCard
title="Keyboard shortcuts"
description="Navigate Zen with ease using keyboard shortcuts."
/>
<FeatureCard
title="Your browsing experience, your way"
description="Zen is designed to be customizable to fit your needs."
/>
<FeatureCard
title="Tab groups"
description="Organize your tabs into groups to keep your browsing experience organized."
todo
/>
<FeatureCard
title="Vertical tabs"
description="Keep your tabs organized with vertical tabs."
/>
</div>
<Button
onClick={() => (window.location.href = "/download")}
className="mt-8"
>
Download Zen Browser
</Button>
<Link href="/download">
<Button className="mt-8">Download Zen Browser</Button>
</Link>
</div>
</div>
);

View File

@@ -1,12 +1,18 @@
import Link from "next/link";
import Logo from "./logo";
import TextReveal from "./ui/text-reveal";
export default function Footer() {
return (
<div className="font-medium flex-col md:flex-row px-10 md:px-0 border-t w-full border-grey py-10 mt-10 flex justify-center align-center">
Zen Browser © {new Date().getFullYear()} -
Made with by the Zen team.
<a className="mt-5 md:mt-0 md:ml-2 font-bold" href="https://github.com/zen-browser" target="_blank">Source Code</a>
Zen Browser © {new Date().getFullYear()} - Made with by the Zen team.
<Link
href={"https://github.com/zen-browser"}
target="_blank"
className="mt-5 md:mt-0 md:ml-2 font-bold"
>
Source Code
</Link>
</div>
);
}

View File

@@ -1,86 +1,88 @@
'use client'
import { ArrowRightIcon } from '@radix-ui/react-icons'
import { useInView } from 'framer-motion'
import { useRef } from 'react'
import AnimatedGradientText from './ui/animated-gradient-text'
import { Button } from './ui/button'
import { BorderBeam } from './ui/border-beam'
import { ny } from '@/lib/utils'
import { ChevronRight } from 'lucide-react'
import Particles from './ui/particles'
"use client";
import { ArrowRightIcon } from "@radix-ui/react-icons";
import { useInView } from "framer-motion";
import { useRef } from "react";
import AnimatedGradientText from "./ui/animated-gradient-text";
import { Button } from "./ui/button";
import { BorderBeam } from "./ui/border-beam";
import { ny } from "@/lib/utils";
import { ChevronRight } from "lucide-react";
import Particles from "./ui/particles";
import Image from "next/image";
import Link from "next/link";
export default function Header() {
const ref = useRef(null)
const inView = useInView(ref, { once: true, margin: '-100px' })
return (
const ref = useRef(null);
const inView = useInView(ref, { once: true, margin: "-100px" });
return (
<>
<section
id="hero"
className="relative mx-auto mt-40 max-w-7xl px-6 text-center md:px-8"
id="hero"
className="relative mx-auto mt-40 max-w-7xl px-6 text-center md:px-8"
>
<a href="/download">
<AnimatedGradientText>
🎉
{' '}
<hr className="mx-2 h-4 w-[1px] shrink-0 bg-gray-300" />
{' '}
<span
className={ny(
`inline animate-gradient bg-gradient-to-r from-[#ffaa40] via-[#9c40ff] to-[#ffaa40] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent`,
)}
>
Introducing Zen Alpha
</span>
<ChevronRight className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
</AnimatedGradientText>
</a>
<h1 className="animate-fade-in -translate-y-4 text-balance bg-gradient-to-br from-black from-30% to-black/40 bg-clip-text py-6 text-5xl font-semibold leading-none tracking-tighter text-transparent opacity-0 [--animation-delay:200ms] sm:text-6xl md:text-7xl lg:text-8xl dark:from-white dark:to-white/40">
Zen is the best way
<br className="hidden md:block" />
{' '}
to browse the web.
</h1>
<p className="animate-fade-in mb-12 -translate-y-4 text-balance text-lg tracking-tight text-gray-400 opacity-0 [--animation-delay:400ms] md:text-xl">
Beautifully designed, privacy-focused, and packed with features.
<br className="hidden md:block" />
{' '}
We care about your experience, not your data.
</p>
<Button className="animate-fade-in -translate-y-4 gap-1 rounded-lg text-white opacity-0 ease-in-out [--animation-delay:600ms] dark:text-black" onClick={() => window.location.href = '/download'}>
<span>Download Zen Now </span>
<ArrowRightIcon className="ml-1 size-4 transition-transform duration-300 ease-in-out group-hover:translate-x-1" />
</Button>
<div
ref={ref}
className="animate-fade-up relative mt-32 opacity-0 [--animation-delay:400ms] [perspective:2000px] after:absolute after:inset-0 after:z-50 after:[background:linear-gradient(to_top,hsl(var(--background))_30%,transparent)]"
>
<div
className={`rounded-xl border border-white/10 bg-white bg-opacity-[0.01] before:absolute before:bottom-1/2 before:left-0 before:top-0 before:size-full before:opacity-0 before:[background-image:linear-gradient(to_bottom,var(--color-one),var(--color-one),transparent_40%)] before:[filter:blur(180px)] ${
inView ? 'before:animate-image-glow' : ''
}`}
<Link href="/download">
<AnimatedGradientText>
🎉 <hr className="mx-2 h-4 w-[1px] shrink-0 bg-gray-300" />{" "}
<span
className={ny(
`inline animate-gradient bg-gradient-to-r from-[#ffaa40] via-[#9c40ff] to-[#ffaa40] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent`
)}
>
<BorderBeam
size={200}
duration={12}
delay={11}
colorFrom="var(--color-one)"
colorTo="var(--color-two)"
/>
Introducing Zen Alpha
</span>
<ChevronRight className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
</AnimatedGradientText>
</Link>
<h1 className="animate-fade-in -translate-y-4 text-balance bg-gradient-to-br from-black from-30% to-black/40 bg-clip-text py-6 text-5xl font-semibold leading-none tracking-tighter text-transparent opacity-0 [--animation-delay:200ms] sm:text-6xl md:text-7xl lg:text-8xl dark:from-white dark:to-white/40">
Zen is the best way
<br className="hidden md:block" /> to browse the web.
</h1>
<p className="animate-fade-in mb-12 -translate-y-4 text-balance text-lg tracking-tight text-gray-400 opacity-0 [--animation-delay:400ms] md:text-xl">
Beautifully designed, privacy-focused, and packed with features.
<br className="hidden md:block" /> We care about your experience, not
your data.
</p>
<Link href="/download">
<Button
className="animate-fade-in -translate-y-4 gap-1 rounded-lg text-white opacity-0 ease-in-out [--animation-delay:600ms] dark:text-black"
>
<span>Download Zen Now </span>
<ArrowRightIcon className="ml-1 size-4 transition-transform duration-300 ease-in-out group-hover:translate-x-1" />
</Button>
</Link>
<div
ref={ref}
className="animate-fade-up relative mt-32 opacity-0 [--animation-delay:400ms] [perspective:2000px] after:absolute after:inset-0 after:z-50 after:[background:linear-gradient(to_top,hsl(var(--background))_30%,transparent)]"
>
<div
className={`rounded-xl border border-white/10 bg-white bg-opacity-[0.01] before:absolute before:bottom-1/2 before:left-0 before:top-0 before:size-full before:opacity-0 before:[background-image:linear-gradient(to_bottom,var(--color-one),var(--color-one),transparent_40%)] before:[filter:blur(180px)] ${
inView ? "before:animate-image-glow" : ""
}`}
>
<BorderBeam
size={200}
duration={12}
delay={11}
colorFrom="var(--color-one)"
colorTo="var(--color-two)"
/>
<img
src="/browser-dark.png"
alt="browser Image"
className="relative hidden size-full rounded-[inherit] border object-contain dark:block"
/>
<img
src="/browser-light.png"
alt="browser Image"
className="relative block size-full rounded-[inherit] border object-contain dark:hidden"
/>
</div>
</div>
<Image
width={1600}
height={800}
src="/browser-dark.png"
alt="browser Image"
className="relative hidden rounded-[inherit] border object-contain dark:block"
/>
<Image
width={1600}
height={800}
src="/browser-light.png"
alt="browser Image"
className="relative block rounded-[inherit] border object-contain dark:hidden"
/>
</div>
</div>
</section>
<Particles
className="absolute inset-0 -z-10 hidden dark:block"
@@ -99,5 +101,5 @@ export default function Header() {
color="#000000"
/>
</>
)
);
}

View File

@@ -1,8 +1,8 @@
import Image from "next/image";
export default function Logo({ withText, ...props }: any) {
return (
<div className="flex items-center m-0" {...props}>
<img src="/logo.png" alt="Zen Logo" className="w-12 h-12" />
<Image src="/logo.png" alt="Zen Logo" width={50} height={50} />
{withText && <span className="text-2xl font-bold ml-2">Zen</span>}
</div>
);

View File

@@ -33,7 +33,7 @@ export const components: { title: string; href: string; description: string }[]
export function Navigation() {
return (
<div className="bg-background fixed z-10 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
<div className="bg-background z-10 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
<MobileNav />
<NavigationMenu>
<NavigationMenuList className="w-full hidden sm:flex">
@@ -48,7 +48,7 @@ export function Navigation() {
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<li className="row-span-3">
<NavigationMenuLink asChild>
<a
<Link
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
href="/"
>
@@ -60,7 +60,7 @@ export function Navigation() {
Firefox based browser with a focus on privacy and
customization.
</p>
</a>
</Link>
</NavigationMenuLink>
</li>
<ListItem href="/download" title="Download">

View File

@@ -2,7 +2,7 @@ import { ReleaseNote } from "@/lib/release-notes";
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { CheckCheckIcon, StarIcon } from "lucide-react";
import { Button } from "./ui/button";
import Link from "next/link";
export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
return (
<div className="flex flex-col mt-52 mb-24">
@@ -10,7 +10,7 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
<h1 className="text-4xl font-bold">Release notes for {data.version} 🎉</h1>
<p className="text-sm mt-1 font-bold text-muted-foreground">{data.date}</p>
<p className="text-md mt-4 text-muted-foreground">
If you encounter any issues, please report them on <a href="https://github.com/zen-browser/desktop/issues/" className="text-underline text-blue-500">the issues page</a>. Thanks everyone for your feedback!
If you encounter any issues, please report them on <Link href="https://github.com/zen-browser/desktop/issues/" className="text-underline text-blue-500">the issues page</Link>. Thanks everyone for your feedback!
</p>
{data.extra && (
<p className="text-md mt-8" dangerouslySetInnerHTML=
@@ -57,21 +57,23 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
<li key={index} className="mt-1 text-muted-foreground">
{fix.description}
{fix.issue && (
<a
<Link
href={`https://github.com/zen-browser/desktop/issues/${fix.issue}`}
target="_blank"
className="ml-1 text-blue-500"
>
issue #{fix.issue}
</a>
</Link>
)}
</li>
))}
</ul>
</>
)}
)}
</div>
<Button className="mt-12 w-fit mx-auto" onClick={() => window.location.href = '/download'}>Download zen now!</Button>
</div>
<Link href='/download'>
<Button className="mt-12 w-fit mx-auto">Download zen now!</Button>
</Link>
</div>
);
}