Merge branch 'main' into nav-ui-fix

This commit is contained in:
mauro 🤙
2024-09-08 23:36:51 +02:00
committed by GitHub
42 changed files with 498 additions and 518 deletions

2
.gitignore vendored
View File

@@ -36,3 +36,5 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts
!src/app/.env/

View File

@@ -9,6 +9,8 @@ Zen Browser Website
[![](https://data.jsdelivr.com/v1/package/gh/zen-browser/www/badge)](https://www.jsdelivr.com/package/gh/zen-browser/www) [![](https://data.jsdelivr.com/v1/package/gh/zen-browser/www/badge)](https://www.jsdelivr.com/package/gh/zen-browser/www)
[Analytics](https://plausible.io/zen-browser.app/) | [Uptime-Phare](https://uptime.zen-browser.app)
This repository contains the source code for the Zen Browser Website. We are thrilled to welcome you to our community. Before you start, please read this document to understand how you can contribute to this project. This repository contains the source code for the Zen Browser Website. We are thrilled to welcome you to our community. Before you start, please read this document to understand how you can contribute to this project.
Zen Browser's website is built with [Next.js](https://nextjs.org/), [TypeScript](https://www.typescriptlang.org/), and [Tailwind CSS](https://tailwindcss.com/). Zen Browser's website is built with [Next.js](https://nextjs.org/), [TypeScript](https://www.typescriptlang.org/), and [Tailwind CSS](https://tailwindcss.com/).

View File

@@ -1,18 +0,0 @@
# Contributing Translations
To contribute to the translation of your language you must modify the json in `/messages` that is named corresponding to the ISO Language Code of your given language.
If you do not see a JSON for your language then add the language.
## Adding a language
1. To add a language you must add the language to the `const SUPPORTED_LANGUAGES = ['en', 'de'];` variable in the `./src/i18n.ts` file.
2. You must create a new `.json` file in the `./messages` directory
3. Copy the contents of the `en.json` file, make your way down the key-value pairs and change **only the values** to the translated equivalent.

View File

@@ -1,7 +0,0 @@
{
"navigation": {
"getting-started": "Erste Schritte",
"donate": "Spenden",
"useful-links": "Nützliche Links"
}
}

View File

@@ -1,7 +0,0 @@
{
"navigation": {
"getting-started": "Getting Started",
"donate": "Donate",
"useful-links": "Useful Links"
}
}

View File

@@ -1,9 +1,5 @@
const createNextIntlPlugin = require('next-intl/plugin');
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants') const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
const {setupDevPlatform} = require('@cloudflare/next-on-pages/next-dev')
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = (phase, { defaultConfig }) => { const nextConfig = (phase, { defaultConfig }) => {
@@ -17,9 +13,11 @@ const nextConfig = (phase, { defaultConfig }) => {
{ {
protocol: "https", protocol: "https",
hostname: "cdn.jsdelivr.net", hostname: "cdn.jsdelivr.net",
port: '',
pathname: '/gh/zen-browser/**',
} }
], ],
domains: ['cdn.jsdelivr.net', "raw.githubusercontent.com"], // Allow images from jsDelivr domains: ['localhost', 'cdn.jsdelivr.net', "raw.githubusercontent.com"], // Allow images from jsDelivr
}, },
experimental: { experimental: {
serverActions: { serverActions: {
@@ -44,4 +42,4 @@ const nextConfig = (phase, { defaultConfig }) => {
}; };
}; };
module.exports = withNextIntl(nextConfig); module.exports = nextConfig;

97
package-lock.json generated
View File

@@ -32,7 +32,6 @@
"framer-motion": "^11.3.24", "framer-motion": "^11.3.24",
"lucide-react": "^0.400.0", "lucide-react": "^0.400.0",
"next": "14.2.4", "next": "14.2.4",
"next-intl": "^3.18.1",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@@ -3123,55 +3122,6 @@
"integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==", "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@formatjs/ecma402-abstract": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz",
"integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==",
"license": "MIT",
"dependencies": {
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/fast-memoize": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
"integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "2.7.8",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz",
"integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==",
"license": "MIT",
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/icu-skeleton-parser": "1.8.2",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz",
"integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==",
"license": "MIT",
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/intl-localematcher": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
"integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
"license": "MIT",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@hapi/hoek": { "node_modules/@hapi/hoek": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
@@ -11792,18 +11742,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/intl-messageformat": {
"version": "10.5.14",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz",
"integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==",
"license": "BSD-3-Clause",
"dependencies": {
"@formatjs/ecma402-abstract": "2.0.0",
"@formatjs/fast-memoize": "2.2.0",
"@formatjs/icu-messageformat-parser": "2.7.8",
"tslib": "^2.4.0"
}
},
"node_modules/invariant": { "node_modules/invariant": {
"version": "2.2.4", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -14647,6 +14585,7 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
@@ -14708,27 +14647,6 @@
} }
} }
}, },
"node_modules/next-intl": {
"version": "3.18.1",
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.18.1.tgz",
"integrity": "sha512-ht8HyroJeiJIte9yhg1f0Nc2rlZmkvSYQ3nhqFVJLzhq7T1Xb8nfjilffrOJc3sA8kEjBOS4bdIrg4YX8REO0Q==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"license": "MIT",
"dependencies": {
"@formatjs/intl-localematcher": "^0.5.4",
"negotiator": "^0.6.3",
"use-intl": "^3.18.1"
},
"peerDependencies": {
"next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/next-themes": { "node_modules/next-themes": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
@@ -19102,19 +19020,6 @@
} }
} }
}, },
"node_modules/use-intl": {
"version": "3.18.1",
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.18.1.tgz",
"integrity": "sha512-BFNhVnszG1AB04DbNvJ+TLLd1oBDGergAKI8t9xaE4vDJYZaVKQH4zmpdArbegzTu5U9XMen6w14d1P1hBwKOQ==",
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "^2.2.0",
"intl-messageformat": "^10.5.14"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/use-sidecar": { "node_modules/use-sidecar": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",

View File

@@ -39,7 +39,6 @@
"framer-motion": "^11.3.24", "framer-motion": "^11.3.24",
"lucide-react": "^0.400.0", "lucide-react": "^0.400.0",
"next": "14.2.4", "next": "14.2.4",
"next-intl": "^3.18.1",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

7
src/app/.env/page.tsx Normal file
View File

@@ -0,0 +1,7 @@
import { redirect } from "next/navigation";
export default function WhyAreYouEvenHere() {
redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
return null;
}

39
src/app/about/page.tsx Normal file
View File

@@ -0,0 +1,39 @@
"use client";
import Footer from "@/components/footer";
import { Navigation } from "@/components/navigation";
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
import Link from "next/link";
import Markdown from 'react-markdown'
import '../privacy-policy/markdown.css';
export default function PrivacyPolicy() {
return (
<main className="flex min-h-screen flex-col items-center justify-start">
<div id="policy" className="min-h-screen py-42 flex mx-auto my-52 p-10 lg:p-0 w-full lg:w-1/3 flex-col">
<Markdown>
{`
# Main Developer Team
* [**Mauro Baladés**](https://github.com/mauro-balades): Creator, Main Developer, and a funny guy.
* **Oscar Gonzalez**: Site Reliability Engineer (SRE) and code signing.
* [**Onno**](https://www.onnno.nl/index.html): logo designer.
* [**Jafeth Garro**](https://iamjafeth.com/): Documentation writer.
* **Peter Jung**: general contributor and AUR maintainer.
* [**Gunir**](https://github.com/gunir): Active contributor.
* [**n7itro**](https://github.com/n7itro): Active contributor.
* [**Canoa**](https://thatcanoa.org/) Active contributor, and very active in issue handling
* [**Jan Heres**](https://janheres.eu/): Active contributor and helps with MacOS builds.
# Many more contributors
![Contributors](https://contributors-img.web.app/image?repo=zen-browser/desktop)
---
![Contributors](https://contributors-img.web.app/image?repo=zen-browser/www)
`}
</Markdown>
</div>
</main>
)
}

View File

@@ -6,8 +6,6 @@ export default function BrandingAssetsPage() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<BrandingAssets /> <BrandingAssets />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -6,8 +6,6 @@ export default function BrandingAssetsPage() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<CreateThemePage /> <CreateThemePage />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -7,8 +7,6 @@ export default function Download() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<DownloadPage /> <DownloadPage />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -1,110 +0,0 @@
import { Feed } from "feed";
import { releaseNotes } from "@/lib/release-notes";
import type { ReleaseNote } from "@/lib/release-notes";
// Force feed.xml to be cached as static and remain constant for the lifetime of the current site build.
// The supplied releaseNotes array is constant per build, so this will always be the latest release notes.
export const dynamic = "force-static";
/** The default number of entries to include in the RSS feed. */
const RSS_ENTRY_LIMIT = 20;
/**
* Handles the GET request for the `feed.xml` endpoint.
* @returns The RSS feed for the Zen Browser release notes.
*/
export async function GET() {
// Just in case the release notes array is empty for whatever reason.
const latestDate = releaseNotes.length > 0
? formatRssDate(releaseNotes[0].date)
: new Date();
const feed = new Feed({
id: "https://www.zen-browser.app/release-notes",
link: "https://www.zen-browser.app/release-notes",
title: "Zen Browser Release Notes",
description: "Release Notes for the Zen Browser",
language: "en",
favicon: "https://www.zen-browser.app/favicon.ico",
copyright: `Zen Browser © ${new Date().getFullYear()} - Made with ❤️ by the Zen team.`,
updated: latestDate,
});
for (const releaseNote of releaseNotes.slice(0, RSS_ENTRY_LIMIT)) {
feed.addItem({
title: `Release notes for version ${releaseNote.version}`,
id: `https://www.zen-browser.app/release-notes/${releaseNote.version}`,
link: `https://www.zen-browser.app/release-notes/${releaseNote.version}`,
date: formatRssDate(releaseNote.date),
description: releaseNote.extra,
content: formatReleaseNote(releaseNote),
});
}
return new Response(feed.rss2(), {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
},
});
}
/**
* Formats a date string in the format day/month/year.
*
* Note: If release notes change to ISO format, this will need to be updated.
* @param dateStr The date string to format.
* @returns The passed in date string as a Date object.
*/
function formatRssDate(dateStr: string) {
const splitDate = dateStr.split("/");
if (splitDate.length !== 3) {
throw new Error("Invalid date format");
}
const day = Number(splitDate[0]);
const month = Number(splitDate[1]) - 1;
const year = Number(splitDate[2]);
return new Date(year, month, day);
}
/**
* Formats the release note entry for use as the content of the RSS feed.
* @param releaseNote The release note to format.
* @returns The formatted release note as a HTML string.
*/
function formatReleaseNote(releaseNote: ReleaseNote) {
let content = "<p>If you encounter any issues, please report them on <a href=\"https://github.com/zen-browser/desktop/issues/\">the issues page</a>. Thanks everyone for your feedback! ❤️</p>";
if (releaseNote.extra) {
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`
}
if (releaseNote.breakingChanges) {
content += `<h2>⚠️ Breaking changes</h2>`
content += `<ul>`
for (const breakingChange of releaseNote.breakingChanges) {
content += `<li>${breakingChange}</li>`
}
content += `</ul>`
}
if (releaseNote.features) {
content += `<h2>⭐ Features</h2>`
content += `<ul>`
for (const feature of releaseNote.features) {
content += `<li>${feature}</li>`
}
content += `</ul>`
}
if (releaseNote.fixes) {
content += `<h2>✓ Fixes</h2>`
content += `<ul>`
for (const fix of releaseNote.fixes) {
content += `<li>${fix.description}</li>`
}
content += `</ul>`
}
return content;
}

View File

@@ -50,7 +50,7 @@
*/ */
} }
.dark { [data-theme='dark'], .dark {
--background: 0 0% 0%; --background: 0 0% 0%;
--foreground: 0 0% 98%; --foreground: 0 0% 98%;
@@ -85,12 +85,13 @@
} }
@layer base { @layer base {
html {
@apply scroll-smooth;
}
* { * {
@apply border-border; @apply border-border;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
scroll-behavior: smooth;
} }
} }

View File

@@ -3,13 +3,11 @@ import { Inter } from "next/font/google";
import "./globals.css"; import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider"; import { ThemeProvider } from "@/components/theme-provider";
import StyledComponentsRegistry from "@/lib/styled-components-registry"; import StyledComponentsRegistry from "@/lib/styled-components-registry";
import {NextIntlClientProvider} from 'next-intl'; import Footer from "@/components/footer";
import {getLocale, getMessages} from 'next-intl/server'; import { Navigation } from "@/components/navigation";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
export const runtime = 'edge';
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Zen Browser", title: "Zen Browser",
description: "Download now and experience the Zen Browser", description: "Download now and experience the Zen Browser",
@@ -21,27 +19,28 @@ export default async function RootLayout({
}: Readonly<{ }: Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
const locale = await getLocale();
const messages = await getMessages();
return ( return (
<html lang={locale} suppressHydrationWarning> <html suppressHydrationWarning>
<head> <head>
<link rel="me" href="https://fosstodon.org/@zenbrowser"></link> <link rel="me" href="https://fosstodon.org/@zenbrowser"></link>
<script defer data-domain="zen-browser.app" src="https://plausible.io/js/script.js"></script>
<link rel="alternate" type="application/rss+xml" title="Zen Browser Release Notes" href="https://www.zen-browser.app/feed.xml" /> <link rel="alternate" type="application/rss+xml" title="Zen Browser Release Notes" href="https://www.zen-browser.app/feed.xml" />
</head> </head>
<body className={inter.className}> <body className={inter.className}>
<NextIntlClientProvider messages={messages}> <ThemeProvider
<ThemeProvider attribute="class"
attribute="class" enableSystem
defaultTheme="dark" disableTransitionOnChange
enableSystem >
disableTransitionOnChange <StyledComponentsRegistry>
> <div>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry> {children}
</ThemeProvider> <Footer />
</NextIntlClientProvider> <Navigation /> {/* At the bottom of the page */}
</div>
</StyledComponentsRegistry>
</ThemeProvider>
</body> </body>
</html> </html>
); );

View File

@@ -1,15 +1,8 @@
import { BrandingAssets } from "@/components/branding-assets";
import Footer from "@/components/footer";
import { Navigation } from "@/components/navigation";
export const runtime = 'edge'
export default function NotFoundPage() { export default function NotFoundPage() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<h1>404</h1> <h1>404</h1>
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -10,8 +10,6 @@ export default function Home() {
<main className="flex min-h-screen overflow-x-hidden flex-col items-center justify-start"> <main className="flex min-h-screen overflow-x-hidden flex-col items-center justify-start">
<Header /> <Header />
<Features /> <Features />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -83,7 +83,7 @@ You can also optionally enable telemetry data collection and other Mozilla Resea
# 9. Contact Us # 9. Contact Us
If you have any questions or concerns about this Privacy Policy or Zen Browser, please contact us at: If you have any questions or concerns about this Privacy Policy or Zen Browser, please contact us at:
* Discord: [Zen Browser's Discord](https://discord.gg/nnShMQzR4b) * Discord: [Zen Browser's Discord](https://discord.com/servers/mauro-s-little-sweatshop-1088172780480114748)
* GitHub: [Organization](https://github.com/zen-browser) * GitHub: [Organization](https://github.com/zen-browser)
--- ---
@@ -91,8 +91,6 @@ If you have any questions or concerns about this Privacy Policy or Zen Browser,
By using Zen Browser, you agree to this Privacy Policy. Remember, with Zen, your privacy is in your hands.`} By using Zen Browser, you agree to this Privacy Policy. Remember, with Zen, your privacy is in your hands.`}
</Markdown> </Markdown>
</div> </div>
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
) )
} }

View File

@@ -30,16 +30,12 @@ export default function ReleaseNotePage({ params }: { params: { version: string
</Button> </Button>
</a> </a>
</div> </div>
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }
return ( return (
<main className="flex min-h-screen flex-col items-center justify-center"> <main className="flex min-h-screen flex-col items-center justify-center">
<ReleaseNote data={releaseNote} /> <ReleaseNote data={releaseNote} />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -28,8 +28,6 @@ export default function ReleaseNotes() {
))} ))}
</div> </div>
</div> </div>
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
) )
} }

View File

@@ -49,8 +49,6 @@ export default async function ThemeInfoPage({ params }: { params: { theme: strin
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<ThemePage themeID={theme} /> <ThemePage themeID={theme} />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -2,13 +2,13 @@
import Footer from "@/components/footer"; import Footer from "@/components/footer";
import MarketplacePage from "@/components/marketplace"; import MarketplacePage from "@/components/marketplace";
import { Navigation } from "@/components/navigation"; import { Navigation } from "@/components/navigation";
import { getAllThemes, ZenTheme } from "@/lib/themes";
import { GetStaticProps } from "next";
export default function ThemesMarketplace() { export default async function ThemesMarketplace() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<MarketplacePage /> <MarketplacePage themes={await getAllThemes()} />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -7,8 +7,6 @@ export default function Download() {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-start"> <main className="flex min-h-screen flex-col items-center justify-start">
<WelcomePage /> <WelcomePage />
<Footer />
<Navigation /> {/* At the bottom of the page */}
</main> </main>
); );
} }

View File

@@ -0,0 +1,9 @@
import Image from "next/image";
function imageLoader({ src }: { src: string }) {
return `https://cdn.jsdelivr.net/gh/zen-browser/${src}`;
}
export default function CachedImage({ ...props }: any) {
return <Image {...props} loader={imageLoader} />;
}

