This commit is contained in:
mauro 🤙
2024-08-27 23:14:46 +00:00
17 changed files with 90 additions and 101 deletions

View File

@@ -12,6 +12,7 @@ const nextConfig = {
hostname: "cdn.jsdelivr.net", hostname: "cdn.jsdelivr.net",
} }
], ],
domains: ['cdn.jsdelivr.net', "raw.githubusercontent.com"], // Allow images from jsDelivr
}, },
experimental: { experimental: {
serverActions: { serverActions: {
@@ -22,19 +23,6 @@ const nextConfig = {
compiler: { compiler: {
styledComponents: true, styledComponents: true,
}, },
async headers() {
return [
{
source: "/",
headers: [
{
key: "Cache-Control",
value: "s-maxage=1, stale-while-revalidate=59",
},
],
},
]
}
}; };
export default nextConfig; export default nextConfig;

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View 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));
}

View File

@@ -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));
}

View File

@@ -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";

View File

@@ -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") {

View File

@@ -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";

View File

@@ -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>

View File

@@ -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();
}; };

View File

@@ -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,7 +230,7 @@ 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="https://cdn.jsdelivr.net/gh/zen-browser/www/public/floorp.png" src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/floorp.png"
@@ -240,7 +240,7 @@ export default function Features() {
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="https://cdn.jsdelivr.net/gh/zen-browser/www/public/librewolf.png" src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/librewolf.png"

View File

@@ -67,14 +67,14 @@ export default function Header() {
colorTo="var(--color-two)" colorTo="var(--color-two)"
/> />
<Image <img
width={1500} width={1500}
height={700} height={700}
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/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="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-light.png" src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-light.png"

View File

@@ -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={`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")} /> <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>
); );

View File

@@ -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">

View File

@@ -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 && (

View File

@@ -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)
}
}

View File

@@ -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.");
} }

View File

@@ -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