From 937eae37926592b9e498579ced72fc13f01dcb31 Mon Sep 17 00:00:00 2001 From: zahyaah Date: Fri, 23 Aug 2024 02:27:32 +0530 Subject: [PATCH 01/23] fix typo and grammar in features.tsx --- src/components/features.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/features.tsx b/src/components/features.tsx index b5df379..214e3ab 100644 --- a/src/components/features.tsx +++ b/src/components/features.tsx @@ -73,7 +73,7 @@ export default function Features() { Goodbye bad performance

- We are constantly tweak firefox's engine and settings to make it + We are constantly tweaking Firefox's engine and settings to make it faster than ever. Learn more

@@ -101,7 +101,7 @@ export default function Features() { Secure by default

- We are always using the latest security features from firefox to + We are always using the latest security features from Firefox to keep you safe. Learn more

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 02/23] 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() {
- +
{COLORS.map((color) => ( @@ -163,7 +164,7 @@ export default function Features() { Killer feature
- +
diff --git a/src/components/release-note.tsx b/src/components/release-note.tsx index 8cf450a..9dc2c15 100644 --- a/src/components/release-note.tsx +++ b/src/components/release-note.tsx @@ -97,7 +97,7 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
- +
From da088d029266897771d54a328950d27058d296ab Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Fri, 23 Aug 2024 20:09:23 +0200 Subject: [PATCH 06/23] refactor: Disable "Create theme" button on CreateThemePage This commit disables the "Create theme" button on the CreateThemePage component by adding the `disabled` attribute to the Button component. This change is made to prevent users from creating new color themes for the browser until a more accessible solution is implemented. However, users can still create their own themes and share them with the community. --- src/components/create-theme.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/create-theme.tsx b/src/components/create-theme.tsx index 806be32..1d3be00 100644 --- a/src/components/create-theme.tsx +++ b/src/components/create-theme.tsx @@ -187,9 +187,12 @@ export default function CreateThemePage() { setDialogBg(e.target.value)} />
+
+ Right now, we aren't taking more color themes for the browser, until we find a way to make it more accessible for everyone. However, you can still create your own theme and share it with the community. +
- + From 1c0ad13629b762f7269830e13de0872022be2995 Mon Sep 17 00:00:00 2001 From: Shawn Santhoshgeorge <32755895+ShawnGeorge03@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:03:12 -0400 Subject: [PATCH 07/23] fix: Fixed download links for Branding Assets --- src/components/branding-assets.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/branding-assets.tsx b/src/components/branding-assets.tsx index fb14914..5100b07 100644 --- a/src/components/branding-assets.tsx +++ b/src/components/branding-assets.tsx @@ -1,3 +1,4 @@ + import { LOGO_COLORS } from "@/lib/logos"; export function BrandingAssets() { @@ -19,6 +20,7 @@ export function BrandingAssets() {
{color} @@ -40,7 +42,7 @@ export function BrandingAssets() {
{color} From de147a219f9358c5d81006bb34f59b090f36cc32 Mon Sep 17 00:00:00 2001 From: busybox11 Date: Sat, 24 Aug 2024 01:43:09 +0200 Subject: [PATCH 08/23] fix: Use NextJS recommended config for styled-components --- next.config.mjs | 10 +++++---- src/app/layout.tsx | 5 +++-- src/lib/styled-components-registry.tsx | 29 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/lib/styled-components-registry.tsx diff --git a/next.config.mjs b/next.config.mjs index 48f03d4..431d026 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -3,17 +3,19 @@ const nextConfig = { images: { remotePatterns: [ { - protocol: 'https', - hostname: 'raw.githubusercontent.com', + protocol: "https", + hostname: "raw.githubusercontent.com", }, ], }, experimental: { serverActions: { // edit: updated to new key. Was previously `allowedForwardedHosts` - allowedOrigins: ['localhost:3000', 'get-zen.vercel.app'], + allowedOrigins: ["localhost:3000", "get-zen.vercel.app"], }, - + }, + compiler: { + styledComponents: true, }, }; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3de6cf4..971e56e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,8 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; -import { ThemeProvider } from "@/components/theme-provider" +import { ThemeProvider } from "@/components/theme-provider"; +import StyledComponentsRegistry from "@/lib/styled-components-registry"; const inter = Inter({ subsets: ["latin"] }); @@ -25,7 +26,7 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > - {children} + {children} diff --git a/src/lib/styled-components-registry.tsx b/src/lib/styled-components-registry.tsx new file mode 100644 index 0000000..fa12293 --- /dev/null +++ b/src/lib/styled-components-registry.tsx @@ -0,0 +1,29 @@ +"use client"; + +import React, { useState } from "react"; +import { useServerInsertedHTML } from "next/navigation"; +import { ServerStyleSheet, StyleSheetManager } from "styled-components"; + +export default function StyledComponentsRegistry({ + children, +}: { + children: React.ReactNode; +}) { + // Only create stylesheet once with lazy initial state + // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state + const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet()); + + useServerInsertedHTML(() => { + const styles = styledComponentsStyleSheet.getStyleElement(); + styledComponentsStyleSheet.instance.clearTag(); + return <>{styles}; + }); + + if (typeof window !== "undefined") return <>{children}; + + return ( + + {children} + + ); +} From 465b1ab524b7f2339d4d9399c01155211d01be48 Mon Sep 17 00:00:00 2001 From: camilo Date: Fri, 23 Aug 2024 21:21:14 -0500 Subject: [PATCH 09/23] fix(theme-page): resolve sidebar overlapping footer issue - Fixed the issue where the sidebar was overlapping the footer by changing `lg:fixed` to `lg:sticky` and adjusting padding/margin. - Removed unused imports (`LoaderIcon`, `LoaderPinwheelIcon`, `MoveLeftIcon`) from `lucide-react`. - Moved "Go back" button to the top of the sidebar for better UX. --- src/components/theme-page.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index b8be7fd..6a89b9d 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -4,7 +4,7 @@ import { Button } from "./ui/button"; import { useEffect, useState } from "react"; import Markdown from "react-markdown"; import '../app/privacy-policy/markdown.css'; -import { ChevronLeft, LoaderCircleIcon, LoaderIcon, LoaderPinwheelIcon, MoveLeftIcon } from "lucide-react"; +import { ChevronLeft, LoaderCircleIcon } from "lucide-react"; export default function ThemePage({ theme }: { theme: ZenTheme }) { const [readme, setReadme] = useState(null); @@ -14,7 +14,11 @@ export default function ThemePage({ theme }: { theme: ZenTheme }) { return (
-
+
-
-
window.history.back()}> - -

Go back

-
+
{readme === null ? ( - + ) : ( {`${readme}`} )} From 0861a2f44d8afcc8f30c0aec93734dd0ae25c0f2 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Sat, 24 Aug 2024 14:46:58 +0530 Subject: [PATCH 10/23] fix: capitalize "firefox" --- src/app/privacy-policy/page.tsx | 2 +- src/components/features.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/privacy-policy/page.tsx b/src/app/privacy-policy/page.tsx index 7a9af0a..5408dea 100644 --- a/src/app/privacy-policy/page.tsx +++ b/src/app/privacy-policy/page.tsx @@ -52,7 +52,7 @@ Zen Browser offers a "Sync" feature, this is implemented using Mozilla Firefox's # 4. Data Security Although Zen Browser does not collect your data, we are committed to protecting the information that is stored locally on your device and, if you use the Sync feature, the encrypted data stored on Mozilla's servers. We recommend that you use secure passwords, enable device encryption, and regularly update your software to ensure your data remains safe. -* Note that most of the security measures are taken care by mozilla firefox. +* Note that most of the security measures are taken care by Mozilla Firefox. # 5. Your Control ## 5.1. Data Deletion diff --git a/src/components/features.tsx b/src/components/features.tsx index 384f621..2b10417 100644 --- a/src/components/features.tsx +++ b/src/components/features.tsx @@ -74,7 +74,7 @@ export default function Features() { Goodbye bad performance

- We are constantly tweak firefox's engine and settings to make it + We are constantly tweak Firefox's engine and settings to make it faster than ever. Learn more

@@ -102,7 +102,7 @@ export default function Features() { Secure by default

- We are always using the latest security features from firefox to + We are always using the latest security features from Firefox to keep you safe. Learn more

From e0ba5c0fbcc0be5d4ef7d48349c3fbf719d7d3fa Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sat, 24 Aug 2024 11:40:36 +0200 Subject: [PATCH 11/23] refactor: Remove redundant code for features layout --- src/components/features.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/features.tsx b/src/components/features.tsx index 384f621..7490690 100644 --- a/src/components/features.tsx +++ b/src/components/features.tsx @@ -118,8 +118,6 @@ export default function Features() {
-
-
@@ -149,8 +147,6 @@ export default function Features() {
-
-
From 9c49f996c3d289e848ce684b504bed29ca5557cb Mon Sep 17 00:00:00 2001 From: thebluedev Date: Sat, 24 Aug 2024 15:16:13 +0530 Subject: [PATCH 12/23] fix: Fix grammar in features --- src/components/features.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/features.tsx b/src/components/features.tsx index 014fdce..eecd57c 100644 --- a/src/components/features.tsx +++ b/src/components/features.tsx @@ -73,7 +73,7 @@ export default function Features() { Goodbye bad performance

- We are constantly tweak firefox's engine and settings to make it + We constantly tweak firefox's engine and settings to make it faster than ever. Learn more

From f49d5a8410147b35121831899d44eabe1ae3aa8a Mon Sep 17 00:00:00 2001 From: nitro <143457057+n7itro@users.noreply.github.com> Date: Sat, 24 Aug 2024 14:52:47 +0200 Subject: [PATCH 13/23] v29 release notes --- src/lib/release-notes.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/lib/release-notes.ts b/src/lib/release-notes.ts index eb4ea52..8d0cfaf 100644 --- a/src/lib/release-notes.ts +++ b/src/lib/release-notes.ts @@ -601,6 +601,31 @@ export const releaseNotes: ReleaseNote[] = [ } ] }, + { + version: "1.0.0-a.29", + date: "24/08/2024", + extra: "This release is the twenty-ninth alpha release of the 1.0.0-alpha series.", + features: [ + "Added Spanish translations", + "Added documentation for contributing", + "Added support for multi-tab splitting with shortcuts", + "Fixed sidebar shortcuts" + ], + fixes: [ + { + description: "Text on websites is blurry", + issue: 383 + }, + { + description: "Expanded compact mode triggers too early", + issue: 520 + }, + { + description: "Ampersand in workspace name breaks workspace menu", + issue: 439 + } + ] + } ].reverse(); export function releaseNoteIsAlpha(note: ReleaseNote) { From f9616f47878da52e43ba2af8b59bfb8c7893a3b6 Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sat, 24 Aug 2024 23:53:16 +0200 Subject: [PATCH 14/23] feat: Add link to personal website in the head of RootLayout component --- src/app/layout.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3de6cf4..fb59c9d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -18,6 +18,9 @@ export default function RootLayout({ }>) { return ( + + + Date: Sat, 24 Aug 2024 23:57:27 +0200 Subject: [PATCH 15/23] chore: Add generateMetadata function to theme page --- src/app/themes/[theme]/page.tsx | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/app/themes/[theme]/page.tsx b/src/app/themes/[theme]/page.tsx index bb2d5c2..e8edb1b 100644 --- a/src/app/themes/[theme]/page.tsx +++ b/src/app/themes/[theme]/page.tsx @@ -3,7 +3,40 @@ import Footer from "@/components/footer"; import { Navigation } from "@/components/navigation"; import ThemePage from "@/components/theme-page"; import { getThemeFromId } from "@/lib/themes"; +import { Metadata, ResolvingMetadata } from "next"; import { useParams } from "next/navigation"; +import { Props } from "next/script"; + +export async function generateMetadata( + { params, searchParams }: Props, + parent: ResolvingMetadata +): Promise { + const theme = params.theme + const themeData = await getThemeFromId(theme); + if (!themeData) { + return { + title: "Theme not found", + description: "Theme not found", + }; + } + return { + title: themeData.name, + description: themeData.description, + keywords: [themeData.name, themeData.description], + openGraph: { + title: themeData.name, + description: themeData.description, + images: [ + { + url: themeData.image, + width: 500, + height: 500, + alt: themeData.name, + }, + ], + }, + }; +} export default async function ThemeInfoPage() { const params = useParams<{ theme: string }>(); From cdf6216d795e92c800df13d3c431d96b377d68ed Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sat, 24 Aug 2024 23:59:43 +0200 Subject: [PATCH 16/23] chore: Refactor generateMetadata function in theme page --- src/app/themes/[theme]/page.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/themes/[theme]/page.tsx b/src/app/themes/[theme]/page.tsx index e8edb1b..7d7b0e9 100644 --- a/src/app/themes/[theme]/page.tsx +++ b/src/app/themes/[theme]/page.tsx @@ -1,14 +1,13 @@ -"use client"; + import Footer from "@/components/footer"; import { Navigation } from "@/components/navigation"; import ThemePage from "@/components/theme-page"; import { getThemeFromId } from "@/lib/themes"; import { Metadata, ResolvingMetadata } from "next"; import { useParams } from "next/navigation"; -import { Props } from "next/script"; export async function generateMetadata( - { params, searchParams }: Props, + { params, searchParams }: any, parent: ResolvingMetadata ): Promise { const theme = params.theme From 0e334272891e34a76e77486d3d3a72c1dbe367ce Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:01:09 +0200 Subject: [PATCH 17/23] chore: Remove unused code and fix theme page rendering --- src/app/themes/[theme]/page.tsx | 11 +---------- src/components/theme-page.tsx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/app/themes/[theme]/page.tsx b/src/app/themes/[theme]/page.tsx index 7d7b0e9..ab32280 100644 --- a/src/app/themes/[theme]/page.tsx +++ b/src/app/themes/[theme]/page.tsx @@ -4,7 +4,6 @@ import { Navigation } from "@/components/navigation"; import ThemePage from "@/components/theme-page"; import { getThemeFromId } from "@/lib/themes"; import { Metadata, ResolvingMetadata } from "next"; -import { useParams } from "next/navigation"; export async function generateMetadata( { params, searchParams }: any, @@ -38,17 +37,9 @@ export async function generateMetadata( } export default async function ThemeInfoPage() { - const params = useParams<{ theme: string }>(); - const { theme: themeID } = params; - - const theme = await getThemeFromId(themeID); - if (!theme) { - return
Theme not found
; - } - return (
- +
{/* At the bottom of the page */}
diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index 6a89b9d..b61c8ff 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -1,12 +1,21 @@ import Image from "next/image"; -import { getThemeAuthorLink, getThemeMarkdown, ZenTheme } from "@/lib/themes"; +import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes"; import { Button } from "./ui/button"; import { useEffect, useState } from "react"; import Markdown from "react-markdown"; import '../app/privacy-policy/markdown.css'; import { ChevronLeft, LoaderCircleIcon } from "lucide-react"; +import { useParams } from "next/navigation"; + +export default async function ThemePage() { + const params = useParams<{ theme: string }>(); + const { theme: themeID } = params; + + const theme = await getThemeFromId(themeID); + if (!theme) { + return
Theme not found
; + } -export default function ThemePage({ theme }: { theme: ZenTheme }) { const [readme, setReadme] = useState(null); useEffect(() => { getThemeMarkdown(theme).then(setReadme); From 353d0af72d88ffa1236ae22f75089355d9e23d67 Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:02:00 +0200 Subject: [PATCH 18/23] chore: Fix typo in theme-page.tsx --- src/components/theme-page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index b61c8ff..38e47ff 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -1,3 +1,4 @@ +"use cient"; import Image from "next/image"; import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes"; import { Button } from "./ui/button"; From 171d759ca344070a8fa1fdf321e825a12346087d Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:02:50 +0200 Subject: [PATCH 19/23] fixed typo --- src/components/theme-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index 38e47ff..445454d 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -1,4 +1,4 @@ -"use cient"; +"use client"; import Image from "next/image"; import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes"; import { Button } from "./ui/button"; From 5a465c9e36a738e709a9b4cc1f126ed175b31f92 Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:05:20 +0200 Subject: [PATCH 20/23] chore: Update ThemePage component to fetch readme asynchronously --- src/components/theme-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index 445454d..a45bf17 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -9,6 +9,7 @@ import { ChevronLeft, LoaderCircleIcon } from "lucide-react"; import { useParams } from "next/navigation"; export default async function ThemePage() { + const [readme, setReadme] = useState(null); const params = useParams<{ theme: string }>(); const { theme: themeID } = params; @@ -17,7 +18,6 @@ export default async function ThemePage() { return
Theme not found
; } - const [readme, setReadme] = useState(null); useEffect(() => { getThemeMarkdown(theme).then(setReadme); }, [theme]); From c691a4e7e80e9aeba58e7f22c6666f36ef1078ae Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:07:33 +0200 Subject: [PATCH 21/23] chore: Update ThemePage component to fetch readme asynchronously --- src/components/theme-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index a45bf17..b5fe68b 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -20,7 +20,7 @@ export default async function ThemePage() { useEffect(() => { getThemeMarkdown(theme).then(setReadme); - }, [theme]); + }, []); return (
From ba4372b91274b70f035a551ec186bae01a2628ff Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 25 Aug 2024 00:09:03 +0200 Subject: [PATCH 22/23] chore: Refactor ThemePage component to fetch readme asynchronously --- src/components/theme-page.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/theme-page.tsx b/src/components/theme-page.tsx index b5fe68b..bfef366 100644 --- a/src/components/theme-page.tsx +++ b/src/components/theme-page.tsx @@ -9,7 +9,6 @@ import { ChevronLeft, LoaderCircleIcon } from "lucide-react"; import { useParams } from "next/navigation"; export default async function ThemePage() { - const [readme, setReadme] = useState(null); const params = useParams<{ theme: string }>(); const { theme: themeID } = params; @@ -18,9 +17,7 @@ export default async function ThemePage() { return
Theme not found
; } - useEffect(() => { - getThemeMarkdown(theme).then(setReadme); - }, []); + const readme = await getThemeMarkdown(theme); return (
From 2a7dc0cae3d6f53ce89fce9572500ed1ea5f3eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?mauro=20=F0=9F=A4=99?= <91018726+mauro-balades@users.noreply.github.com> Date: Sun, 25 Aug 2024 00:51:46 +0200 Subject: [PATCH 23/23] Revert "refactor: Improved platform detection, UI enhancements, and overall code quality" --- src/components/download.tsx | 467 ++++++++++++++++++++---------------- src/lib/db.ts | 60 ++--- src/lib/releases.ts | 76 +++--- 3 files changed, 312 insertions(+), 291 deletions(-) diff --git a/src/components/download.tsx b/src/components/download.tsx index 3a80113..2ab7f6e 100644 --- a/src/components/download.tsx +++ b/src/components/download.tsx @@ -1,7 +1,6 @@ "use client"; - -import { incrementDownloadCount } from "@/lib/db"; -import { useState, useEffect, useCallback } from "react"; +import { addDownload } from "@/lib/db"; +import { useState, useEffect } from "react"; import styled, { keyframes } from "styled-components"; import { ny } from "@/lib/utils"; import { Checkbox } from "./ui/checkbox"; @@ -9,36 +8,50 @@ 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 @@ -46,59 +59,53 @@ const FormField = styled.div<{ enter: boolean; out: boolean }>` animation-delay: ${({ enter }) => (enter ? "0.4s" : "0s")}; `; -const FieldTitle = ({ - children, - className, -}: React.PropsWithChildren & React.HTMLAttributes) => ( -

{children}

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

@@ -350,33 +369,39 @@ export default function DownloadPage() { Click the button below to download Zen for MacOS. -
- -
+
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" + "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" + : "" )} > -

x64

-

Intel

-

+

+ x64 +

+

Intel

+

64-bit Intel architecture, for older Macs

- +
)} @@ -391,35 +416,41 @@ export default function DownloadPage() { Choose the type of download you want for Zen for Windows. -
- - +
)} @@ -434,51 +465,61 @@ 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 space-y-2", - 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", + 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 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border space-y-2", - selectedLinuxDownloadType === "portable" && - "border-blue-400" + "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" + : "" )} > -

📦

-

Portable

-

+

+ 📦 +

+

Portable

+

Download Zen as a ZIP file

-
-
+
changeToFlatpak()} 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 === "flatpak" && - "border-blue-400", - selectedArchitecture === "generic" && - "opacity-50 cursor-not-allowed" + "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" + : "" )} > -

🧑‍💻

-

Flatpak

-

+

+ 🧑‍💻 +

+

Flatpak

+

Install Zen from the Flatpak repository.

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