diff --git a/package.json b/package.json index a4636fd..5d96eb0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "@hookform/resolvers": "^3.7.0", + "@hookform/resolvers": "^3.9.0", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", @@ -26,29 +26,29 @@ "clsx": "^2.1.1", "cobe": "^0.6.3", "dotenv": "^16.4.5", - "framer-motion": "^11.2.12", + "framer-motion": "^11.3.24", "lucide-react": "^0.400.0", "next": "14.2.4", "next-themes": "^0.3.0", - "react": "^18", - "react-dom": "^18", - "react-hook-form": "^7.52.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.52.2", "react-markdown": "^9.0.1", - "react-spring": "^9.7.3", + "react-spring": "^9.7.4", "styled-components": "^6.1.12", - "tailwind-merge": "^2.3.0", + "tailwind-merge": "^2.5.1", "tailwindcss-animate": "^1.0.7", "zod": "^3.23.8" }, "devDependencies": { "@types/canvas-confetti": "^1.6.4", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "eslint": "^8", + "@types/node": "^20.14.15", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "eslint": "^8.57.0", "eslint-config-next": "14.2.4", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "typescript": "^5" + "postcss": "^8.4.41", + "tailwindcss": "^3.4.9", + "typescript": "^5.5.4" } } diff --git a/src/app/page.tsx b/src/app/page.tsx index d8461fd..d3867cd 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -15,3 +15,4 @@ export default function Home() { ); } + \ No newline at end of file diff --git a/src/app/release-notes/[version]/page.tsx b/src/app/release-notes/[version]/page.tsx index 1072e7f..8992c4f 100644 --- a/src/app/release-notes/[version]/page.tsx +++ b/src/app/release-notes/[version]/page.tsx @@ -1,39 +1,43 @@ -'use client' +"use client"; -import Footer from '@/components/footer'; -import { Navigation } from '@/components/navigation'; -import ReleaseNote from '@/components/release-note'; -import { Button } from '@/components/ui/button'; -import { releaseNotes } from '@/lib/release-notes'; -import Link from 'next/link'; -import { redirect, useParams } from 'next/navigation' +import Footer from "@/components/footer"; +import { Navigation } from "@/components/navigation"; +import ReleaseNote from "@/components/release-note"; +import { Button } from "@/components/ui/button"; +import { releaseNotes } from "@/lib/release-notes"; +import Link from "next/link"; +import { redirect, useParams } from "next/navigation"; export default function ReleaseNotePage() { - const params = useParams<{ version: string }>() + const params = useParams<{ version: string }>(); const { version } = params; - if (version === 'latest') { + if (version === "latest") { return redirect(`/release-notes/${releaseNotes[0].version}`); } const releaseNote = releaseNotes.find((note) => note.version === version); if (!releaseNote) { return ( -
-
+
+

Release note not found

- + + +
-
+
{/* At the bottom of the page */}
); } return ( -
+
-
+
{/* At the bottom of the page */}
- ) + ); } diff --git a/src/app/release-notes/page.tsx b/src/app/release-notes/page.tsx index 67c56a6..8650f56 100644 --- a/src/app/release-notes/page.tsx +++ b/src/app/release-notes/page.tsx @@ -7,7 +7,7 @@ export default function ReleaseNotes() { return (
-

Release Notes

+

Release Notes

{releaseNotes.map((releaseNote) => ( diff --git a/src/app/themes/page.tsx b/src/app/themes/page.tsx new file mode 100644 index 0000000..4dd2eda --- /dev/null +++ b/src/app/themes/page.tsx @@ -0,0 +1,14 @@ + +import Footer from "@/components/footer"; +import MarketplacePage from "@/components/marketplace"; +import { Navigation } from "@/components/navigation"; + +export default function ThemesMarketplace() { + return ( +
+ +
+ {/* At the bottom of the page */} +
+ ); +} diff --git a/src/components/download.tsx b/src/components/download.tsx index eb991d4..683fc17 100644 --- a/src/components/download.tsx +++ b/src/components/download.tsx @@ -1,36 +1,20 @@ "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"; +import Link from "next/link"; +const BASE_URL = + "https://github.com/zen-browser/desktop/releases/latest/download"; + import SparklesText from "./ui/sparkles-text"; -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 ""; -} - const field_enter = keyframes` 0% { opacity: 0; @@ -64,14 +48,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 +73,43 @@ const FieldDescription = styled.div` export default function DownloadPage() { const [platform, setPlatform] = useState(null); const [architecture, setArchitecture] = useState(null); - const [windowsDownloadType, setWindowsDownloadType] = useState(null); - const [linuxDownloadType, setLinuxDownloadType] = useState(null); + const [windowsDownloadType, setWindowsDownloadType] = useState( + null + ); + const [linuxDownloadType, setLinuxDownloadType] = useState( + 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 +118,7 @@ export default function DownloadPage() { startVelocity: 60, origin: { x: 0, y: 0.5 }, colors, - }) + }); confetti({ particleCount: 2, angle: 120, @@ -122,16 +126,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 +145,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 +163,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 +175,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,43 +183,77 @@ 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 ( <> - - - - + + + +
-
- {hasDownloaded && ( +
+ {(hasDownloaded && (

Downloaded! ❤️

-

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

+

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

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

Installation Instructions

-

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

- +

+ Installation Instructions +

+

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

+
)}
- ) || ( + )) || ( <>

Download

@@ -222,23 +263,40 @@ export default function DownloadPage() { )}

{platform === null && ( - + 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" : "")}> + + 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" : "")}> - +
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" : "")}> +
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
@@ -246,94 +304,217 @@ export default function DownloadPage() { )} {/* Architecture */} - {((platform === "Windows" || platform === "Linux") && flowIndex === 1) && ( - = 1} - > - Select Architecture - Choose the architecture of your device, either optimized or generic. -
-
setSelectedArchitecture("specific")} className={ny("select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", selectedArchitecture === "specific" ? "border-blue-400" : "")}> -

🚀

-

Optimized

-

Blazing fast and compatible with modern devices

+ {(platform === "Windows" || platform === "Linux") && + flowIndex === 1 && ( + = 1 + } + > + Select Architecture + + Choose the architecture of your device, either optimized or + generic. + +
+
setSelectedArchitecture("specific")} + className={ny( + "select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", + selectedArchitecture === "specific" + ? "border-blue-400" + : "" + )} + > +

+ 🚀 +

+

Optimized

+

+ Blazing fast and compatible with modern devices +

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

+ 👴 +

+

Generic

+

+ Slow but compatible with older devices. +

+
-
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" : "")}> -

👴

-

Generic

-

Slow but compatible with older devices.

-
-
- - )} - {(platform === "MacOS" && flowIndex === 1) && ( + + )} + {platform === "MacOS" && flowIndex === 1 && ( Download Zen for MacOS - Click the button below to download Zen for MacOS. + + Click the button below to download Zen for MacOS. +
-
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" : "")}> -

🍏

+
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" + : "" + )} + > +

+ 🍏 +

aarch64

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

-
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" : "")}> -

x64

+
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" + : "" + )} + > +

+ x64 +

Intel

-

64-bit Intel architecture, for older Macs

+

+ 64-bit Intel architecture, for older Macs +

)} - {flowIndex === 2 && (platform === "Windows") && ( + {flowIndex === 2 && platform === "Windows" && ( = 2} > - Download Zen for Windows {selectedArchitecture} - Choose the type of download you want for Zen for Windows. + + Download Zen for Windows {selectedArchitecture} + + + Choose the type of download you want for Zen for Windows. +
-
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" : "")}> -

🚀

+
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" + : "" + )} + > +

+ 🚀 +

Installer

-

Install Zen with a setup wizard

+

+ Install Zen with a setup wizard +

-
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" : "")}> -

📦

+
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" + : "" + )} + > +

+ 📦 +

Portable

-

Download Zen as a ZIP file

+

+ Download Zen as a ZIP file +

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

🚀

+
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" + : "" + )} + > +

+ 🚀 +

AppImage

-

Install Zen with a setup wizard

+

+ 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" : "")}> -

📦

+
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" + : "" + )} + > +

+ 📦 +

Portable

-

Download Zen as a ZIP file

+

+ Download Zen as a ZIP file +

-
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" : "")}> -

🧑‍💻

+
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" + : "" + )} + > +

+ 🧑‍💻 +

Flatpak

Install Zen from the Flatpak repository. @@ -345,23 +526,44 @@ export default function DownloadPage() {

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

Confused about which build to choose? System requirements.

-
- )} + {(platform === "Linux" || platform === "Windows") && + flowIndex === 1 && ( +
+ +

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

+
+ )}
Stay organized and clutter-free by creating workspaces tailored to your browsing needs.

- +
@@ -68,14 +86,26 @@ export default function Features() {

Seamlessly switch between work and personal profiles for a focused browsing experience.

- +

Side web panels

Access favorite sites and services instantly, without leaving your current page.

- +
@@ -94,17 +124,34 @@ export default function Features() { How Zen compares to other browsers - - + + zen Zen - - + + floorp Floorp - - - + + librewolf LibreWolf @@ -179,6 +226,7 @@ export default function Features() { Zen is engineered for speed, consistently outperforming competitors with every release, ensuring a faster browsing experience.

+
@@ -197,6 +245,7 @@ export default function Features() { Zen incorporates advanced security technologies that outshine other Firefox-based browsers, keeping you safe online.

+
@@ -220,12 +269,9 @@ export default function Features() {
- + + +
); diff --git a/src/components/footer.tsx b/src/components/footer.tsx index 23f5a76..c500fa2 100644 --- a/src/components/footer.tsx +++ b/src/components/footer.tsx @@ -1,12 +1,18 @@ +import Link from "next/link"; import Logo from "./logo"; import TextReveal from "./ui/text-reveal"; export default function Footer() { return (
- Zen Browser © {new Date().getFullYear()} - - Made with ❤️ by the Zen team. - Source Code + Zen Browser © {new Date().getFullYear()} - Made with ❤️ by the Zen team. + + Source Code +
); } diff --git a/src/components/header.tsx b/src/components/header.tsx index 7b61dd4..7ca7234 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -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 ( <>
- - - 🎉 - {' '} -
- {' '} - - Introducing Zen Alpha - - -
-
-

- Zen is the best way -
- {' '} - to browse the web. -

-

- Beautifully designed, privacy-focused, and packed with features. -
- {' '} - We care about your experience, not your data. -

- -
-
+ + 🎉
{" "} + - + Introducing Zen Alpha + + +
+ +

+ Zen is the best way +
to browse the web. +

+

+ Beautifully designed, privacy-focused, and packed with features. +
We care about your experience, not + your data. +

+ + + +
+
+ - browser Image - browser Image -
-
+ browser Image + browser Image +
+
- ) + ); } diff --git a/src/components/logo.tsx b/src/components/logo.tsx index d718f80..6e46143 100644 --- a/src/components/logo.tsx +++ b/src/components/logo.tsx @@ -1,8 +1,8 @@ - +import Image from "next/image"; export default function Logo({ withText, ...props }: any) { return (
- Zen Logo + Zen Logo {withText && Zen}
); diff --git a/src/components/marketplace.tsx b/src/components/marketplace.tsx new file mode 100644 index 0000000..0678b98 --- /dev/null +++ b/src/components/marketplace.tsx @@ -0,0 +1,28 @@ +"use client"; +import React from "react"; +import ThemesSearch from "./themes-search"; +import { getAllThemes, getThemesFromSearch, ZenTheme } from "@/lib/themes"; +import ThemeCard from "./theme-card"; + +export default function MarketplacePage() { + const [searchInput, setSearchInput] = React.useState(""); + const [themes, setThemes] = React.useState([]); + + React.useEffect(() => { + setThemes(getAllThemes()); + }, []); + + return ( +
+
+

Themes Marketplace

+ +
+
+ {getThemesFromSearch(themes, searchInput).map((theme) => ( + + ))} +
+
+ ); +} diff --git a/src/components/mobile-nav.tsx b/src/components/mobile-nav.tsx index 397d6ac..02aab0c 100644 --- a/src/components/mobile-nav.tsx +++ b/src/components/mobile-nav.tsx @@ -42,6 +42,12 @@ export function MobileNav() { > Download + + Themes + +
@@ -48,7 +53,7 @@ export function Navigation() {
  • - @@ -60,14 +65,14 @@ export function Navigation() { Firefox based browser with a focus on privacy and customization.

    -
    +
  • Start using Zen Browser today with just a few clicks. - - View the source code on GitHub and maybe leave a star! + + Customize your browser with a variety of themes! Stay up to date with the latest changes. diff --git a/src/components/release-note.tsx b/src/components/release-note.tsx index 5f2e7d2..c905a45 100644 --- a/src/components/release-note.tsx +++ b/src/components/release-note.tsx @@ -2,20 +2,34 @@ 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 (
    -

    Release notes for {data.version} 🎉

    -

    {data.date}

    +

    + Release notes for {data.version} 🎉 +

    +

    + {data.date} +

    - If you encounter any issues, please report them on the issues page. Thanks everyone for your feedback! ❤️ + If you encounter any issues, please report them on{" "} + + the issues page + + . Thanks everyone for your feedback! ❤️

    {data.extra && ( -

    ")}}> -

    +

    "), + }} + >

    )} {data.breakingChanges && ( <> @@ -23,10 +37,14 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) { Breaking changes -

    The following changes may break existing functionality:

    +

    + The following changes may break existing functionality: +

      {data.breakingChanges?.map((change, index) => ( -
    • {change}
    • +
    • + {change} +
    • ))}
    @@ -37,10 +55,14 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) { Features -

    The following features have been added:

    +

    + The following features have been added: +

      {data.features?.map((feature, index) => ( -
    • {feature}
    • +
    • + {feature} +
    • ))}
    @@ -51,19 +73,21 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) { Fixes -

    The following issues have been fixed:

    +

    + The following issues have been fixed: +

      {data.fixes?.map((fix, index) => (
    • {fix.description} {fix.issue && ( - issue #{fix.issue} - + )}
    • ))} @@ -71,7 +95,11 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) { )}
    - +
    + + + +
    ); -} \ No newline at end of file +} diff --git a/src/components/theme-card.tsx b/src/components/theme-card.tsx new file mode 100644 index 0000000..84f2df8 --- /dev/null +++ b/src/components/theme-card.tsx @@ -0,0 +1,41 @@ +import { ZenTheme } from "@/lib/themes"; +import styled from "styled-components"; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; +import { Button } from "./ui/button"; + +const ThemeCardWrapepr = styled.div` +`; + +export default function ThemeCard({ + theme +}: { + theme: ZenTheme; +}) { + return ( + + + + {theme.name} +

    {theme.name}

    +

    {theme.description}

    +
    +
    + + + {theme.name} + {theme.name} + {theme.description} +
    +
    + +

    + You need to have Zen Browser installed to use this theme. Download +

    +
    +
    +
    +
    + ); +} diff --git a/src/components/themes-search.tsx b/src/components/themes-search.tsx new file mode 100644 index 0000000..2a13020 --- /dev/null +++ b/src/components/themes-search.tsx @@ -0,0 +1,21 @@ +import { SearchIcon } from "lucide-react"; + +export default function ThemesSearch({ + input, setInput +}: { + input: string; + setInput: (input: string) => void; +}) { + return ( +
    + + setInput(e.target.value)} + placeholder="Search themes" + className="w-full bg-transparent border-none focus:outline-none focus:border-none focus:ring-0 text-white placeholder-muted" + /> +
    + ); +} diff --git a/src/components/ui/blur-fade.tsx b/src/components/ui/blur-fade.tsx index df2e1dc..f7427b7 100644 --- a/src/components/ui/blur-fade.tsx +++ b/src/components/ui/blur-fade.tsx @@ -15,7 +15,7 @@ interface BlurFadeProps { delay?: number yOffset?: number inView?: boolean - inViewMargin?: string + inViewMargin?: any blur?: string } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..81886b1 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,126 @@ +'use client' + +import * as React from 'react' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { Cross2Icon } from '@radix-ui/react-icons' + +import { ny } from '@/lib/utils' + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +function DialogHeader({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ) +} +DialogHeader.displayName = 'DialogHeader' + +function DialogFooter({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ) +} +DialogFooter.displayName = 'DialogFooter' + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/src/lib/themes.ts b/src/lib/themes.ts new file mode 100644 index 0000000..3ff214c --- /dev/null +++ b/src/lib/themes.ts @@ -0,0 +1,25 @@ + +export interface ZenTheme { + name: string + description: string + image: string + downloadUrl: string + id: string +} + +export function getAllThemes(): ZenTheme[] { + // TODO: Fetch themes from the marketplace (database or JSON file) + return [ + { + name: "Zen", + description: "The default theme for Zen Browser", + downloadUrl: "https://zen-browser.app/download", // idrc + id: "zen", + image: "https://imgs.search.brave.com/qcDBMGuBLvJGLxWR3IkZyg35vROTSZ2omLn_0iLU2rs/rs:fit:860:0:0:0/g:ce/aHR0cHM6Ly9pLnBp/bmltZy5jb20vb3Jp/Z2luYWxzLzgxL2Mz/LzE0LzgxYzMxNDI5/MmViOGM3YzYxNmY5/ZjM3YTRmZDI5ODU4/LmpwZw", + }, + ]; +} + +export function getThemesFromSearch(themes: ZenTheme[], query: string): ZenTheme[] { + return themes.filter((theme) => theme.name.toLowerCase().includes(query.toLowerCase())); +}