mirror of
https://github.com/zen-browser/www.git
synced 2025-07-08 09:20:00 +02:00
Refactor next.config.js and form.tsx
This commit is contained in:
parent
00c7ce4c56
commit
5ec0fcbb56
31 changed files with 388 additions and 336 deletions
|
@ -88,9 +88,18 @@ function formatReleaseNote(releaseNote: ReleaseNote) {
|
||||||
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`;
|
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
content += addReleaseNoteSection("⚠️ Breaking changes", releaseNote.breakingChanges);
|
content += addReleaseNoteSection(
|
||||||
content += addReleaseNoteSection("✓ Fixes", releaseNote.fixes?.map(fixToReleaseNote));
|
"⚠️ Breaking changes",
|
||||||
content += addReleaseNoteSection("🖌 Theme Changes", releaseNote.themeChanges)
|
releaseNote.breakingChanges,
|
||||||
|
);
|
||||||
|
content += addReleaseNoteSection(
|
||||||
|
"✓ Fixes",
|
||||||
|
releaseNote.fixes?.map(fixToReleaseNote),
|
||||||
|
);
|
||||||
|
content += addReleaseNoteSection(
|
||||||
|
"🖌 Theme Changes",
|
||||||
|
releaseNote.themeChanges,
|
||||||
|
);
|
||||||
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
|
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
|
@ -112,7 +121,9 @@ function addReleaseNoteSection(title: string, items?: string[]): string {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixToReleaseNote(fix?: Exclude<ReleaseNote['fixes'], undefined>[number]) {
|
function fixToReleaseNote(
|
||||||
|
fix?: Exclude<ReleaseNote["fixes"], undefined>[number],
|
||||||
|
) {
|
||||||
if (!fix || !fix.description || fix.description.length === 0) {
|
if (!fix || !fix.description || fix.description.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
background-color: var(--surface);
|
background-color: var(--surface);
|
||||||
padding: 0.2em 0.4em;
|
padding: 0.2em 0.4em;
|
||||||
border: 1px solid light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2));
|
border: 1px solid light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2));
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from "react";
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
export default function ThemesPage() {
|
export default function ThemesPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
router.replace('/mods');
|
router.replace("/mods");
|
||||||
}, [router]);
|
}, [router]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
|
|
||||||
const inDev = process.env.NODE_ENV === "development";
|
const inDev = process.env.NODE_ENV === "development";
|
||||||
function imageLoader({ src }: { src: string }) {
|
function imageLoader({ src }: { src: string }) {
|
||||||
// Load locally if we are in development
|
// Load locally if we are in development
|
||||||
|
|
|
@ -31,7 +31,7 @@ export const AlertModal = ({
|
||||||
</div>
|
</div>
|
||||||
</AlertDialog.Title>
|
</AlertDialog.Title>
|
||||||
<AlertDialog.Description asChild>
|
<AlertDialog.Description asChild>
|
||||||
<p className="text-center text-sm text-muted-foreground mb-6">
|
<p className="mb-6 text-center text-sm text-muted-foreground">
|
||||||
Please select other formats if you want to install the Optimized
|
Please select other formats if you want to install the Optimized
|
||||||
version.
|
version.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -75,7 +75,12 @@ export function BrandingAssets() {
|
||||||
CC BY-SA 4.0
|
CC BY-SA 4.0
|
||||||
</a>
|
</a>
|
||||||
. Thanks to{" "}
|
. Thanks to{" "}
|
||||||
<a href="https://www.onnno.nl/" rel="noopener noreferrer" target="_blank" className="text-blue-500">
|
<a
|
||||||
|
href="https://www.onnno.nl/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
className="text-blue-500"
|
||||||
|
>
|
||||||
Donno (mr. Logos)
|
Donno (mr. Logos)
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
for the assets.
|
for the assets.
|
||||||
|
|
|
@ -8,18 +8,27 @@ import React from "react";
|
||||||
export default function BrowserComplexityExample() {
|
export default function BrowserComplexityExample() {
|
||||||
const [selectedImage, setSelectedImage] = React.useState([1]);
|
const [selectedImage, setSelectedImage] = React.useState([1]);
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen items-center flex-col mx-auto mb-32 xl:mb-64 w-full md:w-5/6 lg:w-3/4">
|
<div className="mx-auto mb-32 flex h-screen w-full flex-col items-center md:w-5/6 lg:w-3/4 xl:mb-64">
|
||||||
<h1 className="text-4xl md:text-5xl font-bold text-center">How much browser do you want?</h1>
|
<h1 className="text-center text-4xl font-bold md:text-5xl">
|
||||||
<p className="mt-4 text-center text-md mx-auto w-2/3 text-muted-foreground">
|
How much browser do you want?
|
||||||
Zen is designed to be simple and easy to use. We believe that the best software is
|
</h1>
|
||||||
the one that you don't notice. However, we can assure you that if you want customization, we have you covered
|
<p className="text-md mx-auto mt-4 w-2/3 text-center text-muted-foreground">
|
||||||
|
Zen is designed to be simple and easy to use. We believe that the best
|
||||||
|
software is the one that you don't notice. However, we can assure you
|
||||||
|
that if you want customization, we have you covered
|
||||||
</p>
|
</p>
|
||||||
<div className="w-64 mb-6 mt-12 flex gap-4">
|
<div className="mb-6 mt-12 flex w-64 gap-4">
|
||||||
<span className="opacity-90">🌱</span>
|
<span className="opacity-90">🌱</span>
|
||||||
<Slider step={1} max={3} showSteps="half" value={selectedImage} onValueChange={setSelectedImage} />
|
<Slider
|
||||||
|
step={1}
|
||||||
|
max={3}
|
||||||
|
showSteps="half"
|
||||||
|
value={selectedImage}
|
||||||
|
onValueChange={setSelectedImage}
|
||||||
|
/>
|
||||||
<span className="opacity-90">🌳</span>
|
<span className="opacity-90">🌳</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto md:mb-36 flex justify-center">
|
<div className="mx-auto flex justify-center md:mb-36">
|
||||||
{[...Array(4)].map((_, i) => (
|
{[...Array(4)].map((_, i) => (
|
||||||
<CachedImage
|
<CachedImage
|
||||||
width={1620}
|
width={1620}
|
||||||
|
@ -28,12 +37,15 @@ export default function BrowserComplexityExample() {
|
||||||
key={i}
|
key={i}
|
||||||
src={`www/public/browsers/image${i + 1}.png`}
|
src={`www/public/browsers/image${i + 1}.png`}
|
||||||
alt="Zen Browser"
|
alt="Zen Browser"
|
||||||
className={ny("rounded-md object-cover shadow object-right mx-12 w-full", selectedImage[0] === i
|
className={ny(
|
||||||
|
"mx-12 w-full rounded-md object-cover object-right shadow",
|
||||||
|
selectedImage[0] === i
|
||||||
? "" //"animate-fade-up duration-500 !opacity-100"
|
? "" //"animate-fade-up duration-500 !opacity-100"
|
||||||
: "hidden")}
|
: "hidden",
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import s from './styles.module.css'
|
import s from "./styles.module.css";
|
||||||
|
|
||||||
export default function CoolHeaderText() {
|
export default function CoolHeaderText() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="relative mb-3 mt-5 -translate-y-4 animate-fade-in text-balance bg-gradient-to-br 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] dark:from-white dark:to-white/40 sm:text-6xl md:text-7xl lg:text-8xl">
|
<div className="relative mb-3 mt-5 -translate-y-4 animate-fade-in text-balance bg-gradient-to-br 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] dark:from-white dark:to-white/40 sm:text-6xl md:text-7xl lg:text-8xl">
|
||||||
<h1 className={s.title}>
|
<h1 className={s.title}>Stay focused, browse faster with Zen</h1>
|
||||||
Stay focused, browse faster with Zen
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="pointer-events-none absolute right-20 top-[-5px] mt-12 hidden h-fit w-fit !rotate-[15deg] transform animate-fade-in rounded-full bg-surface border-2 px-3 py-1 opacity-0 shadow [--animation-delay:400ms] md:block">
|
<div className="pointer-events-none absolute right-20 top-[-5px] mt-12 hidden h-fit w-fit !rotate-[15deg] transform animate-fade-in rounded-full border-2 bg-surface px-3 py-1 opacity-0 shadow [--animation-delay:400ms] md:block">
|
||||||
Alpha Version
|
Alpha Version
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
100% {
|
100% {
|
||||||
filter: hue-rotate(0deg);
|
filter: hue-rotate(0deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
background-image: linear-gradient(90deg, #0077e7, #01d8d1);
|
background-image: linear-gradient(90deg, #0077e7, #01d8d1);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
|
@ -20,5 +20,4 @@
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { Button } from "./ui/button";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { Architecture } from "@/components/download/types";
|
import { Architecture } from "@/components/download/types";
|
||||||
import { ny } from "@/lib/utils";
|
import { ny } from "@/lib/utils";
|
||||||
|
|
|
@ -46,9 +46,7 @@ export const MacArchitectureCard = ({
|
||||||
>
|
>
|
||||||
<h1 className="my-2 text-5xl opacity-40 dark:opacity-20">{icon}</h1>
|
<h1 className="my-2 text-5xl opacity-40 dark:opacity-20">{icon}</h1>
|
||||||
<h1 className="my-2 text-2xl font-semibold">{label}</h1>
|
<h1 className="my-2 text-2xl font-semibold">{label}</h1>
|
||||||
<p className="mx-auto text-center text-muted-foreground">
|
<p className="mx-auto text-center text-muted-foreground">{description}</p>
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { Platforms } from "@/components/download/types";
|
import { Platforms } from "@/components/download/types";
|
||||||
import { ny } from "@/lib/utils";
|
import { ny } from "@/lib/utils";
|
||||||
|
@ -10,7 +10,7 @@ interface PlatformCardProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PLATFORMS_DATA: Record<
|
const PLATFORMS_DATA: Record<
|
||||||
Exclude<Platforms, 'Unsupported'>,
|
Exclude<Platforms, "Unsupported">,
|
||||||
{ label: string; icon: string; borderColor: string }
|
{ label: string; icon: string; borderColor: string }
|
||||||
> = {
|
> = {
|
||||||
Windows: {
|
Windows: {
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import CachedImage from "@/components/CachedImage";
|
import CachedImage from "@/components/CachedImage";
|
||||||
import Logo from "@/components/logo";
|
import Logo from "@/components/logo";
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
import {
|
||||||
import { ExternalLinkIcon, EyeClosedIcon, LockClosedIcon, QuestionMarkCircledIcon } from "@radix-ui/react-icons";
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import {
|
||||||
|
ExternalLinkIcon,
|
||||||
|
EyeClosedIcon,
|
||||||
|
LockClosedIcon,
|
||||||
|
QuestionMarkCircledIcon,
|
||||||
|
} from "@radix-ui/react-icons";
|
||||||
import { ShieldCheck, ShieldAlertIcon } from "lucide-react";
|
import { ShieldCheck, ShieldAlertIcon } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
|
@ -48,8 +48,8 @@ export default function Features() {
|
||||||
<PaintBucket className="inline h-10 w-10"></PaintBucket>
|
<PaintBucket className="inline h-10 w-10"></PaintBucket>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mt-4 text-lg text-gray-600 dark:text-gray-300">
|
<p className="mt-4 text-lg text-gray-600 dark:text-gray-300">
|
||||||
With Zen Mods, you can customize your browsing experience
|
With Zen Mods, you can customize your browsing experience to
|
||||||
to reflect your unique style and preferences. Choose from a wide
|
reflect your unique style and preferences. Choose from a wide
|
||||||
array of Mods, colors, and layouts to make Zen truly your own,
|
array of Mods, colors, and layouts to make Zen truly your own,
|
||||||
transforming your browser into a personalized digital space.
|
transforming your browser into a personalized digital space.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -14,7 +14,9 @@ export function ModeToggle() {
|
||||||
if (savedTheme) {
|
if (savedTheme) {
|
||||||
setTheme(savedTheme);
|
setTheme(savedTheme);
|
||||||
} else {
|
} else {
|
||||||
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
const prefersDark = window.matchMedia(
|
||||||
|
"(prefers-color-scheme: dark)",
|
||||||
|
).matches;
|
||||||
setTheme(prefersDark ? "dark" : "light");
|
setTheme(prefersDark ? "dark" : "light");
|
||||||
}
|
}
|
||||||
}, [setTheme]);
|
}, [setTheme]);
|
||||||
|
|
|
@ -122,9 +122,9 @@ export function Navigation() {
|
||||||
<div className="border-grey fixed left-0 top-0 z-40 flex w-full items-center justify-center border-b bg-background p-2">
|
<div className="border-grey fixed left-0 top-0 z-40 flex w-full items-center justify-center border-b bg-background p-2">
|
||||||
<MobileNav />
|
<MobileNav />
|
||||||
<NavigationMenu>
|
<NavigationMenu>
|
||||||
<NavigationMenuList className="hidden w-full py-3 sm:flex items-center justify-between gap-32">
|
<NavigationMenuList className="hidden w-full items-center justify-between gap-32 py-3 sm:flex">
|
||||||
<div>
|
<div>
|
||||||
<NavigationMenuItem className="cursor-pointer flex items-center">
|
<NavigationMenuItem className="flex cursor-pointer items-center">
|
||||||
<NavigationMenuLink href="/">
|
<NavigationMenuLink href="/">
|
||||||
<Logo withText />
|
<Logo withText />
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
|
@ -186,8 +186,8 @@ export function Navigation() {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
Ko-fi is a way to support us with a one-time donation and help
|
Ko-fi is a way to support us with a one-time donation and
|
||||||
us keep the project alive.
|
help us keep the project alive.
|
||||||
</ListItem2>
|
</ListItem2>
|
||||||
</ul>
|
</ul>
|
||||||
</NavigationMenuContent>
|
</NavigationMenuContent>
|
||||||
|
@ -215,7 +215,10 @@ export function Navigation() {
|
||||||
<ModeToggle />
|
<ModeToggle />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<NavigationMenuLink href={`/release-notes/${latestRelease.version}`} className="text-[10px] bg-surface py-1 px-2 font-semibold rounded h-fit w-fit flex items-center hover:bg-accent hover:text-accent-foreground transition-colors">
|
<NavigationMenuLink
|
||||||
|
href={`/release-notes/${latestRelease.version}`}
|
||||||
|
className="flex h-fit w-fit items-center rounded bg-surface px-2 py-1 text-[10px] font-semibold transition-colors hover:bg-accent hover:text-accent-foreground"
|
||||||
|
>
|
||||||
v{latestRelease.version}
|
v{latestRelease.version}
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,8 +3,13 @@ import { getThemeAuthorLink, ZenTheme } from "@/lib/mods";
|
||||||
import { TagIcon } from "lucide-react";
|
import { TagIcon } from "lucide-react";
|
||||||
|
|
||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import Link from "next/link";
|
import {
|
||||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "./ui/card";
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "./ui/card";
|
||||||
|
|
||||||
export default function ThemeCard({
|
export default function ThemeCard({
|
||||||
theme,
|
theme,
|
||||||
|
@ -18,7 +23,8 @@ export default function ThemeCard({
|
||||||
const authorLink = getThemeAuthorLink(theme);
|
const authorLink = getThemeAuthorLink(theme);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="select-none h-full flex-col justify-between rounded-xl border-2 border-[transparent] bg-surface transition-all duration-200 hover:border-[rgba(0,0,0,.5)] hover:shadow-lg dark:bg-[#121212] dark:hover:border-[#333]"
|
<Card
|
||||||
|
className="h-full select-none flex-col justify-between rounded-xl border-2 border-[transparent] bg-surface transition-all duration-200 hover:border-[rgba(0,0,0,.5)] hover:shadow-lg dark:bg-[#121212] dark:hover:border-[#333]"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
// IMPORTANT NOTE: We do NOT use a Link component here because of how zen manages site injection.
|
// IMPORTANT NOTE: We do NOT use a Link component here because of how zen manages site injection.
|
||||||
// please for the love of god, dont change this to a Link component. Please.
|
// please for the love of god, dont change this to a Link component. Please.
|
||||||
|
@ -28,7 +34,8 @@ export default function ThemeCard({
|
||||||
if (e.button !== 0 && e.button !== 1) return;
|
if (e.button !== 0 && e.button !== 1) return;
|
||||||
if (e.target instanceof HTMLAnchorElement) return;
|
if (e.target instanceof HTMLAnchorElement) return;
|
||||||
window.open(`/mods/${theme.id}`, e.button === 1 ? "_blank" : "_self");
|
window.open(`/mods/${theme.id}`, e.button === 1 ? "_blank" : "_self");
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<div className="relative m-2 mb-0 hidden aspect-[1.85/1] h-48 overflow-hidden rounded-xl border-2 border-[rgba(0,0,0,.5)] object-cover shadow dark:border-[#333] lg:block lg:h-auto">
|
<div className="relative m-2 mb-0 hidden aspect-[1.85/1] h-48 overflow-hidden rounded-xl border-2 border-[rgba(0,0,0,.5)] object-cover shadow dark:border-[#333] lg:block lg:h-auto">
|
||||||
<img
|
<img
|
||||||
src={theme.image}
|
src={theme.image}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||||
return (
|
return (
|
||||||
<div className="relative mx-auto mt-24 flex flex-col items-start lg:mt-56 lg:flex-row">
|
<div className="relative mx-auto mt-24 flex flex-col items-start lg:mt-56 lg:flex-row">
|
||||||
<div className="w-md relative mx-auto mr-5 flex h-full w-full flex-col rounded-lg border bg-surface p-5 shadow md:mx-0 md:max-w-sm lg:sticky lg:top-0">
|
<div className="w-md relative mx-auto mr-5 flex h-full w-full flex-col rounded-lg border bg-surface p-5 shadow md:mx-0 md:max-w-sm lg:sticky lg:top-0">
|
||||||
<div className="flex justify-between w-full items-center mb-2">
|
<div className="mb-2 flex w-full items-center justify-between">
|
||||||
<a
|
<a
|
||||||
className="flex cursor-pointer items-center opacity-70"
|
className="flex cursor-pointer items-center opacity-70"
|
||||||
href="/mods"
|
href="/mods"
|
||||||
|
@ -67,11 +67,9 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<hr className="my-4" />
|
<hr className="my-4" />
|
||||||
<div className="text-sm text-muted-foreground flex justify-between">
|
<div className="flex justify-between text-sm text-muted-foreground">
|
||||||
<div>
|
<div>
|
||||||
<span className="opacity-70">
|
<span className="opacity-70">Theme by </span>
|
||||||
Theme by{" "}
|
|
||||||
</span>
|
|
||||||
<a
|
<a
|
||||||
href={getThemeAuthorLink(theme)}
|
href={getThemeAuthorLink(theme)}
|
||||||
className="text-md mt-4 text-blue-500"
|
className="text-md mt-4 text-blue-500"
|
||||||
|
@ -81,9 +79,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||||
{theme.author}
|
{theme.author}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="opacity-70">
|
<div className="opacity-70">v{theme.version}</div>
|
||||||
v{theme.version}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full max-w-xl flex-col px-5 lg:min-h-[calc(100vh/2-2rem)] lg:min-w-96 lg:pl-10">
|
<div className="flex w-full max-w-xl flex-col px-5 lg:min-h-[calc(100vh/2-2rem)] lg:min-w-96 lg:pl-10">
|
||||||
|
@ -92,7 +88,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
|
||||||
alt={theme.name}
|
alt={theme.name}
|
||||||
className="w-full rounded-2xl border-2 object-cover shadow"
|
className="w-full rounded-2xl border-2 object-cover shadow"
|
||||||
/>
|
/>
|
||||||
<div id="policy" className="w-full !mt-0">
|
<div id="policy" className="!mt-0 w-full">
|
||||||
{readme === null ? (
|
{readme === null ? (
|
||||||
<LoaderCircleIcon className="mx-auto h-12 w-12 animate-spin" />
|
<LoaderCircleIcon className="mx-auto h-12 w-12 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { ny } from "@/lib/utils"
|
import { ny } from "@/lib/utils";
|
||||||
|
|
||||||
const Card = React.forwardRef<
|
const Card = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
@ -10,12 +10,12 @@ const Card = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={ny(
|
className={ny(
|
||||||
"rounded-xl border bg-card text-card-foreground shadow",
|
"rounded-xl border bg-card text-card-foreground shadow",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Card.displayName = "Card"
|
Card.displayName = "Card";
|
||||||
|
|
||||||
const CardHeader = React.forwardRef<
|
const CardHeader = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
|
||||||
className={ny("flex flex-col space-y-1.5", className)}
|
className={ny("flex flex-col space-y-1.5", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardHeader.displayName = "CardHeader"
|
CardHeader.displayName = "CardHeader";
|
||||||
|
|
||||||
const CardTitle = React.forwardRef<
|
const CardTitle = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
|
@ -38,8 +38,8 @@ const CardTitle = React.forwardRef<
|
||||||
className={ny("font-semibold leading-none tracking-tight", className)}
|
className={ny("font-semibold leading-none tracking-tight", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardTitle.displayName = "CardTitle"
|
CardTitle.displayName = "CardTitle";
|
||||||
|
|
||||||
const CardDescription = React.forwardRef<
|
const CardDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
|
@ -50,27 +50,30 @@ const CardDescription = React.forwardRef<
|
||||||
className={ny("text-sm text-muted-foreground", className)}
|
className={ny("text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardDescription.displayName = "CardDescription"
|
CardDescription.displayName = "CardDescription";
|
||||||
|
|
||||||
const CardContent = React.forwardRef<
|
const CardContent = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div ref={ref} className={ny("", className)} {...props} />
|
<div ref={ref} className={ny("", className)} {...props} />
|
||||||
))
|
));
|
||||||
CardContent.displayName = "CardContent"
|
CardContent.displayName = "CardContent";
|
||||||
|
|
||||||
const CardFooter = React.forwardRef<
|
const CardFooter = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div
|
<div ref={ref} className={ny("flex items-center", className)} {...props} />
|
||||||
ref={ref}
|
));
|
||||||
className={ny("flex items-center", className)}
|
CardFooter.displayName = "CardFooter";
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
CardFooter.displayName = "CardFooter"
|
|
||||||
|
|
||||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
|
|
||||||
import { ny } from '@/lib/utils'
|
import { ny } from "@/lib/utils";
|
||||||
|
|
||||||
interface RainbowButtonProps
|
interface RainbowButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
||||||
|
@ -9,20 +9,20 @@ export function RainbowButton({ children, ...props }: RainbowButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={ny(
|
className={ny(
|
||||||
'focus-visible:ring-ring animate-rainbow text-primary-foreground group relative inline-flex h-11 cursor-pointer items-center justify-center rounded-xl border-0 bg-[length:200%] px-4 py-2 font-medium transition-colors [background-clip:padding-box,border-box,border-box] [background-origin:border-box] [border:calc(0.08*1rem)_solid_transparent] focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50',
|
"group relative inline-flex h-11 animate-rainbow cursor-pointer items-center justify-center rounded-xl border-0 bg-[length:200%] px-4 py-2 font-medium text-primary-foreground transition-colors [background-clip:padding-box,border-box,border-box] [background-origin:border-box] [border:calc(0.08*1rem)_solid_transparent] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
|
||||||
// before styles
|
// before styles
|
||||||
'before:animate-rainbow before:absolute before:bottom-[-20%] before:left-1/2 before:z-0 before:h-1/5 before:w-3/5 before:-translate-x-1/2 before:bg-[linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))] before:bg-[length:200%] before:[filter:blur(calc(0.8*1rem))]',
|
"before:absolute before:bottom-[-20%] before:left-1/2 before:z-0 before:h-1/5 before:w-3/5 before:-translate-x-1/2 before:animate-rainbow before:bg-[linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))] before:bg-[length:200%] before:[filter:blur(calc(0.8*1rem))]",
|
||||||
|
|
||||||
// light mode colors
|
// light mode colors
|
||||||
'bg-[linear-gradient(#121213,#121213),linear-gradient(#121213_50%,rgba(18,18,19,0.6)_80%,rgba(18,18,19,0)),linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))]',
|
"bg-[linear-gradient(#121213,#121213),linear-gradient(#121213_50%,rgba(18,18,19,0.6)_80%,rgba(18,18,19,0)),linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))]",
|
||||||
|
|
||||||
// dark mode colors
|
// dark mode colors
|
||||||
' dark:bg-[linear-gradient(#fff,#fff),linear-gradient(#fff_50%,rgba(255,255,255,0.6)_80%,rgba(0,0,0,0)),linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))]',
|
"dark:bg-[linear-gradient(#fff,#fff),linear-gradient(#fff_50%,rgba(255,255,255,0.6)_80%,rgba(0,0,0,0)),linear-gradient(90deg,hsl(var(--color-1)),hsl(var(--color-5)),hsl(var(--color-3)),hsl(var(--color-4)),hsl(var(--color-2)))]",
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ export default function WelcomePage() {
|
||||||
Start using it by clicking on the sidebar icon or trying out the split
|
Start using it by clicking on the sidebar icon or trying out the split
|
||||||
view feature!
|
view feature!
|
||||||
</p>
|
</p>
|
||||||
<p className="text-md w-2/5 mx-auto mt-12 opacity-70">
|
<p className="text-md mx-auto mt-12 w-2/5 opacity-70">
|
||||||
<InfoCircledIcon className="inline-block mr-4 size-5 text-yellow-500" />
|
<InfoCircledIcon className="mr-4 inline-block size-5 text-yellow-500" />
|
||||||
Zen Browser is still in development and may have bugs. This welcome page is under construction.
|
Zen Browser is still in development and may have bugs. This welcome page
|
||||||
|
is under construction.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -38,7 +38,10 @@ function isValidDate(date: any): date is Date {
|
||||||
* @param assignFutureDate - Whether to assign a future date if parsing fails.
|
* @param assignFutureDate - Whether to assign a future date if parsing fails.
|
||||||
* @returns A valid Date object.
|
* @returns A valid Date object.
|
||||||
*/
|
*/
|
||||||
function parseDate(dateString: string | undefined, assignFutureDate: boolean = false): Date {
|
function parseDate(
|
||||||
|
dateString: string | undefined,
|
||||||
|
assignFutureDate: boolean = false,
|
||||||
|
): Date {
|
||||||
const date = new Date(dateString || "");
|
const date = new Date(dateString || "");
|
||||||
if (isValidDate(date)) {
|
if (isValidDate(date)) {
|
||||||
return date;
|
return date;
|
||||||
|
@ -83,7 +86,10 @@ export async function getAllThemes(): Promise<ZenTheme[]> {
|
||||||
homepage: theme.homepage,
|
homepage: theme.homepage,
|
||||||
readme: theme.readme,
|
readme: theme.readme,
|
||||||
preferences: theme.preferences,
|
preferences: theme.preferences,
|
||||||
isColorTheme: typeof theme.isColorTheme === 'boolean' ? theme.isColorTheme : false,
|
isColorTheme:
|
||||||
|
typeof theme.isColorTheme === "boolean"
|
||||||
|
? theme.isColorTheme
|
||||||
|
: false,
|
||||||
author: theme.author,
|
author: theme.author,
|
||||||
version: theme.version,
|
version: theme.version,
|
||||||
tags: uniqueTags,
|
tags: uniqueTags,
|
||||||
|
@ -125,7 +131,7 @@ export function getThemesFromSearch(
|
||||||
query: string,
|
query: string,
|
||||||
tags: string[],
|
tags: string[],
|
||||||
sortBy: string,
|
sortBy: string,
|
||||||
createdBefore?: Date
|
createdBefore?: Date,
|
||||||
): ZenTheme[] {
|
): ZenTheme[] {
|
||||||
const normalizedQuery = query.toLowerCase();
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
|
||||||
|
@ -166,7 +172,9 @@ export function getThemesFromSearch(
|
||||||
* @param id - The ID of the theme to retrieve.
|
* @param id - The ID of the theme to retrieve.
|
||||||
* @returns A promise that resolves to the ZenTheme object or undefined if not found.
|
* @returns A promise that resolves to the ZenTheme object or undefined if not found.
|
||||||
*/
|
*/
|
||||||
export async function getThemeFromId(id: string): Promise<ZenTheme | undefined> {
|
export async function getThemeFromId(
|
||||||
|
id: string,
|
||||||
|
): Promise<ZenTheme | undefined> {
|
||||||
const allThemes = await getAllThemes();
|
const allThemes = await getAllThemes();
|
||||||
return allThemes.find((theme) => theme.id === id);
|
return allThemes.find((theme) => theme.id === id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,8 +285,7 @@ export const releaseNotes: ReleaseNote[] = [
|
||||||
issue: 76,
|
issue: 76,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description:
|
description: "Added more contrast to web context menus on light mods.",
|
||||||
"Added more contrast to web context menus on light mods.",
|
|
||||||
issue: 88,
|
issue: 88,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -745,8 +744,7 @@ export const releaseNotes: ReleaseNote[] = [
|
||||||
issue: 1168,
|
issue: 1168,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description:
|
description: "Theme Store settings page doesn't display installed mods",
|
||||||
"Theme Store settings page doesn't display installed mods",
|
|
||||||
issue: 1125,
|
issue: 1125,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1109,7 +1107,8 @@ export const releaseNotes: ReleaseNote[] = [
|
||||||
date: "10/10/2024",
|
date: "10/10/2024",
|
||||||
image: true,
|
image: true,
|
||||||
workflowId: 11279059812,
|
workflowId: 11279059812,
|
||||||
extra: "This release brings Zen to Firefox v131.0.2, which patches a significant security vulnerability.\n\nThis update improves the split view and pinned tabs features.\nWe have also released Zen Twilight; automated unstable builds where you can test out the latest features!",
|
extra:
|
||||||
|
"This release brings Zen to Firefox v131.0.2, which patches a significant security vulnerability.\n\nThis update improves the split view and pinned tabs features.\nWe have also released Zen Twilight; automated unstable builds where you can test out the latest features!",
|
||||||
features: [
|
features: [
|
||||||
"Updated to the latest stable version of Firefox (131.0.2)",
|
"Updated to the latest stable version of Firefox (131.0.2)",
|
||||||
"Added floating compact mode",
|
"Added floating compact mode",
|
||||||
|
@ -1126,29 +1125,31 @@ export const releaseNotes: ReleaseNote[] = [
|
||||||
description: "Fixed performance issue when scrolling",
|
description: "Fixed performance issue when scrolling",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Fixed buffering issues on YouTube"
|
description: "Fixed buffering issues on YouTube",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Fixed Zen Mod settings page crashing when a mod ceases to exist"
|
description:
|
||||||
|
"Fixed Zen Mod settings page crashing when a mod ceases to exist",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Fixed extension menu breaking compact mode when held open",
|
description:
|
||||||
issue: 1925
|
"Fixed extension menu breaking compact mode when held open",
|
||||||
|
issue: 1925,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Fixed internal keyboard shortcuts for macOS",
|
description: "Fixed internal keyboard shortcuts for macOS",
|
||||||
issue: 1629
|
issue: 1629,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Fixed display issues with certain keyboard layouts",
|
description: "Fixed display issues with certain keyboard layouts",
|
||||||
issue: 1930
|
issue: 1930,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Applied patches to fix CVE-2024-9680",
|
description: "Applied patches to fix CVE-2024-9680",
|
||||||
issue: 1993
|
issue: 1993,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
].reverse();
|
].reverse();
|
||||||
|
|
||||||
export function releaseNoteIsAlpha(note: ReleaseNote) {
|
export function releaseNoteIsAlpha(note: ReleaseNote) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue