Merge branch 'main' into runjan/feature
This commit is contained in:
@@ -1,12 +1,18 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
output: 'export',
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "raw.githubusercontent.com",
|
hostname: "raw.githubusercontent.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "cdn.jsdelivr.net",
|
||||||
|
}
|
||||||
],
|
],
|
||||||
|
domains: ['cdn.jsdelivr.net', "raw.githubusercontent.com"], // Allow images from jsDelivr
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
serverActions: {
|
serverActions: {
|
||||||
|
|||||||
7256
package-lock.json
generated
7256
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
25
src/app/api/get-theme/[id]/route.ts
Normal file
25
src/app/api/get-theme/[id]/route.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { getAllThemes, getThemeFromId } from '@/lib/themes';
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
// Static NextJS API route. We will have /get-theme?id=theme-id static route
|
||||||
|
export async function generateStaticParams() {
|
||||||
|
const themes = await getAllThemes();
|
||||||
|
return themes.map((theme) => ({
|
||||||
|
id: theme.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function removeUneccessaryKeys(theme: any) {
|
||||||
|
delete theme["isDarkMode"];
|
||||||
|
delete theme["isColorTheme"];
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(request: any, { params }: { params: { id: string } }) {
|
||||||
|
const themes = await getAllThemes();
|
||||||
|
const theme = themes.find((theme) => theme.id === params.id);
|
||||||
|
console.log(theme);
|
||||||
|
return NextResponse.json(removeUneccessaryKeys(theme));
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
|
|
||||||
import { getThemeFromId } from "@/lib/themes";
|
|
||||||
|
|
||||||
function getQSParamFromURL(
|
|
||||||
key: string,
|
|
||||||
url: string | undefined
|
|
||||||
): string | null {
|
|
||||||
if (!url) return "";
|
|
||||||
const search = new URL(url).search;
|
|
||||||
const urlParams = new URLSearchParams(search);
|
|
||||||
return urlParams.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeUneccessaryKeys(theme: any) {
|
|
||||||
delete theme["isDarkMode"];
|
|
||||||
delete theme["isColorTheme"];
|
|
||||||
return theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function GET(request: Request, response: Response) {
|
|
||||||
const id = getQSParamFromURL("id", request.url);
|
|
||||||
if (!id) {
|
|
||||||
return Response.json({ error: "id is required" });
|
|
||||||
}
|
|
||||||
const theme = await getThemeFromId(id);
|
|
||||||
if (!theme) {
|
|
||||||
return Response.json({ error: "theme not found" });
|
|
||||||
}
|
|
||||||
return Response.json(removeUneccessaryKeys(theme));
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
"use client";
|
||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
import { Navigation } from "@/components/navigation";
|
import { Navigation } from "@/components/navigation";
|
||||||
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
import { Navigation } from "@/components/navigation";
|
import { Navigation } from "@/components/navigation";
|
||||||
@@ -6,10 +5,13 @@ import ReleaseNote from "@/components/release-note";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { releaseNotes } from "@/lib/release-notes";
|
import { releaseNotes } from "@/lib/release-notes";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { redirect, useParams } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default function ReleaseNotePage() {
|
export async function generateStaticParams() {
|
||||||
const params = useParams<{ version: string }>();
|
return [{version: "latest"}, ...releaseNotes.map((note) => ({ version: note.version }))];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ReleaseNotePage({ params }: { params: { version: string } }) {
|
||||||
const { version } = params;
|
const { version } = params;
|
||||||
|
|
||||||
if (version === "latest") {
|
if (version === "latest") {
|
||||||
@@ -22,11 +24,11 @@ export default function ReleaseNotePage() {
|
|||||||
<main className="flex min-h-screen flex-col items-center justify-center">
|
<main className="flex min-h-screen flex-col items-center justify-center">
|
||||||
<div className="h-screen flex flex-wrap items-center justify-center">
|
<div className="h-screen flex flex-wrap items-center justify-center">
|
||||||
<h1 className="text-4xl font-bold mt-12">Release note not found</h1>
|
<h1 className="text-4xl font-bold mt-12">Release note not found</h1>
|
||||||
<Link href="/release-notes">
|
<a href="/release-notes">
|
||||||
<Button className="mt-4 items-center justify-center">
|
<Button className="mt-4 items-center justify-center">
|
||||||
Back to release notes
|
Back to release notes
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
<Navigation /> {/* At the bottom of the page */}
|
<Navigation /> {/* At the bottom of the page */}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
import { Navigation } from "@/components/navigation";
|
import { Navigation } from "@/components/navigation";
|
||||||
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
||||||
@@ -10,7 +12,7 @@ export default function ReleaseNotes() {
|
|||||||
<h1 className="text-4xl text-center font-bold mt-24">Release Notes</h1>
|
<h1 className="text-4xl text-center font-bold mt-24">Release Notes</h1>
|
||||||
<div className="grid gap-5 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-10">
|
<div className="grid gap-5 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-10">
|
||||||
{releaseNotes.map((releaseNote) => (
|
{releaseNotes.map((releaseNote) => (
|
||||||
<Link href={`/release-notes/${releaseNote.version}`} className="bg-background relative max-w-64 overflow-hidden rounded-lg border p-5 hover:border-blue-500 transition-all duration-300 hover:-translate-y-1 hover:-translate-x-1" key={releaseNote.version}>
|
<a href={`/release-notes/${releaseNote.version}`} className="bg-background relative max-w-64 overflow-hidden rounded-lg border p-5 hover:border-blue-500 transition-all duration-300 hover:-translate-y-1 hover:-translate-x-1" key={releaseNote.version}>
|
||||||
<div className="text-md font-medium mb-5">
|
<div className="text-md font-medium mb-5">
|
||||||
{releaseNote.version}
|
{releaseNote.version}
|
||||||
</div>
|
</div>
|
||||||
@@ -22,7 +24,7 @@ export default function ReleaseNotes() {
|
|||||||
Alpha Release
|
Alpha Release
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
import { Navigation } from "@/components/navigation";
|
import { Navigation } from "@/components/navigation";
|
||||||
import ThemePage from "@/components/theme-page";
|
import ThemePage from "@/components/theme-page";
|
||||||
import { getThemeFromId } from "@/lib/themes";
|
import { getAllThemes, getThemeFromId } from "@/lib/themes";
|
||||||
import { Metadata, ResolvingMetadata } from "next";
|
import { Metadata, ResolvingMetadata } from "next";
|
||||||
|
|
||||||
export async function generateMetadata(
|
export async function generateMetadata(
|
||||||
@@ -36,10 +36,19 @@ export async function generateMetadata(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ThemeInfoPage() {
|
export async function generateStaticParams() {
|
||||||
|
const themes = await getAllThemes();
|
||||||
|
console.log(themes);
|
||||||
|
return themes.map((theme) => ({
|
||||||
|
theme: theme.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ThemeInfoPage({ params }: { params: { theme: string } }) {
|
||||||
|
const { theme } = params;
|
||||||
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 />
|
<ThemePage themeID={theme} />
|
||||||
<Footer />
|
<Footer />
|
||||||
<Navigation /> {/* At the bottom of the page */}
|
<Navigation /> {/* At the bottom of the page */}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function BrandingAssets() {
|
|||||||
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-10 mt-10 w-full">
|
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-10 mt-10 w-full">
|
||||||
{LOGO_COLORS.map((color) => (
|
{LOGO_COLORS.map((color) => (
|
||||||
<div key={color} className="flex flex-col items-center">
|
<div key={color} className="flex flex-col items-center">
|
||||||
<img src={`/logos/zen-${color}.svg`} alt={`Zen Browser ${color} logo`} className="w-24 h-24 mt-4" />
|
<img src={`https://cdn.jsdelivr.net/gh/zen-browser/www/public/logos/zen-${color}.svg`} alt={`Zen Browser ${color} logo`} className="w-24 h-24 mt-4" />
|
||||||
<div className="flex items-center my-2">
|
<div className="flex items-center my-2">
|
||||||
<a
|
<a
|
||||||
href={`/logos/zen-${color}.svg`}
|
href={`/logos/zen-${color}.svg`}
|
||||||
@@ -38,7 +38,7 @@ export function BrandingAssets() {
|
|||||||
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-10 mt-10 w-full">
|
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-10 mt-10 w-full">
|
||||||
{LOGO_COLORS.map((color) => (
|
{LOGO_COLORS.map((color) => (
|
||||||
<div key={color} className="flex flex-col items-center">
|
<div key={color} className="flex flex-col items-center">
|
||||||
<img src={`/logos/zen-alpha-${color}.svg`} alt={`Zen Browser ${color} logo`} className="w-24 h-24 mt-4" />
|
<img src={`https://cdn.jsdelivr.net/gh/zen-browser/www/public/logos/zen-alpha-${color}.svg`} alt={`Zen Browser ${color} logo`} className="w-24 h-24 mt-4" />
|
||||||
<div className="flex items-center my-2">
|
<div className="flex items-center my-2">
|
||||||
<a
|
<a
|
||||||
href={`/logos/zen-alpha-${color}.svg`}
|
href={`/logos/zen-alpha-${color}.svg`}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { addDownload } from "@/lib/db";
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import styled, { keyframes } from "styled-components";
|
import styled, { keyframes } from "styled-components";
|
||||||
import { ny } from "@/lib/utils";
|
import { ny } from "@/lib/utils";
|
||||||
@@ -158,7 +157,6 @@ export default function DownloadPage() {
|
|||||||
window.location.replace(`${BASE_URL}/${releases[releaseTarget]}`);
|
window.location.replace(`${BASE_URL}/${releases[releaseTarget]}`);
|
||||||
}
|
}
|
||||||
setHasDownloaded(true);
|
setHasDownloaded(true);
|
||||||
addDownload(releaseTarget);
|
|
||||||
throwConfetti();
|
throwConfetti();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -221,16 +219,16 @@ export default function DownloadPage() {
|
|||||||
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">
|
||||||
<Link href="https://github.com/zen-browser">Source Code</Link>
|
<a href="https://github.com/zen-browser">Source Code</a>
|
||||||
<Link
|
<a
|
||||||
className="ml-5"
|
className="ml-5"
|
||||||
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"
|
||||||
>
|
>
|
||||||
Donate
|
Donate
|
||||||
</Link>
|
</a>
|
||||||
<Link className="ml-5" href="/release-notes/latest">
|
<a className="ml-5" href="/release-notes/latest">
|
||||||
Release Notes
|
Release Notes
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{selectedPlatform === "MacOS" && (
|
{selectedPlatform === "MacOS" && (
|
||||||
<div className="mt-12 flex flex-col items-start border justify-between rounded-md bg-background p-5">
|
<div className="mt-12 flex flex-col items-start border justify-between rounded-md bg-background p-5">
|
||||||
@@ -571,13 +569,13 @@ export default function DownloadPage() {
|
|||||||
<InfoCircledIcon className="size-4 mr-2" />
|
<InfoCircledIcon className="size-4 mr-2" />
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
Confused about which build to choose?{" "}
|
Confused about which build to choose?{" "}
|
||||||
<Link
|
<a
|
||||||
href="https://docs.zen-browser.app/guides/generic-optimized"
|
href="https://docs.zen-browser.app/guides/generic-optimized"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="text-blue-400"
|
className="text-blue-400"
|
||||||
>
|
>
|
||||||
System requirements
|
System requirements
|
||||||
</Link>
|
</a>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -150,11 +150,11 @@ export default function Features() {
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Link href="/download">
|
<a href="/download">
|
||||||
<Button className="mt-4 rounded-full p-5 ml-auto">
|
<Button className="mt-4 rounded-full p-5 ml-auto">
|
||||||
Download Zen now!
|
Download Zen now!
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="border rounded-lg shadow-md mt-16 mx-auto p-4 bg-white dark:bg-black flex w-fit transform -translate-x-1/3">
|
<div className="border rounded-lg shadow-md mt-16 mx-auto p-4 bg-white dark:bg-black flex w-fit transform -translate-x-1/3">
|
||||||
{COLORS.map((color) => (
|
{COLORS.map((color) => (
|
||||||
@@ -190,14 +190,14 @@ export default function Features() {
|
|||||||
Killer feature
|
Killer feature
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link href="/download">
|
<a href="/download">
|
||||||
<Button className="mt-4 rounded-full p-5 ml-4">
|
<Button className="mt-4 rounded-full p-5 ml-4">
|
||||||
Download Zen now!
|
Download Zen now!
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
src="/compact-mode.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/compact-mode.png"
|
||||||
className="scale-105 hover:scale-110 transform rotate-[-2deg] transition-all duration-100 rounded-md w-full shadow-md dark:shadow-none dark:border-2 mt-16 border-blue-600"
|
className="scale-105 hover:scale-110 transform rotate-[-2deg] transition-all duration-100 rounded-md w-full shadow-md dark:shadow-none dark:border-2 mt-16 border-blue-600"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -207,7 +207,7 @@ export default function Features() {
|
|||||||
<div className="font-bold text-md">
|
<div className="font-bold text-md">
|
||||||
What makes Zen Browser different?
|
What makes Zen Browser different?
|
||||||
</div>
|
</div>
|
||||||
<img src="/favicon.ico" className="ml-auto w-7 h-7" />
|
<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/favicon.ico" className="ml-auto w-7 h-7" />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full w-full flex items-center justify-center">
|
<div className="h-full w-full flex items-center justify-center">
|
||||||
<Table className="w-full">
|
<Table className="w-full">
|
||||||
@@ -220,7 +220,7 @@ export default function Features() {
|
|||||||
<span className="">How Zen compares to other browsers</span>
|
<span className="">How Zen compares to other browsers</span>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableHead className="py-2 font-bold text-center">
|
<TableHead className="py-2 font-bold text-center">
|
||||||
<Image
|
<img
|
||||||
height={32}
|
height={32}
|
||||||
width={32}
|
width={32}
|
||||||
src="/favicon.ico"
|
src="/favicon.ico"
|
||||||
@@ -230,20 +230,20 @@ export default function Features() {
|
|||||||
Zen
|
Zen
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableHead className="py-2 pl-4 lg:pr-0 pr-2 font-bold text-center opacity-60">
|
<TableHead className="py-2 pl-4 lg:pr-0 pr-2 font-bold text-center opacity-60">
|
||||||
<Image
|
<img
|
||||||
height={32}
|
height={32}
|
||||||
width={32}
|
width={32}
|
||||||
src="/floorp.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/floorp.png"
|
||||||
className="bg-black dark:bg-white rounded-md p-1 mx-auto mb-2 w-7 h-7"
|
className="bg-black dark:bg-white rounded-md p-1 mx-auto mb-2 w-7 h-7"
|
||||||
alt="floorp"
|
alt="floorp"
|
||||||
/>
|
/>
|
||||||
Floorp
|
Floorp
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableHead className="py-2 pl-0 font-bold text-center opacity-60">
|
<TableHead className="py-2 pl-0 font-bold text-center opacity-60">
|
||||||
<Image
|
<img
|
||||||
height={32}
|
height={32}
|
||||||
width={32}
|
width={32}
|
||||||
src="/librewolf.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/librewolf.png"
|
||||||
className="bg-black dark:bg-white rounded-md mx-auto p-1 mb-2 w-7 h-7"
|
className="bg-black dark:bg-white rounded-md mx-auto p-1 mb-2 w-7 h-7"
|
||||||
alt="librewolf"
|
alt="librewolf"
|
||||||
/>
|
/>
|
||||||
@@ -382,21 +382,21 @@ export default function Features() {
|
|||||||
<div className="relative p-16 border-r-2 flex flex-col items-center justify-center row-span-2 col-span-2">
|
<div className="relative p-16 border-r-2 flex flex-col items-center justify-center row-span-2 col-span-2">
|
||||||
<div className="relative w-full h-full flex items-center justify-center">
|
<div className="relative w-full h-full flex items-center justify-center">
|
||||||
<img
|
<img
|
||||||
src="/split-view.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/split-view.png"
|
||||||
className={ny(
|
className={ny(
|
||||||
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
||||||
feature === 0 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
feature === 0 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src="/workspaces.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/workspaces.png"
|
||||||
className={ny(
|
className={ny(
|
||||||
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
||||||
feature === 1 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
feature === 1 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src="/sidebar.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/sidebar.png"
|
||||||
className={ny(
|
className={ny(
|
||||||
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
'absolute hover:scale-105 rounded-md w-full shadow-md dark:shadow-none dark:border-2 border-blue-500 transform transition-all duration-300',
|
||||||
feature === 2 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
feature === 2 ? 'translate-x-0' : '-translate-x-1/4 opacity-0'
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ 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 flex-col md:flex-row px-10 md:px-0 border-t w-full border-grey py-10 mt-10 flex justify-center align-center">
|
||||||
Zen Browser © {new Date().getFullYear()} - Made with ❤️ by the Zen team.
|
Zen Browser © {new Date().getFullYear()} - Made with ❤️ by the Zen team.
|
||||||
<Link
|
<a
|
||||||
href={"https://github.com/zen-browser"}
|
href={"https://github.com/zen-browser"}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="mt-5 md:mt-0 md:ml-2 font-bold"
|
className="mt-5 md:mt-0 md:ml-2 font-bold"
|
||||||
>
|
>
|
||||||
Source Code
|
Source Code
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function Header() {
|
|||||||
id="hero"
|
id="hero"
|
||||||
className="relative mx-auto mt-40 max-w-7xl px-6 text-center md:px-8"
|
className="relative mx-auto mt-40 max-w-7xl px-6 text-center md:px-8"
|
||||||
>
|
>
|
||||||
<Link href="/download">
|
<a href="/download">
|
||||||
<AnimatedGradientText>
|
<AnimatedGradientText>
|
||||||
🎉 <hr className="mx-2 h-4 w-[1px] shrink-0 bg-gray-300" />{" "}
|
🎉 <hr className="mx-2 h-4 w-[1px] shrink-0 bg-gray-300" />{" "}
|
||||||
<span
|
<span
|
||||||
@@ -32,7 +32,7 @@ export default function Header() {
|
|||||||
</span>
|
</span>
|
||||||
<ChevronRight className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
|
<ChevronRight className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
|
||||||
</AnimatedGradientText>
|
</AnimatedGradientText>
|
||||||
</Link>
|
</a>
|
||||||
<h1 className="animate-fade-in -translate-y-4 text-balance bg-gradient-to-br from-black from-30% to-black/40 bg-clip-text py-6 text-5xl font-semibold leading-none tracking-tighter text-transparent opacity-0 [--animation-delay:200ms] sm:text-6xl md:text-7xl lg:text-8xl dark:from-white dark:to-white/40">
|
<h1 className="animate-fade-in -translate-y-4 text-balance bg-gradient-to-br from-black from-30% to-black/40 bg-clip-text py-6 text-5xl font-semibold leading-none tracking-tighter text-transparent opacity-0 [--animation-delay:200ms] sm:text-6xl md:text-7xl lg:text-8xl dark:from-white dark:to-white/40">
|
||||||
Zen is the best way
|
Zen is the best way
|
||||||
<br className="hidden md:block" /> to browse the web.
|
<br className="hidden md:block" /> to browse the web.
|
||||||
@@ -42,14 +42,14 @@ export default function Header() {
|
|||||||
<br className="hidden md:block" /> We care about your experience, not
|
<br className="hidden md:block" /> We care about your experience, not
|
||||||
your data.
|
your data.
|
||||||
</p>
|
</p>
|
||||||
<Link href="/download">
|
<a href="/download">
|
||||||
<Button
|
<Button
|
||||||
className="animate-fade-in -translate-y-4 gap-1 rounded-lg text-white opacity-0 ease-in-out [--animation-delay:600ms] dark:text-black"
|
className="animate-fade-in -translate-y-4 gap-1 rounded-lg text-white opacity-0 ease-in-out [--animation-delay:600ms] dark:text-black"
|
||||||
>
|
>
|
||||||
<span>Download Zen Now </span>
|
<span>Download Zen Now </span>
|
||||||
<ArrowRightIcon className="ml-1 size-4 transition-transform duration-300 ease-in-out group-hover:translate-x-1" />
|
<ArrowRightIcon className="ml-1 size-4 transition-transform duration-300 ease-in-out group-hover:translate-x-1" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</a>
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="animate-fade-up relative mt-32 opacity-0 [--animation-delay:400ms] [perspective:2000px] after:absolute after:inset-0 after:z-50 after:[background:linear-gradient(to_top,hsl(var(--background))_10%,transparent)]"
|
className="animate-fade-up relative mt-32 opacity-0 [--animation-delay:400ms] [perspective:2000px] after:absolute after:inset-0 after:z-50 after:[background:linear-gradient(to_top,hsl(var(--background))_10%,transparent)]"
|
||||||
@@ -67,17 +67,17 @@ export default function Header() {
|
|||||||
colorTo="var(--color-two)"
|
colorTo="var(--color-two)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Image
|
<img
|
||||||
width={1500}
|
width={1500}
|
||||||
height={700}
|
height={700}
|
||||||
src="/browser-dark.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-dark.png"
|
||||||
alt="browser Image"
|
alt="browser Image"
|
||||||
className="relative hidden rounded-[inherit] border object-contain dark:block"
|
className="relative hidden rounded-[inherit] border object-contain dark:block"
|
||||||
/>
|
/>
|
||||||
<Image
|
<img
|
||||||
width={1500}
|
width={1500}
|
||||||
height={700}
|
height={700}
|
||||||
src="/browser-light.png"
|
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-light.png"
|
||||||
alt="browser Image"
|
alt="browser Image"
|
||||||
className="relative block rounded-[inherit] border object-contain dark:hidden"
|
className="relative block rounded-[inherit] border object-contain dark:hidden"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default function Logo({ withText, ...props }: any) {
|
|||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center m-0" {...props}>
|
<div className="flex items-center m-0" {...props}>
|
||||||
<Image src={`/logos/zen-${randomColor}.svg`} width={40} height={40} alt="Zen Logo" className={ny("transition-all duration-300 hover:scale-110", withText && "mr-2")} />
|
<img src={`https://cdn.jsdelivr.net/gh/zen-browser/www/public/logos/zen-${randomColor}.svg`} width={40} height={40} alt="Zen Logo" className={ny("transition-all duration-300 hover:scale-110", withText && "mr-2")} />
|
||||||
{withText && <span className="text-2xl font-bold ml-2">zen</span>}
|
{withText && <span className="text-2xl font-bold ml-2">zen</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ function MobileLink({
|
|||||||
}: MobileLinkProps) {
|
}: MobileLinkProps) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
return (
|
return (
|
||||||
<Link
|
<a
|
||||||
href={href}
|
href={href.toString()}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push(href.toString())
|
router.push(href.toString())
|
||||||
onOpenChange?.(false)
|
onOpenChange?.(false)
|
||||||
@@ -104,6 +104,6 @@ function MobileLink({
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</a>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ export function Navigation() {
|
|||||||
<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">
|
||||||
<NavigationMenuLink asChild>
|
<NavigationMenuLink asChild>
|
||||||
<Link
|
<a
|
||||||
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
|
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
|
||||||
href="/"
|
href="/"
|
||||||
>
|
>
|
||||||
@@ -76,7 +76,7 @@ export function Navigation() {
|
|||||||
Firefox based browser with a focus on privacy and
|
Firefox based browser with a focus on privacy and
|
||||||
customization.
|
customization.
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</a>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
</li>
|
</li>
|
||||||
<ListItem href="/download" title="Download">
|
<ListItem href="/download" title="Download">
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
|
|||||||
</p>
|
</p>
|
||||||
<p className="text-md mt-4 text-muted-foreground">
|
<p className="text-md mt-4 text-muted-foreground">
|
||||||
If you encounter any issues, please report them on{" "}
|
If you encounter any issues, please report them on{" "}
|
||||||
<Link
|
<a
|
||||||
href="https://github.com/zen-browser/desktop/issues/"
|
href="https://github.com/zen-browser/desktop/issues/"
|
||||||
className="text-underline text-blue-500"
|
className="text-underline text-blue-500"
|
||||||
>
|
>
|
||||||
the issues page
|
the issues page
|
||||||
</Link>
|
</a>
|
||||||
. Thanks everyone for your feedback! ❤️
|
. Thanks everyone for your feedback! ❤️
|
||||||
</p>
|
</p>
|
||||||
{data.extra && (
|
{data.extra && (
|
||||||
@@ -81,13 +81,13 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
|
|||||||
<li key={index} className="mt-1 text-muted-foreground">
|
<li key={index} className="mt-1 text-muted-foreground">
|
||||||
{fix.description}
|
{fix.description}
|
||||||
{fix.issue && (
|
{fix.issue && (
|
||||||
<Link
|
<a
|
||||||
href={`https://github.com/zen-browser/desktop/issues/${fix.issue}`}
|
href={`https://github.com/zen-browser/desktop/issues/${fix.issue}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="ml-1 text-blue-500"
|
className="ml-1 text-blue-500"
|
||||||
>
|
>
|
||||||
issue #{fix.issue}
|
issue #{fix.issue}
|
||||||
</Link>
|
</a>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@@ -96,9 +96,9 @@ export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap items-center justify-center">
|
<div className="flex flex-wrap items-center justify-center">
|
||||||
<Link href="/download">
|
<a href="/download">
|
||||||
<Button className="mt-12 w-fit mx-auto">Download Zen now!</Button>
|
<Button className="mt-12 w-fit mx-auto">Download Zen now!</Button>
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function ThemeCard({
|
|||||||
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="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="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 ">
|
||||||
<Image src={theme.image} alt={theme.name} width={500} height={500} quality={100}
|
<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>
|
||||||
<div className="flex mt-2">
|
<div className="flex mt-2">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"use client";
|
|
||||||
import Image from "next/image";
|
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";
|
||||||
@@ -6,11 +6,8 @@ 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";
|
||||||
import { useParams } from "next/navigation";
|
|
||||||
|
|
||||||
export default async function ThemePage() {
|
export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||||
const params = useParams<{ theme: string }>();
|
|
||||||
const { theme: themeID } = params;
|
|
||||||
|
|
||||||
const theme = await getThemeFromId(themeID);
|
const theme = await getThemeFromId(themeID);
|
||||||
if (!theme) {
|
if (!theme) {
|
||||||
@@ -22,11 +19,11 @@ export default async function ThemePage() {
|
|||||||
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="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="flex mt-2 mb-9 items-center cursor-pointer opacity-70" onClick={() => window.history.back()}>
|
<a className="flex mt-2 mb-9 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>
|
||||||
</div>
|
</a>
|
||||||
<Image src={theme.image} alt={theme.name} width={500} height={500} className="w-full object-cover rounded-lg border-2 shadow" />
|
<img src={theme.image} alt={theme.name} width={500} height={500} className="w-full object-cover rounded-lg border-2 shadow" />
|
||||||
<h1 className="text-2xl mt-5 font-bold">{theme.name}</h1>
|
<h1 className="text-2xl mt-5 font-bold">{theme.name}</h1>
|
||||||
<p className="text-sm text-muted-foreground mt-2">{theme.description}</p>
|
<p className="text-sm text-muted-foreground mt-2">{theme.description}</p>
|
||||||
{theme.homepage && (
|
{theme.homepage && (
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
import { createClient } from '@supabase/supabase-js'
|
|
||||||
|
|
||||||
const supabaseUrl = 'https://dmthyedfjzcysoekmyns.supabase.co'
|
|
||||||
const supabaseKey = process.env.SUPABASE_KEY as string;
|
|
||||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
||||||
|
|
||||||
export async function addDownload(platform: string) {
|
|
||||||
// Check if the download count for the platform exists
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('downloads')
|
|
||||||
.select('count')
|
|
||||||
.eq('platform', platform)
|
|
||||||
// If it doesn't exist, create it
|
|
||||||
console.log(data)
|
|
||||||
if (data?.length === 0 || data === null) {
|
|
||||||
const {data, error} = await supabase
|
|
||||||
.from('downloads')
|
|
||||||
.insert([{ platform, count: 1 }]);
|
|
||||||
if (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it exists, increment the count
|
|
||||||
await supabase
|
|
||||||
.from('downloads')
|
|
||||||
.update({ count: data![0].count + 1 })
|
|
||||||
.eq('platform', platform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -628,11 +628,10 @@ export const releaseNotes: ReleaseNote[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
version: "1.0.0-a.30",
|
version: "1.0.0-a.30",
|
||||||
date: "24/08/2024",
|
date: "26/08/2024",
|
||||||
extra: "This release is the thirtieth alpha release of the 1.0.0-alpha series.",
|
extra: "This release is the thirtieth alpha release of the 1.0.0-alpha series.",
|
||||||
features: [
|
features: [
|
||||||
"Added support for 24 more languages!",
|
"Added support for 24 more languages!",
|
||||||
"Better wordmark and icons for Private Browsing mode",
|
|
||||||
"Update installed themes from the browser settings"
|
"Update installed themes from the browser settings"
|
||||||
],
|
],
|
||||||
fixes: [
|
fixes: [
|
||||||
@@ -655,11 +654,38 @@ export const releaseNotes: ReleaseNote[] = [
|
|||||||
{
|
{
|
||||||
description: "Can't rename created workspace",
|
description: "Can't rename created workspace",
|
||||||
issue: 604
|
issue: 604
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "JavaScript won't execute in the browser console",
|
||||||
|
issue: 913
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "1.0.0-a.31",
|
||||||
|
date: "27/08/2024",
|
||||||
|
extra: "This release is the thirty-first alpha release of the 1.0.0-alpha series.",
|
||||||
|
features: [
|
||||||
|
"Better wordmark and icons for Private Browsing mode",
|
||||||
|
"Patched security issue with remote debugging",
|
||||||
|
"Fixed incorrect position of right-side tabs in compact mode",
|
||||||
|
"Optimized image loading on website",
|
||||||
|
"Refactored website to be static"
|
||||||
|
],
|
||||||
|
fixes: [
|
||||||
|
{
|
||||||
|
description: "Horizontal and vertical split don't work with shortcuts",
|
||||||
|
issue: 915
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Buttons dissapear if there are too many tabs",
|
||||||
|
issue: 934
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
].reverse();
|
].reverse();
|
||||||
|
|
||||||
export function releaseNoteIsAlpha(note: ReleaseNote) {
|
export function releaseNoteIsAlpha(note: ReleaseNote) {
|
||||||
|
"use client";
|
||||||
return note.version.includes("-a.");
|
return note.version.includes("-a.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export interface ZenTheme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const THEME_API = "https://zen-browser.github.io/theme-store/themes.json";
|
const THEME_API = "https://zen-browser.github.io/theme-store/themes.json";
|
||||||
const CACHE_OPTIONS = { cache: "no-cache" } as RequestInit;
|
const CACHE_OPTIONS = { next: {
|
||||||
|
revalidate: 60,
|
||||||
|
} } as RequestInit;
|
||||||
|
|
||||||
export async function getAllThemes() {
|
export async function getAllThemes() {
|
||||||
// Fetch from the API
|
// Fetch from the API
|
||||||
|
|||||||
Reference in New Issue
Block a user