Merge pull request #596 from zen-browser/refactor/app

This commit is contained in:
mr. m 2025-05-15 14:41:17 +02:00 committed by GitHub
commit bdf9bb81d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 453 additions and 351 deletions

View file

@ -20,16 +20,26 @@
"useEditorconfig": true "useEditorconfig": true
}, },
"files": { "files": {
"ignore": [ "ignore": ["node_modules", ".git", "dist"]
"node_modules",
".git",
"dist"
]
}, },
"javascript": { "javascript": {
"formatter": { "formatter": {
"quoteStyle": "single", "quoteStyle": "single",
"semicolons": "asNeeded" "semicolons": "asNeeded"
} }
},
"assists": {
"actions": {
"source": {
"sortJsxProps": "on"
}
}
},
"vcs": {
"enabled": true,
"clientKind": "git",
"defaultBranch": "main",
"root": ".",
"useIgnoreFile": true
} }
} }

View file

@ -10,7 +10,7 @@
"wrangler": "wrangler", "wrangler": "wrangler",
"astro": "astro", "astro": "astro",
"lint": "biome lint ./src", "lint": "biome lint ./src",
"format": "biome format ./src --write", "format": "biome format ./src",
"prepare": "husky" "prepare": "husky"
}, },
"dependencies": { "dependencies": {
@ -45,8 +45,6 @@
"wrangler": "^3.94.0" "wrangler": "^3.94.0"
}, },
"lint-staged": { "lint-staged": {
"src/**/*.{ts,tsx,astro,js,jsx}": [ "src/**/*.{ts,tsx,astro,js,jsx}": ["biome check --write ./src"]
"biome check --write ./src"
]
} }
} }

View file

@ -1,68 +1,70 @@
{ {
"version": "v1.0.0", "version": "v1.0.0",
"entity": { "entity": {
"type": "individual", "type": "individual",
"role": "owner", "role": "owner",
"name": "Mauro", "name": "Mauro",
"email": "funding@zen-browser.com", "email": "funding@zen-browser.com",
"description": "Im the developer of Zen Browser, a web browser that is fast, secure, and easy to use. I am passionate about creating software that makes people's lives easier and more enjoyable.", "description": "Im the developer of Zen Browser, a web browser that is fast, secure, and easy to use. I am passionate about creating software that makes people's lives easier and more enjoyable.",
"webpageUrl": { "webpageUrl": {
"url": "https://cheff.dev", "url": "https://cheff.dev",
"wellKnown": "https://cheff.dev/.well-known/funding-manifest-urls" "wellKnown": "https://cheff.dev/.well-known/funding-manifest-urls"
}
},
"projects": [{
"guid": "zen-browser",
"name": "Zen",
"description": "Zen is a beautiful, fast, and productive web browser. It is designed to be packed with features that make it easy to use and navigate. Zen is built on the latest Firefox engine, providing speed, privacy, and security.",
"webpageUrl": {
"url": "https://zen-browser.app"
},
"repositoryUrl": {
"url": "https://github.com/zen-browser/desktop",
"wellKnown": "https://github.com/zen-browser/desktop/blob/dev/.well-known/funding-manifest-urls"
},
"licenses": ["MPL-2.0"],
"tags": ["browser", "web", "desktop", "open-source"]
}],
"funding": {
"channels": [
{
"guid": "patreon",
"name": "Patreon",
"description": "Patreon is a membership platform that makes it easy for artists and creators to get paid.",
"url": "https://www.patreon.com/zen_browser",
"type": "other"
},
{
"guid": "ko-fi",
"name": "Ko-fi",
"description": "Ko-fi is a platform that allows creators to receive donations from their fans.",
"url": "https://ko-fi.com/zen_browser",
"type": "other"
}
],
"plans": [
{
"guid": "licenses-and-hosting",
"status": "active",
"name": "Licenses and hosting",
"description": "Help me pay for the licenses and hosting of the project. This includes self-hosting build servers, cloudflare services, and software lienses.",
"amount": 420,
"currency": "EUR",
"frequency": "yearly",
"channels": ["patreon", "ko-fi"]
},
{
"guid": "angel-plan",
"status": "active",
"name": "Goodwill plan",
"description": "Pay anything you wish to show your goodwill for the project.",
"amount": 0,
"currency": "EUR",
"frequency": "one-time",
"channels": ["patreon", "ko-fi"]
}
]
} }
},
"projects": [
{
"guid": "zen-browser",
"name": "Zen",
"description": "Zen is a beautiful, fast, and productive web browser. It is designed to be packed with features that make it easy to use and navigate. Zen is built on the latest Firefox engine, providing speed, privacy, and security.",
"webpageUrl": {
"url": "https://zen-browser.app"
},
"repositoryUrl": {
"url": "https://github.com/zen-browser/desktop",
"wellKnown": "https://github.com/zen-browser/desktop/blob/dev/.well-known/funding-manifest-urls"
},
"licenses": ["MPL-2.0"],
"tags": ["browser", "web", "desktop", "open-source"]
}
],
"funding": {
"channels": [
{
"guid": "patreon",
"name": "Patreon",
"description": "Patreon is a membership platform that makes it easy for artists and creators to get paid.",
"url": "https://www.patreon.com/zen_browser",
"type": "other"
},
{
"guid": "ko-fi",
"name": "Ko-fi",
"description": "Ko-fi is a platform that allows creators to receive donations from their fans.",
"url": "https://ko-fi.com/zen_browser",
"type": "other"
}
],
"plans": [
{
"guid": "licenses-and-hosting",
"status": "active",
"name": "Licenses and hosting",
"description": "Help me pay for the licenses and hosting of the project. This includes self-hosting build servers, cloudflare services, and software lienses.",
"amount": 420,
"currency": "EUR",
"frequency": "yearly",
"channels": ["patreon", "ko-fi"]
},
{
"guid": "angel-plan",
"status": "active",
"name": "Goodwill plan",
"description": "Pay anything you wish to show your goodwill for the project.",
"amount": 0,
"currency": "EUR",
"frequency": "one-time",
"channels": ["patreon", "ko-fi"]
}
]
}
} }

View file

@ -1,5 +1,5 @@
--- ---
import { ArrowLeft } from 'lucide-astro' import ArrowLeftIcon from '~/icons/ArrowLeftIcon.astro'
import { getLocale, getUI } from '~/utils/i18n' import { getLocale, getUI } from '~/utils/i18n'
const locale = getLocale(Astro) const locale = getLocale(Astro)
@ -15,6 +15,6 @@ const {
onclick="window.history.back()" onclick="window.history.back()"
class="mb-8 flex w-min items-center gap-2" class="mb-8 flex w-min items-center gap-2"
> >
<ArrowLeft class="size-4" /> <ArrowLeftIcon class="size-4" />
{slug.back} {slug.back}
</button> </button>

View file

@ -1,11 +1,12 @@
--- ---
import Image from 'astro/components/Image.astro' import Image from 'astro/components/Image.astro'
import { Check, Github } from 'lucide-astro'
import { motion } from 'motion/react' import { motion } from 'motion/react'
import { getTitleAnimation } from '~/animations' import { getTitleAnimation } from '~/animations'
import ComImage from '~/assets/ComImage.png' import ComImage from '~/assets/ComImage.png'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import CheckIcon from '~/icons/CheckIcon.astro'
import GitHubIcon from '~/icons/GitHubIcon.astro'
import { getLocale, getUI } from '~/utils/i18n' import { getLocale, getUI } from '~/utils/i18n'
const locale = getLocale(Astro) const locale = getLocale(Astro)
@ -19,9 +20,9 @@ const {
<section <section
id="Community" id="Community"
class="relative flex w-full flex-col items-center px-4 text-start md:px-0 md:text-center lg:pt-36" class="relative flex w-full flex-col items-center gap-6 py-12 text-start md:text-center lg:py-36"
> >
<Description class="mb-2 px-4 text-6xl font-bold"> <Description class="mb-2 text-6xl font-bold">
<motion.span client:load {...getTitleAnimation(0.2)}> <motion.span client:load {...getTitleAnimation(0.2)}>
{community.title[0]} {community.title[0]}
</motion.span> </motion.span>
@ -35,16 +36,14 @@ const {
<motion.p <motion.p
client:load client:load
{...getTitleAnimation(0.6)} {...getTitleAnimation(0.6)}
className="px-4 md:px-24 lg:w-1/2 lg:px-0" className="lg:w-1/2 lg:px-0"
> >
{community.description} {community.description}
</motion.p> </motion.p>
<div <div class="flex w-full flex-wrap gap-3 sm:gap-10 md:justify-center">
class="mt-6 flex w-full flex-wrap gap-3 px-4 sm:gap-10 sm:px-0 md:justify-center"
>
<motion.span client:load {...getTitleAnimation(0.8)}> <motion.span client:load {...getTitleAnimation(0.8)}>
<Button class:list={['px-4']} href="https://github.com/zen-browser"> <Button class:list={['px-4']} href="https://github.com/zen-browser">
<Github class="size-4" /> <GitHubIcon class="size-4" />
<span>{community.lists.freeAndOpenSource.title}</span> <span>{community.lists.freeAndOpenSource.title}</span>
</Button> </Button>
</motion.span> </motion.span>
@ -53,7 +52,7 @@ const {
{...getTitleAnimation(1)} {...getTitleAnimation(1)}
className="flex items-center gap-4" className="flex items-center gap-4"
> >
<Check class="size-4" /> <CheckIcon class="size-4" />
<span>{community.lists.simpleYetPowerful.title}</span> <span>{community.lists.simpleYetPowerful.title}</span>
</motion.div> </motion.div>
<motion.div <motion.div
@ -61,19 +60,19 @@ const {
{...getTitleAnimation(1.2)} {...getTitleAnimation(1.2)}
className="flex items-center gap-4" className="flex items-center gap-4"
> >
<Check class="size-4" /> <CheckIcon class="size-4" />
<span>{community.lists.privateAndAlwaysUpToDate.title}</span> <span>{community.lists.privateAndAlwaysUpToDate.title}</span>
</motion.div> </motion.div>
</div> </div>
<motion.span <motion.span
className="flex max-w-full px-8 lg:max-w-none lg:flex-none lg:px-0" className="flex max-w-full lg:max-w-none lg:flex-none"
client:load client:load
{...getTitleAnimation(1.4)} {...getTitleAnimation(1.4)}
> >
<Image <Image
src={ComImage} src={ComImage}
alt={community.images.community.alt} alt={community.images.community.alt}
class="my-24 rounded-3xl shadow-md lg:mx-auto lg:w-3/4 dark:opacity-80" class="rounded-3xl shadow-md lg:mx-auto dark:opacity-80"
/> />
</motion.span> </motion.span>
</section> </section>

View file

@ -26,7 +26,7 @@ const descriptions = Object.values(features.featureTabs).map((tab) => tab.descri
<section <section
id="Features" id="Features"
class="relative flex w-full flex-col px-4 text-start md:px-24 lg:mx-auto lg:w-3/4 lg:px-0 lg:py-36" class="relative flex w-full flex-col py-12 text-start lg:py-36"
> >
<Description class="mb-2 text-6xl font-bold"> <Description class="mb-2 text-6xl font-bold">
<motion.span client:load {...getTitleAnimation(0.2)}> <motion.span client:load {...getTitleAnimation(0.2)}>
@ -42,9 +42,7 @@ const descriptions = Object.values(features.featureTabs).map((tab) => tab.descri
<motion.p client:load {...getTitleAnimation(0.6)} className="lg:w-1/2"> <motion.p client:load {...getTitleAnimation(0.6)} className="lg:w-1/2">
{features.description} {features.description}
</motion.p> </motion.p>
<div <div class="mt-6 flex flex-col gap-6 lg:flex-row lg:justify-between lg:gap-2">
class="mb-12 mt-6 flex flex-col gap-6 lg:flex-row lg:justify-between lg:gap-2"
>
<div class="flex w-full flex-col lg:w-1/3"> <div class="flex w-full flex-col lg:w-1/3">
<!-- Mobile tabs --> <!-- Mobile tabs -->
<div class="flex gap-2 overflow-x-auto overflow-y-clip lg:hidden"> <div class="flex gap-2 overflow-x-auto overflow-y-clip lg:hidden">

View file

@ -1,9 +1,9 @@
--- ---
import { ArrowRight } from 'lucide-astro'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Circles from '~/components/Circles.astro' import Circles from '~/components/Circles.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import SocialMediaStrip from '~/components/SocialMediaStrip.astro' import SocialMediaStrip from '~/components/SocialMediaStrip.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import { getLocale, getPath, getUI } from '~/utils/i18n' import { getLocale, getPath, getUI } from '~/utils/i18n'
const locale = getLocale(Astro) const locale = getLocale(Astro)
@ -15,11 +15,13 @@ const {
<footer <footer
id="footer" id="footer"
class="relative flex w-full flex-col gap-16 overflow-hidden border-t border-dark bg-dark px-4 py-12 text-paper lg:p-24" class="relative flex w-full flex-col items-center gap-16 overflow-hidden border-t border-dark bg-dark px-4 py-12 text-paper lg:p-24"
role="contentinfo" role="contentinfo"
aria-label="Site footer" aria-label="Site footer"
> >
<div class="flex w-full flex-col items-start justify-between gap-12"> <div
class="container flex w-full flex-col items-start justify-between gap-12"
>
<section <section
class="w-full text-center lg:w-1/2 lg:text-left" class="w-full text-center lg:w-1/2 lg:text-left"
aria-labelledby="footer-title" aria-labelledby="footer-title"
@ -39,7 +41,7 @@ const {
aria-label={footer.download} aria-label={footer.download}
> >
{footer.download} {footer.download}
<ArrowRight class="size-4" aria-hidden="true" /> <ArrowRightIcon class="size-4" aria-hidden="true" />
</Button> </Button>
</section> </section>
<section <section

View file

@ -1,11 +1,11 @@
--- ---
import { ArrowRight } from 'lucide-astro'
import { motion } from 'motion/react' import { motion } from 'motion/react'
import { getTitleAnimation } from '~/animations' import { getTitleAnimation } from '~/animations'
import HomePageVideo from '~/assets/HomePageVideo.webm' import HomePageVideo from '~/assets/HomePageVideo.webm'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import Title from '~/components/Title.astro' import Title from '~/components/Title.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import { getLocale, getPath, getUI } from '~/utils/i18n' import { getLocale, getPath, getUI } from '~/utils/i18n'
import SocialMediaStrip from './SocialMediaStrip.astro' import SocialMediaStrip from './SocialMediaStrip.astro'
import Video from './Video.astro' import Video from './Video.astro'
@ -37,7 +37,7 @@ const {
> >
<div class="flex h-full flex-col items-center justify-center"> <div class="flex h-full flex-col items-center justify-center">
<Title <Title
class="relative px-12 text-center !font-normal !leading-8 leading-[108px] md:!text-7xl lg:px-0 lg:!text-9xl" class="relative px-12 text-center !font-normal leading-8 md:text-7xl lg:px-0 lg:text-9xl"
> >
<motion.span client:load {...getHeroTitleAnimation()}> <motion.span client:load {...getHeroTitleAnimation()}>
{hero.title[0]} {hero.title[0]}
@ -71,7 +71,7 @@ const {
<motion.span client:load {...getHeroTitleAnimation()}> <motion.span client:load {...getHeroTitleAnimation()}>
<Button class="w-full" href={getLocalePath('/download')} isPrimary> <Button class="w-full" href={getLocalePath('/download')} isPrimary>
{hero.buttons.beta} {hero.buttons.beta}
<ArrowRight class="size-4" /> <ArrowRightIcon class="size-4" />
</Button> </Button>
</motion.span> </motion.span>
<motion.span client:load {...getHeroTitleAnimation()}> <motion.span client:load {...getHeroTitleAnimation()}>
@ -88,7 +88,7 @@ const {
</div> </div>
</header> </header>
<motion.span <motion.span
className="flex max-w-full px-8 lg:max-w-none lg:flex-none lg:px-0" className="flex max-w-full lg:max-w-none lg:flex-none"
client:load client:load
{...getHeroTitleAnimation()} {...getHeroTitleAnimation()}
> >
@ -99,6 +99,6 @@ const {
muted muted
playsinline playsinline
preload="none" preload="none"
class="mb-24 rounded-3xl shadow-md lg:mx-auto lg:w-3/4 dark:opacity-80" class="mb-24 rounded-3xl shadow-md dark:opacity-80"
/> />
</motion.span> </motion.span>

View file

@ -89,36 +89,36 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
return ( return (
<div className="mx-auto mb-12 flex items-center justify-center gap-4 px-8"> <div className="mx-auto mb-12 flex items-center justify-center gap-4 px-8">
<button <button
type="button"
onClick={() => navigatePage(page - 1)}
className={`px-3 py-2 ${page === 1 ? 'pointer-events-none text-gray-400' : 'text-dark hover:text-gray-600'}`} className={`px-3 py-2 ${page === 1 ? 'pointer-events-none text-gray-400' : 'text-dark hover:text-gray-600'}`}
onClick={() => navigatePage(page - 1)}
type="button"
> >
&lt; &lt;
</button> </button>
<form onSubmit={handlePageSubmit} className="flex items-center gap-2"> <form className="flex items-center gap-2" onSubmit={handlePageSubmit}>
{mods.pagination.pagination.split('{input}').map((value, index) => { {mods.pagination.pagination.split('{input}').map((value, index) => {
if (index === 0) { if (index === 0) {
return ( return (
<input <input
aria-label="Page number"
className="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
onInput={handlePageInputChange}
type="text" type="text"
value={pageInput} value={pageInput}
onInput={handlePageInputChange}
className="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
aria-label="Page number"
/> />
) )
} }
return ( return (
<span key={value} className="text-sm"> <span className="text-sm" key={value}>
{value.replace('{totalPages}', totalPages.toString()).replace('{totalItems}', totalItems.toString())} {value.replace('{totalPages}', totalPages.toString()).replace('{totalItems}', totalItems.toString())}
</span> </span>
) )
})} })}
</form> </form>
<button <button
type="button"
onClick={() => navigatePage(page + 1)}
className={`px-3 py-2 ${page === totalPages ? 'pointer-events-none text-gray-400' : 'text-dark hover:text-gray-600'}`} className={`px-3 py-2 ${page === totalPages ? 'pointer-events-none text-gray-400' : 'text-dark hover:text-gray-600'}`}
onClick={() => navigatePage(page + 1)}
type="button"
> >
&gt; &gt;
</button> </button>
@ -128,24 +128,24 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
return ( return (
<div> <div>
<div className="mx-auto flex flex-col items-start gap-4 px-8 lg:w-1/2"> <div className="flex flex-col items-center gap-4">
<div className="flex w-full flex-col items-center gap-6"> <div className="flex w-full flex-col items-center justify-center gap-6">
<input <input
type="text"
id="search"
className="w-full rounded-full border-2 border-dark bg-transparent px-6 py-2 text-lg outline-none" className="w-full rounded-full border-2 border-dark bg-transparent px-6 py-2 text-lg outline-none"
placeholder={mods.search} id="search"
value={search}
onInput={handleSearch} onInput={handleSearch}
placeholder={mods.search}
type="text"
value={search}
/> />
</div> </div>
<div className="grid w-full grid-cols-2 place-items-center gap-4 sm:grid-cols-3"> <div className="grid w-full grid-cols-2 place-items-center gap-4 sm:grid-cols-3">
<div className="flex flex-col items-start gap-2"> <div className="flex flex-col items-start gap-2">
<button <button
type="button"
onClick={toggleCreatedSort}
className="flex items-center gap-2 px-4 py-2 font-semibold text-md" className="flex items-center gap-2 px-4 py-2 font-semibold text-md"
onClick={toggleCreatedSort}
type="button"
> >
{mods.sort.lastCreated} {mods.sort.lastCreated}
<span <span
@ -159,9 +159,9 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<button <button
type="button"
onClick={toggleUpdatedSort}
className="flex items-center gap-2 px-4 py-2 font-semibold text-md" className="flex items-center gap-2 px-4 py-2 font-semibold text-md"
onClick={toggleUpdatedSort}
type="button"
> >
{mods.sort.lastUpdated} {mods.sort.lastUpdated}
<span <span
@ -174,14 +174,14 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
</div> </div>
<div className="flex items-center gap-2 px-4 py-2"> <div className="flex items-center gap-2 px-4 py-2">
<label htmlFor="limit" className="font-semibold text-md"> <label className="font-semibold text-md" htmlFor="limit">
{mods.sort.perPage} {mods.sort.perPage}
</label> </label>
<select <select
id="limit"
value={limit}
onInput={handleLimitChange}
className="rounded border border-dark bg-transparent px-2 py-1 text-sm [&>option]:text-black" className="rounded border border-dark bg-transparent px-2 py-1 text-sm [&>option]:text-black"
id="limit"
onInput={handleLimitChange}
value={limit}
> >
<option value="12">12</option> <option value="12">12</option>
<option value="24">24</option> <option value="24">24</option>
@ -192,20 +192,20 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
</div> </div>
</div> </div>
<div className="mx-auto grid grid-cols-1 place-items-start gap-12 p-10 md:grid-cols-2 lg:grid-cols-3 lg:p-24 lg:px-24 2xl:grid-cols-4"> <div className="grid w-full grid-cols-1 place-items-start gap-12 py-6 md:grid-cols-2 xl:grid-cols-3">
{paginatedMods.length > 0 ? ( {paginatedMods.length > 0 ? (
paginatedMods.map((mod) => ( paginatedMods.map((mod) => (
<a <a
key={mod.id} className="flex w-full flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90"
href={`/mods/${mod.id}`} href={`/mods/${mod.id}`}
className="flex flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90" key={mod.id}
> >
<div className="relative mb-0 block aspect-[1.85/1] h-48 overflow-hidden rounded-md border-2 border-dark object-cover shadow-md"> <div className="relative mb-0 block aspect-[1.85/1] h-48 overflow-hidden rounded-md border-2 border-dark object-cover shadow-md">
<img <img
src={mod.image}
alt={mod.name} alt={mod.name}
loading="lazy"
className="h-full w-full object-cover transition-transform duration-100 hover:scale-105" className="h-full w-full object-cover transition-transform duration-100 hover:scale-105"
loading="lazy"
src={mod.image}
/> />
</div> </div>
<div> <div>

View file

@ -1,8 +1,11 @@
--- ---
import { Astronav, Dropdown, DropdownItems, MenuItems } from 'astro-navbar' import { Astronav, Dropdown, DropdownItems, MenuItems } from 'astro-navbar'
import { ArrowRight, ChevronDown, Download, Menu } from 'lucide-astro'
import { motion } from 'motion/react' import { motion } from 'motion/react'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import ChevronDownIcon from '~/icons/ChevronDownIcon.astro'
import DownloadIcon from '~/icons/DownloadIcon.astro'
import MenuIcon from '~/icons/MenuIcon.astro'
import { getLocale, getPath, getUI } from '~/utils/i18n' import { getLocale, getPath, getUI } from '~/utils/i18n'
import { getTitleAnimation } from '../animations.ts' import { getTitleAnimation } from '../animations.ts'
import Logo from './Logo.astro' import Logo from './Logo.astro'
@ -21,7 +24,7 @@ const {
<!-- Desktop Navigation --> <!-- Desktop Navigation -->
<Astronav> <Astronav>
<MenuItems <MenuItems
class="relative z-20 mx-auto grid w-full grid-cols-2 items-center gap-2 bg-paper px-4 py-3 lg:grid lg:min-w-fit lg:grid-cols-[auto_1fr_auto] lg:p-6 xl:w-3/4" class="container relative z-20 grid w-full grid-cols-2 items-center gap-2 bg-paper py-3 lg:grid lg:grid-cols-[auto_1fr_auto] lg:py-6"
> >
<a <a
class="flex items-center gap-2 text-lg font-bold" class="flex items-center gap-2 text-lg font-bold"
@ -36,7 +39,7 @@ const {
<Dropdown class="group"> <Dropdown class="group">
<button class="flex items-center"> <button class="flex items-center">
<span>{menu.gettingStarted}</span> <span>{menu.gettingStarted}</span>
<ChevronDown <ChevronDownIcon
class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2" class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2"
/> />
</button> </button>
@ -56,7 +59,7 @@ const {
</div> </div>
<Button isPrimary class="mt-auto"> <Button isPrimary class="mt-auto">
{menu.tryZenMods} {menu.tryZenMods}
<ArrowRight class="size-4" /> <ArrowRightIcon class="size-4" />
</Button> </Button>
</a> </a>
<a class="dropdown-item" href={getLocalePath('/release-notes')}> <a class="dropdown-item" href={getLocalePath('/release-notes')}>
@ -77,7 +80,7 @@ const {
<Dropdown class="group"> <Dropdown class="group">
<button class="flex items-center"> <button class="flex items-center">
<span>{menu.usefulLinks}</span> <span>{menu.usefulLinks}</span>
<ChevronDown <ChevronDownIcon
class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2" class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2"
/> />
</button> </button>
@ -129,10 +132,10 @@ const {
<Button href="/download" class="hidden lg:flex" isPrimary> <Button href="/download" class="hidden lg:flex" isPrimary>
<span class="hidden items-center gap-2 lg:flex"> <span class="hidden items-center gap-2 lg:flex">
{menu.download} {menu.download}
<ArrowRight class="size-4" /> <ArrowRightIcon class="size-4" />
</span> </span>
<span class="flex items-center gap-2 lg:hidden"> <span class="flex items-center gap-2 lg:hidden">
<Download class="size-4" /> <DownloadIcon class="size-4" />
</span> </span>
</Button> </Button>
<label <label
@ -140,7 +143,7 @@ const {
class="cursor-pointer p-2 text-dark lg:hidden" class="cursor-pointer p-2 text-dark lg:hidden"
aria-label="Open menu" aria-label="Open menu"
> >
<Menu class="h-6 w-6" /> <MenuIcon class="h-6 w-6" />
</label> </label>
</div> </div>
</MenuItems> </MenuItems>

View file

@ -1,6 +1,6 @@
--- ---
import { Accordion, AccordionItem } from 'free-astro-components' import { Accordion, AccordionItem } from 'free-astro-components'
import { Info } from 'lucide-astro' import InfoIcon from '~/icons/InfoIcon.astro'
import { releaseNotes as releaseNotesData } from '~/release-notes' import { releaseNotes as releaseNotesData } from '~/release-notes'
import { getLocale, getPath, getUI } from '~/utils/i18n' import { getLocale, getPath, getUI } from '~/utils/i18n'
@ -112,7 +112,7 @@ if (prevReleaseNote && !isTwilight) {
} }
</div> </div>
<div class="text-muted-forground mt-6 flex text-sm opacity-70"> <div class="text-muted-forground mt-6 flex text-sm opacity-70">
{isTwilight ? <Info class="mx-4 my-0 size-6 text-yellow-500" /> : null} {isTwilight ? <InfoIcon class="mx-4 my-0 size-6 text-yellow-500" /> : null}
<p class="m-0"> <p class="m-0">
{isTwilight ? <>{releaseNoteItem.twilightWarning}</> : null} {isTwilight ? <>{releaseNoteItem.twilightWarning}</> : null}
<span set:html={releaseNoteItem.reportIssues} /> <span set:html={releaseNoteItem.reportIssues} />

View file

@ -18,12 +18,10 @@ const {
} = getUI(locale) } = getUI(locale)
--- ---
<section id="sponsors" class:list={['mb-32 px-4', !showSponsors && 'hidden']}> <section id="sponsors" class:list={['py-12', !showSponsors && 'hidden']}>
<div class="mx-auto flex flex-col px-6 text-center"> <div class="mx-auto flex flex-col text-center">
<motion.span client:load {...getTitleAnimation(0.2)}> <motion.span client:load {...getTitleAnimation(0.2)}>
<Description class="mb-2 px-4 text-6xl font-bold" <Description class="mb-2 text-6xl font-bold">Our Sponsors</Description>
>Our Sponsors</Description
>
</motion.span> </motion.span>
<motion.span client:load {...getTitleAnimation(0.4)}> <motion.span client:load {...getTitleAnimation(0.4)}>
<Description set:html={sponsors.description} /> <Description set:html={sponsors.description} />

View file

@ -2,18 +2,6 @@
const { class: className } = Astro.props const { class: className } = Astro.props
--- ---
<h1 class:list={['title text-dark', className]}> <h1 class:list={['text-dark leading-[0.9] mb-[0.4rem] font-junicode font-semibold text-5xl xl:text-6xl', className]}>
<slot /> <slot />
</h1> </h1>
<style>
.title {
line-height: 0.9;
margin-bottom: 0.4rem;
font-family: 'Junicode', serif;
font-weight: 600;
font-style: normal;
font-feature-settings: 'swsh' 1;
@apply text-5xl xl:text-6xl;
}
</style>

View file

@ -85,12 +85,22 @@ import DownloadCard from './ButtonCard.astro'
checksum={releases.universal.checksum} checksum={releases.universal.checksum}
/> />
)} )}
{releases.x86_64 && 'tarball' in releases.x86_64 && releases.x86_64.tarball && releases.x86_64.tarball.label && ( {releases.x86_64 && (
<DownloadCard 'tarball' in releases.x86_64
label={releases.x86_64.tarball.label} ? releases.x86_64.tarball.label && (
href={releases.x86_64.tarball.link} <DownloadCard
checksum={releases.x86_64.tarball.checksum} label={releases.x86_64.tarball.label}
/> href={releases.x86_64.tarball.link}
checksum={releases.x86_64.tarball.checksum}
/>
)
: releases.x86_64.label && (
<DownloadCard
label={releases.x86_64.label}
href={releases.x86_64.link}
checksum={releases.x86_64.checksum}
/>
)
)} )}
{releases.arm64 && releases.arm64.label && ( {releases.arm64 && releases.arm64.label && (
<DownloadCard <DownloadCard

View file

@ -144,86 +144,107 @@
} }
}, },
"about": { "about": {
"title": "About - Zen Browser", "title": "About Zen",
"description": "We are simply a group of developers and designers who care about your experience on the web. We believe that the internet should be a place where you can explore, learn, and connect without worrying about your data being collected.", "description": "We are simply a group of developers and designers who care about your experience on the web. We believe that the internet should be a place where you can explore, learn, and connect without worrying about your data being collected.",
"littleHelp": "A little help?", "littleHelp": "A little help?",
"mainTeam": { "mainTeam": {
"title": "Main Team", "title": "Main Team",
"description": "This list shows the main team members who are working hard to bring you the best browsing experience.", "description": "This list shows the main team members who are working hard to bring you the best browsing experience.",
"subTitle": {
"browser": "Browser",
"website": "Website and Branding"
},
"members": { "members": {
"mauro": { "browser": {
"name": "Mauro B.", "mauro": {
"description": "Creator, Main Developer", "name": "Mauro B.",
"link": "https://cheff.dev/" "description": "Creator, Main Developer",
"link": "https://cheff.dev/"
},
"jan": {
"name": "Jan Heres",
"description": "Active contributor and helps with MacOS builds",
"link": "https://janheres.eu/"
},
"bryan": {
"name": "Bryan Galdámez",
"description": "Huge contributor on theme functionalities",
"link": "https://josuegalre.netlify.app/"
},
"oscar": {
"name": "Oscar Gonzalez",
"description": "Site Reliability Engineer (SRE) and code signing.",
"link": false
},
"daniel": {
"name": "Daniel García",
"description": "MacOS certificate and app notarization maintainer",
"link": false
},
"brhm": {
"name": "BrhmDev",
"description": "Active contributor with great contributions",
"link": "https://github.com/BrhmDev"
},
"kristijanribaric": {
"name": "Kristijan Ribaric",
"description": "Active contributor",
"link": "https://github.com/kristijanribaric"
},
"larvey": {
"name": "Larvey",
"description": "AUR maintainer",
"link": "https://github.com/LarveyOfficial/"
}
}, },
"oscar": { "website": {
"name": "Oscar Gonzalez", "taroj1205": {
"description": "Site Reliability Engineer (SRE) and code signing.", "name": "Shintaro Jokagi",
"link": false "description": "Core Website Architect, Spearheading Refactoring and Technical Enhancements",
}, "link": "https://github.com/taroj1205"
"jan": { },
"name": "Jan Heres", "jace": {
"description": "Active contributor and helps with MacOS builds", "name": "Jace",
"link": "https://janheres.eu/" "description": "Contributes to website design and branding",
}, "link": "https://x.com/JaceThings"
"brhm": { },
"name": "BrhmDev", "canoa": {
"description": "Active contributor with great contributions", "name": "Canoa",
"link": "https://github.com/BrhmDev" "description": "Active contributor, and very active in issue handling and website management",
}, "link": "https://thatcanoa.org/"
"canoa": { },
"name": "Canoa", "adam": {
"description": "Active contributor, and very active in issue handling and website management", "name": "Adam",
"link": "https://thatcanoa.org/" "description": "Branding and design",
}, "link": "https://cybrneon.xyz/"
"adam": { },
"name": "Adam", "n7itro": {
"description": "Branding and design", "name": "n7itro",
"link": "https://cybrneon.xyz/" "description": "Active contributor and release notes writer",
}, "link": "https://github.com/n7itro"
"kristijanribaric": { },
"name": "Kristijan Ribaric", "jafeth": {
"description": "Active contributor", "name": "Jafeth Garro",
"link": "https://github.com/kristijanribaric" "description": "Documentation writer",
}, "link": "https://iamjafeth.com/"
"n7itro": { }
"name": "n7itro",
"description": "Active contributor and release notes writer",
"link": "https://github.com/n7itro"
},
"bryan": {
"name": "Bryan Galdámez",
"description": "Huge contributor on theme functionalities",
"link": "https://josuegalre.netlify.app/"
},
"jafeth": {
"name": "Jafeth Garro",
"description": "Documentation writer",
"link": "https://iamjafeth.com/"
},
"larvey": {
"name": "Larvey",
"description": "AUR maintainer",
"link": "https://github.com/LarveyOfficial/"
},
"daniel": {
"name": "Daniel García",
"description": "MacOS certificate and app notarization maintainer",
"link": false
} }
} }
}, },
"contributors": { "contributors": {
"title": "Contributors", "title": "Contributors",
"description": "This list shows the contributors who have helped us to make Zen Browser the best it can be." "description": "This list shows the contributors who have helped us to make Zen Browser the best it can be.",
"browser": "Browser",
"website": "Website"
} }
}, },
"donate": { "donate": {
"title": "Donate - Zen Browser", "title": "Donate",
"description": "We are a small team of developers working hard to bring you the best browsing experience. If you like what we do, please consider supporting us.", "description": "We are a small team of developers working hard to bring you the best browsing experience. If you like what we do, please consider supporting us.",
"patreon": { "patreon": {
"title": "Patreon", "title": "Patreon",
"description": "Patreon allows you to support us with a monthly donation. You can choose the level of support that works best for you." "description": "Patreon allows you to support us with a monthly donation. You can choose the level of support that works best for you.",
"button": "Go to Patreon"
}, },
"koFi": { "koFi": {
"title": "Ko-fi", "title": "Ko-fi",
@ -395,7 +416,7 @@
"description": "Stay up to date with the latest changes to Zen Browser! Since the first release till {latestVersion}, we've been working hard to make Zen Browser the best it can be. Thanks everyone for your feedback! ❤️" "description": "Stay up to date with the latest changes to Zen Browser! Since the first release till {latestVersion}, we've been working hard to make Zen Browser the best it can be. Thanks everyone for your feedback! ❤️"
}, },
"about": { "about": {
"title": "About - Zen", "title": "About Zen",
"description": "We are simply a group of developers and designers who care about your experience on the web. We believe that the internet should be a place where you can explore, learn, and connect without worrying about your data being collected." "description": "We are simply a group of developers and designers who care about your experience on the web. We believe that the internet should be a place where you can explore, learn, and connect without worrying about your data being collected."
}, },
"donate": { "donate": {

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-arrow-left-icon lucide-arrow-left", className]} {...props}><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-arrow-right-icon lucide-arrow-right", className]} {...props}><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>

5
src/icons/ArrowUp.astro Normal file
View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-arrow-up-icon lucide-arrow-up", className]} {...props}><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-check-icon lucide-check", className]} {...props}><path d="M20 6 9 17l-5-5"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-chevron-down-icon lucide-chevron-down", className]} {...props}><path d="m6 9 6 6 6-6"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-download-icon lucide-download", className]} {...props}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-external-link-icon lucide-external-link", className]} {...props}><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>

View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-github-icon lucide-github", className]} {...props}><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg>

5
src/icons/InfoIcon.astro Normal file
View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-info-icon lucide-info", className]} {...props}><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>

5
src/icons/LockIcon.astro Normal file
View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-lock-icon lucide-lock", className]} {...props}><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>

5
src/icons/MenuIcon.astro Normal file
View file

@ -0,0 +1,5 @@
---
const { class: className, ...props } = Astro.props
---
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class:list={["lucide lucide-menu-icon lucide-menu", className]} {...props}><path d="M4 12h16"/><path d="M4 18h16"/><path d="M4 6h16"/></svg>

View file

@ -89,7 +89,7 @@ const locale = getLocale(Astro)
<script> <script>
console.log( console.log(
'%c✌ Zen-Browser%c\nWelcome to a calmer internet!%c', '%c✌ Zen-Browser%c\nWelcome to a calmer internet!',
'filter: invert(1); font-size: 28px; font-weight: bolder; font-family: "Rubik"; margin-top: 20px; margin-bottom: 8px;', 'filter: invert(1); font-size: 28px; font-weight: bolder; font-family: "Rubik"; margin-top: 20px; margin-bottom: 8px;',
'color: #f76f53; font-size: 16px; font-family: "Rubik"; margin-bottom: 20px;' 'color: #f76f53; font-size: 16px; font-family: "Rubik"; margin-bottom: 20px;'
); );
@ -97,7 +97,7 @@ const locale = getLocale(Astro)
</head> </head>
<body <body
class="overflow-x-hidden bg-paper font-['bricolage-grotesque'] text-dark" class="overflow-x-hidden bg-paper font-['bricolage-grotesque'] text-dark text-balance"
> >
<NavBar /> <NavBar />
<slot /> <slot />

View file

@ -15,17 +15,19 @@ const {
<Layout title={notFound.title}> <Layout title={notFound.title}>
<main <main
class="flex min-h-[70vh] flex-col items-center justify-center py-24 text-center" class="container flex min-h-[70vh] flex-col items-center justify-center gap-6 py-24 text-center"
> >
<Title class="mb-4 text-7xl font-bold text-coral md:text-9xl">404</Title> <Title class="text-7xl font-bold text-coral md:text-9xl">404</Title>
<Description class="mb-6 text-xl md:text-2xl"> <div class="flex flex-col items-center gap-6">
{notFound.title} <Description class="text-xl md:text-2xl">
</Description> {notFound.title}
<p class="mb-8 max-w-xl text-lg text-gray-500 dark:text-gray-400"> </Description>
{notFound.description} <p class="max-w-xl text-lg text-gray-500 dark:text-gray-400">
</p> {notFound.description}
<Button href={getLocalePath('/')} isPrimary> </p>
{notFound.button} <Button href={getLocalePath('/')} isPrimary class="w-fit">
</Button> {notFound.button}
</Button>
</div>
</main> </main>
</Layout> </Layout>

View file

@ -1,9 +1,10 @@
--- ---
import Button from '~/components/Button.astro' import { Image } from 'astro:assets'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import Layout from '~/layouts/Layout.astro' import Layout from '~/layouts/Layout.astro'
import { getLocale, getUI } from '~/utils/i18n' import { getLocale, getUI } from '~/utils/i18n'
export { getStaticPaths } from '~/utils/i18n' export { getStaticPaths } from '~/utils/i18n'
import Button from '~/components/Button.astro'
const locale = getLocale(Astro) const locale = getLocale(Astro)
@ -18,65 +19,67 @@ const {
description={layout.about.description} description={layout.about.description}
> >
<main <main
class="relative flex min-h-screen flex-col items-center justify-center py-24" class="flex min-h-screen flex-col py-24 container w-full gap-24"
> >
<div class="mb-24 p-4 text-center lg:w-1/2"> <div class="w-full flex flex-col gap-6">
<Description class="text-6xl font-bold">{about.title}</Description> <Description class="text-6xl font-bold leading-none">{about.title}</Description>
<Description> <Description class="max-w-4xl">
{about.description} {about.description}
</Description> </Description>
<Button href="/donate" class="mx-auto mt-4 w-fit" isPrimary <Button href="/donate" class="w-fit" isPrimary
>{about.littleHelp}</Button >{about.littleHelp}</Button
> >
</div> </div>
<div <div class="flex flex-col gap-4 w-full">
class="relative flex w-full flex-col items-center justify-center lg:flex-row" <div class="text-4xl lg:text-5xl font-bold leading-none">{about.mainTeam.title}</div>
>
<div class="flex flex-col p-8 lg:w-1/3 lg:pr-24">
<div class="text-4xl font-bold lg:text-6xl">{about.mainTeam.title}</div>
<Description> <Description>
{about.mainTeam.description} {about.mainTeam.description}
</Description> </Description>
<div class="mt-4"> <div class="flex flex-col gap-6">
<ul> {Object.entries(about.mainTeam.members).map(([team, members]) => (
{Object.entries(about.mainTeam.members).map(([_key, member]) => ( <div class="flex flex-col gap-2">
<li class="text-sm"> <div class="text-3xl font-semibold">{about.mainTeam.subTitle[team as keyof typeof about.mainTeam.subTitle]}</div>
{member.link ? ( <ul class="flex flex-col gap-2">
<a href={member.link === true ? '' : member.link}> {Object.entries(members).map(([_key, member]) => (
<strong class="zen-link font-bold">{member.name}</strong> <li class="text-sm">
</a> {member.link && typeof member.link === 'string' ? (
<span class="opacity-60"> : {member.description}</span> <a href={member.link}>
) : ( <strong class="zen-link font-bold">{member.name}</strong>
<strong class="font-bold">{member.name}</strong> </a>
<span class="opacity-60"> : {member.description}</span> ) : (
)} <strong class="font-bold">{member.name}</strong>
</li> )}
))} <span class="opacity-80">: {member.description}</span>
</ul> </li>
))}
</ul>
</div>
))}
</div> </div>
</div> </div>
<div class="absolute hidden h-full w-[1px] bg-dark opacity-15 lg:block"> <div class="flex flex-col gap-4 w-full">
</div> <div class="text-4xl lg:text-5xl font-bold leading-none">{about.contributors.title}</div>
<div class="flex flex-col p-8 lg:w-1/3 lg:pl-24">
<div class="text-4xl font-bold lg:text-6xl">{about.contributors.title}</div>
<Description> <Description>
{about.contributors.description} {about.contributors.description}
</Description> </Description>
<a href="https://github.com/zen-browser/desktop/graphs/contributors" <div class="flex flex-col gap-4 w-fit"><Description class="text-3xl font-semibold lg:text-4xl">{about.contributors.browser}</Description>
><img <a href="https://github.com/zen-browser/desktop/graphs/contributors"
><Image
src="https://contributors-img.web.app/image?repo=zen-browser/desktop" src="https://contributors-img.web.app/image?repo=zen-browser/desktop"
alt="Contributors" alt="Contributors"
class="mt-8" width={500}
height={500}
/></a /></a
> ></div>
<div class="flex flex-col gap-4 w-fit"><Description class="text-3xl font-semibold lg:text-4xl">{about.contributors.website}</Description>
<a href="https://github.com/zen-browser/www/graphs/contributors" <a href="https://github.com/zen-browser/www/graphs/contributors"
><img ><Image
src="https://contributors-img.web.app/image?repo=zen-browser/www" src="https://contributors-img.web.app/image?repo=zen-browser/www"
alt="Contributors (website)" alt="Contributors (website)"
class="mt-8" width={500}
height={500}
/></a /></a
> ></div></div>
</div>
</div>
</main> </main>
</Layout> </Layout>

View file

@ -1,7 +1,7 @@
--- ---
import { ArrowRight } from 'lucide-astro'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import Layout from '~/layouts/Layout.astro' import Layout from '~/layouts/Layout.astro'
import { getLocale, getUI } from '~/utils/i18n' import { getLocale, getUI } from '~/utils/i18n'
export { getStaticPaths } from '~/utils/i18n' export { getStaticPaths } from '~/utils/i18n'
@ -14,51 +14,41 @@ const {
--- ---
<Layout title={layout.donate.title} description={layout.donate.description}> <Layout title={layout.donate.title} description={layout.donate.description}>
<main class="pb-52 pt-36"> <main class="container pb-52 pt-24 flex flex-col items-center gap-12">
<div <div class="flex flex-col gap-4 lg:text-center">
class="relative flex w-full flex-col items-center justify-center gap-12"
>
<div class="px-8 lg:w-2/5 lg:text-center xl:px-0">
<Description class="text-6xl font-bold">{donate.title}</Description> <Description class="text-6xl font-bold">{donate.title}</Description>
<Description> <Description class="max-w-3xl">
{donate.description} {donate.description}
</Description> </Description>
</div> </div>
<div class="flex w-full flex-col items-center justify-center lg:flex-row"> <div
<div class="flex flex-col p-8 lg:w-1/3 lg:pr-24"> class="grid max-w-5xl grid-cols-1 gap-12 text-center lg:grid-cols-[1fr_1px_1fr]"
>
<div class="flex flex-col items-center gap-4">
<div class="text-6xl font-bold">{donate.patreon.title}</div> <div class="text-6xl font-bold">{donate.patreon.title}</div>
<Description> <Description>
{donate.patreon.description} {donate.patreon.description}
</Description> </Description>
<div class="mt-6"> <Button
<Button isPrimary
isPrimary href="https://www.patreon.com/zen_browser"
href="https://www.patreon.com/zen_browser" class="w-fit"
class="w-fit" >
> {donate.patreon.button}
Go to Patreon <ArrowRightIcon class="size-4" />
<ArrowRight class="size-4" /> </Button>
</Button>
</div>
</div> </div>
<div class="hidden h-72 w-[1px] bg-dark opacity-15 lg:block"></div> <hr class="hidden h-72 w-[1px] bg-dark opacity-15 lg:block" />
<div class="flex flex-col p-8 lg:w-1/3 lg:pl-24"> <div class="flex flex-col items-center gap-4">
<div class="text-6xl font-bold">{donate.koFi.title}</div> <div class="text-6xl font-bold">{donate.koFi.title}</div>
<Description> <Description>
{donate.koFi.description} {donate.koFi.description}
</Description> </Description>
<div class="mt-6"> <Button href="https://ko-fi.com/zen_browser" isPrimary class="w-fit">
<Button {donate.koFi.button}
href="https://ko-fi.com/zen_browser" <ArrowRightIcon class="size-4" />
isPrimary </Button>
class="w-fit"
>
{donate.koFi.button}
<ArrowRight class="size-4" />
</Button>
</div>
</div> </div>
</div> </div>
</div>
</main> </main>
</Layout> </Layout>

View file

@ -9,7 +9,8 @@ import { getLocale, getUI } from '~/utils/i18n'
import { icon, library } from '@fortawesome/fontawesome-svg-core' import { icon, library } from '@fortawesome/fontawesome-svg-core'
import { faApple, faGithub, faLinux, faWindows } from '@fortawesome/free-brands-svg-icons' import { faApple, faGithub, faLinux, faWindows } from '@fortawesome/free-brands-svg-icons'
import { ExternalLink, Lock } from 'lucide-astro' import ExternalLinkIcon from '~/icons/ExternalLink.astro'
import LockIcon from '~/icons/LockIcon.astro'
export { getStaticPaths } from '~/utils/i18n' export { getStaticPaths } from '~/utils/i18n'
@ -36,7 +37,7 @@ const platformDescriptions = download.platformDescriptions
<Layout title={layout.download.title} description={layout.download.description}> <Layout title={layout.download.title} description={layout.download.description}>
<main class="flex min-h-screen flex-col px-6 data-[os='windows']:bg-zen-blue"> <main class="flex min-h-screen flex-col px-6 data-[os='windows']:bg-zen-blue">
<div class="container relative mx-auto max-w-5xl py-12"> <div class="container relative mx-auto py-12">
<div class="mb-6 mt-12 flex flex-col gap-4"> <div class="mb-6 mt-12 flex flex-col gap-4">
<Description id="download-title" class="text-6xl font-bold" <Description id="download-title" class="text-6xl font-bold"
>{download.title}</Description >{download.title}</Description
@ -180,7 +181,7 @@ const platformDescriptions = download.platformDescriptions
<div <div
class="rounded-xl border border-subtle p-3 transition-all duration-100 hover:bg-coral hover:bg-opacity-10 group-hover:border-coral group-hover:border-opacity-20" class="rounded-xl border border-subtle p-3 transition-all duration-100 hover:bg-coral hover:bg-opacity-10 group-hover:border-coral group-hover:border-opacity-20"
> >
<ExternalLink <ExternalLinkIcon
class="h-5 w-5 transition-all duration-200 group-hover:text-coral" class="h-5 w-5 transition-all duration-200 group-hover:text-coral"
/> />
</div> </div>
@ -194,7 +195,7 @@ const platformDescriptions = download.platformDescriptions
class="bg-opaicty-10 grid grid-cols-[auto,1fr] gap-4 rounded-2xl bg-subtle p-6" class="bg-opaicty-10 grid grid-cols-[auto,1fr] gap-4 rounded-2xl bg-subtle p-6"
> >
<div class="h-fit rounded-xl bg-subtle p-3"> <div class="h-fit rounded-xl bg-subtle p-3">
<Lock class="h-5 w-5" /> <LockIcon class="h-5 w-5" />
</div> </div>
<div> <div>

View file

@ -17,7 +17,7 @@ const { layout } = getUI(locale)
description={layout.index.description} description={layout.index.description}
isHome isHome
> >
<main> <main class="container">
<Hero /> <Hero />
<Features /> <Features />
<Sponsors showSponsors /> <Sponsors showSponsors />

View file

@ -1,8 +1,9 @@
--- ---
import { ArrowRight, Info } from 'lucide-astro'
import BackButton from '~/components/BackButton.astro' import BackButton from '~/components/BackButton.astro'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import InfoIcon from '~/icons/InfoIcon.astro'
import Layout from '~/layouts/Layout.astro' import Layout from '~/layouts/Layout.astro'
import { getAllMods, getAuthorLink, getLocalizedDate } from '~/mods' import { getAllMods, getAuthorLink, getLocalizedDate } from '~/mods'
import { getUI } from '~/utils/i18n' import { getUI } from '~/utils/i18n'
@ -64,7 +65,7 @@ const {
class="flex flex-col items-center justify-center gap-2 rounded-xl bg-red-200 p-2 px-4 md:flex-row md:justify-between dark:bg-red-700" class="flex flex-col items-center justify-center gap-2 rounded-xl bg-red-200 p-2 px-4 md:flex-row md:justify-between dark:bg-red-700"
> >
<div class="flex items-center gap-2 text-center md:text-left"> <div class="flex items-center gap-2 text-center md:text-left">
<Info /> <InfoIcon />
<p class="text-sm"> <p class="text-sm">
{slug.alert.description} {slug.alert.description}
</p> </p>
@ -75,7 +76,7 @@ const {
isAlert isAlert
> >
{slug.alert.button} {slug.alert.button}
<ArrowRight class="size-4" /> <ArrowRightIcon class="size-4" />
</Button> </Button>
</div> </div>
<BackButton /> <BackButton />

View file

@ -18,16 +18,12 @@ const allMods = (await getAllMods()) || []
--- ---
<Layout title={layout.mods.title}> <Layout title={layout.mods.title}>
<main class="mx-auto mt-32 max-w-[120rem] 2xl:mt-0"> <main class="container mt-32 flex flex-col gap-10 2xl:mt-32">
<header class="mb-10 mt-32 flex w-full flex-col justify-center border-dark"> <header class="flex w-full flex-col gap-8 border-dark">
<div class="mx-auto flex flex-col gap-6 px-8 lg:w-1/2"> <Description class="text-6xl font-bold">{mods.title}</Description>
<div> <Description class="max-w-3xl">
<Description class="text-6xl font-bold">{mods.title}</Description> {mods.description}
<Description> </Description>
{mods.description}
</Description>
</div>
</div>
</header> </header>
<!-- Importing ModList component --> <!-- Importing ModList component -->

View file

@ -1,9 +1,9 @@
--- ---
import { Modal, ModalBody, ModalHeader } from 'free-astro-components' import { Modal, ModalBody, ModalHeader } from 'free-astro-components'
import { ArrowUp } from 'lucide-astro'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import ReleaseNoteItem from '~/components/ReleaseNoteItem.astro' import ReleaseNoteItem from '~/components/ReleaseNoteItem.astro'
import ArrowUpIcon from '~/icons/ArrowUp.astro'
import Layout from '~/layouts/Layout.astro' import Layout from '~/layouts/Layout.astro'
import { releaseNotes as releaseNotesData, releaseNotesTwilight } from '~/release-notes' import { releaseNotes as releaseNotesData, releaseNotesTwilight } from '~/release-notes'
import { getLocale, getUI } from '~/utils/i18n' import { getLocale, getUI } from '~/utils/i18n'
@ -19,11 +19,11 @@ const {
<Layout title={layout.releaseNotes.title}> <Layout title={layout.releaseNotes.title}>
<main <main
class="flex h-full min-h-[1000px] flex-1 flex-col items-center justify-center py-4" class="container flex h-full min-h-[1000px] flex-1 flex-col items-center justify-center py-4"
> >
<div <div
id="release-notes" id="release-notes"
class="py-42 flex min-h-screen flex-col justify-center px-10 lg:px-10 xl:px-10 2xl:w-3/5" class="py-42 flex min-h-screen w-full flex-col justify-center"
> >
<Description class="mt-48 text-4xl font-bold">Release Notes</Description> <Description class="mt-48 text-4xl font-bold">Release Notes</Description>
<p <p
@ -58,9 +58,9 @@ const {
<Button href="#" id="scroll-top" isPrimary class="fixed bottom-8 right-8"> <Button href="#" id="scroll-top" isPrimary class="fixed bottom-8 right-8">
<p class="hidden items-center gap-2 sm:flex"> <p class="hidden items-center gap-2 sm:flex">
{releaseNotes.backToTop} {releaseNotes.backToTop}
<ArrowUp aria-hidden="true" class="size-4" /> <ArrowUpIcon aria-hidden="true" class="size-4" />
</p> </p>
<ArrowUp aria-label="Back to the top" class="size-4 sm:hidden" /> <ArrowUpIcon aria-label="Back to the top" class="size-4 sm:hidden" />
</Button> </Button>
</Layout> </Layout>
<Modal id="version-modal" class="m-auto border border-[--zen-dark] !bg-paper"> <Modal id="version-modal" class="m-auto border border-[--zen-dark] !bg-paper">

View file

@ -13,9 +13,7 @@ const {
--- ---
<Layout title={layout.welcome.title} description={layout.welcome.description}> <Layout title={layout.welcome.title} description={layout.welcome.description}>
<main <main class="container">
class="relative mx-auto flex flex-col items-center gap-24 px-6 lg:gap-0 lg:px-24"
>
<Features <Features
title1={welcome.title[0]} title1={welcome.title[0]}
title2={welcome.title[1]} title2={welcome.title[1]}

View file

@ -1,8 +1,8 @@
--- ---
import { ArrowRight } from 'lucide-astro'
import Button from '~/components/Button.astro' import Button from '~/components/Button.astro'
import Description from '~/components/Description.astro' import Description from '~/components/Description.astro'
import SocialMediaStrip from '~/components/SocialMediaStrip.astro' import SocialMediaStrip from '~/components/SocialMediaStrip.astro'
import ArrowRightIcon from '~/icons/ArrowRightIcon.astro'
import Layout from '~/layouts/Layout.astro' import Layout from '~/layouts/Layout.astro'
import whatsNewVideo from '~/assets/whats-new.mp4' import whatsNewVideo from '~/assets/whats-new.mp4'
@ -34,7 +34,7 @@ if (latestVersion.version.split('.').length > 2 && whatsNewText[1] !== latestVer
)} )}
> >
<main <main
class="relative mx-auto flex flex-col items-center gap-24 px-6 pb-52 pt-36 lg:px-24 xl:flex-row" class="xl:mt-22 container flex flex-col gap-12 py-12 xl:grid xl:min-h-[calc(100vh-12rem)] xl:grid-cols-[2fr_3fr]"
> >
<div class="flex flex-col gap-8"> <div class="flex flex-col gap-8">
<div> <div>
@ -51,37 +51,38 @@ if (latestVersion.version.split('.').length > 2 && whatsNewText[1] !== latestVer
<div> <div>
<Fragment set:html={whatsNewText[0].replace(/\n/g, '<br>')} /> <Fragment set:html={whatsNewText[0].replace(/\n/g, '<br>')} />
</div> </div>
<ul class="hidden flex-col gap-2 md:flex"> <ul class="hidden list-disc flex-col gap-2 xl:container xl:flex">
<a <a
href="https://github.com/zen-browser/desktop/issues/new/choose" href="https://github.com/zen-browser/desktop/issues/new/choose"
target="_blank" target="_blank"
> >
<li class="ml-3 list-disc"> <li>
<Description class="text-base font-bold" <Description class="text-base font-bold">
>{whatsNew.reportIssue}</Description {whatsNew.reportIssue}
> </Description>
</li> </li>
</a> </a>
<a href="https://discord.gg/zen-browser" target="_blank"> <a href="https://discord.gg/zen-browser" target="_blank">
<li class="ml-3 list-disc"> <li>
<Description class="text-base font-bold" <Description class="text-base font-bold">
>{whatsNew.joinDiscord}</Description {whatsNew.joinDiscord}
> </Description>
</li> </li>
</a> </a>
</ul> </ul>
<div class="flex flex-col gap-8 md:flex-row"> <div class="flex flex-wrap gap-8 place-self-start xl:place-self-center">
<Button <Button
href={`/release-notes#${latestVersion.version}`} href={`/release-notes#${latestVersion.version}`}
isPrimary isPrimary
class="flex w-fit items-center gap-2" class="flex w-fit items-center gap-2"
> >
<span>{whatsNew.readFullReleaseNotes}</span> <span>{whatsNew.readFullReleaseNotes}</span>
<ArrowRight /> <ArrowRightIcon />
</Button> </Button>
<SocialMediaStrip gap="6" /> <SocialMediaStrip gap="6" />
</div> </div>
</div> </div>
<Video <Video
src={whatsNewVideo} src={whatsNewVideo}
autoplay autoplay
@ -89,7 +90,7 @@ if (latestVersion.version.split('.').length > 2 && whatsNewText[1] !== latestVer
muted muted
playsinline playsinline
preload="none" preload="none"
class="w-full rounded-3xl object-cover shadow-lg" class="rounded-3xl object-cover shadow-lg"
/> />
</main> </main>
</Layout> </Layout>

View file

@ -3,6 +3,32 @@ export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
darkMode: ['selector', '[data-theme="dark"]'], darkMode: ['selector', '[data-theme="dark"]'],
theme: { theme: {
container: {
screens: {
sm: '100%',
md: '100%',
lg: '1024px',
xl: '1280px',
},
padding: {
DEFAULT: '1rem',
sm: '1.5rem',
md: '1.5rem',
lg: '1.5rem',
xl: '2rem',
},
center: true,
},
fontFamily: {
junicode: [
'Junicode, serif',
{
fontFeatureSettings: {
swsh: 1,
},
},
],
},
extend: { extend: {
screens: { screens: {
'-sm': '@media (max-width: 639px)', '-sm': '@media (max-width: 639px)',