mirror of
https://github.com/zen-browser/www.git
synced 2025-07-07 17:05:32 +02:00
Merge pull request #595 from zen-browser/feat/i18n#541
feat(i18n): add i18n support and restructure pages for localization
This commit is contained in:
commit
1c56e00c6f
40 changed files with 1649 additions and 913 deletions
|
@ -1,6 +1,6 @@
|
|||
import tailwind from '@astrojs/tailwind'
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config'
|
||||
import tailwind from '@astrojs/tailwind'
|
||||
|
||||
import preact from '@astrojs/preact'
|
||||
|
||||
|
@ -8,6 +8,14 @@ import sitemap from '@astrojs/sitemap'
|
|||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [tailwind(), preact({ compat: true }), sitemap({})],
|
||||
integrations: [tailwind(), preact({ compat: true }), sitemap()],
|
||||
site: 'https://zen-browser.app',
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en'],
|
||||
routing: {
|
||||
fallbackType: 'rewrite',
|
||||
prefixDefaultLocale: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
---
|
||||
import { ArrowLeft } from 'lucide-astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
mods: { slug },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<button
|
||||
|
@ -7,5 +16,5 @@ import { ArrowLeft } from 'lucide-astro'
|
|||
class="mb-8 flex w-min items-center gap-2"
|
||||
>
|
||||
<ArrowLeft class="size-4" />
|
||||
Back
|
||||
{slug.back}
|
||||
</button>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
---
|
||||
import { getLocale, getPath } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
class: className,
|
||||
isPrimary,
|
||||
|
@ -15,7 +19,7 @@ const {
|
|||
<a
|
||||
id={id}
|
||||
{...extra}
|
||||
href={href}
|
||||
href={getLocalePath(href)}
|
||||
class:list={[
|
||||
'transition-bg flex items-center justify-center gap-2 rounded-xl px-6 py-4 transition-transform duration-150 hover:scale-[1.02] active:scale-[0.98]',
|
||||
className,
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
---
|
||||
import Description from '../components/Description.astro'
|
||||
import Button from '../components/Button.astro'
|
||||
import { motion } from 'motion/react'
|
||||
import { Github, Check } from 'lucide-astro'
|
||||
import { getTitleAnimation } from '../animations'
|
||||
import ComImage from '../assets/ComImage.png'
|
||||
import Image from 'astro/components/Image.astro'
|
||||
import { Check, Github } from 'lucide-astro'
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import ComImage from '~/assets/ComImage.png'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { community },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<section
|
||||
|
@ -13,20 +22,22 @@ import Image from 'astro/components/Image.astro'
|
|||
class="relative flex w-full flex-col items-center px-4 text-start md:px-0 md:text-center lg:pt-36"
|
||||
>
|
||||
<Description class="mb-2 px-4 text-6xl font-bold">
|
||||
<motion.span client:load {...getTitleAnimation(0.2)}> Our </motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.4)}> Core </motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.6)}> Values </motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.2)}>
|
||||
{community.title[0]}
|
||||
</motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.4)}>
|
||||
{community.title[1]}
|
||||
</motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.6)}>
|
||||
{community.title[2]}
|
||||
</motion.span>
|
||||
</Description>
|
||||
<motion.p
|
||||
client:load
|
||||
{...getTitleAnimation(0.6)}
|
||||
className="px-4 md:px-24 lg:w-1/2 lg:px-0"
|
||||
>
|
||||
We make it not only a priority, but a necessity to ensure that Zen always
|
||||
strikes the right balance between beauty, performance, and privacy. We are
|
||||
committed to making Zen the most beautiful, productive, and
|
||||
privacy-respecting browser out there — without compromising on your
|
||||
experience.
|
||||
{community.description}
|
||||
</motion.p>
|
||||
<div
|
||||
class="mt-6 flex w-full flex-wrap gap-3 px-4 sm:gap-10 sm:px-0 md:justify-center"
|
||||
|
@ -34,7 +45,7 @@ import Image from 'astro/components/Image.astro'
|
|||
<motion.span client:load {...getTitleAnimation(0.8)}>
|
||||
<Button class:list={['px-4']} href="https://github.com/zen-browser">
|
||||
<Github class="size-4" />
|
||||
<span>Free and open-source</span>
|
||||
<span>{community.lists.freeAndOpenSource.title}</span>
|
||||
</Button>
|
||||
</motion.span>
|
||||
<motion.div
|
||||
|
@ -43,7 +54,7 @@ import Image from 'astro/components/Image.astro'
|
|||
className="flex items-center gap-4"
|
||||
>
|
||||
<Check class="size-4" />
|
||||
<span>Simple yet powerful</span>
|
||||
<span>{community.lists.simpleYetPowerful.title}</span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
client:load
|
||||
|
@ -51,7 +62,7 @@ import Image from 'astro/components/Image.astro'
|
|||
className="flex items-center gap-4"
|
||||
>
|
||||
<Check class="size-4" />
|
||||
<span>Private and always up-to-date</span>
|
||||
<span>{community.lists.privateAndAlwaysUpToDate.title}</span>
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.span
|
||||
|
@ -61,7 +72,7 @@ import Image from 'astro/components/Image.astro'
|
|||
>
|
||||
<Image
|
||||
src={ComImage}
|
||||
alt="Community"
|
||||
alt={community.images.community.alt}
|
||||
class="my-24 rounded-3xl shadow-md lg:mx-auto lg:w-3/4 dark:opacity-80"
|
||||
/>
|
||||
</motion.span>
|
||||
|
|
|
@ -1,20 +1,33 @@
|
|||
---
|
||||
import Description from '../components/Description.astro'
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '../animations'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import Description from '~/components/Description.astro'
|
||||
|
||||
import WorkspacesVideo from '../assets/Workspaces.webm'
|
||||
import GlanceVideo from '../assets/Glance.webm'
|
||||
import CompactModeVideo from '../assets/CompactMode.webm'
|
||||
import SplitViewsVideo from '../assets/SplitViews.webm'
|
||||
import CompactModeVideo from '~/assets/CompactMode.webm'
|
||||
import GlanceVideo from '~/assets/Glance.webm'
|
||||
import SplitViewsVideo from '~/assets/SplitViews.webm'
|
||||
import WorkspacesVideo from '~/assets/Workspaces.webm'
|
||||
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
import Video from './Video.astro'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
title1 = 'Productivity',
|
||||
title2 = 'at',
|
||||
title3 = 'its best',
|
||||
routes: {
|
||||
index: { features },
|
||||
},
|
||||
} = getUI(locale)
|
||||
|
||||
const {
|
||||
title1 = features.title1,
|
||||
title2 = features.title2,
|
||||
title3 = features.title3,
|
||||
} = Astro.props
|
||||
|
||||
const descriptions = Object.values(features.featureTabs).map(
|
||||
(tab) => tab.description,
|
||||
)
|
||||
---
|
||||
|
||||
<section
|
||||
|
@ -33,9 +46,7 @@ const {
|
|||
</motion.span>
|
||||
</Description>
|
||||
<motion.p client:load {...getTitleAnimation(0.6)} className="lg:w-1/2">
|
||||
Zen Browser is packed with features that help you stay productive and
|
||||
focused. Browsers should be tools that help you get things done, not
|
||||
distractions that keep you from your work.
|
||||
{features.description}
|
||||
</motion.p>
|
||||
<div
|
||||
class="mb-12 mt-6 flex flex-col gap-6 lg:flex-row lg:justify-between lg:gap-2"
|
||||
|
@ -49,28 +60,28 @@ const {
|
|||
class="feature-tab whitespace-nowrap"
|
||||
data-active="true"
|
||||
>
|
||||
Workspaces
|
||||
{features.featureTabs.workspaces.title}
|
||||
</motion.button>
|
||||
<motion.button
|
||||
client:load
|
||||
{...getTitleAnimation(0.2)}
|
||||
class="feature-tab whitespace-nowrap"
|
||||
>
|
||||
Compact Mode
|
||||
{features.featureTabs.compactMode.title}
|
||||
</motion.button>
|
||||
<motion.button
|
||||
client:load
|
||||
{...getTitleAnimation(0.4)}
|
||||
class="feature-tab whitespace-nowrap"
|
||||
>
|
||||
Glance
|
||||
{features.featureTabs.glance.title}
|
||||
</motion.button>
|
||||
<motion.button
|
||||
client:load
|
||||
{...getTitleAnimation(0.6)}
|
||||
class="feature-tab whitespace-nowrap"
|
||||
>
|
||||
Split View
|
||||
{features.featureTabs.splitView.title}
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
|
@ -82,37 +93,45 @@ const {
|
|||
className="feature"
|
||||
data-active="true"
|
||||
>
|
||||
<Description class="text-2xl font-bold">Workspaces</Description>
|
||||
<Description class="text-2xl font-bold">
|
||||
{features.featureTabs.workspaces.title}
|
||||
</Description>
|
||||
<Description>
|
||||
Organize your tabs into Workspaces to keep your projects separate
|
||||
and organized, and switch between them with ease.
|
||||
{features.featureTabs.workspaces.description}
|
||||
</Description>
|
||||
</motion.div>
|
||||
<motion.div client:load {...getTitleAnimation(1)} className="feature">
|
||||
<Description class="text-2xl font-bold">Compact Mode</Description>
|
||||
<Description class="text-2xl font-bold">
|
||||
{features.featureTabs.compactMode.title}
|
||||
</Description>
|
||||
<Description>
|
||||
Zen's Compact Mode gives you more screen real estate by hiding the
|
||||
tab bar when you don't need it, and showing it when you do.
|
||||
{features.featureTabs.compactMode.description}
|
||||
</Description>
|
||||
</motion.div>
|
||||
<motion.div client:load {...getTitleAnimation(1.2)} className="feature">
|
||||
<Description class="text-2xl font-bold">Glance</Description>
|
||||
<Description class="text-2xl font-bold">
|
||||
{features.featureTabs.glance.title}
|
||||
</Description>
|
||||
<Description>
|
||||
Zen's Glance lets you preview tabs without switching to them, so you
|
||||
can quickly find the page you're looking for.
|
||||
{features.featureTabs.glance.description}
|
||||
</Description>
|
||||
</motion.div>
|
||||
<motion.div client:load {...getTitleAnimation(1.4)} className="feature">
|
||||
<Description class="text-2xl font-bold">Split View</Description>
|
||||
<Description class="text-2xl font-bold">
|
||||
{features.featureTabs.splitView.title}
|
||||
</Description>
|
||||
<Description>
|
||||
Zen's Split View lets you view up to 4 tabs side by side, so you can
|
||||
compare information or multitask easily.
|
||||
{features.featureTabs.splitView.description}
|
||||
</Description>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile description -->
|
||||
<div class="feature-description mt-4 lg:hidden"></div>
|
||||
<div
|
||||
class="feature-description mt-4 lg:hidden"
|
||||
data-descriptions={descriptions}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative w-full lg:w-3/5">
|
||||
|
@ -160,17 +179,16 @@ const {
|
|||
</section>
|
||||
|
||||
<script>
|
||||
const features = document.querySelectorAll('.feature, .feature-tab')
|
||||
const descriptions = [
|
||||
'Organize your tabs into Workspaces to keep your projects separate and organized, and switch between them with ease.',
|
||||
"Zen's Compact Mode gives you more screen real estate by hiding the tab bar when you don't need it, and showing it when you do.",
|
||||
"Zen's Glance lets you preview tabs without switching to them, so you can quickly find the page you're looking for.",
|
||||
"Zen's Split View lets you view up to 4 tabs side by side, so you can compare information or multitask easily.",
|
||||
]
|
||||
const features = document.querySelectorAll(
|
||||
'.feature, .feature-tab',
|
||||
) as NodeListOf<HTMLElement>
|
||||
|
||||
// Set initial description
|
||||
const descriptionEl = document.querySelector('.feature-description')
|
||||
if (descriptionEl) {
|
||||
const descriptionEl = document.querySelector(
|
||||
'.feature-description',
|
||||
) as HTMLDivElement
|
||||
const descriptions = descriptionEl?.dataset.descriptions?.split(',')
|
||||
if (descriptionEl && descriptions) {
|
||||
descriptionEl.textContent = descriptions[0]
|
||||
}
|
||||
|
||||
|
@ -196,7 +214,7 @@ const {
|
|||
|
||||
// Update mobile description
|
||||
const descriptionEl = document.querySelector('.feature-description')
|
||||
if (descriptionEl) {
|
||||
if (descriptionEl && descriptions) {
|
||||
descriptionEl.textContent = descriptions[index]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
---
|
||||
import Title from '../components/Title.astro'
|
||||
import Description from '../components/Description.astro'
|
||||
import Button from '../components/Button.astro'
|
||||
import Circles from '../components/Circles.astro'
|
||||
import SocialMediaStrip from '../components/SocialMediaStrip.astro'
|
||||
import { ArrowRight } from 'lucide-astro'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Circles from '~/components/Circles.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import SocialMediaStrip from '~/components/SocialMediaStrip.astro'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: { footer },
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<footer
|
||||
|
@ -18,10 +24,11 @@ import { ArrowRight } from 'lucide-astro'
|
|||
class="w-full text-center lg:w-1/2 lg:text-left"
|
||||
aria-labelledby="footer-title"
|
||||
>
|
||||
<Title id="footer-title" class="!text-paper">Zen Browser</Title>
|
||||
<Description id="footer-title" class="text-6xl font-bold !text-paper"
|
||||
>{footer.title}</Description
|
||||
>
|
||||
<Description class="mx-auto max-w-xl lg:mx-0">
|
||||
Beautifully designed, privacy-focused, and packed with features. We care
|
||||
about your experience, not your data.
|
||||
{footer.description}
|
||||
</Description>
|
||||
</section>
|
||||
<section class="grid gap-10 place-self-center lg:place-self-start">
|
||||
|
@ -29,9 +36,9 @@ import { ArrowRight } from 'lucide-astro'
|
|||
href="/download"
|
||||
isPrimary
|
||||
class="h-fit w-fit bg-paper !text-dark"
|
||||
aria-label="Download Zen Browser"
|
||||
aria-label={footer.download}
|
||||
>
|
||||
Download
|
||||
{footer.download}
|
||||
<ArrowRight class="size-4" aria-hidden="true" />
|
||||
</Button>
|
||||
</section>
|
||||
|
@ -50,7 +57,7 @@ import { ArrowRight } from 'lucide-astro'
|
|||
aria-labelledby="follow-us-heading"
|
||||
>
|
||||
<h2 id="follow-us-heading" class="text-base !font-semibold">
|
||||
Follow Us
|
||||
{footer.followUs}
|
||||
</h2>
|
||||
<SocialMediaStrip />
|
||||
</section>
|
||||
|
@ -59,16 +66,18 @@ import { ArrowRight } from 'lucide-astro'
|
|||
aria-labelledby="about-us-heading"
|
||||
>
|
||||
<h2 id="about-us-heading" class="text-base !font-semibold">
|
||||
About Us
|
||||
{footer.aboutUs}
|
||||
</h2>
|
||||
<nav aria-label="About navigation">
|
||||
<ul class="grid gap-2 opacity-80">
|
||||
<li>
|
||||
<a href="/about" class="font-normal">Team & Contributors</a>
|
||||
<a href={getLocalePath('/about')} class="font-normal"
|
||||
>{footer.teamAndContributors}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/privacy-policy" class="font-normal"
|
||||
>Privacy Policy</a
|
||||
<a href={getLocalePath('/privacy-policy')} class="font-normal"
|
||||
>{footer.privacyPolicy}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -77,42 +86,50 @@ import { ArrowRight } from 'lucide-astro'
|
|||
</div>
|
||||
<nav class="flex flex-col gap-2" aria-labelledby="get-started-heading">
|
||||
<h2 id="get-started-heading" class="text-base !font-semibold">
|
||||
Get Started
|
||||
{footer.getStarted}
|
||||
</h2>
|
||||
<ul class="grid gap-2 opacity-80">
|
||||
<li>
|
||||
<a href="https://docs.zen-browser.app/" class="font-normal"
|
||||
>Documentation</a
|
||||
>{footer.documentation}</a
|
||||
>
|
||||
</li>
|
||||
<li><a href="/mods" class="font-normal">Zen Mods</a></li>
|
||||
<li>
|
||||
<a href="/release-notes" class="font-normal">Release Notes</a>
|
||||
<a href={getLocalePath('/mods')} class="font-normal"
|
||||
>{footer.zenMods}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/download?twilight" class="font-normal">Twilight</a>
|
||||
<a href={getLocalePath('/release-notes')} class="font-normal"
|
||||
>{footer.releaseNotes}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={getLocalePath('/download?twilight')} class="font-normal"
|
||||
>{footer.twilight}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="flex flex-col gap-2" aria-labelledby="get-help-heading">
|
||||
<h2 id="get-help-heading" class="text-base !font-semibold">
|
||||
Get Help
|
||||
{footer.getHelp}
|
||||
</h2>
|
||||
<ul class="grid gap-2 opacity-80">
|
||||
<li>
|
||||
<a href="https://discord.gg/zen-browser" class="font-normal"
|
||||
>Discord</a
|
||||
>{footer.discord}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://uptime.zen-browser.app/" class="font-normal"
|
||||
>Uptime Status</a
|
||||
>{footer.uptimeStatus}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/zen-browser/desktop/issues/new/choose"
|
||||
class="font-normal">Report an Issue</a
|
||||
class="font-normal">{footer.reportAnIssue}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -123,12 +140,10 @@ import { ArrowRight } from 'lucide-astro'
|
|||
class="grid w-full grid-cols-[1fr_auto] items-center gap-2"
|
||||
aria-label="Copyright information"
|
||||
>
|
||||
<p class="flex justify-center gap-2 lg:justify-start">
|
||||
Made with <span aria-label="love">❤️</span> by the <a
|
||||
href="/about"
|
||||
class="zen-link inline-block font-bold">Zen Team</a
|
||||
>
|
||||
</p>
|
||||
<p
|
||||
class="flex justify-center gap-2 lg:justify-start"
|
||||
set:html={footer.madeWith.replace('{link}', getLocalePath('/about'))}
|
||||
/>
|
||||
</section>
|
||||
<section class="absolute bottom-0 right-0">
|
||||
<Circles
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
---
|
||||
import Title from '../components/Title.astro'
|
||||
import Description from '../components/Description.astro'
|
||||
import Button from '../components/Button.astro'
|
||||
import { Image } from 'astro:assets'
|
||||
import HomePageVideo from '../assets/HomePageVideo.webm'
|
||||
import { ArrowRight } from 'lucide-astro'
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '../animations'
|
||||
import Video from './Video.astro'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import HomePageVideo from '~/assets/HomePageVideo.webm'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import Title from '~/components/Title.astro'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
import SocialMediaStrip from './SocialMediaStrip.astro'
|
||||
import Video from './Video.astro'
|
||||
|
||||
let titleAnimationCounter = 0
|
||||
function getNewAnimationDelay() {
|
||||
|
@ -19,6 +19,16 @@ function getNewAnimationDelay() {
|
|||
function getHeroTitleAnimation() {
|
||||
return getTitleAnimation(getNewAnimationDelay())
|
||||
}
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const getLocalePath = getPath(locale)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { hero },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<header
|
||||
|
@ -30,42 +40,42 @@ function getHeroTitleAnimation() {
|
|||
class="relative px-12 text-center !font-normal !leading-8 leading-[108px] md:!text-7xl lg:px-0 lg:!text-9xl"
|
||||
>
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
{'welcome'}
|
||||
{hero.title[0]}
|
||||
</motion.span>
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
{'to'}
|
||||
{hero.title[1]}
|
||||
</motion.span>
|
||||
<br class="hidden md:block" />
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
{'a'}
|
||||
{hero.title[2]}
|
||||
</motion.span>
|
||||
<motion.span
|
||||
client:load
|
||||
{...getHeroTitleAnimation()}
|
||||
className="italic text-coral"
|
||||
>
|
||||
{'calmer'}
|
||||
{hero.title[3]}
|
||||
</motion.span>
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
{'internet'}
|
||||
{hero.title[4]}
|
||||
</motion.span>
|
||||
</Title>
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
<Description class="px-12 text-center lg:px-0">
|
||||
Beautifully designed, privacy-focused, and packed with features.
|
||||
{hero.description[0]}.
|
||||
<br class="hidden sm:inline" />
|
||||
We care about your experience, not your data.</Description
|
||||
{hero.description[1]}</Description
|
||||
>
|
||||
</motion.span>
|
||||
<div class="mt-6 flex w-2/3 flex-col gap-3 sm:gap-6 md:w-fit md:flex-row">
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
<Button class="w-full" href="/download" isPrimary>
|
||||
Beta is now available!
|
||||
<Button class="w-full" href={getLocalePath('/download')} isPrimary>
|
||||
{hero.buttons.beta}
|
||||
<ArrowRight class="size-4" />
|
||||
</Button>
|
||||
</motion.span>
|
||||
<motion.span client:load {...getHeroTitleAnimation()}>
|
||||
<Button href="/donate">Support Us ❤️</Button>
|
||||
<Button href={getLocalePath('/donate')}>{hero.buttons.support}</Button>
|
||||
</motion.span>
|
||||
</div>
|
||||
<motion.span
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
---
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: {
|
||||
nav: { menu },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<!-- Hidden checkbox for menu toggle -->
|
||||
<input
|
||||
type="checkbox"
|
||||
|
@ -12,7 +24,7 @@
|
|||
class="fixed inset-y-0 right-0 z-40 w-64 translate-x-full transform bg-paper shadow-lg transition-transform duration-300 peer-checked:translate-x-0 lg:hidden"
|
||||
>
|
||||
<div class="flex items-center justify-between border-b border-dark px-4 py-2">
|
||||
<div class="text-lg font-bold">Menu</div>
|
||||
<div class="text-lg font-bold">{menu.menu}</div>
|
||||
<label
|
||||
for="mobile-menu-toggle"
|
||||
class="cursor-pointer p-2 text-dark"
|
||||
|
@ -37,63 +49,70 @@
|
|||
<ul class="space-y-4">
|
||||
<!-- Getting Started Links -->
|
||||
<li>
|
||||
<div class="mb-2 font-bold">Getting Started</div>
|
||||
<div class="mb-2 font-bold">{menu.gettingStarted}</div>
|
||||
<ul class="ml-4 space-y-2">
|
||||
<li>
|
||||
<a href="/mods" class="block text-dark hover:text-coral">Zen Mods</a
|
||||
<a
|
||||
href={getLocalePath('/mods')}
|
||||
class="block text-dark hover:text-coral">{menu.zenMods}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/release-notes" class="block text-dark hover:text-coral"
|
||||
>Release Notes</a
|
||||
<a
|
||||
href={getLocalePath('/release-notes')}
|
||||
class="block text-dark hover:text-coral">{menu.releaseNotes}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://discord.gg/zen-browser"
|
||||
class="block text-dark hover:text-coral">Discord</a
|
||||
class="block text-dark hover:text-coral">{menu.discord}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Useful Links -->
|
||||
<li>
|
||||
<div class="mb-2 font-bold">Useful Links</div>
|
||||
<div class="mb-2 font-bold">{menu.usefulLinks}</div>
|
||||
<ul class="ml-4 space-y-2">
|
||||
<li>
|
||||
<a href="/donate" class="block text-dark hover:text-coral"
|
||||
>Donate ❤️</a
|
||||
<a
|
||||
href={getLocalePath('/donate')}
|
||||
class="block text-dark hover:text-coral">{menu.donate}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/about" class="block text-dark hover:text-coral"
|
||||
>About Us 🌟</a
|
||||
<a
|
||||
href={getLocalePath('/about')}
|
||||
class="block text-dark hover:text-coral">{menu.aboutUs}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://docs.zen-browser.app"
|
||||
class="block text-dark hover:text-coral">Documentation</a
|
||||
class="block text-dark hover:text-coral">{menu.documentation}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/zen-browser"
|
||||
target="_blank"
|
||||
class="block text-dark hover:text-coral">GitHub</a
|
||||
class="block text-dark hover:text-coral">{menu.github}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Extra Links -->
|
||||
<li>
|
||||
<a href="/mods" class="block font-bold text-dark hover:text-coral"
|
||||
>Mods</a
|
||||
<a
|
||||
href={getLocalePath('/mods')}
|
||||
class="block font-bold text-dark hover:text-coral">{menu.mods}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/download" class="block font-bold text-dark hover:text-coral"
|
||||
>Download</a
|
||||
<a
|
||||
href={getLocalePath('/download')}
|
||||
class="block font-bold text-dark hover:text-coral">{menu.download}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { useState, useEffect } from 'preact/hooks'
|
||||
import type { ZenTheme } from '../mods'
|
||||
import { library, icon } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons'
|
||||
import { useModsSearch } from '../hooks/useModsSearch'
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons'
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
import { useModsSearch } from '~/hooks/useModsSearch'
|
||||
import type { ZenTheme } from '~/mods'
|
||||
import { type Locale, getUI } from '~/utils/i18n'
|
||||
|
||||
// Add icons to the library
|
||||
library.add(faSort, faSortUp, faSortDown)
|
||||
|
@ -13,10 +14,11 @@ const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' })
|
|||
const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' })
|
||||
|
||||
interface ModsListProps {
|
||||
mods: ZenTheme[]
|
||||
allMods: ZenTheme[]
|
||||
locale: Locale
|
||||
}
|
||||
|
||||
export default function ModsList({ mods }: ModsListProps) {
|
||||
export default function ModsList({ allMods, locale }: ModsListProps) {
|
||||
const {
|
||||
search,
|
||||
createdSort,
|
||||
|
@ -31,8 +33,8 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
setPage,
|
||||
setLimit,
|
||||
mods: paginatedMods,
|
||||
searchParams,
|
||||
} = useModsSearch(mods)
|
||||
// searchParams,
|
||||
} = useModsSearch(allMods)
|
||||
|
||||
const [pageInput, setPageInput] = useState(page.toString())
|
||||
|
||||
|
@ -78,6 +80,10 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
window.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
const {
|
||||
routes: { mods },
|
||||
} = getUI(locale)
|
||||
|
||||
function renderPagination() {
|
||||
if (totalPages <= 1) return null
|
||||
return (
|
||||
|
@ -94,17 +100,26 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
<
|
||||
</button>
|
||||
<form onSubmit={handlePageSubmit} className="flex items-center gap-2">
|
||||
<span className="text-sm">Page</span>
|
||||
<input
|
||||
type="text"
|
||||
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"
|
||||
/>
|
||||
<span className="text-sm">
|
||||
of {totalPages} ({totalItems} items)
|
||||
</span>
|
||||
{mods.pagination.pagination.split('{input}').map((value, index) => {
|
||||
if (index === 0) {
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
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 (
|
||||
<span className="text-sm">
|
||||
{value
|
||||
.replace('{totalPages}', totalPages.toString())
|
||||
.replace('{totalItems}', totalItems.toString())}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</form>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -129,7 +144,7 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
type="text"
|
||||
id="search"
|
||||
className="w-full rounded-full border-2 border-dark bg-transparent px-6 py-2 text-lg outline-none"
|
||||
placeholder="Type to search..."
|
||||
placeholder={mods.search}
|
||||
value={search}
|
||||
onInput={handleSearch}
|
||||
/>
|
||||
|
@ -142,7 +157,7 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
onClick={toggleCreatedSort}
|
||||
className="text-md flex items-center gap-2 px-4 py-2 font-semibold"
|
||||
>
|
||||
Last created
|
||||
{mods.sort.lastCreated}
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: getSortIcon(createdSort).html[0],
|
||||
|
@ -157,7 +172,7 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
onClick={toggleUpdatedSort}
|
||||
className="text-md flex items-center gap-2 px-4 py-2 font-semibold"
|
||||
>
|
||||
Last updated
|
||||
{mods.sort.lastUpdated}
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: getSortIcon(updatedSort).html[0],
|
||||
|
@ -168,7 +183,7 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
|
||||
<div className="flex items-center gap-2 px-4 py-2">
|
||||
<label htmlFor="limit" className="text-md font-semibold">
|
||||
Per page:
|
||||
{mods.sort.perPage}
|
||||
</label>
|
||||
<select
|
||||
id="limit"
|
||||
|
@ -214,10 +229,8 @@ export default function ModsList({ mods }: ModsListProps) {
|
|||
))
|
||||
) : (
|
||||
<div className="col-span-4 grid place-items-center gap-4 place-self-center px-8 text-center">
|
||||
<h2 className="text-lg font-bold">No results found</h2>
|
||||
<p className="text-sm font-thin">
|
||||
Try searching for a different term or check back later.
|
||||
</p>
|
||||
<h2 className="text-lg font-bold">{mods.noResults}</h2>
|
||||
<p className="text-sm font-thin">{mods.noResultsDescription}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
---
|
||||
import { motion } from 'motion/react'
|
||||
import Button from '../components/Button.astro'
|
||||
import { Astronav, MenuItems, Dropdown, DropdownItems } from 'astro-navbar'
|
||||
import { Astronav, Dropdown, DropdownItems, MenuItems } from 'astro-navbar'
|
||||
import { ArrowRight, ChevronDown, Download, Menu } from 'lucide-astro'
|
||||
import Logo from './Logo.astro'
|
||||
import { motion } from 'motion/react'
|
||||
import Button from '~/components/Button.astro'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
import { getTitleAnimation } from '../animations.ts'
|
||||
import ThemeSwitch from './ThemeSwitch.astro'
|
||||
import Logo from './Logo.astro'
|
||||
import MobileMenu from './MobileMenu.astro'
|
||||
import ThemeSwitch from './ThemeSwitch.astro'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: {
|
||||
nav: { brand, menu },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
|
@ -14,16 +23,19 @@ import MobileMenu from './MobileMenu.astro'
|
|||
<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"
|
||||
>
|
||||
<a class="flex items-center gap-2 text-lg font-bold" href="/">
|
||||
<a
|
||||
class="flex items-center gap-2 text-lg font-bold"
|
||||
href={getLocalePath('/')}
|
||||
>
|
||||
<Logo class="text-coral" />
|
||||
<span>zen browser</span>
|
||||
<span>{brand}</span>
|
||||
</a>
|
||||
<div
|
||||
class="hidden items-center gap-6 place-self-center text-xs sm:text-sm lg:flex lg:text-base"
|
||||
>
|
||||
<Dropdown class="group">
|
||||
<button class="flex items-center">
|
||||
<span>Getting Started</span>
|
||||
<span>{menu.gettingStarted}</span>
|
||||
<ChevronDown
|
||||
class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2"
|
||||
/>
|
||||
|
@ -34,26 +46,29 @@ import MobileMenu from './MobileMenu.astro'
|
|||
{...getTitleAnimation(0, 0.3, false)}
|
||||
client:load
|
||||
>
|
||||
<a class="dropdown-item bg-dark/5 row-span-2" href="/mods">
|
||||
<div class="dropdown-title">Zen Mods</div>
|
||||
<a
|
||||
class="dropdown-item bg-dark/5 row-span-2"
|
||||
href={getLocalePath('/mods')}
|
||||
>
|
||||
<div class="dropdown-title">{menu.zenMods}</div>
|
||||
<div class="dropdown-description">
|
||||
Customize your browsing experience with Zen Mods.
|
||||
{menu.zenModsDesc}
|
||||
</div>
|
||||
<Button isPrimary class="mt-auto">
|
||||
Try Zen Mods
|
||||
{menu.tryZenMods}
|
||||
<ArrowRight class="size-4" />
|
||||
</Button>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/release-notes">
|
||||
<div class="dropdown-title">Release Notes</div>
|
||||
<a class="dropdown-item" href={getLocalePath('/release-notes')}>
|
||||
<div class="dropdown-title">{menu.releaseNotes}</div>
|
||||
<div class="dropdown-description">
|
||||
Stay up to date with the latest features and improvements.
|
||||
{menu.releaseNotesDesc}
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="https://discord.gg/zen-browser">
|
||||
<div class="dropdown-title">Discord</div>
|
||||
<div class="dropdown-title">{menu.discord}</div>
|
||||
<div class="dropdown-description">
|
||||
Join our community on Discord to chat with other Zen users!
|
||||
{menu.discordDesc}
|
||||
</div>
|
||||
</a>
|
||||
</motion.div>
|
||||
|
@ -61,7 +76,7 @@ import MobileMenu from './MobileMenu.astro'
|
|||
</Dropdown>
|
||||
<Dropdown class="group">
|
||||
<button class="flex items-center">
|
||||
<span>Useful Links</span>
|
||||
<span>{menu.usefulLinks}</span>
|
||||
<ChevronDown
|
||||
class="size-4 transform transition-transform duration-200 group-open:rotate-180 md:ml-2"
|
||||
/>
|
||||
|
@ -72,22 +87,22 @@ import MobileMenu from './MobileMenu.astro'
|
|||
{...getTitleAnimation(0, 0.3, false)}
|
||||
client:load
|
||||
>
|
||||
<a class="dropdown-item" href="/donate">
|
||||
<div class="dropdown-title">Donate ❤️</div>
|
||||
<a class="dropdown-item" href={getLocalePath('/donate')}>
|
||||
<div class="dropdown-title">{menu.donate}</div>
|
||||
<div class="dropdown-description">
|
||||
Support the development of Zen Browser with a donation.
|
||||
{menu.donateDesc}
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="/about">
|
||||
<div class="dropdown-title">About Us 🌟</div>
|
||||
<a class="dropdown-item" href={getLocalePath('/about')}>
|
||||
<div class="dropdown-title">{menu.aboutUs}</div>
|
||||
<div class="dropdown-description">
|
||||
Learn more about the team behind Zen Browser.
|
||||
{menu.aboutUsDesc}
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="https://docs.zen-browser.app">
|
||||
<div class="dropdown-title">Documentation</div>
|
||||
<div class="dropdown-title">{menu.documentation}</div>
|
||||
<div class="dropdown-description">
|
||||
Learn how to use Zen Browser with our documentation.
|
||||
{menu.documentationDesc}
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
|
@ -95,16 +110,16 @@ import MobileMenu from './MobileMenu.astro'
|
|||
href="https://github.com/zen-browser"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="dropdown-title">GitHub</div>
|
||||
<div class="dropdown-title">{menu.github}</div>
|
||||
<div class="dropdown-description">
|
||||
Contribute to the development of Zen Browser on GitHub.
|
||||
{menu.githubDesc}
|
||||
</div>
|
||||
</a>
|
||||
</motion.div>
|
||||
</DropdownItems>
|
||||
</Dropdown>
|
||||
<a class="hidden items-center lg:block" href="/mods">
|
||||
<span>Mods</span>
|
||||
<a class="hidden items-center lg:block" href={getLocalePath('/mods')}>
|
||||
<span>{menu.mods}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 place-self-end lg:gap-4">
|
||||
|
@ -113,7 +128,7 @@ import MobileMenu from './MobileMenu.astro'
|
|||
</div>
|
||||
<Button href="/download" class="hidden lg:flex" isPrimary>
|
||||
<span class="hidden items-center gap-2 lg:flex">
|
||||
Download
|
||||
{menu.download}
|
||||
<ArrowRight class="size-4" />
|
||||
</span>
|
||||
<span class="flex items-center gap-2 lg:hidden">
|
||||
|
|
|
@ -2,31 +2,42 @@
|
|||
import { Accordion, AccordionItem } from 'free-astro-components'
|
||||
import { Info } from 'lucide-astro'
|
||||
|
||||
import { releaseNotes as releaseNotesData } from '~/release-notes'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
import {
|
||||
type ReleaseNote,
|
||||
type BreakingChange,
|
||||
type ReleaseNote,
|
||||
getReleaseNoteFirefoxVersion,
|
||||
} from '../release-notes';
|
||||
import { releaseNotes } from '../release-notes'
|
||||
} from '../release-notes'
|
||||
export type Props = ReleaseNote
|
||||
const { isTwilight, ...props } = Astro.props
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
routes: {
|
||||
releaseNotes: {
|
||||
components: { releaseNoteItem },
|
||||
},
|
||||
},
|
||||
} = getUI(locale)
|
||||
|
||||
let date
|
||||
if (props.date) {
|
||||
const [day, month, year] = props.date.split('/')
|
||||
date = new Date(Date.parse(`${year}-${month}-${day}`))
|
||||
}
|
||||
|
||||
const ffVersion = getReleaseNoteFirefoxVersion(props);
|
||||
const currentReleaseIndex = releaseNotes.findIndex(
|
||||
(releaseNote: ReleaseNote) => releaseNote.version === props.version
|
||||
);
|
||||
const prevReleaseNote = releaseNotes[currentReleaseIndex + 1];
|
||||
let compareLink = '';
|
||||
const ffVersion = getReleaseNoteFirefoxVersion(props)
|
||||
const currentReleaseIndex = releaseNotesData.findIndex(
|
||||
(releaseNote: ReleaseNote) => releaseNote.version === props.version,
|
||||
)
|
||||
const prevReleaseNote = releaseNotesData[currentReleaseIndex + 1]
|
||||
let compareLink = ''
|
||||
if (prevReleaseNote && !isTwilight) {
|
||||
compareLink = `https://github.com/zen-browser/desktop/compare/${prevReleaseNote.version}...${props.version}`;
|
||||
compareLink = `https://github.com/zen-browser/desktop/compare/${prevReleaseNote.version}...${props.version}`
|
||||
}
|
||||
---
|
||||
---
|
||||
|
||||
<section
|
||||
class="release-note-item relative mt-24 flex flex-col border-t pt-24 lg:flex-row"
|
||||
|
@ -37,24 +48,31 @@ if (prevReleaseNote && !isTwilight) {
|
|||
isTwilight ? (
|
||||
<a
|
||||
class="!mb-2 block w-fit rounded-full bg-coral px-3 py-1 text-xs text-paper"
|
||||
href="/download?twilight"
|
||||
href={getLocalePath('/download?twilight')}
|
||||
>
|
||||
Twilight
|
||||
{releaseNoteItem.twilight}
|
||||
</a>
|
||||
) : null
|
||||
}
|
||||
<h1 class="flex items-center text-3xl font-bold">
|
||||
{
|
||||
isTwilight ? (
|
||||
<>Twilight changes for {props.version} 🌙</>
|
||||
<>
|
||||
{releaseNoteItem.twilightChanges} {props.version} 🌙
|
||||
</>
|
||||
) : (
|
||||
<>Release notes for {props.version} 🎉</>
|
||||
<>
|
||||
{releaseNoteItem.releaseChanges.replaceAll(
|
||||
'{version}',
|
||||
props.version,
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
ffVersion ? (
|
||||
<div class="!mb-2 ml-6 mt-1 block inline w-fit rounded-full bg-blue-500 px-3 py-1 text-xs text-paper dark:bg-blue-50">
|
||||
Firefox {ffVersion}
|
||||
{releaseNoteItem.firefoxVersion.replace('{version}', ffVersion)}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
@ -66,7 +84,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
class="zen-link whitespace-nowrap text-sm opacity-60"
|
||||
target="_blank"
|
||||
href={`https://github.com/zen-browser/desktop/releases/tag/${isTwilight ? 'twilight' : props.version}`}
|
||||
>GitHub Release</a
|
||||
>{releaseNoteItem.githubRelease}</a
|
||||
>
|
||||
{
|
||||
!isTwilight ? (
|
||||
|
@ -78,7 +96,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
target="_blank"
|
||||
href={`https://github.com/zen-browser/desktop/actions/runs/${props.workflowId}`}
|
||||
>
|
||||
Workflow run
|
||||
{releaseNoteItem.workflowRun}
|
||||
</a>
|
||||
</>
|
||||
) : null
|
||||
|
@ -93,7 +111,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
target="_blank"
|
||||
href={compareLink}
|
||||
>
|
||||
Compare changes
|
||||
{releaseNoteItem.compareChanges}
|
||||
</a>
|
||||
</>
|
||||
) : null
|
||||
|
@ -102,20 +120,8 @@ if (prevReleaseNote && !isTwilight) {
|
|||
<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}
|
||||
<p class="m-0">
|
||||
{
|
||||
isTwilight ? (
|
||||
<>
|
||||
Please note that Twilight is a pre-release version of Zen Browser.
|
||||
It may contain bugs and unfinished features.
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
If you encounter any issues, please report them on <a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href="https://github.com/zen-browser/desktop/issues/"
|
||||
class="zen-link">the issues page</a
|
||||
>.
|
||||
{isTwilight ? <>{releaseNoteItem.twilightWarning}</> : null}
|
||||
<span set:html={releaseNoteItem.reportIssues} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -147,7 +153,10 @@ if (prevReleaseNote && !isTwilight) {
|
|||
href={`https://github.com/zen-browser/desktop/issues/${fix.issue}`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
aria-label={`View issue number ${fix.issue} on GitHub`}
|
||||
aria-label={releaseNoteItem.viewIssue.replace(
|
||||
'{issue}',
|
||||
fix.issue,
|
||||
)}
|
||||
>
|
||||
#{fix.issue}
|
||||
</a>
|
||||
|
@ -163,7 +172,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
}
|
||||
{
|
||||
props.features?.length ? (
|
||||
<AccordionItem title="Features">
|
||||
<AccordionItem title={releaseNoteItem.sections.features}>
|
||||
<ul class="list-inside list-disc">
|
||||
{props.features.map((feature: string) => (
|
||||
<li class="text-md text-muted-foreground">{feature}</li>
|
||||
|
@ -174,7 +183,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
}
|
||||
{
|
||||
props.themeChanges?.length ? (
|
||||
<AccordionItem title="Theme Changes">
|
||||
<AccordionItem title={releaseNoteItem.sections.themeChanges}>
|
||||
<ul class="list-inside list-disc">
|
||||
{props.themeChanges.map((themeChange: string) => (
|
||||
<li class="text-md text-muted-foreground">{themeChange}</li>
|
||||
|
@ -185,7 +194,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
}
|
||||
{
|
||||
props.breakingChanges?.length ? (
|
||||
<AccordionItem title="Breaking Changes">
|
||||
<AccordionItem title={releaseNoteItem.sections.breakingChanges.title}>
|
||||
<ul class="list-inside list-disc">
|
||||
{props.breakingChanges.map((breakingChange: BreakingChange) => (
|
||||
<li class="text-md text-muted-foreground">
|
||||
|
@ -199,9 +208,11 @@ if (prevReleaseNote && !isTwilight) {
|
|||
href={breakingChange.link}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
aria-label={`View breaking change on GitHub`}
|
||||
aria-label={
|
||||
releaseNoteItem.sections.breakingChanges.description
|
||||
}
|
||||
>
|
||||
Learn more
|
||||
{releaseNoteItem.learnMore}
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
const { gap = 4 } = Astro.props
|
||||
|
||||
import { library, icon } from '@fortawesome/fontawesome-svg-core'
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faMastodon,
|
||||
faBluesky,
|
||||
faGithub,
|
||||
faXTwitter,
|
||||
faMastodon,
|
||||
faReddit,
|
||||
faXTwitter,
|
||||
} from '@fortawesome/free-brands-svg-icons'
|
||||
|
||||
library.add(faMastodon, faBluesky, faGithub, faXTwitter, faReddit)
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
---
|
||||
import Description from '../components/Description.astro'
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '../animations'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import Description from '~/components/Description.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
import tutaLogo from '../assets/tuta-logo.png'
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
import tutaLogo from '~/assets/tuta-logo.png'
|
||||
|
||||
import Image from 'astro/components/Image.astro'
|
||||
const { showSponsors = true } = Astro.props
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { sponsors },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<section id="sponsors" class:list={['mb-32 px-4', !showSponsors && 'hidden']}>
|
||||
|
@ -17,18 +26,16 @@ const { showSponsors = true } = Astro.props
|
|||
>
|
||||
</motion.span>
|
||||
<motion.span client:load {...getTitleAnimation(0.4)}>
|
||||
<Description>
|
||||
We are grateful to our sponsors for their support. They help us to keep
|
||||
the project alive.<br />You can also be part of this journey by <a
|
||||
href="/donate"
|
||||
class="zen-link">donating us directly</a
|
||||
>!
|
||||
</Description>
|
||||
<Description set:html={sponsors.description} />
|
||||
</motion.span>
|
||||
<div class="relative mt-8 flex items-center justify-center">
|
||||
<motion.span client:load {...getTitleAnimation(0.6)}>
|
||||
<a href="https://tuta.com/" target="_blank" class="w-fit">
|
||||
<Image src={tutaLogo} alt="Tuta" class="h-16 w-fit object-contain" />
|
||||
<a href={sponsors.sponsors['tuta'].url} target="_blank" class="w-fit">
|
||||
<Image
|
||||
src={tutaLogo}
|
||||
alt={sponsors.sponsors['tuta'].name}
|
||||
class="h-16 w-fit object-contain"
|
||||
/>
|
||||
</a>
|
||||
</motion.span>
|
||||
</div>
|
||||
|
|
4
src/constants/i18n.ts
Normal file
4
src/constants/i18n.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const I18N = {
|
||||
DEFAULT_LOCALE: 'en',
|
||||
LOCALES: [{ label: 'English', value: 'en' }],
|
||||
} as const
|
5
src/constants/index.ts
Normal file
5
src/constants/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { I18N } from './i18n'
|
||||
|
||||
export const CONSTANT = {
|
||||
I18N,
|
||||
}
|
467
src/i18n/en/translation.json
Normal file
467
src/i18n/en/translation.json
Normal file
|
@ -0,0 +1,467 @@
|
|||
{
|
||||
"routes": {
|
||||
"index": {
|
||||
"title": "Zen Browser",
|
||||
"hero": {
|
||||
"title": ["welcome", "to", "a", "calmer", "internet"],
|
||||
"description": [
|
||||
"Beautifully designed, privacy-focused, and packed with features.",
|
||||
"We care about your experience, not your data."
|
||||
],
|
||||
"buttons": {
|
||||
"beta": "Beta is now available!",
|
||||
"support": "Support Us ❤️"
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"title1": "Productivity",
|
||||
"title2": "at",
|
||||
"title3": "its best",
|
||||
"description": "Zen Browser is packed with features that help you stay productive and focused. Browsers should be tools that help you get things done, not distractions that keep you from your work.",
|
||||
"featureTabs": {
|
||||
"workspaces": {
|
||||
"title": "Workspaces",
|
||||
"description": "Organize your tabs into Workspaces to keep your projects separate and organized, and switch between them with ease."
|
||||
},
|
||||
"compactMode": {
|
||||
"title": "Compact Mode",
|
||||
"description": "Zen's Compact Mode gives you more screen real estate by hiding the tab bar when you don't need it, and showing it when you do."
|
||||
},
|
||||
"glance": {
|
||||
"title": "Glance",
|
||||
"description": "Glance allows you to quickly switch between your most used tabs, without having to scroll through your history."
|
||||
},
|
||||
"splitView": {
|
||||
"title": "Split View",
|
||||
"description": "Split View allows you to view two tabs side by side, making it easier to compare and switch between them."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sponsors": {
|
||||
"title": "Our Sponsors",
|
||||
"description": "We are grateful to our sponsors for their support. They help us to keep the project alive.<br />You can also be part of this journey by <a href=\"/donate\" class=\"zen-link\">donating us directly</a>!",
|
||||
"sponsors": {
|
||||
"tuta": {
|
||||
"name": "Tuta",
|
||||
"url": "https://tuta.com/"
|
||||
}
|
||||
}
|
||||
},
|
||||
"community": {
|
||||
"title": ["Our", "Core", "Values"],
|
||||
"description": "We make it not only a priority, but a necessity to ensure that Zen always strikes the right balance between beauty, performance, and privacy. We are committed to making Zen the most beautiful, productive, and privacy-respecting browser out there — without compromising on your experience.",
|
||||
"lists": {
|
||||
"freeAndOpenSource": {
|
||||
"title": "Free and open-source",
|
||||
"description": "Zen is free and open-source software, which means you can use it without any cost and can modify it to suit your needs."
|
||||
},
|
||||
"simpleYetPowerful": {
|
||||
"title": "Simple yet powerful",
|
||||
"description": "Zen is simple to use, but powerful enough to handle your daily tasks."
|
||||
},
|
||||
"privateAndAlwaysUpToDate": {
|
||||
"title": "Private and always up-to-date",
|
||||
"description": "Zen is private and always up-to-date, which means you can use it without any cost and can modify it to suit your needs."
|
||||
}
|
||||
},
|
||||
"images": {
|
||||
"community": {
|
||||
"alt": "Community"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mods": {
|
||||
"title": "Zen Mods",
|
||||
"description": "Browse our diverse collection of Zen Mods, community-made plugins and themes for Zen Browser. Discover a theme to match every mood, and a plugin to fulfill every requirement. Start customizing your browser experience today!",
|
||||
"pagination": {
|
||||
"pagination": "{input} of {totalPages} ({totalItems} items)"
|
||||
},
|
||||
"search": "Type to search...",
|
||||
"sort": {
|
||||
"lastCreated": "Last created",
|
||||
"lastUpdated": "Last updated",
|
||||
"perPage": "Per page"
|
||||
},
|
||||
"noResults": "No results found",
|
||||
"noResultsDescription": "Try searching for a different term or check back later.",
|
||||
"slug": {
|
||||
"title": "{name} - Zen Mods",
|
||||
"description": "Learn more about {name} mod available on Zen Browser",
|
||||
"alert": {
|
||||
"description": "You need to have Zen Browser installed to install this theme.",
|
||||
"button": "Download now!"
|
||||
},
|
||||
"createdBy": "Created by <a href={link} class=\"zen-link font-bold\">{author}</a> • <span class=\"font-bold\">v{version}</span>",
|
||||
"creationDate": "Creation date • <b>{createdAt}</b>",
|
||||
"latestUpdate": "Latest update • <b>{updatedAt}</b>",
|
||||
"visitModHomepage": "Visit mod homepage",
|
||||
"installMod": "Install Mod 🎉",
|
||||
"uninstallMod": "Uninstall Mod",
|
||||
"back": "Back"
|
||||
}
|
||||
},
|
||||
"releaseNotes": {
|
||||
"title": "Release notes - Zen Browser",
|
||||
"topSection": {
|
||||
"title": "Release Notes",
|
||||
"description": "Stay up to date with the latest changes to Zen Browser! Since the <a class=\"zen-link\" href=\"#1.0.0-a.1\">first release</a> till <a class=\"zen-link\" href=\"#{latestVersion}\">{latestVersion}</a>, we've been working hard to make Zen Browser the best it can be. Thanks everyone for your feedback! ❤️"
|
||||
},
|
||||
"list": {
|
||||
"support": "Give us some support!",
|
||||
"expandAll": "Expand all",
|
||||
"navigateToVersion": "Navigate to version..."
|
||||
},
|
||||
"backToTop": "Back to the top",
|
||||
"chooseVersion": "Choose version",
|
||||
"components": {
|
||||
"releaseNoteItem": {
|
||||
"twilight": "Twilight",
|
||||
"twilightChanges": "Twilight changes for {version} 🌙",
|
||||
"releaseChanges": "Release notes for {version} 🎉",
|
||||
"firefoxVersion": "Firefox {version}",
|
||||
"githubRelease": "GitHub Release",
|
||||
"workflowRun": "Workflow run",
|
||||
"compareChanges": "Compare changes",
|
||||
"twilightWarning": "Please note that Twilight is a pre-release version of Zen Browser. It may contain bugs and unfinished features.",
|
||||
"reportIssues": " If you encounter any issues, please report them on <a rel=\"noopener noreferrer\" target=\"_blank\" href=\"https://github.com/zen-browser/desktop/issues/\" class=\"zen-link\">the issues page</a>.",
|
||||
"sections": {
|
||||
"fixes": "Fixes",
|
||||
"features": "Features",
|
||||
"themeChanges": "Theme Changes",
|
||||
"breakingChanges": {
|
||||
"title": "Breaking Changes",
|
||||
"description": "View breaking changes on GitHub"
|
||||
}
|
||||
},
|
||||
"learnMore": "Learn more",
|
||||
"viewIssue": "View issue number {issue} on GitHub"
|
||||
}
|
||||
},
|
||||
"slug": {
|
||||
"title": "Release notes",
|
||||
"redirect": "Redirecting to release notes for version {version}..."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "About - Zen Browser",
|
||||
"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?",
|
||||
"mainTeam": {
|
||||
"title": "Main Team",
|
||||
"description": "This list shows the main team members who are working hard to bring you the best browsing experience.",
|
||||
"members": {
|
||||
"mauro": {
|
||||
"name": "Mauro B.",
|
||||
"description": "Creator, Main Developer",
|
||||
"link": "https://cheff.dev/"
|
||||
},
|
||||
"oscar": {
|
||||
"name": "Oscar Gonzalez",
|
||||
"description": "Site Reliability Engineer (SRE) and code signing.",
|
||||
"link": false
|
||||
},
|
||||
"jan": {
|
||||
"name": "Jan Heres",
|
||||
"description": "Active contributor and helps with MacOS builds",
|
||||
"link": "https://janheres.eu/"
|
||||
},
|
||||
"brhm": {
|
||||
"name": "BrhmDev",
|
||||
"description": "Active contributor with great contributions",
|
||||
"link": "https://github.com/BrhmDev"
|
||||
},
|
||||
"canoa": {
|
||||
"name": "Canoa",
|
||||
"description": "Active contributor, and very active in issue handling and website management",
|
||||
"link": "https://thatcanoa.org/"
|
||||
},
|
||||
"adam": {
|
||||
"name": "Adam",
|
||||
"description": "Branding and design",
|
||||
"link": "https://cybrneon.xyz/"
|
||||
},
|
||||
"kristijanribaric": {
|
||||
"name": "Kristijan Ribaric",
|
||||
"description": "Active contributor",
|
||||
"link": "https://github.com/kristijanribaric"
|
||||
},
|
||||
"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": {
|
||||
"title": "Contributors",
|
||||
"description": "This list shows the contributors who have helped us to make Zen Browser the best it can be."
|
||||
}
|
||||
},
|
||||
"donate": {
|
||||
"title": "Donate - Zen Browser",
|
||||
"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": {
|
||||
"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."
|
||||
},
|
||||
"koFi": {
|
||||
"title": "Ko-fi",
|
||||
"description": "Ko-fi allows you to support us with a one-time donation. You can choose the amount that works best for you. Monthly donations are also available.",
|
||||
"button": "Go to Ko-fi"
|
||||
}
|
||||
},
|
||||
"download": {
|
||||
"title": "Download - Zen Browser",
|
||||
"description": "Download Zen Browser for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification.",
|
||||
"twilightInfo": "You're currently in Twilight mode, this means you're downloading the latest experimental features and updates.",
|
||||
"alertInfo": {
|
||||
"description": "<strong class='font-medium text-zen-blue'>Twilight Mode:</strong> You're currently in Twilight mode, this means you're downloading the latest experimental features and updates."
|
||||
},
|
||||
"platformSelector": {
|
||||
"title": "Platform Selector",
|
||||
"description": "Select your platform to download Zen Browser."
|
||||
},
|
||||
"additionalResources": {
|
||||
"title": "Additional Resources",
|
||||
"sourceCode": {
|
||||
"title": "Source Code",
|
||||
"description": "Explore Zen Browser's source code on GitHub. Contribute to the project or build your own version."
|
||||
},
|
||||
"documentation": {
|
||||
"title": "Documentation",
|
||||
"description": "Access comprehensive documentation, guides, and tutorials for Zen Browser."
|
||||
}
|
||||
},
|
||||
"securityNotice": {
|
||||
"title": "Verified & Secure Downloads",
|
||||
"description": "All Zen downloads are signed and verified for your security. We recommend downloading directly from our official website or GitHub repository. If your download seems broken or gets flagged by your antivirus, please <a href='https://github.com/zen-browser/desktop/issues/new/choose' class='zen-link ml-1'>report it to us</a>."
|
||||
},
|
||||
"platformNames": {
|
||||
"mac": "macOS",
|
||||
"windows": "Windows",
|
||||
"linux": "Linux",
|
||||
"macDownload": "MacOS Download",
|
||||
"windowsDownload": "Windows Download",
|
||||
"linuxDownload": "Linux Download"
|
||||
},
|
||||
"platformDescriptions": {
|
||||
"mac": "Works on both new Apple (M-Series) and older Intel Macs.<br />Requires macOS 11.0 or later.",
|
||||
"windows": "Works on Windows 10 and Windows 11.<br />Not sure which version to get? Most people should choose the 64-bit installer.",
|
||||
"linux": "Works with many Linux versions.<br />Pick the download that matches your system."
|
||||
}
|
||||
},
|
||||
"privacyPolicy": {
|
||||
"title": "Privacy Policy",
|
||||
"lastUpdated": "Last updated: 2025-02-5",
|
||||
"sections": {
|
||||
"introduction": {
|
||||
"title": "Introduction",
|
||||
"body": "Welcome to Zen Browser! Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen Browser.",
|
||||
"summary": "We don't sell data - We don't collect data - We don't track you"
|
||||
},
|
||||
"noCollect": {
|
||||
"title": "1. Information We Do Not Collect",
|
||||
"body": "Zen Browser is designed with privacy in mind. We do not collect, store, or share any of your personal data. Here's what that means:"
|
||||
},
|
||||
"noTelemetry": {
|
||||
"title": "1.1. No Telemetry",
|
||||
"body": "We do not collect any telemetry data or crash reports.",
|
||||
"body2": "Zen Browser has stripped out telemetry built into Mozilla Firefox. We have removed all telemetry data collection and crash reports."
|
||||
},
|
||||
"noPersonalData": {
|
||||
"title": "1.2. No Personal Data Collection",
|
||||
"body": "Zen Browser does not collect any personal information such as your IP address, browsing history, search queries, or form data."
|
||||
},
|
||||
"noThirdParty": {
|
||||
"title": "1.3. No Third-Party Tracking",
|
||||
"body": "We do not allow third-party trackers or analytics tools to operate within Zen Browser. Your browsing activity remains entirely private and is not shared with any third party. Mozilla is not considered a third party as it is the base of Zen Browser."
|
||||
},
|
||||
"externalConnections": {
|
||||
"title": "1.4. External connections made at startup",
|
||||
"body": "Zen Browser may make external connections at startup to check for updates and ensure the browser is up to date on plugins, addons, check for connectivity and Geolocation/push notifications services in order to comply with web standards. We, at Zen, do not collect any data from these connections, but they may be logged by third-party services or websites you visit. These connections are necessary for the proper functioning of the browser and are not used for tracking or profiling purposes. They can be disabled through the browser flags (about:config)."
|
||||
},
|
||||
"localStorage": {
|
||||
"title": "2. Information Stored Locally on Your Device"
|
||||
},
|
||||
"browsingData": {
|
||||
"title": "2.1. Browsing Data",
|
||||
"body": "Zen Browser stores certain data locally on your device to enhance your browsing experience. This includes:"
|
||||
},
|
||||
"cookies": {
|
||||
"title": "Cookies",
|
||||
"body": "Cookies are stored locally on your device and are not shared with Zen Browser or any third party. You have full control over the management of cookies through the browser's settings."
|
||||
},
|
||||
"cache": {
|
||||
"title": "Cache and Temporary Files",
|
||||
"body": "Zen Browser may store cache files and other temporary data locally to improve performance. These files can be cleared at any time through the browser's settings."
|
||||
},
|
||||
"settings": {
|
||||
"title": "2.2. Settings and Preferences",
|
||||
"body": "Any customizations, settings, and preferences you make within Zen Browser are stored locally on your device. We do not have access to or control over this data."
|
||||
},
|
||||
"sync": {
|
||||
"title": "3. Sync Feature",
|
||||
"body": "Zen Browser offers a \"Sync\" feature, which is implemented using Mozilla Firefox's Sync feature. This feature allows you to synchronize your bookmarks, history, passwords, and other data across multiple devices. For this feature to work, your data is encrypted and stored on Mozilla's servers and is treated in accordance with their Privacy Policy. We, at Zen, cannot view any of this data.",
|
||||
"link1": "Mozilla Firefox Sync",
|
||||
"link2": "This is how we store your passwords"
|
||||
},
|
||||
"addons": {
|
||||
"title": "4. Add-ons and \"Mods\"",
|
||||
"body": "You can install Add-ons from addons.mozilla.org. Zen Browser periodically checks for updates to these Add-ons.\nYou can also install \"Mods\" from zen-browser.app/mods. These Mods are hosted by our services and follow the same privacy policy our website. We do not collect any data from these Mods, they are purely static content that is downloaded to your device."
|
||||
},
|
||||
"security": {
|
||||
"title": "5. Data Security",
|
||||
"body": "Although Zen Browser does not collect your data, we are committed to protecting the information that is stored locally on your device and, if you use the Sync feature, the encrypted data stored on Mozilla's servers. We recommend that you use secure passwords, enable device encryption, and regularly update your software to ensure your data remains safe.",
|
||||
"note": "Note that most of the security measures are taken care by Mozilla Firefox."
|
||||
},
|
||||
"control": {
|
||||
"title": "6. Your Control",
|
||||
"deletionTitle": "6.1. Data Deletion",
|
||||
"deletionBody": "You have full control over all data stored locally on your device by Zen Browser. You can clear your browsing data, cookies, and cache at any time using the browser's settings."
|
||||
},
|
||||
"website": {
|
||||
"title": "7. Our Website and Services",
|
||||
"body": "Zen Browser's website and services do not use any third-party analytics, tracking, or CDN services. We do not collect any personal information from users visiting our website. The website is hosted on Cloudflare but with analytics and tracking disabled, Cloudflare may collect some analytics data from HTTP requests in order to provide security and performance improvements. However, this data is not linked to any personal information and is not used for tracking purposes.",
|
||||
"externalLinksTitle": "7.1. External links",
|
||||
"externalLinksBody": "Zen Browser may contain links to external websites or services that are not owned or operated by us. We are not responsible for the content or privacy practices of these sites. We recommend that you review the privacy policies of these sites before providing them with any personal information."
|
||||
},
|
||||
"changes": {
|
||||
"title": "8. Changes to This Privacy Policy",
|
||||
"body": "We may update this Privacy Policy from time to time to reflect changes in our practices or legal requirements. We will notify you of any significant changes by updating the effective date at the top of this policy. Continued use of Zen Browser after such changes constitutes your acceptance of the new terms."
|
||||
},
|
||||
"otherTelemetry": {
|
||||
"title": "9. Other telemetry done by Mozilla Firefox",
|
||||
"body": "We try to disable all telemetry data collection in Zen Browser. But, we may have missed some. Check the below links for more information.",
|
||||
"firefoxPrivacyNotice": "Firefox Privacy Notice",
|
||||
"forMoreInformation": "for more information."
|
||||
},
|
||||
"contact": {
|
||||
"title": "10. Contact Us",
|
||||
"body": "If you have any questions or concerns about this Privacy Policy or Zen Browser, please contact us at:",
|
||||
"discord": "Discord: ",
|
||||
"discordLink": "Zen Browser's Discord",
|
||||
"github": "GitHub: ",
|
||||
"githubLink": "Organization"
|
||||
}
|
||||
}
|
||||
},
|
||||
"welcome": {
|
||||
"title": ["Welcome", "to", "Zen!"]
|
||||
},
|
||||
"whatsNew": {
|
||||
"title": "What's New in {latestVersion.version}!",
|
||||
"reportIssue": "Report an issue",
|
||||
"joinDiscord": "Join our Discord",
|
||||
"readFullReleaseNotes": "Read the full release notes"
|
||||
},
|
||||
"notFound": {
|
||||
"title": "Page Not Found",
|
||||
"description": "Sorry, the page you are looking for does not exist or has been moved.",
|
||||
"button": "Go Home"
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"index": {
|
||||
"title": "Zen Browser",
|
||||
"description": "Beautifully designed, privacy-focused, and packed with features."
|
||||
},
|
||||
"mods": {
|
||||
"title": "Zen Mods",
|
||||
"description": "Browse our diverse collection of Zen Mods, community-made plugins and themes for Zen Browser. Discover a theme to match every mood, and a plugin to fulfill every requirement. Start customizing your browser experience today!"
|
||||
},
|
||||
"releaseNotes": {
|
||||
"title": "Release notes - Zen",
|
||||
"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": {
|
||||
"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."
|
||||
},
|
||||
"donate": {
|
||||
"title": "Donate - Zen",
|
||||
"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."
|
||||
},
|
||||
"download": {
|
||||
"title": "Download - Zen",
|
||||
"description": "Download Zen Browser for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification."
|
||||
},
|
||||
"privacyPolicy": {
|
||||
"title": "Privacy Policy - Zen",
|
||||
"description": "Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen Browser."
|
||||
},
|
||||
"welcome": {
|
||||
"title": "Welcome!",
|
||||
"description": "Welcome to Zen!"
|
||||
},
|
||||
"whatsNew": {
|
||||
"title": "What's New in {latestVersion.version}!"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"footer": {
|
||||
"title": "Zen Browser",
|
||||
"description": "Beautifully designed, privacy-focused, and packed with features. We care about your experience, not your data.",
|
||||
"download": "Download",
|
||||
"followUs": "Follow Us",
|
||||
"aboutUs": "About Us",
|
||||
"teamAndContributors": "Team & Contributors",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"getStarted": "Get Started",
|
||||
"documentation": "Documentation",
|
||||
"zenMods": "Zen Mods",
|
||||
"releaseNotes": "Release Notes",
|
||||
"getHelp": "Get Help",
|
||||
"discord": "Discord",
|
||||
"uptimeStatus": "Uptime Status",
|
||||
"reportAnIssue": "Report an Issue",
|
||||
"twilight": "Twilight",
|
||||
"madeWith": "Made with <span aria-label='love'>❤️</span> by the <a href='{link}' class='zen-link inline-block font-bold'>Zen Team</a>"
|
||||
},
|
||||
"nav": {
|
||||
"brand": "Zen Browser",
|
||||
"menu": {
|
||||
"gettingStarted": "Getting Started",
|
||||
"usefulLinks": "Useful Links",
|
||||
"mods": "Mods",
|
||||
"download": "Download",
|
||||
"discord": "Discord",
|
||||
"releaseNotes": "Release Notes",
|
||||
"zenMods": "Zen Mods",
|
||||
"tryZenMods": "Try Zen Mods",
|
||||
"zenModsDesc": "Customize your browsing experience with Zen Mods.",
|
||||
"releaseNotesDesc": "Stay up to date with the latest features and improvements.",
|
||||
"discordDesc": "Join our community on Discord to chat with other Zen users!",
|
||||
"donate": "Donate ❤️",
|
||||
"donateDesc": "Support the development of Zen Browser with a donation.",
|
||||
"aboutUs": "About Us 🌟",
|
||||
"aboutUsDesc": "Learn more about the team behind Zen Browser.",
|
||||
"documentation": "Documentation",
|
||||
"documentationDesc": "Learn how to use Zen Browser with our documentation.",
|
||||
"github": "GitHub",
|
||||
"githubDesc": "Contribute to the development of Zen Browser on GitHub.",
|
||||
"menu": "Menu"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,23 @@
|
|||
---
|
||||
interface Props {
|
||||
title: string
|
||||
description?: string
|
||||
ogImage?: string
|
||||
isHome?: boolean
|
||||
redirect?: string
|
||||
title: string;
|
||||
description?: string;
|
||||
ogImage?: string;
|
||||
isHome?: boolean;
|
||||
redirect?: string;
|
||||
}
|
||||
|
||||
const { title, description, ogImage, isHome, redirect } = Astro.props
|
||||
const defaultDescription = 'Zen Browser is built for speed, security, and true privacy. Download now to enjoy a beautifully-designed, distraction-free web experience packed with features.';
|
||||
const defaultOgImage = '/share-pic.png';
|
||||
import '@fontsource/bricolage-grotesque/400.css'
|
||||
import '@fontsource/bricolage-grotesque/500.css'
|
||||
import '@fontsource/bricolage-grotesque/600.css'
|
||||
import NavBar from '../components/NavBar.astro'
|
||||
import Footer from '../components/Footer.astro'
|
||||
const { title, description, ogImage, isHome, redirect } = Astro.props;
|
||||
const defaultDescription =
|
||||
"Zen Browser is built for speed, security, and true privacy. Download now to enjoy a beautifully-designed, distraction-free web experience packed with features.";
|
||||
const defaultOgImage = "/share-pic.png";
|
||||
import "@fontsource/bricolage-grotesque/400.css";
|
||||
import "@fontsource/bricolage-grotesque/500.css";
|
||||
import "@fontsource/bricolage-grotesque/600.css";
|
||||
import Footer from "~/components/Footer.astro";
|
||||
import NavBar from "~/components/NavBar.astro";
|
||||
import { getLocale } from "~/utils/i18n";
|
||||
const locale = getLocale(Astro);
|
||||
---
|
||||
|
||||
<script is:inline data-cfasync="false">
|
||||
|
@ -37,7 +40,7 @@ import Footer from '../components/Footer.astro'
|
|||
</script>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang={locale}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
{redirect ? <meta http-equiv="refresh" content={`0;url=${redirect}`} /> : null}
|
||||
|
|
5
src/pages/404.astro
Normal file
5
src/pages/404.astro
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
import NotFound from './[...locale]/404.astro'
|
||||
---
|
||||
|
||||
<NotFound />
|
31
src/pages/[...locale]/404.astro
Normal file
31
src/pages/[...locale]/404.astro
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import Title from '~/components/Title.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
routes: { notFound },
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={notFound.title}>
|
||||
<main
|
||||
class="flex min-h-[70vh] flex-col items-center justify-center py-24 text-center"
|
||||
>
|
||||
<Title class="mb-4 text-7xl font-bold text-coral md:text-9xl">404</Title>
|
||||
<Description class="mb-6 text-xl md:text-2xl">
|
||||
{notFound.title}
|
||||
</Description>
|
||||
<p class="mb-8 max-w-xl text-lg text-gray-500 dark:text-gray-400">
|
||||
{notFound.description}
|
||||
</p>
|
||||
<Button href={getLocalePath('/')} isPrimary>
|
||||
{notFound.button}
|
||||
</Button>
|
||||
</main>
|
||||
</Layout>
|
82
src/pages/[...locale]/about.astro
Normal file
82
src/pages/[...locale]/about.astro
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
import Button from "~/components/Button.astro";
|
||||
import Description from "~/components/Description.astro";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
|
||||
const {
|
||||
routes: { about },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={layout.about.title}
|
||||
description={layout.about.description}
|
||||
>
|
||||
<main
|
||||
class="relative flex min-h-screen flex-col items-center justify-center py-24"
|
||||
>
|
||||
<div class="mb-24 p-4 text-center lg:w-1/2">
|
||||
<Description class="text-6xl font-bold">{about.title}</Description>
|
||||
<Description>
|
||||
{about.description}
|
||||
</Description>
|
||||
<Button href="/donate" class="mx-auto mt-4 w-fit" isPrimary
|
||||
>{about.littleHelp}</Button
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="relative flex w-full flex-col items-center justify-center lg:flex-row"
|
||||
>
|
||||
<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>
|
||||
{about.mainTeam.description}
|
||||
</Description>
|
||||
<div class="mt-4">
|
||||
<ul>
|
||||
{Object.entries(about.mainTeam.members).map(([_key, member]) => (
|
||||
<li class="text-sm">
|
||||
{member.link ? (
|
||||
<a href={member.link === true ? '' : member.link}>
|
||||
<strong class="zen-link font-bold">{member.name}</strong>
|
||||
</a>
|
||||
<span class="opacity-60"> : {member.description}</span>
|
||||
) : (
|
||||
<strong class="font-bold">{member.name}</strong>
|
||||
<span class="opacity-60"> : {member.description}</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute hidden h-full w-[1px] bg-dark opacity-15 lg:block">
|
||||
</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>
|
||||
{about.contributors.description}
|
||||
</Description>
|
||||
<a href="https://github.com/zen-browser/desktop/graphs/contributors"
|
||||
><img
|
||||
src="https://contributors-img.web.app/image?repo=zen-browser/desktop"
|
||||
alt="Contributors"
|
||||
class="mt-8"
|
||||
/></a
|
||||
>
|
||||
<a href="https://github.com/zen-browser/www/graphs/contributors"
|
||||
><img
|
||||
src="https://contributors-img.web.app/image?repo=zen-browser/www"
|
||||
alt="Contributors (website)"
|
||||
class="mt-8"
|
||||
/></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,32 +1,34 @@
|
|||
---
|
||||
import { ArrowRight, ChevronRight } from 'lucide-astro'
|
||||
import Button from '../components/Button.astro'
|
||||
import Description from '../components/Description.astro'
|
||||
import Title from '../components/Title.astro'
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
import { ArrowRight } from 'lucide-astro'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const {
|
||||
routes: { donate },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title="Donate - Zen Browser">
|
||||
<Layout title={layout.donate.title} description={layout.donate.description}>
|
||||
<main class="pb-52 pt-36">
|
||||
<div
|
||||
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"
|
||||
>Help us build <br class="hidden lg:block" />a better browser!</Description
|
||||
>
|
||||
<Description class="text-6xl font-bold">{donate.title}</Description>
|
||||
<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.
|
||||
{donate.description}
|
||||
</Description>
|
||||
</div>
|
||||
<div class="flex w-full flex-col items-center justify-center lg:flex-row">
|
||||
<div class="flex flex-col p-8 lg:w-1/3 lg:pr-24">
|
||||
<div class="text-6xl font-bold">Patreon</div>
|
||||
<div class="text-6xl font-bold">{donate.patreon.title}</div>
|
||||
<Description>
|
||||
Patreon allows you to support us with a monthly donation. You can
|
||||
choose the level of support that works best for you.
|
||||
{donate.patreon.description}
|
||||
</Description>
|
||||
<div class="mt-6">
|
||||
<Button
|
||||
|
@ -41,11 +43,9 @@ import Layout from '../layouts/Layout.astro'
|
|||
</div>
|
||||
<div class="hidden h-72 w-[1px] bg-dark opacity-15 lg:block"></div>
|
||||
<div class="flex flex-col p-8 lg:w-1/3 lg:pl-24">
|
||||
<div class="text-6xl font-bold">Ko-fi</div>
|
||||
<div class="text-6xl font-bold">{donate.koFi.title}</div>
|
||||
<Description>
|
||||
Ko-fi allows you to support us with a one-time donation. You can
|
||||
choose the amount that works best for you. Monthly donations are
|
||||
also available.
|
||||
{donate.koFi.description}
|
||||
</Description>
|
||||
<div class="mt-6">
|
||||
<Button
|
||||
|
@ -53,7 +53,7 @@ import Layout from '../layouts/Layout.astro'
|
|||
isPrimary
|
||||
class="w-fit"
|
||||
>
|
||||
Go to Ko-fi
|
||||
{donate.koFi.button}
|
||||
<ArrowRight class="size-4" />
|
||||
</Button>
|
||||
</div>
|
|
@ -1,20 +1,28 @@
|
|||
---
|
||||
import Description from '../components/Description.astro'
|
||||
import Title from '../components/Title.astro'
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
import { getReleasesWithChecksums } from '../components/download/release-data.astro'
|
||||
import PlatformDownload from '../components/download/PlatformDownload.astro'
|
||||
import DownloadScript from '../components/download/DownloadScript.astro'
|
||||
import { getChecksums } from '../utils/githubChecksums'
|
||||
import Description from '~/components/Description.astro'
|
||||
import DownloadScript from '~/components/download/DownloadScript.astro'
|
||||
import PlatformDownload from '~/components/download/PlatformDownload.astro'
|
||||
import { getReleasesWithChecksums } from '~/components/download/release-data.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getChecksums } from '~/utils/githubChecksums'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
import { library, icon } from '@fortawesome/fontawesome-svg-core'
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faWindows,
|
||||
faLinux,
|
||||
faApple,
|
||||
faGithub,
|
||||
faLinux,
|
||||
faWindows,
|
||||
} from '@fortawesome/free-brands-svg-icons'
|
||||
import { Lock, ExternalLink } from 'lucide-astro'
|
||||
import { ExternalLink, Lock } from 'lucide-astro'
|
||||
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const {
|
||||
routes: { download },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
|
||||
library.add(faWindows, faLinux, faApple, faGithub)
|
||||
const windowsIcon = icon({ prefix: 'fab', iconName: 'windows' })
|
||||
|
@ -24,21 +32,22 @@ const githubIcon = icon({ prefix: 'fab', iconName: 'github' })
|
|||
|
||||
const checksums = await getChecksums()
|
||||
const releases = getReleasesWithChecksums(checksums)
|
||||
|
||||
const platformNames = download.platformNames
|
||||
const platformDescriptions = download.platformDescriptions
|
||||
---
|
||||
|
||||
<DownloadScript />
|
||||
|
||||
<Layout title="Download Zen">
|
||||
<main class="flex min-h-screen flex-col px-2 data-[os='windows']:bg-zen-blue">
|
||||
<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">
|
||||
<div class="container relative mx-auto max-w-5xl py-12">
|
||||
<div class="mb-6 mt-12 flex flex-col gap-4">
|
||||
<Description id="download-title" class="text-6xl font-bold"
|
||||
>Download Zen</Description
|
||||
>{download.title}</Description
|
||||
>
|
||||
<Description class="max-w-xl text-pretty">
|
||||
Download Zen Browser for your platform and experience a more mindful
|
||||
internet browsing experience. All downloads include SHA256 checksums
|
||||
for verification.
|
||||
{download.description}
|
||||
</Description>
|
||||
<div
|
||||
id="twilight-info"
|
||||
|
@ -58,11 +67,7 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
<line x1="12" y1="8" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
||||
</svg>
|
||||
<Description>
|
||||
<strong class="font-medium text-zen-blue">Twilight Mode:</strong> You're
|
||||
currently in Twilight mode, this means you're downloading the latest
|
||||
experimental features and updates.
|
||||
</Description>
|
||||
<Description set:html={download.alertInfo.description} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -77,7 +82,7 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<Fragment set:html={appleIcon.html} />
|
||||
<span>macOS</span>
|
||||
<span>{platformNames.mac}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
|
@ -86,7 +91,7 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<Fragment set:html={windowsIcon.html} />
|
||||
<span>Windows</span>
|
||||
<span>{platformNames.windows}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
|
@ -95,7 +100,7 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<Fragment set:html={linuxIcon.html} />
|
||||
<span>Linux</span>
|
||||
<span>{platformNames.linux}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -109,16 +114,16 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
<PlatformDownload
|
||||
platform="mac"
|
||||
icon={appleIcon.html}
|
||||
title="MacOS Download"
|
||||
description="Works on both new Apple (M-Series) and older Intel Macs.<br />Requires macOS 11.0 or later."
|
||||
title={platformNames.macDownload}
|
||||
description={platformDescriptions.mac}
|
||||
releases={releases.macos}
|
||||
/>
|
||||
<!-- Windows Download -->
|
||||
<PlatformDownload
|
||||
platform="windows"
|
||||
icon={windowsIcon.html}
|
||||
title="Windows Download"
|
||||
description="Works on Windows 10 and Windows 11.<br />Not sure which version to get? Most people should choose the 64-bit installer."
|
||||
title={platformNames.windowsDownload}
|
||||
description={platformDescriptions.windows}
|
||||
releases={releases.windows}
|
||||
/>
|
||||
|
||||
|
@ -126,16 +131,16 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
<PlatformDownload
|
||||
platform="linux"
|
||||
icon={linuxIcon.html}
|
||||
title="Linux Download"
|
||||
description="Works with many Linux versions.<br />Pick the download that matches your system."
|
||||
title={platformNames.linuxDownload}
|
||||
description={platformDescriptions.linux}
|
||||
releases={releases.linux}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Additional resources -->
|
||||
<section class="mb-16">
|
||||
<h2 class="mb-4 text-3xl font-bold font-medium">
|
||||
Additional Resources
|
||||
<h2 class="mb-4 text-3xl font-semibold">
|
||||
{download.additionalResources.title}
|
||||
</h2>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
|
@ -145,10 +150,11 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
>
|
||||
<div class="flex items-start justify-between">
|
||||
<div>
|
||||
<h3 class="mb-2 text-xl font-medium">Source Code</h3>
|
||||
<h3 class="mb-2 text-xl font-medium">
|
||||
{download.additionalResources.sourceCode.title}
|
||||
</h3>
|
||||
<p class="text-muted-foreground">
|
||||
Explore Zen Browser's source code on GitHub. Contribute to the
|
||||
project or build your own version.
|
||||
{download.additionalResources.sourceCode.description}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
|
@ -169,10 +175,11 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
>
|
||||
<div class="flex items-start justify-between">
|
||||
<div>
|
||||
<h3 class="mb-2 text-xl font-medium">Documentation</h3>
|
||||
<h3 class="mb-2 text-xl font-medium">
|
||||
{download.additionalResources.documentation.title}
|
||||
</h3>
|
||||
<p class="text-muted-foreground">
|
||||
Access comprehensive documentation, guides, and tutorials for
|
||||
Zen Browser.
|
||||
{download.additionalResources.documentation.description}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
|
@ -196,17 +203,13 @@ const releases = getReleasesWithChecksums(checksums)
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="mb-2 text-lg font-medium">Verified & Secure Downloads</h3>
|
||||
<p class="text-muted-foreground">
|
||||
All Zen downloads are signed and verified for your security. We
|
||||
recommend downloading directly from our official website or GitHub
|
||||
repository. If your download seems broken or gets flagged by your
|
||||
antivirus, please
|
||||
<a
|
||||
href="https://github.com/zen-browser/desktop/issues/new/choose"
|
||||
class="text-accent zen-link ml-1">report it to us</a
|
||||
>.
|
||||
</p>
|
||||
<h3 class="mb-2 text-lg font-medium">
|
||||
{download.securityNotice.title}
|
||||
</h3>
|
||||
<p
|
||||
class="text-muted-foreground"
|
||||
set:html={download.securityNotice.description}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,6 +1,7 @@
|
|||
import rss, { type RSSOptions } from '@astrojs/rss'
|
||||
import { releaseNotes } from '../release-notes'
|
||||
import type { ReleaseNote } from '../release-notes'
|
||||
import { releaseNotes } from '~/release-notes'
|
||||
import type { ReleaseNote } from '~/release-notes'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
/** The default number of entries to include in the RSS feed. */
|
||||
const RSS_ENTRY_LIMIT = 20
|
||||
|
@ -73,14 +74,14 @@ function formatRssDate(dateStr: string) {
|
|||
*/
|
||||
function formatReleaseNote(releaseNote: ReleaseNote) {
|
||||
let content = `<p>
|
||||
If you encounter any issues, please report them on <a href="https://github.com/zen-browser/desktop/issues/">the issues page</a>.
|
||||
If you encounter any issues, please report them on <a href="https://github.com/zen-browser/desktop/issues/">the issues page</a>.
|
||||
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"
|
||||
alt="Release Image for version ${releaseNote.version}"
|
||||
style="max-width: 30em; width: 100%; border-radius: 0.5rem;"
|
||||
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;"
|
||||
/>`
|
||||
}
|
||||
|
41
src/pages/[...locale]/index.astro
Normal file
41
src/pages/[...locale]/index.astro
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import Community from '~/components/Community.astro'
|
||||
import Features from '~/components/Features.astro'
|
||||
import Hero from '~/components/Hero.astro'
|
||||
import Sponsors from '~/components/Sponsors.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const { layout } = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={layout.index.title}
|
||||
description={layout.index.description}
|
||||
isHome
|
||||
>
|
||||
<main>
|
||||
<Hero />
|
||||
<Features />
|
||||
<Sponsors showSponsors />
|
||||
<Community />
|
||||
</main>
|
||||
</Layout>
|
||||
<style>
|
||||
@keyframes headerSlideIn {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
#header-browser-image {
|
||||
animation: headerSlideIn 0.5s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
<script></script>
|
|
@ -1,19 +1,37 @@
|
|||
---
|
||||
import { getAbsoluteLocaleUrl } from 'astro:i18n'
|
||||
import { getAllMods, getAuthorLink, getLocalizedDate } from '../../mods'
|
||||
import Layout from '../../layouts/Layout.astro'
|
||||
import Title from '../../components/Title.astro'
|
||||
import Description from '../../components/Description.astro'
|
||||
import Button from '../../components/Button.astro'
|
||||
import BackButton from '../../components/BackButton.astro'
|
||||
import { ArrowRight, Info } from 'lucide-astro'
|
||||
import BackButton from '~/components/BackButton.astro'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getAllMods, getAuthorLink, getLocalizedDate } from '~/mods'
|
||||
import { getUI } from '~/utils/i18n'
|
||||
import { getLocale, getOtherLocales } from '~/utils/i18n'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const mods = await getAllMods()
|
||||
return mods.map((mod) => ({
|
||||
params: { slug: mod.id },
|
||||
props: { ...mod },
|
||||
}))
|
||||
return mods.flatMap((mod) => [
|
||||
...getOtherLocales().map((locale) => ({
|
||||
params: {
|
||||
slug: mod.id,
|
||||
locale: locale,
|
||||
},
|
||||
props: {
|
||||
...mod,
|
||||
locale: locale,
|
||||
},
|
||||
})),
|
||||
{
|
||||
params: {
|
||||
slug: mod.id,
|
||||
locale: undefined,
|
||||
},
|
||||
props: {
|
||||
...mod,
|
||||
locale: undefined,
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/TeaClientMC/Website/blob/7faacc9f8b2c79c74f711d413b155c84faafc00d/src/pages/news/%5B...slug%5D.astro
|
||||
|
@ -24,11 +42,19 @@ const dates = {
|
|||
createdAt: getLocalizedDate(mod.createdAt),
|
||||
updatedAt: getLocalizedDate(mod.updatedAt),
|
||||
}
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
mods: { slug },
|
||||
},
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={`${mod.name} - Zen Mods`}
|
||||
description={`Learn more about ${mod.name} mod available on Zen Browser`}
|
||||
title={slug.title.replace('{name}', mod.name)}
|
||||
description={slug.description.replace('{name}', mod.name)}
|
||||
ogImage={mod.image}
|
||||
>
|
||||
<main class="mt-6 2xl:mt-0">
|
||||
|
@ -40,7 +66,7 @@ const dates = {
|
|||
<div class="flex items-center gap-2 text-center md:text-left">
|
||||
<Info />
|
||||
<p class="text-sm">
|
||||
You need to have Zen Browser installed to install this theme.{' '}
|
||||
{slug.alert.description}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
|
@ -48,7 +74,7 @@ const dates = {
|
|||
class="inline-flex flex-shrink-0 whitespace-nowrap !rounded-lg bg-red-300 dark:bg-red-800"
|
||||
isAlert
|
||||
>
|
||||
Download now!
|
||||
{slug.alert.button}
|
||||
<ArrowRight class="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -64,18 +90,23 @@ const dates = {
|
|||
/>
|
||||
<div class="flex flex-col justify-between gap-2 sm:flex-row">
|
||||
<div class="flex flex-shrink-0 flex-col gap-2 font-normal">
|
||||
<p>
|
||||
Created by <a
|
||||
href={getAuthorLink(mod.author)}
|
||||
class="zen-link font-bold">@{mod.author}</a
|
||||
> • <span class="font-bold">v{mod.version}</span>
|
||||
</p>
|
||||
<p>Creation date • <b>{dates.createdAt}</b></p>
|
||||
<p
|
||||
set:html={slug.createdBy
|
||||
.replace('{author}', mod.author)
|
||||
.replace('{version}', mod.version)
|
||||
.replace('{link}', getAuthorLink(mod.author))}
|
||||
/>
|
||||
<p
|
||||
set:html={slug.creationDate.replace('{createdAt}', dates.createdAt)}
|
||||
/>
|
||||
{
|
||||
dates.createdAt !== dates.updatedAt && (
|
||||
<p>
|
||||
Latest update • <b>{dates.updatedAt}</b>
|
||||
</p>
|
||||
<p
|
||||
set:html={slug.latestUpdate.replace(
|
||||
'{updatedAt}',
|
||||
dates.updatedAt,
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
|
@ -86,7 +117,7 @@ const dates = {
|
|||
rel="noopener noreferrer"
|
||||
class="zen-link"
|
||||
>
|
||||
Visit mod homepage
|
||||
{slug.visitModHomepage}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
@ -98,7 +129,7 @@ const dates = {
|
|||
extra={{ 'zen-theme-id': mod.id }}
|
||||
isPrimary
|
||||
>
|
||||
Install Theme 🎉
|
||||
{slug.installMod}
|
||||
</Button>
|
||||
<Button
|
||||
class="hidden"
|
||||
|
@ -106,11 +137,11 @@ const dates = {
|
|||
extra={{ 'zen-theme-id': mod.id }}
|
||||
isPrimary
|
||||
>
|
||||
Uninstall Theme
|
||||
{slug.uninstallMod}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO: Readme markdown
|
||||
<!-- TODO: Readme markdown
|
||||
<div class="h-[1px] opacity-80 bg-dark w-full"></div>
|
||||
-->
|
||||
</div>
|
40
src/pages/[...locale]/mods/index.astro
Normal file
40
src/pages/[...locale]/mods/index.astro
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
import Description from '~/components/Description.astro'
|
||||
import ModsList from '~/components/ModsList'
|
||||
import { CONSTANT } from '~/constants'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getAllMods } from '~/mods'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { mods },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
|
||||
const allMods = (await getAllMods()) || []
|
||||
---
|
||||
|
||||
<Layout title={layout.mods.title}>
|
||||
<main class="mx-auto mt-32 max-w-[120rem] 2xl:mt-0">
|
||||
<header class="mb-10 mt-32 flex w-full flex-col justify-center border-dark">
|
||||
<div class="mx-auto flex flex-col gap-6 px-8 lg:w-1/2">
|
||||
<div>
|
||||
<Description class="text-6xl font-bold">{mods.title}</Description>
|
||||
<Description>
|
||||
{mods.description}
|
||||
</Description>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Importing ModList component -->
|
||||
<ModsList
|
||||
allMods={allMods}
|
||||
locale={locale ?? CONSTANT.I18N.DEFAULT_LOCALE}
|
||||
client:load
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
201
src/pages/[...locale]/privacy-policy.astro
Normal file
201
src/pages/[...locale]/privacy-policy.astro
Normal file
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
import Title from '~/components/Title.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { privacyPolicy },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={layout.privacyPolicy.title}
|
||||
description={layout.privacyPolicy.description}
|
||||
>
|
||||
<main class="mx-auto mt-52 w-1/2 pb-24">
|
||||
<Title id="privacy-policy">{privacyPolicy.title}</Title>
|
||||
<div class="ml-4 font-bold">{privacyPolicy.lastUpdated}</div>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="introduction">
|
||||
{privacyPolicy.sections.introduction.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.introduction.body}</p>
|
||||
<div class="mx-12 my-12 flex gap-4 font-bold">
|
||||
{privacyPolicy.sections.introduction.summary}
|
||||
</div>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="1-information-we-do-not-collect"
|
||||
>
|
||||
{privacyPolicy.sections.noCollect.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.noCollect.body}</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-1-no-telemetry-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.noTelemetry.title}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.noTelemetry.body}</p>
|
||||
<p>{privacyPolicy.sections.noTelemetry.body2}</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-2-no-personal-data-collection-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.noPersonalData.title}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.noPersonalData.body}</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-4-no-third-party-tracking-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.noThirdParty.title}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.noThirdParty.body}</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-3-no-third-party-tracking-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.externalConnections.title}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.externalConnections.body}</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="2-information-stored-locally-on-your-device"
|
||||
>
|
||||
{privacyPolicy.sections.localStorage.title}
|
||||
</Title>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-2-1-browsing-data-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.browsingData.title}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.browsingData.body}</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong class="font-bold">{privacyPolicy.sections.cookies.title}</strong
|
||||
>: {privacyPolicy.sections.cookies.body}
|
||||
</li>
|
||||
<li>
|
||||
<strong class="font-bold">{privacyPolicy.sections.cache.title}</strong>: {
|
||||
privacyPolicy.sections.cache.body
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-2-2-settings-and-preferences-">
|
||||
<strong class="font-bold">{privacyPolicy.sections.settings.title}</strong>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.settings.body}</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="3-sync-feature">
|
||||
{privacyPolicy.sections.sync.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.sync.body}</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
class="zen-link"
|
||||
href="https://www.mozilla.org/en-US/privacy/mozilla-accounts/"
|
||||
>{privacyPolicy.sections.sync.link1}</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="zen-link"
|
||||
href="https://support.mozilla.org/en-US/kb/how-firefox-securely-saves-passwords#:~:text=Firefox%20Desktop%20encrypts%20your%20passwords,cryptography%20to%20obscure%20your%20passwords."
|
||||
>{privacyPolicy.sections.sync.link2}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="4-add-ons-and-mods">
|
||||
{privacyPolicy.sections.addons.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.addons.body}</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="5-data-security">
|
||||
{privacyPolicy.sections.security.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.security.body}</p>
|
||||
<ul>
|
||||
<li>{privacyPolicy.sections.security.note}</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="6-your-control">
|
||||
{privacyPolicy.sections.control.title}
|
||||
</Title>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-6-1-data-deletion-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.control.deletionTitle}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.control.deletionBody}</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="7-our-website-and-services">
|
||||
{privacyPolicy.sections.website.title}
|
||||
</Title>
|
||||
<p>{privacyPolicy.sections.website.body}</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-7-1-external-links-">
|
||||
<strong class="font-bold"
|
||||
>{privacyPolicy.sections.website.externalLinksTitle}</strong
|
||||
>
|
||||
</h3>
|
||||
<p>{privacyPolicy.sections.website.externalLinksBody}</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="8-changes-to-this-privacy-policy"
|
||||
>
|
||||
{privacyPolicy.sections.changes.title}
|
||||
</Title>
|
||||
<p>
|
||||
{privacyPolicy.sections.changes.body}
|
||||
</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="9-other-telemetry-done-by-mozilla-firefox"
|
||||
>
|
||||
{privacyPolicy.sections.otherTelemetry.title}
|
||||
</Title>
|
||||
<p>
|
||||
{privacyPolicy.sections.otherTelemetry.body}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Please check <a
|
||||
class="zen-link"
|
||||
href="https://www.mozilla.org/en-US/privacy/"
|
||||
>{privacyPolicy.sections.otherTelemetry.firefoxPrivacyNotice}</a
|
||||
>
|
||||
{privacyPolicy.sections.otherTelemetry.forMoreInformation}
|
||||
</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="10-contact-us">
|
||||
{privacyPolicy.sections.contact.title}
|
||||
</Title>
|
||||
<p>
|
||||
{privacyPolicy.sections.contact.body}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
{privacyPolicy.sections.contact.discord}
|
||||
<a class="zen-link" href="https://discord.gg/zen-browser">
|
||||
{privacyPolicy.sections.contact.discordLink}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{privacyPolicy.sections.contact.github}
|
||||
<a class="zen-link" href="https://github.com/zen-browser">
|
||||
{privacyPolicy.sections.contact.githubLink}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
</Layout>
|
||||
<style>
|
||||
p,
|
||||
li {
|
||||
@apply opacity-55;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply ml-4 list-disc;
|
||||
}
|
||||
</style>
|
36
src/pages/[...locale]/release-notes/[...slug].astro
Normal file
36
src/pages/[...locale]/release-notes/[...slug].astro
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { releaseNotes } from '~/release-notes'
|
||||
import { getStaticPaths as getI18nPaths, getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
releaseNotes: { slug },
|
||||
},
|
||||
} = getUI(locale)
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const i18nPaths = getI18nPaths()
|
||||
|
||||
return i18nPaths.flatMap(({ params: { locale } }) => [
|
||||
...releaseNotes.map((release: any) => ({
|
||||
params: { slug: release.version, locale },
|
||||
props: { ...release },
|
||||
})),
|
||||
{
|
||||
params: { slug: 'latest', locale },
|
||||
props: { ...releaseNotes[0] },
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
const release = Astro.props
|
||||
---
|
||||
|
||||
<Layout title={slug.title} redirect={`/release-notes#${release.version}`}>
|
||||
<main class="flex flex-col items-center pb-52 pt-36">
|
||||
{slug.redirect.replaceAll('{version}', release.version)}
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,14 +1,26 @@
|
|||
---
|
||||
import Layout from '../../layouts/Layout.astro'
|
||||
import ReleaseNoteItem from '../../components/ReleaseNoteItem.astro'
|
||||
import { releaseNotes, releaseNotesTwilight } from '../../release-notes'
|
||||
import Description from '../../components/Description.astro'
|
||||
import Button from '../../components/Button.astro'
|
||||
import { Modal, ModalBody, ModalHeader } from 'free-astro-components'
|
||||
import { ArrowUp } from 'lucide-astro'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import ReleaseNoteItem from '~/components/ReleaseNoteItem.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import {
|
||||
releaseNotes as releaseNotesData,
|
||||
releaseNotesTwilight,
|
||||
} from '~/release-notes'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { releaseNotes },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title="Release Notes - Zen Browser">
|
||||
<Layout title={layout.releaseNotes.title}>
|
||||
<main
|
||||
class="flex h-full min-h-[1000px] flex-1 flex-col items-center justify-center py-4"
|
||||
>
|
||||
|
@ -17,26 +29,24 @@ import { ArrowUp } from 'lucide-astro'
|
|||
class="py-42 flex min-h-screen flex-col justify-center px-10 lg:px-10 xl:px-10 2xl:w-3/5"
|
||||
>
|
||||
<Description class="mt-48 text-4xl font-bold">Release Notes</Description>
|
||||
<p class="text-base opacity-55">
|
||||
Stay up to date with the latest changes to Zen Browser! Since the <a
|
||||
class="zen-link"
|
||||
href="#1.0.0-a.1">first release</a
|
||||
> till <a class="zen-link" href={`#${releaseNotes[0].version}`}
|
||||
>{releaseNotes[0].version}</a
|
||||
>, we've been working hard to make Zen Browser the best it can be.
|
||||
Thanks everyone for your feedback! ❤️
|
||||
</p>
|
||||
<p
|
||||
class="text-base opacity-55"
|
||||
set:html={releaseNotes.topSection.description.replaceAll(
|
||||
'{latestVersion}',
|
||||
releaseNotesData[0].version,
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
class="mx-auto mt-8 flex w-fit flex-col gap-4 sm:mr-0 sm:flex-row sm:items-center"
|
||||
>
|
||||
<Button class="flex" isPrimary href="/donate">
|
||||
Give us some support!
|
||||
{releaseNotes.list.support}
|
||||
</Button>
|
||||
<Button id="toggle-notes" class="flex" data-open="false" href="#">
|
||||
Expand all
|
||||
{releaseNotes.list.expandAll}
|
||||
</Button>
|
||||
<Button id="navigate-to-version" href="#" class="flex">
|
||||
Navigate to version...
|
||||
{releaseNotes.list.navigateToVersion}
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
|
@ -45,29 +55,25 @@ import { ArrowUp } from 'lucide-astro'
|
|||
<ReleaseNoteItem {...releaseNotesTwilight} isTwilight />
|
||||
) : null
|
||||
}
|
||||
{releaseNotes.map((notes: any) => <ReleaseNoteItem {...notes} />)}
|
||||
{releaseNotesData.map((notes: any) => <ReleaseNoteItem {...notes} />)}
|
||||
</div>
|
||||
</main>
|
||||
<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">
|
||||
Back to the top <ArrowUp aria-hidden="true" class="size-4" />
|
||||
{releaseNotes.backToTop}
|
||||
<ArrowUp aria-hidden="true" class="size-4" />
|
||||
</p>
|
||||
<ArrowUp aria-label="Back to the top" class="size-4 sm:hidden" />
|
||||
</Button>
|
||||
</Layout>
|
||||
<Modal id="version-modal" class="m-auto border border-[--zen-dark] !bg-paper">
|
||||
<ModalHeader class="border-b border-[--zen-dark]">
|
||||
<p class="text-4xl font-bold text-dark">Choose version</p>
|
||||
<p class="text-4xl font-bold text-dark">{releaseNotes.chooseVersion}</p>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<div id="version-list" class="flex flex-col gap-2 text-xl text-dark">
|
||||
{
|
||||
releaseNotes.map((note) => (
|
||||
releaseNotesData.map((note) => (
|
||||
<button
|
||||
aria-label={`Navigate to version ${note.version}`}
|
||||
class="w-full text-left transition-colors duration-150 hover:text-coral"
|
25
src/pages/[...locale]/welcome.astro
Normal file
25
src/pages/[...locale]/welcome.astro
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import Features from '~/components/Features.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { welcome },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={layout.welcome.title} description={layout.welcome.description}>
|
||||
<main
|
||||
class="relative mx-auto flex flex-col items-center gap-24 px-6 lg:gap-0 lg:px-24"
|
||||
>
|
||||
<Features
|
||||
title1={welcome.title[0]}
|
||||
title2={welcome.title[1]}
|
||||
title3={welcome.title[2]}
|
||||
/>
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,18 +1,26 @@
|
|||
---
|
||||
import { ArrowRight } from 'lucide-astro'
|
||||
import Button from '../components/Button.astro'
|
||||
import Description from '../components/Description.astro'
|
||||
import SocialMediaStrip from '../components/SocialMediaStrip.astro'
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
import Button from '~/components/Button.astro'
|
||||
import Description from '~/components/Description.astro'
|
||||
import SocialMediaStrip from '~/components/SocialMediaStrip.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
|
||||
import { releaseNotes } from '../release-notes'
|
||||
import whatsNewText from '../release-notes/whats-new.json'
|
||||
import Video from '../components/Video.astro'
|
||||
|
||||
import whatsNewVideo from '../assets/whats-new.mp4'
|
||||
import whatsNewVideo from '~/assets/whats-new.mp4'
|
||||
import Video from '~/components/Video.astro'
|
||||
import { releaseNotes } from '~/release-notes'
|
||||
import whatsNewText from '~/release-notes/whats-new.json'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const latestVersion = releaseNotes[0]
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { whatsNew },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
|
||||
// Just redirect to the release notes if we are in a patch version
|
||||
if (
|
||||
latestVersion.version.split('.').length > 2 &&
|
||||
|
@ -22,14 +30,24 @@ if (
|
|||
}
|
||||
---
|
||||
|
||||
<Layout title="What's New - Zen Browser">
|
||||
<Layout
|
||||
title={layout.whatsNew.title.replace(
|
||||
'{latestVersion.version}',
|
||||
latestVersion.version,
|
||||
)}
|
||||
>
|
||||
<main
|
||||
class="relative mx-auto flex flex-col items-center gap-24 px-6 pb-52 pt-36 lg:px-24 xl:flex-row"
|
||||
>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div>
|
||||
<Description class="text-5xl font-bold md:text-6xl"
|
||||
>What's New in {latestVersion.version}!</Description
|
||||
>{
|
||||
whatsNew.title.replace(
|
||||
'{latestVersion.version}',
|
||||
latestVersion.version,
|
||||
)
|
||||
}</Description
|
||||
>
|
||||
<Description>{latestVersion.date}</Description>
|
||||
</div>
|
||||
|
@ -43,14 +61,14 @@ if (
|
|||
>
|
||||
<li class="ml-3 list-disc">
|
||||
<Description class="text-base font-bold"
|
||||
>Report an issue</Description
|
||||
>{whatsNew.reportIssue}</Description
|
||||
>
|
||||
</li>
|
||||
</a>
|
||||
<a href="https://discord.gg/zen-browser" target="_blank">
|
||||
<li class="ml-3 list-disc">
|
||||
<Description class="text-base font-bold"
|
||||
>Join our Discord</Description
|
||||
>{whatsNew.joinDiscord}</Description
|
||||
>
|
||||
</li>
|
||||
</a>
|
||||
|
@ -61,7 +79,7 @@ if (
|
|||
isPrimary
|
||||
class="flex w-fit items-center gap-2"
|
||||
>
|
||||
<span>Read the full release notes</span>
|
||||
<span>{whatsNew.readFullReleaseNotes}</span>
|
||||
<ArrowRight />
|
||||
</Button>
|
||||
<SocialMediaStrip gap="6" />
|
|
@ -1,142 +0,0 @@
|
|||
---
|
||||
import Button from '../components/Button.astro'
|
||||
import Description from '../components/Description.astro'
|
||||
import Title from '../components/Title.astro'
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="About - Zen Browser"
|
||||
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."
|
||||
>
|
||||
<main
|
||||
class="relative flex min-h-screen flex-col items-center justify-center py-24"
|
||||
>
|
||||
<div class="mb-24 p-4 text-center lg:w-1/2">
|
||||
<Description class="text-6xl font-bold">About Us</Description>
|
||||
<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>
|
||||
<Button href="/donate" class="mx-auto mt-4 w-fit" isPrimary
|
||||
>A little help?</Button
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="relative flex w-full flex-col items-center justify-center lg:flex-row"
|
||||
>
|
||||
<div class="flex flex-col p-8 lg:w-1/3 lg:pr-24">
|
||||
<div class="text-4xl font-bold lg:text-6xl">Main Team</div>
|
||||
<Description>
|
||||
This list shows the main team members who are working hard to bring
|
||||
you the best browsing experience.
|
||||
</Description>
|
||||
<div class="mt-4">
|
||||
<ul>
|
||||
<li class="text-sm">
|
||||
<a href="https://cheff.dev/"
|
||||
><strong class="zen-link font-bold">Mauro B.</strong></a
|
||||
><span class="opacity-60"> : Creator, Main Developer</span>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<strong class="font-bold">Oscar Gonzalez</strong><span
|
||||
class="opacity-60"
|
||||
>
|
||||
: Site Reliability Engineer (SRE) and code signing.</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://janheres.eu/"
|
||||
><strong class="zen-link font-bold">Jan Heres</strong></a
|
||||
><span class="opacity-60">
|
||||
: Active contributor and helps with MacOS builds</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://github.com/BrhmDev"
|
||||
><strong class="zen-link font-bold">BrhmDev</strong></a
|
||||
><span class="opacity-60">
|
||||
: Active contributor with great contributions</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://thatcanoa.org/"
|
||||
><strong class="zen-link font-bold">Canoa</strong></a
|
||||
><span class="opacity-60">
|
||||
: Active contributor, and very active in issue handling and
|
||||
website management</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://cybrneon.xyz/"
|
||||
><strong class="zen-link font-bold">Adam</strong></a
|
||||
><span class="opacity-60"> : Branding and design</span>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://github.com/kristijanribaric"
|
||||
><strong class="zen-link font-bold">kristijanribaric</strong></a
|
||||
><span class="opacity-60"> : Active contributor</span>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://github.com/n7itro"
|
||||
><strong class="zen-link font-bold">n7itro</strong></a
|
||||
><span class="opacity-60">
|
||||
: Active contributor and release notes writer</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://josuegalre.netlify.app/"
|
||||
><strong class="zen-link font-bold">Bryan Galdámez</strong></a
|
||||
><span class="opacity-60">
|
||||
: Huge contributor on theme functionalities</span
|
||||
>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://iamjafeth.com/"
|
||||
><strong class="zen-link font-bold">Jafeth Garro</strong></a
|
||||
><span class="opacity-60"> : Documentation writer</span>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<a href="https://github.com/LarveyOfficial/"
|
||||
><strong class="zen-link font-bold">Larvey</strong></a
|
||||
><span class="opacity-60"> : AUR maintainer</span>
|
||||
</li>
|
||||
<li class="mt-2 text-sm">
|
||||
<strong class="font-bold">Daniel García</strong><span
|
||||
class="opacity-60"
|
||||
>
|
||||
: MacOS certificate and app notarization maintainer</span
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute hidden h-full w-[1px] bg-dark opacity-15 lg:block">
|
||||
</div>
|
||||
<div class="flex flex-col p-8 lg:w-1/3 lg:pl-24">
|
||||
<div class="text-4xl font-bold lg:text-6xl">Contributors</div>
|
||||
<Description>
|
||||
Here are all the wonderful people that decided to contribute to the
|
||||
project! The first set of images are from the desktop repository, and
|
||||
the second set is from the website repository.
|
||||
</Description>
|
||||
<a href="https://github.com/zen-browser/desktop/graphs/contributors"
|
||||
><img
|
||||
src="https://contributors-img.web.app/image?repo=zen-browser/desktop"
|
||||
alt="Contributors"
|
||||
class="mt-8"
|
||||
/></a
|
||||
>
|
||||
<a href="https://github.com/zen-browser/www/graphs/contributors"
|
||||
><img
|
||||
src="https://contributors-img.web.app/image?repo=zen-browser/www"
|
||||
alt="Contributors (website)"
|
||||
class="mt-8"
|
||||
/></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
import Hero from '../components/Hero.astro'
|
||||
import Community from '../components/Community.astro'
|
||||
import Features from '../components/Features.astro'
|
||||
import Sponsors from '../components/Sponsors.astro'
|
||||
---
|
||||
|
||||
<Layout title="Zen Browser" isHome>
|
||||
<main>
|
||||
<Hero />
|
||||
<Features />
|
||||
<Sponsors showSponsors />
|
||||
<Community />
|
||||
</main>
|
||||
</Layout>
|
||||
<style>
|
||||
@keyframes headerSlideIn {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
#header-browser-image {
|
||||
animation: headerSlideIn 0.5s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
<script></script>
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
import Description from '../../components/Description.astro'
|
||||
import Title from '../../components/Title.astro'
|
||||
import Layout from '../../layouts/Layout.astro'
|
||||
import ModsList from '../../components/ModsList'
|
||||
import { getAllMods } from '../../mods'
|
||||
|
||||
const mods = (await getAllMods()) || []
|
||||
---
|
||||
|
||||
<Layout title="Zen Mods">
|
||||
<main class="mx-auto mt-32 max-w-[120rem] 2xl:mt-0">
|
||||
<header class="mb-10 mt-32 flex w-full flex-col justify-center border-dark">
|
||||
<div class="mx-auto flex flex-col gap-6 px-8 lg:w-1/2">
|
||||
<div>
|
||||
<Description class="text-6xl font-bold">Zen Mods</Description>
|
||||
<Description>
|
||||
Browse our diverse collection of Zen Mods, community-made plugins
|
||||
and themes for Zen Browser. Discover a theme to match every mood,
|
||||
and a plugin to fulfill every requirement. Start customizing your
|
||||
browser experience today!
|
||||
</Description>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Importing ModList component -->
|
||||
<ModsList mods={mods} client:load />
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,256 +0,0 @@
|
|||
---
|
||||
import Title from '../components/Title.astro'
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
---
|
||||
|
||||
<Layout title="Privacy Policy - Zen">
|
||||
<main class="mx-auto mt-52 w-1/2 pb-24">
|
||||
<Title id="privacy-policy">Privacy Policy</Title>
|
||||
<div class="ml-4 font-bold">Last updated: 2025-02-5</div>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="introduction"
|
||||
>Introduction</Title
|
||||
>
|
||||
<p>
|
||||
Welcome to Zen Browser! Your privacy is our priority. This Privacy Policy
|
||||
outlines the types of personal information we collect, how we use it, and
|
||||
the steps we take to protect your data when you use Zen Browser.
|
||||
</p>
|
||||
<div class="mx-12 my-12 flex gap-4 font-bold">
|
||||
We don't sell data - We don't collect data - We don't track you
|
||||
</div>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="1-information-we-do-not-collect"
|
||||
>1. Information We Do Not Collect</Title
|
||||
>
|
||||
<p>
|
||||
Zen Browser is designed with privacy in mind. We do not collect, store, or
|
||||
share any of your personal data. Here’s what that means:
|
||||
</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-1-no-telemetry-">
|
||||
<strong class="font-bold">1.1. No Telemetry</strong>
|
||||
</h3>
|
||||
<p>We do not collect any telemetry data or crash reports.</p>
|
||||
<p>
|
||||
Zen Browser has stripped out telemetry built into Mozilla Firefox. We have
|
||||
removed all telemetry data collection and crash reports.
|
||||
</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-2-no-personal-data-collection-">
|
||||
<strong class="font-bold">1.2. No Personal Data Collection</strong>
|
||||
</h3>
|
||||
<p>
|
||||
Zen Browser does not collect any personal information such as your IP
|
||||
address, browsing history, search queries, or form data.
|
||||
</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-4-no-third-party-tracking-">
|
||||
<strong class="font-bold">1.3. No Third-Party Tracking</strong>
|
||||
</h3>
|
||||
<p>
|
||||
We do not allow third-party trackers or analytics tools to operate within
|
||||
Zen Browser. Your browsing activity remains entirely private and is not
|
||||
shared with any third party. Mozilla is not considered a third party as it
|
||||
is the base of Zen Browser.
|
||||
</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-1-3-no-third-party-tracking-">
|
||||
<strong class="font-bold"
|
||||
>1.4. External connections made at startup</strong
|
||||
>
|
||||
</h3>
|
||||
<p>
|
||||
Zen Browser may make external connections at startup to check for updates
|
||||
and ensure the browser is up to date on plugins, addons, check for
|
||||
connectivity and Geolocation/push notifications services in order to
|
||||
comply with web standards. We, at Zen, do not collect any data from these
|
||||
connections, but they may be logged by third-party services or websites
|
||||
you visit. These connections are necessary for the proper functioning of
|
||||
the browser and are not used for tracking or profiling purposes. They can
|
||||
be disabled through the browser flags (about:config).
|
||||
</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="2-information-stored-locally-on-your-device"
|
||||
>2. Information Stored Locally on Your Device</Title
|
||||
>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-2-1-browsing-data-">
|
||||
<strong class="font-bold">2.1. Browsing Data</strong>
|
||||
</h3>
|
||||
<p>
|
||||
Zen Browser stores certain data locally on your device to enhance your
|
||||
browsing experience. This includes:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong class="font-bold">Cookies</strong>: Cookies are stored locally
|
||||
on your device and are not shared with Zen Browser or any third party.
|
||||
You have full control over the management of cookies through the
|
||||
browser’s settings.
|
||||
</li>
|
||||
<li>
|
||||
<strong class="font-bold">Cache and Temporary Files</strong>: Zen
|
||||
Browser may store cache files and other temporary data locally to
|
||||
improve performance. These files can be cleared at any time through the
|
||||
browser’s settings.
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-2-2-settings-and-preferences-">
|
||||
<strong class="font-bold">2.2. Settings and Preferences</strong>
|
||||
</h3>
|
||||
<p>
|
||||
Any customizations, settings, and preferences you make within Zen Browser
|
||||
are stored locally on your device. We do not have access to or control
|
||||
over this data.
|
||||
</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="3-sync-feature"
|
||||
>3. Sync Feature</Title
|
||||
>
|
||||
<p>
|
||||
Zen Browser offers a "Sync" feature, which is implemented using
|
||||
Mozilla Firefox's Sync feature. This feature allows you to synchronize
|
||||
your bookmarks, history, passwords, and other data across multiple
|
||||
devices. For this feature to work, your data is encrypted and stored on
|
||||
Mozilla’s servers and is treated in accordance with their Privacy Policy.
|
||||
We, at Zen, cannot view any of this data.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
class="zen-link"
|
||||
href="https://www.mozilla.org/en-US/privacy/mozilla-accounts/"
|
||||
>Mozilla Firefox Sync</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="zen-link"
|
||||
href="https://support.mozilla.org/en-US/kb/how-firefox-securely-saves-passwords#:~:text=Firefox%20Desktop%20encrypts%20your%20passwords,cryptography%20to%20obscure%20your%20passwords."
|
||||
>This is how we store your passwords</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="4-add-ons-and-mods"
|
||||
>4. Add-ons and "Mods"</Title
|
||||
>
|
||||
<p>
|
||||
You can install Add-ons from addons.mozilla.org. Zen Browser periodically
|
||||
checks for updates to these Add-ons.
|
||||
<br />
|
||||
You can also install "Mods" from zen-browser.app/mods. These Mods
|
||||
are hosted by our services and follow the same privacy policy our website.
|
||||
We do not collect any data from these Mods, they are purely static content
|
||||
that is downloaded to your device.
|
||||
</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="5-data-security"
|
||||
>5. Data Security</Title
|
||||
>
|
||||
<p>
|
||||
Although Zen Browser does not collect your data, we are committed to
|
||||
protecting the information that is stored locally on your device and, if
|
||||
you use the Sync feature, the encrypted data stored on Mozilla's
|
||||
servers. We recommend that you use secure passwords, enable device
|
||||
encryption, and regularly update your software to ensure your data remains
|
||||
safe.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Note that most of the security measures are taken care by Mozilla
|
||||
Firefox.
|
||||
</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="6-your-control"
|
||||
>6. Your Control</Title
|
||||
>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-6-1-data-deletion-">
|
||||
<strong class="font-bold">6.1. Data Deletion</strong>
|
||||
</h3>
|
||||
<p>
|
||||
You have full control over all data stored locally on your device by Zen
|
||||
Browser. You can clear your browsing data, cookies, and cache at any time
|
||||
using the browser’s settings.
|
||||
</p>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="7-our-website-and-services"
|
||||
>7. Our Website and Services</Title
|
||||
>
|
||||
<p>
|
||||
Zen Browser's website and services do not use any third-party analytics,
|
||||
tracking, or CDN services. We do not collect any personal information from
|
||||
users visiting our website. The website is hosted on Cloudflare but with
|
||||
analytics and tracking disabled, Cloudflare may collect some analytics
|
||||
data from HTTP requests in order to provide security and performance
|
||||
improvements. However, this data is not linked to any personal information
|
||||
and is not used for tracking purposes.
|
||||
</p>
|
||||
<h3 class="mt-4 text-xl !font-bold" id="-7-1-external-links-">
|
||||
<strong class="font-bold">7.1. External links</strong>
|
||||
</h3>
|
||||
<p>
|
||||
Zen Browser may contain links to external websites or services that are
|
||||
not owned or operated by us. We are not responsible for the content or
|
||||
privacy practices of these sites. We recommend that you review the privacy
|
||||
policies of these sites before providing them with any personal
|
||||
information.
|
||||
</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="8-changes-to-this-privacy-policy"
|
||||
>8. Changes to This Privacy Policy</Title
|
||||
>
|
||||
<p>
|
||||
We may update this Privacy Policy from time to time to reflect changes in
|
||||
our practices or legal requirements. We will notify you of any significant
|
||||
changes by updating the effective date at the top of this policy.
|
||||
Continued use of Zen Browser after such changes constitutes your
|
||||
acceptance of the new terms.
|
||||
</p>
|
||||
<Title
|
||||
class="mt-16 !text-4xl font-bold"
|
||||
id="9-other-telemetry-done-by-mozilla-firefox"
|
||||
>9. Other telemetry done by Mozilla Firefox</Title
|
||||
>
|
||||
<p>
|
||||
We try to disable all telemetry data collection in Zen Browser. But, we
|
||||
may have missed some. Check the below links for more information.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Please check <a
|
||||
class="zen-link"
|
||||
href="https://www.mozilla.org/en-US/privacy/"
|
||||
>Firefox Privacy Notice</a
|
||||
> for more information.
|
||||
</li>
|
||||
</ul>
|
||||
<Title class="mt-16 !text-4xl font-bold" id="10-contact-us"
|
||||
>10. Contact Us</Title
|
||||
>
|
||||
<p>
|
||||
If you have any questions or concerns about this Privacy Policy or Zen
|
||||
Browser, please contact us at:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Discord: <a class="zen-link" href="https://discord.gg/zen-browser"
|
||||
>Zen Browser's Discord</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
GitHub: <a class="zen-link" href="https://github.com/zen-browser"
|
||||
>Organization</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
</Layout>
|
||||
<style>
|
||||
p,
|
||||
li {
|
||||
@apply opacity-55;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply ml-4 list-disc;
|
||||
}
|
||||
</style>
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
import { releaseNotes } from '../../release-notes'
|
||||
import Layout from '../../layouts/Layout.astro'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return [
|
||||
...releaseNotes.map((release: any) => ({
|
||||
params: { slug: release.version },
|
||||
props: { ...release },
|
||||
})),
|
||||
{
|
||||
params: { slug: 'latest' },
|
||||
props: { ...releaseNotes[0] },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const release = Astro.props
|
||||
---
|
||||
|
||||
<Layout title="Release notes" redirect={`/release-notes#${release.version}`}>
|
||||
<main class="flex flex-col items-center pb-52 pt-36">
|
||||
Redirecting to release notes for version {release.version}...
|
||||
</main>
|
||||
</Layout>
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro'
|
||||
import Features from '../components/Features.astro'
|
||||
---
|
||||
|
||||
<Layout title="Welcome!">
|
||||
<main
|
||||
class="relative mx-auto flex flex-col items-center gap-24 px-6 lg:gap-0 lg:px-24"
|
||||
>
|
||||
<Features title1="Welcome" title2="to" title3="Zen!" />
|
||||
</main>
|
||||
</Layout>
|
|
@ -3,25 +3,29 @@
|
|||
* Returns a mapping from filename to checksum.
|
||||
*/
|
||||
export async function getChecksums() {
|
||||
const res = await fetch('https://api.github.com/repos/zen-browser/desktop/releases/latest', {
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'zen-browser-checksum-fetcher',
|
||||
const res = await fetch(
|
||||
'https://api.github.com/repos/zen-browser/desktop/releases/latest',
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'zen-browser-checksum-fetcher',
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to fetch GitHub release: ' + res.statusText);
|
||||
const data = await res.json();
|
||||
const body = data.body as string;
|
||||
)
|
||||
if (!res.ok)
|
||||
throw new Error('Failed to fetch GitHub release: ' + res.statusText)
|
||||
const data = await res.json()
|
||||
const body = data.body as string
|
||||
|
||||
// Extract the checksum block
|
||||
const match = body.match(/File Checksums \(SHA-256\)[\s\S]*?```([\s\S]*?)```/);
|
||||
const checksums: Record<string, string> = {};
|
||||
const match = body.match(/File Checksums \(SHA-256\)[\s\S]*?```([\s\S]*?)```/)
|
||||
const checksums: Record<string, string> = {}
|
||||
if (match && match[1]) {
|
||||
match[1].split('\n').forEach(line => {
|
||||
const [hash, filename] = line.trim().split(/\s+/, 2);
|
||||
if (hash && filename) checksums[filename] = hash;
|
||||
});
|
||||
match[1].split('\n').forEach((line) => {
|
||||
const [hash, filename] = line.trim().split(/\s+/, 2)
|
||||
if (hash && filename) checksums[filename] = hash
|
||||
})
|
||||
}
|
||||
return checksums;
|
||||
}
|
||||
return checksums
|
||||
}
|
||||
|
|
85
src/utils/i18n.ts
Normal file
85
src/utils/i18n.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import type { GetStaticPaths } from 'astro'
|
||||
import { CONSTANT } from '~/constants'
|
||||
import UI_EN from '~/i18n/en/translation.json'
|
||||
|
||||
export type Locale = (typeof locales)[number]
|
||||
|
||||
export const getPath = (locale?: Locale) => (path: string) => {
|
||||
if (locale && !path.startsWith(`/${locale}`)) {
|
||||
return `/${locale}${path.startsWith('/') ? '' : '/'}${path}`
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
export const getLocale = (Astro: any) => {
|
||||
if (Astro.params.locale) {
|
||||
return Astro.params.locale as Locale
|
||||
}
|
||||
}
|
||||
|
||||
export const locales = CONSTANT.I18N.LOCALES.map(({ value }) => value)
|
||||
|
||||
const otherLocales = CONSTANT.I18N.LOCALES.filter(
|
||||
({ value }) => value !== CONSTANT.I18N.DEFAULT_LOCALE,
|
||||
)
|
||||
|
||||
export const getOtherLocales = () => otherLocales
|
||||
|
||||
export type UI = typeof UI_EN
|
||||
|
||||
export const ui = { en: UI_EN }
|
||||
|
||||
export const getUI = (locale?: Locale | string): UI => {
|
||||
const validLocale = locales.includes(locale as Locale)
|
||||
? locale
|
||||
: CONSTANT.I18N.DEFAULT_LOCALE
|
||||
const defaultUI = ui[CONSTANT.I18N.DEFAULT_LOCALE]
|
||||
const localeUI = ui[validLocale as Locale]
|
||||
|
||||
function deepMerge<T>(defaultObj: T, overrideObj: Partial<T>): T {
|
||||
if (typeof defaultObj !== 'object' || defaultObj === null)
|
||||
return (overrideObj ?? defaultObj) as T
|
||||
if (typeof overrideObj !== 'object' || overrideObj === null)
|
||||
return (overrideObj ?? defaultObj) as T
|
||||
const result: any = Array.isArray(defaultObj)
|
||||
? [...defaultObj]
|
||||
: { ...defaultObj }
|
||||
for (const key in defaultObj) {
|
||||
if (Object.prototype.hasOwnProperty.call(defaultObj, key)) {
|
||||
result[key] = deepMerge(
|
||||
(defaultObj as any)[key],
|
||||
(overrideObj as any)?.[key],
|
||||
)
|
||||
}
|
||||
}
|
||||
for (const key in overrideObj) {
|
||||
if (!(key in defaultObj)) {
|
||||
result[key] = (overrideObj as any)[key]
|
||||
}
|
||||
}
|
||||
return result as T
|
||||
}
|
||||
|
||||
return deepMerge<UI>(defaultUI, localeUI)
|
||||
}
|
||||
|
||||
export const getStaticPaths = (() => {
|
||||
return [
|
||||
{
|
||||
params: { locale: undefined },
|
||||
props: { locale: CONSTANT.I18N.DEFAULT_LOCALE },
|
||||
},
|
||||
...CONSTANT.I18N.LOCALES.filter(
|
||||
({ value }) => value !== CONSTANT.I18N.DEFAULT_LOCALE,
|
||||
).map(({ value }) => ({
|
||||
params: { locale: value },
|
||||
props: {
|
||||
locale: value,
|
||||
},
|
||||
})),
|
||||
]
|
||||
}) satisfies GetStaticPaths
|
||||
|
||||
export const getLocales = () => {
|
||||
return [...locales, ...otherLocales]
|
||||
}
|
|
@ -2,6 +2,10 @@
|
|||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact"
|
||||
"jsxImportSource": "preact",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue