Refactor next.config.js and form.tsx

This commit is contained in:
mr. M 2024-10-14 22:52:01 +02:00
parent 00c7ce4c56
commit 5ec0fcbb56
No known key found for this signature in database
GPG key ID: CBD57A2AEDBDA1FB
31 changed files with 388 additions and 336 deletions

View file

@ -41,4 +41,4 @@ const nextConfig = (phase, { defaultConfig }) => {
};
};
module.exports = nextConfig;
module.exports = nextConfig;

View file

@ -77,49 +77,60 @@ function formatReleaseNote(releaseNote: ReleaseNote) {
Thanks everyone for your feedback!
</p>`;
if (releaseNote.image) {
content += `<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/releases/${releaseNote.version}.png"
if (releaseNote.image) {
content += `<img src="https://cdn.jsdelivr.net/gh/zen-browser/www/public/releases/${releaseNote.version}.png"
alt="Release Image for version ${releaseNote.version}"
style="max-width: 30em; width: 100%; border-radius: 0.5rem;"
/>`;
}
}
if (releaseNote.extra) {
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`;
}
content += addReleaseNoteSection("⚠️ Breaking changes", releaseNote.breakingChanges);
content += addReleaseNoteSection("✓ Fixes", releaseNote.fixes?.map(fixToReleaseNote));
content += addReleaseNoteSection("🖌 Theme Changes", releaseNote.themeChanges)
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
content += addReleaseNoteSection(
"⚠️ Breaking changes",
releaseNote.breakingChanges,
);
content += addReleaseNoteSection(
"✓ Fixes",
releaseNote.fixes?.map(fixToReleaseNote),
);
content += addReleaseNoteSection(
"🖌 Theme Changes",
releaseNote.themeChanges,
);
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
return content;
}
function addReleaseNoteSection(title: string, items?: string[]): string {
if (!items) {
return "";
}
if (!items) {
return "";
}
let content = `<h2>${title}</h2>`;
content += `<ul>`;
for (const item of items) {
if (item && item.length > 0) {
content += `<li>${item}</li>`;
}
}
content += `</ul>`;
return content;
let content = `<h2>${title}</h2>`;
content += `<ul>`;
for (const item of items) {
if (item && item.length > 0) {
content += `<li>${item}</li>`;
}
}
content += `</ul>`;
return content;
}
function fixToReleaseNote(fix?: Exclude<ReleaseNote['fixes'], undefined>[number]) {
if (!fix || !fix.description || fix.description.length === 0) {
return "";
}
function fixToReleaseNote(
fix?: Exclude<ReleaseNote["fixes"], undefined>[number],
) {
if (!fix || !fix.description || fix.description.length === 0) {
return "";
}
let note = fix.description;
if (fix.issue) {
note += ` (<a href="https://github.com/zen-browser/desktop/issues/${fix.issue}" target="_blank">#${fix.issue}</a>)`;
}
return note;
let note = fix.description;
if (fix.issue) {
note += ` (<a href="https://github.com/zen-browser/desktop/issues/${fix.issue}" target="_blank">#${fix.issue}</a>)`;
}
return note;
}

View file

@ -49,11 +49,11 @@
--color-three: #ff2e63;
*/
--color-1: 0 100% 63%;
--color-2: 270 100% 63%;
--color-3: 210 100% 63%;
--color-4: 195 100% 63%;
--color-5: 90 100% 63%;
--color-1: 0 100% 63%;
--color-2: 270 100% 63%;
--color-3: 210 100% 63%;
--color-4: 195 100% 63%;
--color-5: 90 100% 63%;
}
[data-theme="dark"],

View file

@ -57,7 +57,7 @@
}
code {
font-size: .8em;
font-size: 0.8em;
background-color: var(--surface);
padding: 0.2em 0.4em;
border: 1px solid light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2));

View file

@ -1,14 +1,14 @@
'use client';
"use client";
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useEffect } from "react";
import { useRouter } from "next/navigation";
export default function ThemesPage() {
const router = useRouter();
const router = useRouter();
useEffect(() => {
router.replace('/mods');
}, [router]);
useEffect(() => {
router.replace("/mods");
}, [router]);
return null;
return null;
}

View file

@ -2,7 +2,6 @@
import Image from "next/image";
const inDev = process.env.NODE_ENV === "development";
function imageLoader({ src }: { src: string }) {
// Load locally if we are in development

View file

@ -31,7 +31,7 @@ export const AlertModal = ({
</div>
</AlertDialog.Title>
<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
version.
</p>

View file

@ -75,7 +75,12 @@ export function BrandingAssets() {
CC BY-SA 4.0
</a>
. 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)
</a>{" "}
for the assets.

View file

@ -6,34 +6,46 @@ import { Slider } from "./ui/slider";
import React from "react";
export default function BrowserComplexityExample() {
const [selectedImage, setSelectedImage] = React.useState([1]);
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">
<h1 className="text-4xl md:text-5xl font-bold text-center">How much browser do you want?</h1>
<p className="mt-4 text-center text-md mx-auto w-2/3 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>
<div className="w-64 mb-6 mt-12 flex gap-4">
<span className="opacity-90">🌱</span>
<Slider step={1} max={3} showSteps="half" value={selectedImage} onValueChange={setSelectedImage} />
<span className="opacity-90">🌳</span>
</div>
<div className="mx-auto md:mb-36 flex justify-center">
{[...Array(4)].map((_, i) => (
<CachedImage
width={1620}
height={900}
priority
key={i}
src={`www/public/browsers/image${i + 1}.png`}
alt="Zen Browser"
className={ny("rounded-md object-cover shadow object-right mx-12 w-full", selectedImage[0] === i
? "" //"animate-fade-up duration-500 !opacity-100"
: "hidden")}
/>
))}
</div>
</div>
)
const [selectedImage, setSelectedImage] = React.useState([1]);
return (
<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-center text-4xl font-bold md:text-5xl">
How much browser do you want?
</h1>
<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>
<div className="mb-6 mt-12 flex w-64 gap-4">
<span className="opacity-90">🌱</span>
<Slider
step={1}
max={3}
showSteps="half"
value={selectedImage}
onValueChange={setSelectedImage}
/>
<span className="opacity-90">🌳</span>
</div>
<div className="mx-auto flex justify-center md:mb-36">
{[...Array(4)].map((_, i) => (
<CachedImage
width={1620}
height={900}
priority
key={i}
src={`www/public/browsers/image${i + 1}.png`}
alt="Zen Browser"
className={ny(
"mx-12 w-full rounded-md object-cover object-right shadow",
selectedImage[0] === i
? "" //"animate-fade-up duration-500 !opacity-100"
: "hidden",
)}
/>
))}
</div>
</div>
);
}

View file

@ -1,14 +1,12 @@
import s from './styles.module.css'
import s from "./styles.module.css";
export default function CoolHeaderText() {
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">
<h1 className={s.title}>
Stay focused, browse faster with Zen
</h1>
<h1 className={s.title}>Stay focused, browse faster with Zen</h1>
</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
</div>
</>

View file

@ -1,24 +1,23 @@
@keyframes hueShift {
0% {
filter: hue-rotate(0deg);
}
50% {
filter: hue-rotate(170deg);
}
100% {
filter: hue-rotate(0deg);
}
}
.title {
background-clip: text;
background-image: linear-gradient(90deg, #0077e7, #01d8d1);
-webkit-background-clip: text;
color: transparent;
filter: hue-rotate(0deg);
animation: hueShift 10s infinite linear 1s;
padding-bottom: 8px;
user-select: none;
cursor: default;
}
0% {
filter: hue-rotate(0deg);
}
50% {
filter: hue-rotate(170deg);
}
100% {
filter: hue-rotate(0deg);
}
}
.title {
background-clip: text;
background-image: linear-gradient(90deg, #0077e7, #01d8d1);
-webkit-background-clip: text;
color: transparent;
filter: hue-rotate(0deg);
animation: hueShift 10s infinite linear 1s;
padding-bottom: 8px;
user-select: none;
cursor: default;
}

View file

@ -5,7 +5,6 @@ import { Button } from "./ui/button";
import React from "react";
import styled from "styled-components";
import {
Sheet,
SheetContent,

View file

@ -1,4 +1,4 @@
'use client';
"use client";
import { Architecture } from "@/components/download/types";
import { ny } from "@/lib/utils";

View file

@ -53,4 +53,4 @@ export const FieldDescription = styled.div`
font-size: 1rem;
color: #666;
margin-bottom: 1rem;
`;
`;

View file

@ -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-2xl font-semibold">{label}</h1>
<p className="mx-auto text-center text-muted-foreground">
{description}
</p>
<p className="mx-auto text-center text-muted-foreground">{description}</p>
</div>
);
};

View file

@ -1,4 +1,4 @@
'use client';
"use client";
import { Platforms } from "@/components/download/types";
import { ny } from "@/lib/utils";
@ -10,7 +10,7 @@ interface PlatformCardProps {
}
const PLATFORMS_DATA: Record<
Exclude<Platforms, 'Unsupported'>,
Exclude<Platforms, "Unsupported">,
{ label: string; icon: string; borderColor: string }
> = {
Windows: {

View file

@ -1,28 +1,28 @@
import confetti from "canvas-confetti";
export const throwConfetti = () => {
const end = Date.now() + 3 * 1000; // 3 seconds
const colors = ["#a786ff", "#fd8bbc", "#eca184", "#f8deb1"];
const frame = () => {
if (Date.now() > end) return;
const end = Date.now() + 3 * 1000; // 3 seconds
const colors = ["#a786ff", "#fd8bbc", "#eca184", "#f8deb1"];
const frame = () => {
if (Date.now() > end) return;
confetti({
particleCount: 2,
angle: 60,
spread: 55,
startVelocity: 60,
origin: { x: 0, y: 0.5 },
colors,
});
confetti({
particleCount: 2,
angle: 120,
spread: 55,
startVelocity: 60,
origin: { x: 1, y: 0.5 },
colors,
});
requestAnimationFrame(frame);
};
frame();
};
confetti({
particleCount: 2,
angle: 60,
spread: 55,
startVelocity: 60,
origin: { x: 0, y: 0.5 },
colors,
});
confetti({
particleCount: 2,
angle: 120,
spread: 55,
startVelocity: 60,
origin: { x: 1, y: 0.5 },
colors,
});
requestAnimationFrame(frame);
};
frame();
};

View file

@ -1,3 +1,3 @@
export type Platforms = "Windows" | "MacOS" | "Linux" | "Unsupported";
export type Architecture = "specific" | "generic";
export type Architecture = "specific" | "generic";

View file

@ -10,16 +10,16 @@ interface WindowsInstallerProps {
flowIndex: number;
platform: Platforms | null;
selectedArchitecture: string;
setSelectedWindowsDownloadType: (value: string) => void;
selectedWindowsDownloadType: string;
setSelectedWindowsDownloadType: (value: string) => void;
selectedWindowsDownloadType: string;
}
export const WindowsInstaller = ({
flowIndex,
platform,
selectedArchitecture,
setSelectedWindowsDownloadType,
selectedWindowsDownloadType,
setSelectedWindowsDownloadType,
selectedWindowsDownloadType,
}: WindowsInstallerProps) => {
return (
<FormField

View file

@ -1,16 +1,26 @@
'use client'
"use client";
import CachedImage from "@/components/CachedImage";
import Logo from "@/components/logo";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { ExternalLinkIcon, EyeClosedIcon, LockClosedIcon, QuestionMarkCircledIcon } from "@radix-ui/react-icons";
import {
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 Link from "next/link";
import { useState } from "react";
export const FAQ = () => {
const [feature, setFeature] = useState("");
const [feature, setFeature] = useState("");
return (
<div className="mx-auto mt-36 flex w-full flex-col bg-surface shadow md:w-5/6 md:rounded-md lg:w-3/4 lg:flex-row">
<div className="relative flex w-full flex-col justify-center p-5 lg:w-1/2 lg:p-12">

View file

@ -48,8 +48,8 @@ export default function Features() {
<PaintBucket className="inline h-10 w-10"></PaintBucket>
</h3>
<p className="mt-4 text-lg text-gray-600 dark:text-gray-300">
With Zen Mods, you can customize your browsing experience
to reflect your unique style and preferences. Choose from a wide
With Zen Mods, you can customize your browsing experience to
reflect your unique style and preferences. Choose from a wide
array of Mods, colors, and layouts to make Zen truly your own,
transforming your browser into a personalized digital space.
</p>

View file

@ -12,12 +12,14 @@ export function ModeToggle() {
setMounted(true);
const savedTheme = localStorage.getItem("theme");
if (savedTheme) {
setTheme(savedTheme);
setTheme(savedTheme);
} else {
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
setTheme(prefersDark ? "dark" : "light");
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)",
).matches;
setTheme(prefersDark ? "dark" : "light");
}
}, [setTheme]);
}, [setTheme]);
const toggleTheme = () => {
const newTheme = theme === "light" ? "dark" : "light";

View file

@ -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">
<MobileNav />
<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>
<NavigationMenuItem className="cursor-pointer flex items-center">
<NavigationMenuItem className="flex cursor-pointer items-center">
<NavigationMenuLink href="/">
<Logo withText />
</NavigationMenuLink>
@ -186,8 +186,8 @@ export function Navigation() {
target="_blank"
rel="noopener noreferrer"
>
Ko-fi is a way to support us with a one-time donation and help
us keep the project alive.
Ko-fi is a way to support us with a one-time donation and
help us keep the project alive.
</ListItem2>
</ul>
</NavigationMenuContent>
@ -215,7 +215,10 @@ export function Navigation() {
<ModeToggle />
</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}
</NavigationMenuLink>
</div>

View file

@ -3,8 +3,13 @@ import { getThemeAuthorLink, ZenTheme } from "@/lib/mods";
import { TagIcon } from "lucide-react";
import { Badge } from "./ui/badge";
import Link from "next/link";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "./ui/card";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "./ui/card";
export default function ThemeCard({
theme,
@ -15,10 +20,11 @@ export default function ThemeCard({
}) {
const maxNameLen = 50;
const maxDescLen = 100;
const authorLink = getThemeAuthorLink(theme);
const authorLink = getThemeAuthorLink(theme);
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) => {
// 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.
@ -28,7 +34,8 @@ export default function ThemeCard({
if (e.button !== 0 && e.button !== 1) return;
if (e.target instanceof HTMLAnchorElement) return;
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">
<img
src={theme.image}
@ -64,31 +71,31 @@ export default function ThemeCard({
</p>
</CardContent>
<CardFooter className="mt-2 flex">
{theme.homepage && (
<a
href={theme.homepage}
className="text-md text-blue-500"
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
Homepage
</a>
)}
{theme.homepage && authorLink && (
<span className="text-md mx-2 text-muted-foreground">·</span>
)}
{authorLink && (
<a
href={authorLink}
className="text-md text-blue-500"
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
Author
</a>
)}
{theme.homepage && (
<a
href={theme.homepage}
className="text-md text-blue-500"
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
Homepage
</a>
)}
{theme.homepage && authorLink && (
<span className="text-md mx-2 text-muted-foreground">·</span>
)}
{authorLink && (
<a
href={authorLink}
className="text-md text-blue-500"
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
Author
</a>
)}
</CardFooter>
</div>
</Card>

View file

@ -19,7 +19,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
return (
<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="flex justify-between w-full items-center mb-2">
<div className="mb-2 flex w-full items-center justify-between">
<a
className="flex cursor-pointer items-center opacity-70"
href="/mods"
@ -67,11 +67,9 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
</a>
</p>
<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>
<span className="opacity-70">
Theme by{" "}
</span>
<span className="opacity-70">Theme by </span>
<a
href={getThemeAuthorLink(theme)}
className="text-md mt-4 text-blue-500"
@ -81,9 +79,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
{theme.author}
</a>
</div>
<div className="opacity-70">
v{theme.version}
</div>
<div className="opacity-70">v{theme.version}</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">
@ -92,7 +88,7 @@ export default async function ThemePage({ themeID }: { themeID: string }) {
alt={theme.name}
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 ? (
<LoaderCircleIcon className="mx-auto h-12 w-12 animate-spin" />
) : (

View file

@ -1,76 +1,79 @@
import * as React from "react"
import * as React from "react";
import { ny } from "@/lib/utils"
import { ny } from "@/lib/utils";
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={ny(
"rounded-xl border bg-card text-card-foreground shadow",
className
)}
{...props}
/>
))
Card.displayName = "Card"
<div
ref={ref}
className={ny(
"rounded-xl border bg-card text-card-foreground shadow",
className,
)}
{...props}
/>
));
Card.displayName = "Card";
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={ny("flex flex-col space-y-1.5", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
<div
ref={ref}
className={ny("flex flex-col space-y-1.5", className)}
{...props}
/>
));
CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={ny("font-semibold leading-none tracking-tight", className)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
<h3
ref={ref}
className={ny("font-semibold leading-none tracking-tight", className)}
{...props}
/>
));
CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={ny("text-sm text-muted-foreground", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
<p
ref={ref}
className={ny("text-sm text-muted-foreground", className)}
{...props}
/>
));
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={ny("", className)} {...props} />
))
CardContent.displayName = "CardContent"
<div ref={ref} className={ny("", className)} {...props} />
));
CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={ny("flex items-center", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
<div ref={ref} className={ny("flex items-center", className)} {...props} />
));
CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View file

@ -1,28 +1,28 @@
import React from 'react'
import React from "react";
import { ny } from '@/lib/utils'
import { ny } from "@/lib/utils";
interface RainbowButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
export function RainbowButton({ children, ...props }: RainbowButtonProps) {
return (
<button
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',
return (
<button
className={ny(
"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: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 styles
"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
'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)))]',
// 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)))]",
// 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)))]',
)}
{...props}
>
{children}
</button>
)
// 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)))]",
)}
{...props}
>
{children}
</button>
);
}

View file

@ -16,9 +16,10 @@ export default function WelcomePage() {
Start using it by clicking on the sidebar icon or trying out the split
view feature!
</p>
<p className="text-md w-2/5 mx-auto mt-12 opacity-70">
<InfoCircledIcon className="inline-block mr-4 size-5 text-yellow-500" />
Zen Browser is still in development and may have bugs. This welcome page is under construction.
<p className="text-md mx-auto mt-12 w-2/5 opacity-70">
<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.
</p>
</div>
);

View file

@ -38,7 +38,10 @@ function isValidDate(date: any): date is Date {
* @param assignFutureDate - Whether to assign a future date if parsing fails.
* @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 || "");
if (isValidDate(date)) {
return date;
@ -83,7 +86,10 @@ export async function getAllThemes(): Promise<ZenTheme[]> {
homepage: theme.homepage,
readme: theme.readme,
preferences: theme.preferences,
isColorTheme: typeof theme.isColorTheme === 'boolean' ? theme.isColorTheme : false,
isColorTheme:
typeof theme.isColorTheme === "boolean"
? theme.isColorTheme
: false,
author: theme.author,
version: theme.version,
tags: uniqueTags,
@ -125,7 +131,7 @@ export function getThemesFromSearch(
query: string,
tags: string[],
sortBy: string,
createdBefore?: Date
createdBefore?: Date,
): ZenTheme[] {
const normalizedQuery = query.toLowerCase();
@ -166,7 +172,9 @@ export function getThemesFromSearch(
* @param id - The ID of the theme to retrieve.
* @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();
return allThemes.find((theme) => theme.id === id);
}
@ -196,4 +204,4 @@ export async function getThemeMarkdown(theme: ZenTheme): Promise<string> {
*/
export function getThemeAuthorLink(theme: ZenTheme): string {
return `https://github.com/${theme.author}`;
}
}

View file

@ -285,8 +285,7 @@ export const releaseNotes: ReleaseNote[] = [
issue: 76,
},
{
description:
"Added more contrast to web context menus on light mods.",
description: "Added more contrast to web context menus on light mods.",
issue: 88,
},
{
@ -745,8 +744,7 @@ export const releaseNotes: ReleaseNote[] = [
issue: 1168,
},
{
description:
"Theme Store settings page doesn't display installed mods",
description: "Theme Store settings page doesn't display installed mods",
issue: 1125,
},
{
@ -1104,51 +1102,54 @@ export const releaseNotes: ReleaseNote[] = [
},
],
},
{
{
version: "1.0.1-a.8",
date: "10/10/2024",
image: true,
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!",
features: [
"Updated to the latest stable version of Firefox (131.0.2)",
"Added floating compact mode",
"Allow moving split view tabs with drag and drop functionality",
"Added option to reset pinned tabs to original state on close",
"Added support for syncing workspaces",
"Allow opening tabs by middle clicking the tab sidebar",
],
fixes: [
{
description: "Fixed tab sidebar flickering when on the right",
},
{
description: "Fixed performance issue when scrolling",
},
{
description: "Fixed buffering issues on YouTube"
},
{
description: "Fixed Zen Mod settings page crashing when a mod ceases to exist"
},
{
description: "Fixed extension menu breaking compact mode when held open",
issue: 1925
},
{
description: "Fixed internal keyboard shortcuts for macOS",
issue: 1629
},
{
description: "Fixed display issues with certain keyboard layouts",
issue: 1930
},
{
description: "Applied patches to fix CVE-2024-9680",
issue: 1993
},
]
}
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: [
"Updated to the latest stable version of Firefox (131.0.2)",
"Added floating compact mode",
"Allow moving split view tabs with drag and drop functionality",
"Added option to reset pinned tabs to original state on close",
"Added support for syncing workspaces",
"Allow opening tabs by middle clicking the tab sidebar",
],
fixes: [
{
description: "Fixed tab sidebar flickering when on the right",
},
{
description: "Fixed performance issue when scrolling",
},
{
description: "Fixed buffering issues on YouTube",
},
{
description:
"Fixed Zen Mod settings page crashing when a mod ceases to exist",
},
{
description:
"Fixed extension menu breaking compact mode when held open",
issue: 1925,
},
{
description: "Fixed internal keyboard shortcuts for macOS",
issue: 1629,
},
{
description: "Fixed display issues with certain keyboard layouts",
issue: 1930,
},
{
description: "Applied patches to fix CVE-2024-9680",
issue: 1993,
},
],
},
].reverse();
export function releaseNoteIsAlpha(note: ReleaseNote) {

View file

@ -22,9 +22,9 @@ const config = {
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
},
screens: {
"3xl": "2200px",
},
screens: {
"3xl": "2200px",
},
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
@ -32,11 +32,11 @@ const config = {
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
surface: "var(--surface)",
"color-1": "hsl(var(--color-1))",
"color-2": "hsl(var(--color-2))",
"color-3": "hsl(var(--color-3))",
"color-4": "hsl(var(--color-4))",
"color-5": "hsl(var(--color-5))",
"color-1": "hsl(var(--color-1))",
"color-2": "hsl(var(--color-2))",
"color-3": "hsl(var(--color-3))",
"color-4": "hsl(var(--color-4))",
"color-5": "hsl(var(--color-5))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
@ -72,10 +72,10 @@ const config = {
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
rainbow: {
"0%": { "background-position": "0%" },
"100%": { "background-position": "200%" },
},
rainbow: {
"0%": { "background-position": "0%" },
"100%": { "background-position": "200%" },
},
orbit: {
"0%": {
transform: