Merge branch 'main' of https://github.com/zen-browser/www
This commit is contained in:
@@ -12,6 +12,7 @@ const nextConfig = {
|
||||
hostname: "cdn.jsdelivr.net",
|
||||
}
|
||||
],
|
||||
domains: ['cdn.jsdelivr.net', "raw.githubusercontent.com"], // Allow images from jsDelivr
|
||||
},
|
||||
experimental: {
|
||||
serverActions: {
|
||||
@@ -22,19 +23,6 @@ const nextConfig = {
|
||||
compiler: {
|
||||
styledComponents: true,
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: "/",
|
||||
headers: [
|
||||
{
|
||||
key: "Cache-Control",
|
||||
value: "s-maxage=1, stale-while-revalidate=59",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
|
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 { Navigation } from "@/components/navigation";
|
||||
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import Footer from "@/components/footer";
|
||||
import { Navigation } from "@/components/navigation";
|
||||
@@ -6,10 +5,13 @@ import ReleaseNote from "@/components/release-note";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { releaseNotes } from "@/lib/release-notes";
|
||||
import Link from "next/link";
|
||||
import { redirect, useParams } from "next/navigation";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function ReleaseNotePage() {
|
||||
const params = useParams<{ version: string }>();
|
||||
export async function generateStaticParams() {
|
||||
return [{version: "latest"}, ...releaseNotes.map((note) => ({ version: note.version }))];
|
||||
}
|
||||
|
||||
export default function ReleaseNotePage({ params }: { params: { version: string } }) {
|
||||
const { version } = params;
|
||||
|
||||
if (version === "latest") {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import Footer from "@/components/footer";
|
||||
import { Navigation } from "@/components/navigation";
|
||||
import { releaseNoteIsAlpha, releaseNotes } from "@/lib/release-notes";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Footer from "@/components/footer";
|
||||
import { Navigation } from "@/components/navigation";
|
||||
import ThemePage from "@/components/theme-page";
|
||||
import { getThemeFromId } from "@/lib/themes";
|
||||
import { getAllThemes, getThemeFromId } from "@/lib/themes";
|
||||
import { Metadata, ResolvingMetadata } from "next";
|
||||
|
||||
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 (
|
||||
<main className="flex min-h-screen flex-col items-center justify-start">
|
||||
<ThemePage />
|
||||
<ThemePage themeID={theme} />
|
||||
<Footer />
|
||||
<Navigation /> {/* At the bottom of the page */}
|
||||
</main>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client";
|
||||
import { addDownload } from "@/lib/db";
|
||||
import { useState, useEffect } from "react";
|
||||
import styled, { keyframes } from "styled-components";
|
||||
import { ny } from "@/lib/utils";
|
||||
@@ -158,7 +157,6 @@ export default function DownloadPage() {
|
||||
window.location.replace(`${BASE_URL}/${releases[releaseTarget]}`);
|
||||
}
|
||||
setHasDownloaded(true);
|
||||
addDownload(releaseTarget);
|
||||
throwConfetti();
|
||||
};
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ export default function Features() {
|
||||
<span className="">How Zen compares to other browsers</span>
|
||||
</TableHead>
|
||||
<TableHead className="py-2 font-bold text-center">
|
||||
<Image
|
||||
<img
|
||||
height={32}
|
||||
width={32}
|
||||
src="/favicon.ico"
|
||||
@@ -230,7 +230,7 @@ export default function Features() {
|
||||
Zen
|
||||
</TableHead>
|
||||
<TableHead className="py-2 pl-4 lg:pr-0 pr-2 font-bold text-center opacity-60">
|
||||
<Image
|
||||
<img
|
||||
height={32}
|
||||
width={32}
|
||||
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/floorp.png"
|
||||
@@ -240,7 +240,7 @@ export default function Features() {
|
||||
Floorp
|
||||
</TableHead>
|
||||
<TableHead className="py-2 pl-0 font-bold text-center opacity-60">
|
||||
<Image
|
||||
<img
|
||||
height={32}
|
||||
width={32}
|
||||
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/librewolf.png"
|
||||
|
||||
@@ -67,14 +67,14 @@ export default function Header() {
|
||||
colorTo="var(--color-two)"
|
||||
/>
|
||||
|
||||
<Image
|
||||
<img
|
||||
width={1500}
|
||||
height={700}
|
||||
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-dark.png"
|
||||
alt="browser Image"
|
||||
className="relative hidden rounded-[inherit] border object-contain dark:block"
|
||||
/>
|
||||
<Image
|
||||
<img
|
||||
width={1500}
|
||||
height={700}
|
||||
src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/browser-light.png"
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function Logo({ withText, ...props }: any) {
|
||||
}, []);
|
||||
return (
|
||||
<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>}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function ThemeCard({
|
||||
if (event.target instanceof HTMLAnchorElement) return;
|
||||
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 ">
|
||||
<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" />
|
||||
<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">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { getThemeAuthorLink, getThemeFromId, getThemeMarkdown, ZenTheme } from "@/lib/themes";
|
||||
import { Button } from "./ui/button";
|
||||
@@ -6,11 +6,8 @@ import { useEffect, useState } from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import '../app/privacy-policy/markdown.css';
|
||||
import { ChevronLeft, LoaderCircleIcon } from "lucide-react";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
export default async function ThemePage() {
|
||||
const params = useParams<{ theme: string }>();
|
||||
const { theme: themeID } = params;
|
||||
export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||
|
||||
const theme = await getThemeFromId(themeID);
|
||||
if (!theme) {
|
||||
@@ -22,11 +19,11 @@ export default async function ThemePage() {
|
||||
return (
|
||||
<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 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" />
|
||||
<h3 className="text-md">Go back</h3>
|
||||
</div>
|
||||
<Image src={theme.image} alt={theme.name} width={500} height={500} className="w-full object-cover rounded-lg border-2 shadow" />
|
||||
</a>
|
||||
<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>
|
||||
<p className="text-sm text-muted-foreground mt-2">{theme.description}</p>
|
||||
{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",
|
||||
date: "24/08/2024",
|
||||
date: "26/08/2024",
|
||||
extra: "This release is the thirtieth alpha release of the 1.0.0-alpha series.",
|
||||
features: [
|
||||
"Added support for 24 more languages!",
|
||||
"Better wordmark and icons for Private Browsing mode",
|
||||
"Update installed themes from the browser settings"
|
||||
],
|
||||
fixes: [
|
||||
@@ -655,11 +654,38 @@ export const releaseNotes: ReleaseNote[] = [
|
||||
{
|
||||
description: "Can't rename created workspace",
|
||||
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();
|
||||
|
||||
export function releaseNoteIsAlpha(note: ReleaseNote) {
|
||||
"use client";
|
||||
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 CACHE_OPTIONS = { cache: "no-cache" } as RequestInit;
|
||||
const CACHE_OPTIONS = { next: {
|
||||
revalidate: 60,
|
||||
} } as RequestInit;
|
||||
|
||||
export async function getAllThemes() {
|
||||
// Fetch from the API
|
||||
|
||||
Reference in New Issue
Block a user