View File

@@ -215,7 +215,7 @@ export default function DownloadPage() {
<div className="flex items-center justify-center flex-col"> <div className="flex items-center justify-center flex-col">
<h1 className="text-6xl font-bold">Downloaded! </h1> <h1 className="text-6xl font-bold">Downloaded! </h1>
<p className="text-muted-foreground mt-3 text-center"> <p className="text-muted-foreground mt-3 text-center">
Zen Browser has been downloaded successfully. Enjoy browsing the Your download of Zen Browser will begin shortly. Enjoy browsing the
web with Zen! web with Zen!
</p> </p>
<div className="flex font-bold mt-5 items-center justify-between mx-auto"> <div className="flex font-bold mt-5 items-center justify-between mx-auto">
@@ -246,7 +246,7 @@ export default function DownloadPage() {
"https://docs.zen-browser.app/guides/install-macos") "https://docs.zen-browser.app/guides/install-macos")
} }
> >
Download Zen for MacOS Installation Instructions for MacOS
</Button> </Button>
</div> </div>
)} )}
@@ -259,6 +259,7 @@ export default function DownloadPage() {
</p> </p>
</> </>
)} )}
{/*Changes for the Choose your platform as checkbox looks old*/}
<div className="relative w-full"> <div className="relative w-full">
{platform === null && ( {platform === null && (
<FormField enter={platform === null} out={platform !== null}> <FormField enter={platform === null} out={platform !== null}>
@@ -266,39 +267,61 @@ export default function DownloadPage() {
<FieldDescription> <FieldDescription>
Choose the platform you want to download Zen for. Choose the platform you want to download Zen for.
</FieldDescription> </FieldDescription>
<div <div className="flex">
onClick={() => setSelectedPlatform("Windows")} <div
className={ny( onClick={() => setSelectedPlatform("Windows")}
"select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", className={ny(
selectedPlatform === "Windows" ? "border-blue-400" : "" "select-none mr-2 flex flex-col items-center justify-center rounded-lg bg-background cursor-pointer border",
)} selectedPlatform === "Windows" ? "border-blue-400" : ""
> )}
<Checkbox checked={selectedPlatform === "Windows"} /> style={{
<i className="devicon-windows8-original ml-3 p-2 border border-blue-400 rounded-lg"></i> height: "11.25rem",
<div className="ml-2">Windows</div> width: "18.75rem",
</div> }}
<div >
onClick={() => setSelectedPlatform("Linux")} <i
className={ny( className="devicon-windows8-original p-2 border border-blue-400 rounded-lg"
"select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", style={{ marginBottom: "10px" }}
selectedPlatform === "Linux" ? "border-yellow-400" : "" ></i>
)} <div className="font-bold">Windows</div>
> </div>
<Checkbox checked={selectedPlatform === "Linux"} />
<i className="devicon-linux-plain ml-3 p-2 border border-yellow-400 rounded-lg"></i> <div
<div className="ml-2">Linux</div> onClick={() => setSelectedPlatform("Linux")}
</div> className={ny(
<div "select-none mr-2 flex flex-col items-center justify-center rounded-lg bg-background cursor-pointer border",
onClick={() => setSelectedPlatform("MacOS")} selectedPlatform === "Linux" ? "border-yellow-400" : ""
className={ny( )}
"select-none mb-2 px-4 py-3 flex items-center rounded-lg bg-background cursor-pointer border", style={{
selectedPlatform === "MacOS" ? "border-purple-400" : "" height: "11.25rem",
)} width: "18.75rem",
> }}
<Checkbox checked={selectedPlatform === "MacOS"} /> >
<i className="devicon-apple-original p-2 border border-purple-400 ml-3 rounded-lg"></i> <i
<div className="ml-2 font-bold">MacOS</div> className="devicon-linux-plain p-2 border border-yellow-400 rounded-lg"
</div> style={{ marginBottom: "10px" }}
></i>
<div className="font-bold">Linux</div>
</div>
<div
onClick={() => setSelectedPlatform("MacOS")}
className={ny(
"select-none flex flex-col items-center justify-center rounded-lg bg-background cursor-pointer border",
selectedPlatform === "MacOS" ? "border-purple-400" : ""
)}
style={{
height: "11.25rem",
width: "18.75rem",
}}
>
<i
className="devicon-apple-original p-2 border border-purple-400 rounded-lg"
style={{ marginBottom: "10px" }}
></i>
<div className="font-bold">MacOS</div>
</div>
</div>
</FormField> </FormField>
)} )}
{/* Architecture */} {/* Architecture */}
@@ -358,51 +381,45 @@ export default function DownloadPage() {
</div> </div>
</FormField> </FormField>
)} )}
{platform === "MacOS" && flowIndex === 1 && ( {platform === "MacOS" && flowIndex === 1 && (
<FormField <FormField
enter={platform === "MacOS"} enter={platform === "MacOS"}
out={platform !== "MacOS"} out={platform !== "MacOS"}
> >
<FieldTitle>Download Zen for MacOS</FieldTitle> <FieldTitle>Download Zen for MacOS</FieldTitle>
<FieldDescription> <FieldDescription>
Click the button below to download Zen for MacOS. Click the button below to download Zen for MacOS.
</FieldDescription> </FieldDescription>
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<div <div
onClick={() => setSelectedArchitecture("specific")} onClick={() => setSelectedArchitecture("specific")}
className={ny( className={ny(
"select-none w-full h-full mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border", "select-none w-full h-64 mb-2 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border",
selectedArchitecture === "specific" selectedArchitecture === "specific" ? "border-blue-400" : ""
? "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>
<h1 className="text-5xl my-2 opacity-40 dark:opacity-20"> <p className="text-muted-foreground mx-auto text-center">
🍏 64-bit ARM architecture, for Apple's M Series Chips
</h1> </p>
<h1 className="text-2xl font-semibold my-2">AArch64</h1> </div>
<p className="text-muted-foreground mx-auto text-center">64-bit ARM architecture, for Apple's M Series Chips</p> <div
</div> onClick={() => setSelectedArchitecture("generic")}
<div className={ny(
onClick={() => setSelectedArchitecture("generic")} "select-none w-full h-64 mb-2 ml-10 p-5 flex flex-col items-center rounded-lg bg-background cursor-pointer border",
className={ny( 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" <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
<h1 className="text-5xl font-bold my-2 opacity-40 dark:opacity-20"> </p>
x64 </div>
</h1> </div>
<h1 className="text-2xl font-semibold my-2">Intel</h1> </FormField>
<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 <FormField
enter={platform === "Windows" && flowIndex === 2} enter={platform === "Windows" && flowIndex === 2}

View File

@@ -1,6 +1,7 @@
'use client'; 'use client';
import Sticky from 'react-sticky-el'; import Sticky from 'react-sticky-el';
import { import {
BookmarkCheckIcon,
CheckIcon, CheckIcon,
ChevronLeft, ChevronLeft,
ChevronRight, ChevronRight,
@@ -18,9 +19,12 @@ import {
ShieldCheck, ShieldCheck,
SidebarCloseIcon, SidebarCloseIcon,
SidebarIcon, SidebarIcon,
SidebarOpenIcon,
SpaceIcon, SpaceIcon,
SplitSquareHorizontal, SplitSquareHorizontal,
SplitSquareVertical, SplitSquareVertical,
SplitSquareVerticalIcon,
TableIcon,
XIcon, XIcon,
} from 'lucide-react'; } from 'lucide-react';
import { import {
@@ -29,11 +33,13 @@ import {
HeartFilledIcon, HeartFilledIcon,
Link1Icon, Link1Icon,
LockClosedIcon, LockClosedIcon,
QuestionMarkCircledIcon,
QuestionMarkIcon, QuestionMarkIcon,
ReloadIcon, ReloadIcon,
SpaceBetweenHorizontallyIcon,
UpdateIcon, UpdateIcon,
} from '@radix-ui/react-icons'; } from '@radix-ui/react-icons';
import Image from 'next/image'; import Image from "next/legacy/image";
import Link from 'next/link'; import Link from 'next/link';
import { Button } from './ui/button'; import { Button } from './ui/button';
import { COLORS } from './create-theme'; import { COLORS } from './create-theme';
@@ -52,6 +58,8 @@ import ThemeCard from './theme-card';
import { getAllThemes, ZenTheme } from '@/lib/themes'; import { getAllThemes, ZenTheme } from '@/lib/themes';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './ui/accordion'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './ui/accordion';
import Logo from './logo'; import Logo from './logo';
import CachedImage from './CachedImage';
import { transform } from 'next/dist/build/swc';
function Checkmark() { function Checkmark() {
return ( return (
@@ -84,8 +92,13 @@ export default function Features() {
<Button className='mt-8' onClick={() => window.open('/themes', '_self')}>View Theme Store</Button> <Button className='mt-8' onClick={() => window.open('/themes', '_self')}>View Theme Store</Button>
</div> </div>
</div> </div>
<div className='flex justify-center lg:mx-0 mx-10'> <hr />
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/themes.webp" alt="Zen Browser" className="rounded-md" /> <div className="flex p-12 flex-col justify-center">
<h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Always up to date <UpdateIcon className='inline w-10 h-10'></UpdateIcon></h3>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser is always up to date, ensuring that you have the latest features and security updates. With automatic updates, you can rest easy knowing that your browser is secure and up to date.</p>
<div className="relative">
<Button className='mt-8' onClick={() => window.open('/download', '_self')}>Download Now</Button>
</div>
</div> </div>
</div> </div>
@@ -124,7 +137,7 @@ export default function Features() {
</div> </div>
<div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<div className='p-16 lg:w-1/2 flex flex-col justify-center'> <div className='p-16 lg:w-1/2 flex flex-col justify-center'>
<h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Built for simplicity</h1> <h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Built for simplicity <EyeIcon className='inline w-8 h-8'></EyeIcon></h1>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser is designed to be simple and easy to use. It's built with the user in mind, so you can focus on what matters most.</p> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser is designed to be simple and easy to use. It's built with the user in mind, so you can focus on what matters most.</p>
<div className='w-full mt-8'> <div className='w-full mt-8'>
<div className='flex items-center'> <div className='flex items-center'>
@@ -141,12 +154,12 @@ export default function Features() {
</div> </div>
</div> </div>
</div> </div>
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-1.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-right" /> <CachedImage width={1350} height={900} src="www/public/browser-1.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-right" />
</div> </div>
<div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-2.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-left" /> <CachedImage width={1350} height={900} src="www/public/browser-2.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-left" />
<div className='p-16 lg:w-1/2 flex flex-col justify-center'> <div className='p-16 lg:w-1/2 flex flex-col justify-center'>
<h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Split Views</h1> <h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Split Views <SplitSquareHorizontal className='inline w-8 h-8'></SplitSquareHorizontal></h1>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser allows you to split your view into multiple panes, so you can work on multiple things at once. It's perfect for multitasking.</p> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser allows you to split your view into multiple panes, so you can work on multiple things at once. It's perfect for multitasking.</p>
<div className="relative"> <div className="relative">
<Button className='mt-8' onClick={() => window.open('/download', '_self')}>Download Now</Button> <Button className='mt-8' onClick={() => window.open('/download', '_self')}>Download Now</Button>
@@ -155,7 +168,7 @@ export default function Features() {
</div> </div>
<div className='w-full md:w-5/6 lg:w-3/4 p-5 lg:p-12 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 p-5 lg:p-12 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<div className="flex p-16 lg:w-1/2 flex-col justify-center"> <div className="flex p-16 lg:w-1/2 flex-col justify-center">
<h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Better tab management</h3> <h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Better tab management <BookmarkCheckIcon className='inline w-8 h-8'></BookmarkCheckIcon></h3>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Better tab management helps you stay organized and focused, reducing clutter and enhancing productivity</p> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Better tab management helps you stay organized and focused, reducing clutter and enhancing productivity</p>
<div className='w-full mt-8'> <div className='w-full mt-8'>
<div className='flex items-center'> <div className='flex items-center'>
@@ -178,7 +191,7 @@ export default function Features() {
</div> </div>
<div className="border-t lg:border-t-0 lg:border-l h-[1px] lg:h-[unset] lg:w-[1px] mx-2"></div> <div className="border-t lg:border-t-0 lg:border-l h-[1px] lg:h-[unset] lg:w-[1px] mx-2"></div>
<div className="flex p-16 lg:w-1/2 flex-col"> <div className="flex p-16 lg:w-1/2 flex-col">
<h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Security and Privacy is <span className='text-purple-500 font-bold'>important</span> to us</h3> <h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Security and Privacy is <span className='text-purple-500 font-bold'>important</span> to us <LockClosedIcon className='inline w-8 h-8'></LockClosedIcon></h3>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>
Zen is based on Firefox, ensuring that your browsing experience prioritizes security and privacy. With advanced tracking protection and minimal data collection, Zen keeps your online activity safe and secure, giving you peace of mind as you explore the web. Zen is based on Firefox, ensuring that your browsing experience prioritizes security and privacy. With advanced tracking protection and minimal data collection, Zen keeps your online activity safe and secure, giving you peace of mind as you explore the web.
</p> </p>
@@ -190,7 +203,7 @@ export default function Features() {
</div> </div>
<div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<div className='p-16 lg:w-1/2 flex flex-col justify-center'> <div className='p-16 lg:w-1/2 flex flex-col justify-center'>
<h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Sidebar</h1> <h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Sidebar <SidebarIcon className='inline w-8 h-8 ml-1'></SidebarIcon></h1>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser has a built-in sidebar that lets you quickly access your favorite websites, bookmarks, and more. It's the perfect way to stay organized.</p> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser has a built-in sidebar that lets you quickly access your favorite websites, bookmarks, and more. It's the perfect way to stay organized.</p>
<div className='w-full mt-8'> <div className='w-full mt-8'>
<div className='flex items-center'> <div className='flex items-center'>
@@ -207,29 +220,22 @@ export default function Features() {
</div> </div>
</div> </div>
</div> </div>
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-3.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-right" /> <CachedImage width={1350} height={900} src="www/public/browser-3.png" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-left" />
</div> </div>
<div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-4.jpg" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-left" /> <CachedImage width={1350} height={900} src="www/public/browser-4.jpg" alt="Zen Browser" className="rounded-md lg:w-1/2 object-cover object-left" />
<div className='p-16 lg:w-1/2 flex flex-col justify-center'> <div className='p-16 lg:w-1/2 flex flex-col justify-center'>
<h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Introducing Compact Mode</h1> <h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Introducing Compact Mode <SidebarCloseIcon className='inline w-8 h-8'></SidebarCloseIcon></h1>
<p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser's compact mode gives you more screen real estate by hiding the title bar and tabs. It's perfect for when you need to focus on your work.</p> <p className='text-lg mt-4 text-gray-600 dark:text-gray-300'>Zen Browser's compact mode gives you more screen real estate by hiding the title bar and tabs. It's perfect for when you need to focus on your work.</p>
<div className="relative"> <div className="relative">
<Button className='mt-8' onClick={() => window.open('/download', '_self')}>What are you waiting for?</Button> <Button className='mt-8' onClick={() => window.open('/download', '_self')}>What are you waiting for?</Button>
</div> </div>
</div> </div>
</div> </div>
{/*<div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<div className="lg:w-1/2 rounded-md relative overflow-hidden"> <div className="relative w-full lg:w-1/2 p-5 lg:p-12 flex flex-col justify-center">
<img src={`https://cdn.jsdelivr.net/gh/zen-browser/www/public/feature-${feature}.png`} alt="Zen Browser" className="rounded-md lg:w-1/2" /> <h1 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Frequently Asked Questions <QuestionMarkCircledIcon className='inline w-8 h-8'></QuestionMarkCircledIcon></h1>
{feature == "item-1" && ( <Accordion type="single" value={feature} onValueChange={setFeature} defaultValue="item-1" className='mt-8'>
<div className="absolute top-[50%] left-[50%] transform -translate-x-1/2 -translate-y-1/2 bg-background p-4 flex rounded-full">
<Logo /> <HeartFilledIcon /> <PaintBucket />
</div>
)}
</div>
<div className="relative w-full lg:w-1/2 p-5 lg:p-12">
<Accordion type="single" collapsible value={feature} onValueChange={setFeature} defaultValue="item-1">
<AccordionItem value="item-1"> <AccordionItem value="item-1">
<AccordionTrigger>is it firefox based?</AccordionTrigger> <AccordionTrigger>is it firefox based?</AccordionTrigger>
<AccordionContent> <AccordionContent>
@@ -250,7 +256,43 @@ export default function Features() {
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>
</div> </div>
</div>*/} <div className="lg:w-1/2 h-auto rounded-md relative overflow-hidden">
<CachedImage width={1350} height={900} src="www/public/feature-item-1.png" alt="Zen Browser" className="object-cover h-full w-full robject-right ounded-md" />
{feature == "item-1" && (
<div className='w-full h-full absolute top-0 left-0 grid grid-rows-3'>
<div></div>
<div className="w-fit h-fit m-auto tems-center bg-surface p-4 border-2 border-white shadow flex rounded-full animate-fade-in">
<Logo className='w-10 h-10' /> <span className='text-4xl mx-4'>+</span> <svg className='w-10 h-10 relative dark:fill-white' xmlns="http://www.w3.org/2000/svg" fill-opacity="context-fill-opacity"><path style={{ transform: "scale(2) translate(5%, 5%)" }} d="M10.39 0C8.948.788 7.987 2.025 7.767 3.66c-1.017.162-1.768.781-1.768.781s.72-.44 1.736-.511a4.04 4.04 0 0 1 3.789 2.034s-.758-.62-1.928-.468c1.315.68 1.872 2.002 1.701 3.369-.17 1.367-1.183 2.435-2.354 2.723-1.171.287-2.333.099-3.229-.61-.896-.708-1.251-1.533-1.305-2.254.213-.533.541-.812 1.1-1.092.558-.279 1.422-.283 1.572-.283s.8-.507.95-.894c-.726-.363-1.292-.65-1.696-.934-.404-.283-.492-.534-1.012-.898-.307-1.006-.021-1.955-.021-1.955s-1.043.437-1.93 1.49c0 0-.342-.338-.28-2.006-.427.155-1.366 1.004-1.947 1.92a7.277 7.277 0 0 0-.798 1.723A8.296 8.296 0 0 0-.003 8a8 8 0 0 0 16 0c0-2.256-.93-4.252-2.188-5.002 0 0 .542.932.813 2.43-.4-1.04-1.235-2.166-1.877-2.844-.643-.678-2.068-1.88-2.357-2.584z" /></svg>
</div>
<a href='https://github.com/zen-browser/desktop?tab=readme-ov-file#compatibility' target='_blank' className="w-fit h-fit m-auto items-center border-2 border-white shadow tems-center bg-surface p-4 flex rounded-full opacity-0 animate-fade-in [--animation-delay:300ms]">
See what version of Firefox Zen uses <ExternalLinkIcon className='opacity-50 h-4 w-4 ml-4' />
</a>
</div>
)}
{feature == "item-2" && (
<div className='w-full h-full absolute top-0 left-0 grid grid-rows-3'>
<div></div>
<div className="w-fit h-fit m-auto tems-center bg-surface p-4 border-2 border-white shadow flex rounded-full animate-fade-in">
<LockClosedIcon className='w-10 h-10' /> <span className='text-4xl mx-4'>+</span> <EyeClosedIcon className='w-10 h-10' />
</div>
<a href='/privacy-policy' target='_blank' className="w-fit h-fit m-auto items-center border-2 border-white shadow tems-center bg-surface p-4 flex rounded-full opacity-0 animate-fade-in [--animation-delay:300ms]">
Learn about Zen's privacy policy <ExternalLinkIcon className='opacity-50 h-4 w-4 ml-4' />
</a>
</div>
)}
{feature == "item-3" && (
<div className='w-full h-full absolute top-0 left-0 grid grid-rows-3'>
<div></div>
<div className="w-fit h-fit m-auto tems-center bg-surface p-4 border-2 border-white shadow flex rounded-full animate-fade-in">
<ShieldCheck className='w-10 h-10' /> <span className='text-4xl mx-4'>+</span> <ShieldAlertIcon className='w-10 h-10' />
</div>
<a href='https://docs.zen-browser.app/security' target='_blank' className="w-fit h-fit m-auto items-center w-fit border-2 border-white shadow tems-center bg-surface p-4 flex rounded-full opacity-0 animate-fade-in [--animation-delay:300ms]">
See how Zen keeps you safe <ExternalLinkIcon className='opacity-50 h-4 w-4 ml-4' />
</a>
</div>
)}
</div>
</div>
<div className='w-full md:w-5/6 lg:w-3/4 p-5 lg:p-12 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'> <div className='w-full md:w-5/6 lg:w-3/4 p-5 lg:p-12 flex flex-col lg:flex-row md:rounded-md mx-auto bg-surface mt-36 shadow'>
<div className="flex p-16 lg:w-1/2 flex-col justify-center"> <div className="flex p-16 lg:w-1/2 flex-col justify-center">
<h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Convinced?</h3> <h3 className='text-4xl font-medium text-gray-800 dark:text-gray-100'>Convinced?</h3>

View File

@@ -1,18 +1,114 @@
import Link from "next/link"; import Link from "next/link";
import Logo from "./logo"; import Logo from "./logo";
import TextReveal from "./ui/text-reveal"; import TextReveal from "./ui/text-reveal";
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
import { MastodonLogo } from "./icons/mastodon";
import { Button } from "./ui/button";
export default function Footer() { export default function Footer() {
return ( 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"> <div className="font-medium px-10 md:px-0 border-t w-full border-grey py-10 mt-10 flex align-center flex-col">
Zen Browser © {new Date().getFullYear()} - Made with by the Zen team. <div className="flex mx-auto px-10 lg:px-0 border-b pb-10 justify-between pt-10 w-full lg:!w-2/3">
<a <div className="flex flex-col">
href={"https://github.com/zen-browser"} <Logo />
target="_blank" <div className="mt-auto">
className="mt-5 md:mt-0 md:ml-2 font-bold" <h1 className="text-2xl font-bold opacity-80">Zen Browser</h1>
> <h2 className="text-md font-bold opacity-80 mt-6">Follow Us</h2>
Source Code <div className="flex mt-4 opacity-70">
</a> <a href="https://github.com/zen-browser">
<GitHubLogoIcon className="w-5 h-5" />
</a>
<a href="https://discord.com/servers/mauro-s-little-sweatshop-1088172780480114748" className="ml-5">
<DiscordLogoIcon className="w-5 h-5" />
</a>
<a href="https://fosstodon.org/@zenbrowser" className="ml-5">
<MastodonLogo className="w-5 h-5" />
</a>
</div>
</div>
</div>
<div className="flex flex-col md:flex-row">
<div>
<h2 className="text-md font-bold opacity-80">Get Started</h2>
<ul className="mt-4 opacity-70 font-normal">
<li>
<a href="/themes">
Themes
</a>
</li>
<li className="mt-2">
<a href="/download">
Download
</a>
</li>
<li className="mt-2">
<a href="/create-theme">
Create a Theme
</a>
</li>
</ul>
</div>
<div className="mt-10 md:mt-0 md:ml-12 lg:ml-24">
<h2 className="text-md font-bold opacity-80">Get Help</h2>
<ul className="mt-4 opacity-70 font-normal">
<li>
<a href="https://discord.com/servers/mauro-s-little-sweatshop-1088172780480114748">
Discord
</a>
</li>
<li className="mt-2 font-normal">
<a href="https://github.com/zen-browser/desktop/issues">
Report an Issue
</a>
</li>
</ul>
<h2 className="text-md font-bold opacity-80 mt-8">About</h2>
<ul className="mt-4 opacity-70 font-normal">
<li className="mt-2">
<a href="/about">
About Us
</a>
</li>
<li className="mt-2">
<a href="/privacy-policy">Privacy Policy</a>
</li>
</ul>
</div>
<div className="mt-10 md:mt-0 md:ml-12 lg:ml-24">
<h2 className="text-md font-bold opacity-80">Resources</h2>
<ul className="mt-4 opacity-70 font-normal">
<li>
<a href="/branding-assets">Branding Assets</a>
</li>
<li className="mt-2">
<a href="https://github.com/zen-browser/desktop">Source Code</a>
</li>
<li className="mt-2">
<a href="https://docs.zen-browser.app">Documentation</a>
</li>
<li className="mt-2">
<a href="/release-notes">Release Notes</a>
</li>
</ul>
<h2 className="text-md font-bold opacity-80 mt-8">Support Us</h2>
<ul className="mt-4 opacity-70 font-normal">
<li>
<a href="https://patreon.com/zen_browser">Patreon</a>
</li>
<li className="mt-2">
<a href="https://ko-fi.com/zen_browser">Ko-fi</a>
</li>
</ul>
</div>
</div>
</div>
<div className="flex w-full pt-10 pr-5 pl-3 mx-auto lg:!w-2/3 items-center">
<p className="text-xs font-normal opacity-30">Crafted with by the community - Copyright © {new Date().getFullYear()} Zen Browser</p>
<a href="/download" className="ml-auto">
<Button className="ml-auto">Download</Button>
</a>
</div>
</div> </div>
); );
} }

View File

@@ -9,7 +9,7 @@ import { BorderBeam } from "./ui/border-beam";
import { ny } from "@/lib/utils"; import { ny } from "@/lib/utils";
import { ChevronDown, ChevronRight } from "lucide-react"; import { ChevronDown, ChevronRight } from "lucide-react";
import Particles from "./ui/particles"; import Particles from "./ui/particles";
import Image from "next/image"; import Image from "next/legacy/image";
import Link from "next/link"; import Link from "next/link";
export default function Header() { export default function Header() {
const ref = useRef(null); const ref = useRef(null);

View File

@@ -0,0 +1,7 @@
export const MastodonLogo = (props: any) => (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256" {...props}>
<path fill="currentColor" d="M184 32H72a40 40 0 0 0-40 40v120a40 40 0 0 0 40 40h88a8 8 0 0 0 0-16H72a24 24 0 0 1-24-24v-8h136a40 40 0 0 0 40-40V72a40 40 0 0 0-40-40m24 112a24 24 0 0 1-24 24H48V72a24 24 0 0 1 24-24h112a24 24 0 0 1 24 24Zm-24-40v32a8 8 0 0 1-16 0v-32a16 16 0 0 0-32 0v32a8 8 0 0 1-16 0v-32a16 16 0 0 0-32 0v32a8 8 0 0 1-16 0v-32a32 32 0 0 1 56-21.13A32 32 0 0 1 184 104"></path>
</svg>
)

View File

@@ -1,23 +1,15 @@
"use client"; "use client";
import { LOGO_COLORS } from "@/lib/logos"; import { LOGO_COLORS } from "@/lib/logos";
import { ny } from "@/lib/utils"; import { ny } from "@/lib/utils";
import Image from "next/image"; import Image from "next/legacy/image";
import React from "react"; import React from "react";
import CachedImage from "./CachedImage";
export default function Logo({ withText, ...props }: any) { export default function Logo({ withText, ...props }: any) {
return ( return (
<div className="m-0 flex items-center" {...props}> <div className="flex items-center m-0" {...props}>
<Image <CachedImage src={`www/public/logos/zen-black.svg`} width={40} height={40} alt="Zen Logo" className={ny("transition-all duration-300 hover:scale-110", withText && "mr-2")} />
src={`https://cdn.jsdelivr.net/gh/zen-browser/www/public/logos/zen-black.svg`} {withText && <span className="text-2xl font-bold ml-2">zen</span>}
width={40}
height={40}
alt="Zen Logo"
className={ny(
"transition-all duration-300 hover:scale-110",
withText && "mr-2",
)}
/>
{withText && <span className="ml-2 text-2xl font-bold">zen</span>}
</div> </div>
); );
} }

View File

@@ -5,24 +5,19 @@ import { getAllThemes, getThemesFromSearch, ZenTheme } from "@/lib/themes";
import ThemeCard from "./theme-card"; import ThemeCard from "./theme-card";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
export default function MarketplacePage() { export default function MarketplacePage({ themes }: {themes:ZenTheme[]}) {
const [searchInput, setSearchInput] = React.useState(""); const [searchInput, setSearchInput] = React.useState("");
const [tags, setTags] = React.useState<string[]>(["all"]); const [tags, setTags] = React.useState<string[]>(["all"]);
const [themes, setThemes] = React.useState<ZenTheme[]>([]);
React.useEffect(() => {
getAllThemes().then(setThemes);
}, []);
return ( return (
<div className="flex flex-col w-full mx-auto items-center justify-center h-full"> <div className="flex flex-col w-full mx-auto items-center justify-center h-full">
<div className="mx-auto w-full text-center border-b pt-48 pb-24 mb-12 bg-gradient-to-r from-[#f6cfbe] to-[#b9dcf2] dark:from-[#0d1117] dark:to-[#0d1117]"> <div className="mx-auto w-full text-center border-b pt-48 pb-24 mb-12 bg-surface">
<div className="w-full lg:w-1/2 xl:w-1/2 mx-auto px-2 lg:px-none"> <div className="w-full lg:w-1/2 xl:w-1/2 mx-auto px-2 lg:px-none">
<h1 className="text-4xl lg:text-7xl font-bold">Themes Store</h1> <h1 className="text-4xl lg:text-7xl font-bold">Themes Store</h1>
<ThemesSearch input={searchInput} setInput={setSearchInput} tags={tags} setTags={setTags} /> <ThemesSearch input={searchInput} setInput={setSearchInput} tags={tags} setTags={setTags} />
</div> </div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8 mt-10 w-full lg:w-1/2 xl:w-2/3 2xl:w-3/4"> <div className="px-5 lg:px-0 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8 mt-10 w-full lg:w-1/2 xl:w-2/3 2xl:w-3/4">
{getThemesFromSearch(themes, searchInput, tags).map((theme) => ( {getThemesFromSearch(themes, searchInput, tags).map((theme) => (
<ThemeCard key={theme.name} theme={theme} /> <ThemeCard key={theme.name} theme={theme} />
))} ))}

View File

@@ -13,7 +13,7 @@ import { ny } from '@/lib/utils'
import { components } from './navigation' import { components } from './navigation'
export function MobileNav() { export function MobileNav() {
const [open, setOpen] = React.useState(false) const [open, setOpen] = React.useState(false);
return ( return (
<Sheet open={open} onOpenChange={setOpen}> <Sheet open={open} onOpenChange={setOpen}>
@@ -37,31 +37,41 @@ export function MobileNav() {
> >
<Logo withText /> <Logo withText />
</MobileLink> </MobileLink>
<ScrollArea className="my-4 h-[calc(100vh-8rem)] pb-10 pl-6"> <ScrollArea className="mt-4 h-[calc(100vh-8rem)] pl-6">
<div className="flex flex-col space-y-3"> <div className="flex flex-col space-y-3">
<MobileLink <MobileLink
href="/download" href="/download"
onOpenChange={setOpen} onOpenChange={setOpen}
> >
Download <div>Download</div>
<p className="opacity-60 text-xs">
Get the latest version of Zen Browser.
</p>
</MobileLink> </MobileLink>
<MobileLink <MobileLink
href="/themes" href="/themes"
onOpenChange={setOpen} onOpenChange={setOpen}
> >
Theme Store <div>Theme Store</div>
<p className="opacity-60 text-xs">
Customize your browsing experience.
</p>
</MobileLink> </MobileLink>
<MobileLink <MobileLink
href="/release-notes" href="/release-notes"
onOpenChange={setOpen} onOpenChange={setOpen}
> >
Release Notes <div>Release Notes</div>
<p className="opacity-60 text-xs">
Stay up to date with the latest changes.
</p>
</MobileLink> </MobileLink>
<MobileLink <MobileLink
href="https://patreon.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink" href="https://patreon.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink"
onOpenChange={setOpen} onOpenChange={setOpen}
> >
Donate {"<"}3 <div>Donate {"<"}3</div>
<p className="opacity-60 text-xs">Support the project</p>
</MobileLink> </MobileLink>
{components.map(({title, href, description}) => ( {components.map(({title, href, description}) => (
<MobileLink <MobileLink
@@ -69,7 +79,8 @@ export function MobileNav() {
key={href} key={href}
onOpenChange={setOpen} onOpenChange={setOpen}
> >
{title} <div>{title}</div>
<p className='opacity-60 text-xs'>{description}</p>
</MobileLink> </MobileLink>
))} ))}
</div> </div>
@@ -100,7 +111,7 @@ function MobileLink({
router.push(href.toString()) router.push(href.toString())
onOpenChange?.(false) onOpenChange?.(false)
}} }}
className={ny(className)} className={ny(className, "my-4")}
{...props} {...props}
> >
{children} {children}

View File

@@ -1,7 +1,7 @@
"use client"; "use client";
import * as React from "react"; import {useEffect, useState} from "react";
import { MoonIcon, SunIcon } from "@radix-ui/react-icons"; import { MoonIcon, SunIcon, Half2Icon } from "@radix-ui/react-icons";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { import {
@@ -12,14 +12,36 @@ import {
} from "./ui/dropdown-menu"; } from "./ui/dropdown-menu";
export function ModeToggle() { export function ModeToggle() {
const [mounted, setMounted] = useState(false);
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
const toggleTheme = () => { const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light"); switch (theme) {
case 'system':
setTheme("dark");
break;
case 'dark':
setTheme("light");
break;
case 'light':
setTheme('system');
break;
}
}; };
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
console.log(theme);
return ( return (
<Button variant="ghost" size="icon" onClick={toggleTheme}> <Button variant="ghost" size="icon" onClick={toggleTheme}>
<SunIcon className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> <MoonIcon className={`${ (theme === 'system') ? 'visible' : 'hidden'} h-[1.2rem] w-[1.2rem]`} />
<MoonIcon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> <SunIcon className={`${ (theme === 'light') ? 'visible' : 'hidden'} h-[1.2rem] w-[1.2rem]`} />
<MoonIcon className={`${ (theme === 'dark') ? 'visible' : 'hidden'} h-[1.2rem] w-[1.2rem]`} />
<span className="sr-only">Toggle theme</span> <span className="sr-only">Toggle theme</span>
</Button> </Button>
); );

View File

@@ -1,4 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import Link from "next/link" import Link from "next/link"
@@ -18,40 +17,41 @@ import { ModeToggle } from "./mode-toggle"
import { MobileNav } from "./mobile-nav" import { MobileNav } from "./mobile-nav"
import { HeartIcon } from "lucide-react" import { HeartIcon } from "lucide-react"
import { HeartFilledIcon } from "@radix-ui/react-icons" import { HeartFilledIcon } from "@radix-ui/react-icons"
import { useTranslations } from "next-intl";
export const components: { title: string; href: string; description: string }[] = [ export const components: { title: string; href: string; description: string }[] = [
{ {
title: "Privacy Policy", title: "Privacy Policy",
href: "/privacy-policy", href: "/privacy-policy",
description: "Learn how we handle your data. Don't worry, we don't collect anything!", description: "Read our privacy policy to learn more about how we handle your data."
}, },
{ {
title: "Discord", title: "Discord",
href: "https://discord.gg/nnShMQzR4b", href: "https://discord.com/servers/mauro-s-little-sweatshop-1088172780480114748",
description: "Join our Discord server to chat with the community." description: "Join our Discord server to chat with the community and get support."
}, },
{ {
title: "Source Code", title: "Source Code",
href: "https://github.com/zen-browser", href: "https://github.com/zen-browser",
description: "Check out our source code on GitHub and leave a star!" description: "View the source code on GitHub and contribute to the project."
}, },
{ {
title: "Branding Assets", title: "Branding Assets",
href: "/branding-assets", href: "/branding-assets",
description: "Download Zen Browser branding assets for your website or project." description: "Download our branding assets to use in your projects."
},
{
title: "About",
href: "/about",
description: "Learn more about the Zen Browser project and the team behind it."
}, },
{ {
title: "Documentation", title: "Documentation",
href: "https://docs.zen-browser.app/", href: "https://docs.zen-browser.app/",
description: "Learn how to use Zen Browser and build your own themes." description: "Read the documentation to learn more about Zen Browser."
} }
] ]
export function Navigation() { export function Navigation() {
const t = useTranslations('navigation');
return ( return (
<div className="bg-background z-40 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center"> <div className="bg-background z-40 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
<MobileNav /> <MobileNav />
@@ -63,7 +63,7 @@ export function Navigation() {
</NavigationMenuLink> </NavigationMenuLink>
</NavigationMenuItem> </NavigationMenuItem>
<NavigationMenuItem> <NavigationMenuItem>
<NavigationMenuTrigger>{t('getting-started')}</NavigationMenuTrigger> <NavigationMenuTrigger>Getting Started</NavigationMenuTrigger>
<NavigationMenuContent> <NavigationMenuContent>
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]"> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<li className="row-span-3"> <li className="row-span-3">
@@ -74,7 +74,7 @@ export function Navigation() {
> >
<Logo /> <Logo />
<div className="mb-2 mt-4 text-lg font-medium"> <div className="mb-2 mt-4 text-lg font-medium">
Zen Browser Zen Browser
</div> </div>
<p className="text-sm leading-tight text-muted-foreground"> <p className="text-sm leading-tight text-muted-foreground">
Firefox based browser with a focus on privacy and Firefox based browser with a focus on privacy and
@@ -84,13 +84,13 @@ export function Navigation() {
</NavigationMenuLink> </NavigationMenuLink>
</li> </li>
<ListItem href="/download" title="Download"> <ListItem href="/download" title="Download">
Start using Zen Browser today with just a few clicks. Start using Zen Browser today with just a few clicks.
</ListItem> </ListItem>
<ListItem href="/themes" title="Themes Store"> <ListItem href="/themes" title="Themes Store">
Customize your browser with a variety of themes! Customize your browser with a variety of themes!
</ListItem> </ListItem>
<ListItem href="/release-notes" title="Release Notes"> <ListItem href="/release-notes" title="Release Notes">
Stay up to date with the latest changes. Stay up to date with the latest changes.
</ListItem> </ListItem>
</ul> </ul>
</NavigationMenuContent> </NavigationMenuContent>
@@ -98,7 +98,7 @@ export function Navigation() {
<NavigationMenuItem> <NavigationMenuItem>
<NavigationMenuTrigger> <NavigationMenuTrigger>
<HeartFilledIcon className="text-red-500" /> <HeartFilledIcon className="text-red-500" />
<span className="ml-2">{t('donate')}</span> <span className="ml-2">Donate</span>
</NavigationMenuTrigger> </NavigationMenuTrigger>
<NavigationMenuContent> <NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] "> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
@@ -109,7 +109,7 @@ export function Navigation() {
Support us on Patreon and get exclusive rewards and keep the project alive. Support us on Patreon and get exclusive rewards and keep the project alive.
</ListItem> </ListItem>
<ListItem <ListItem
title="Ko-fi" title="Ko-Fi"
href="https://ko-fi.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink" href="https://ko-fi.com/zen_browser?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink"
> >
Ko-fi is a way to support us with a one-time donation and help us keep the project alive. Ko-fi is a way to support us with a one-time donation and help us keep the project alive.
@@ -118,7 +118,7 @@ export function Navigation() {
</NavigationMenuContent> </NavigationMenuContent>
</NavigationMenuItem> </NavigationMenuItem>
<NavigationMenuItem> <NavigationMenuItem>
<NavigationMenuTrigger>{t('useful-links')}</NavigationMenuTrigger> <NavigationMenuTrigger>{"Useful Links"}</NavigationMenuTrigger>
<NavigationMenuContent> <NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] "> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
{components.map((component) => ( {components.map((component) => (

View File

@@ -1,4 +1,4 @@
import Image from "next/image";
import { getThemeAuthorLink, ZenTheme } from "@/lib/themes"; import { getThemeAuthorLink, ZenTheme } from "@/lib/themes";
import styled from "styled-components"; import styled from "styled-components";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog";import { Button } from "./ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog";import { Button } from "./ui/button";
@@ -22,7 +22,7 @@ export default function ThemeCard({
<ThemeCardWrapper onClick={(event) => { <ThemeCardWrapper onClick={(event) => {
if (event.target instanceof HTMLAnchorElement) return; if (event.target instanceof HTMLAnchorElement) return;
window.open(`/themes/${theme.id}`, "_self"); window.open(`/themes/${theme.id}`, "_self");
}} className={ny("flex flex-col justify-start p-5 rounded-lg shadow-sm bg-muted dark:bg-muted/50 border border-grey-900 dark:border-muted w-full hover:shadow-lg transition duration-300 ease-in-out hover:bg-muted/100 hover:border-blue-500 cursor-pointer select-none ", className)}> }} className={ny("flex flex-col justify-start p-5 rounded-lg shadow-sm bg-muted dark:bg-muted/50 border border-grey-900 dark:border-muted w-full hover:shadow-lg transition duration-300 ease-in-out hover:bg-surface hover:border-blue-500 cursor-pointer select-none ", className)}>
<img src={theme.image} alt={theme.name} width={500} height={500} <img src={theme.image} alt={theme.name} width={500} height={500}
className="w-full h-32 object-cover rounded-lg border shadow" /> className="w-full h-32 object-cover rounded-lg border shadow" />
<h2 className="text-xl font-bold mt-4 overflow-ellipsis text-start">{theme.name.substring(0, maxNameLen).trim() + (theme.name.length > maxNameLen ? "..." : "")}</h2> <h2 className="text-xl font-bold mt-4 overflow-ellipsis text-start">{theme.name.substring(0, maxNameLen).trim() + (theme.name.length > maxNameLen ? "..." : "")}</h2>

View File

@@ -1,8 +1,7 @@
import Image from "next/image";
import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes"; import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { useEffect, useState } from "react";
import Markdown from "react-markdown"; import Markdown from "react-markdown";
import '../app/privacy-policy/markdown.css'; import '../app/privacy-policy/markdown.css';
import { ChevronLeft, LoaderCircleIcon } from "lucide-react"; import { ChevronLeft, LoaderCircleIcon } from "lucide-react";
@@ -18,8 +17,8 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
return ( return (
<div className="mt-24 lg:mt-56 flex-col lg:flex-row flex mx-auto items-start relative"> <div className="mt-24 lg:mt-56 flex-col lg:flex-row flex mx-auto items-start relative">
<div className="flex flex-col relative lg:sticky lg:top-0 w-md h-full p-5 lg:p-0 lg:pr-5 mr-5 w-full md:max-w-sm"> <div className="mx-auto md:mx-0 flex flex-col relative bg-surface rounded-lg border shadow lg:sticky lg:top-0 w-md h-full p-5 mr-5 w-full md:max-w-sm">
<a className="flex mt-2 mb-9 items-center cursor-pointer opacity-70" href="/themes"> <a className="flex mt-2 mb-4 items-center cursor-pointer opacity-70" href="/themes">
<ChevronLeft className="w-4 h-4 mr-1" /> <ChevronLeft className="w-4 h-4 mr-1" />
<h3 className="text-md">Go back</h3> <h3 className="text-md">Go back</h3>
</a> </a>
@@ -38,19 +37,18 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
)} )}
<hr className="mt-4" /> <hr className="mt-4" />
<Button <Button
className="mt-4 hidden" className="mt-4 hidden !rounded-lg"
id="install-theme" id="install-theme"
zen-theme-id={theme.id} zen-theme-id={theme.id}
>Install Theme 🎉</Button> >Install Theme 🎉</Button>
<Button <Button
className="mt-4 hidden" className="mt-4 hidden !rounded-lg"
id="install-theme-uninstall" id="install-theme-uninstall"
zen-theme-id={theme.id} zen-theme-id={theme.id}
>Uninstall Theme</Button> >Uninstall Theme</Button>
<p id="install-theme-error" className="text-muted-foreground text-sm mt-2">You need to have Zen Browser installed to install this theme. <a href="/download" className="text-blue-500">Download now!</a></p> <p id="install-theme-error" className="text-muted-foreground text-sm mt-2">You need to have Zen Browser installed to install this theme. <a href="/download" className="text-blue-500">Download now!</a></p>
</div> </div>
<hr className="block my-4 lg:hidden" /> <div className="flex flex-col lg:min-h-[calc(100vh/2-2rem)] px-5 lg:pl-10 max-w-xl lg:min-w-96 w-full">
<div className="flex flex-col lg:border-l lg:min-h-96 px-5 lg:pl-10 max-w-xl lg:min-w-96 w-full">
<div id="policy" className="w-full"> <div id="policy" className="w-full">
{readme === null ? ( {readme === null ? (
<LoaderCircleIcon className="animate-spin w-12 h-12 mx-auto" /> <LoaderCircleIcon className="animate-spin w-12 h-12 mx-auto" />

View File

@@ -1,35 +0,0 @@
import { getRequestConfig } from "next-intl/server";
import { headers } from "next/headers";
const SUPPORTED_LANGUAGES = ['en', 'de'];
export default getRequestConfig(async () => {
const headersList = headers();
const acceptLanguage = headersList.get("accept-language") || "en";
const [primaryLanguage] = acceptLanguage
.split(",")
.map((lang) => lang.split(";")[0])
.map((lang) => lang.toLowerCase());
const locale = SUPPORTED_LANGUAGES.includes(primaryLanguage) ? primaryLanguage : 'en';
try {
const messages = (await import(`../messages/${locale}.json`)).default;
return {
locale,
messages,
};
} catch (error) {
console.error(`Failed to load messages for locale: ${locale}`, error);
const fallbackMessages = (await import(`../messages/en.json`)).default;
return {
locale: "en",
messages: fallbackMessages,
};
}
});

View File

@@ -674,8 +674,51 @@ export const releaseNotes: ReleaseNote[] = [
"Added labels to buttons during expand-on-hover" "Added labels to buttons during expand-on-hover"
], ],
fixes: [ fixes: [
{
description: "Tab bar stuck on right side",
issue: 1115
}
] ]
} },
{
version: "1.0.0-a.35",
date: "02/09/2024",
extra: "This release is the thirty-fifth alpha release of the 1.0.0-alpha series. Things are getting stable!",
features: [
"Added option to restore legacy toolbar interface",
"Added profile-guided optimization (Windows)",
"Added Apple developer certificate (macOS)",
"Added experimental Zen Labs settings",
"Changed interface colors",
"Disabled efficiency-mode by default (Windows)",
"Enabled GPU-accelerated web rendering by default",
"Enabled Video Acceleration API for media decoding",
"Improved support for translations",
"Added Identical Code Folding compiler optimization",
],
fixes: [
{
description: "Zen Browser is damaged and can't be opened on macOS",
issue: 53
},
{
description: "Can't reorganize tabs in compact mode",
issue: 1168
},
{
description: "Theme Store settings page doesn't display installed themes",
issue: 1125
},
{
description: "No Homebrew support",
issue: 273
},
{
description: "Remember last active workspaces on startup",
issue: 240
}
]
}
].reverse(); ].reverse();
export function releaseNoteIsAlpha(note: ReleaseNote) { export function releaseNoteIsAlpha(note: ReleaseNote) {

View File

@@ -1,4 +1,4 @@
name = "zenbrowser-www" name = "zenbrowser-www"
compatibility_date = "2024-07-29" compatibility_date = "2024-07-29"
compatibility_flags = ["nodejs_compat"] compatibility_flags = ["nodejs_compat"]
pages_build_output_dir = ".vercel/output/static" pages_build_output_dir = "out"