mirror of
https://github.com/zen-browser/www.git
synced 2025-07-07 17:05:32 +02:00
chore(prettier): format fiels with prettier
This commit is contained in:
parent
193c159db5
commit
e068816f18
36 changed files with 1261 additions and 1256 deletions
|
@ -1,21 +1,21 @@
|
|||
import tailwind from "@astrojs/tailwind";
|
||||
import tailwind from '@astrojs/tailwind'
|
||||
// @ts-check
|
||||
import { defineConfig } from "astro/config";
|
||||
import { defineConfig } from 'astro/config'
|
||||
|
||||
import preact from "@astrojs/preact";
|
||||
import preact from '@astrojs/preact'
|
||||
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
import sitemap from '@astrojs/sitemap'
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [tailwind(), preact({ compat: true }), sitemap({})],
|
||||
site: "https://zen-browser.app",
|
||||
integrations: [tailwind(), preact({ compat: true }), sitemap()],
|
||||
site: 'https://zen-browser.app',
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: ["en"],
|
||||
defaultLocale: 'en',
|
||||
locales: ['en'],
|
||||
routing: {
|
||||
fallbackType: "rewrite",
|
||||
fallbackType: 'rewrite',
|
||||
prefixDefaultLocale: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
---
|
||||
import { ArrowLeft } from "lucide-astro";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
import { ArrowLeft } from 'lucide-astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
mods: { slug },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<button
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import { getLocale, getPath } from "~/utils/i18n";
|
||||
import { getLocale, getPath } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const getLocalePath = getPath(locale);
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
class: className,
|
||||
isPrimary,
|
||||
|
@ -11,7 +11,7 @@ const {
|
|||
href,
|
||||
id,
|
||||
extra,
|
||||
} = Astro.props;
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
const { white, multiplier = 0.9, class: classList } = Astro.props;
|
||||
const sizes = [216, 396, 576, 756];
|
||||
const borderWidths = [20, 30, 40, 50];
|
||||
const { white, multiplier = 0.9, class: classList } = Astro.props
|
||||
const sizes = [216, 396, 576, 756]
|
||||
const borderWidths = [20, 30, 40, 50]
|
||||
---
|
||||
|
||||
<div
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { community },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<section
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
---
|
||||
import { motion } from "motion/react";
|
||||
import { getTitleAnimation } from "~/animations";
|
||||
import Description from "~/components/Description.astro";
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import Description from '~/components/Description.astro'
|
||||
|
||||
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 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";
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
import Video from './Video.astro'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { features },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
const {
|
||||
title1 = features.title1,
|
||||
title2 = features.title2,
|
||||
title3 = features.title3,
|
||||
} = Astro.props;
|
||||
} = Astro.props
|
||||
|
||||
const descriptions = Object.values(features.featureTabs).map(
|
||||
(tab) => tab.description,
|
||||
);
|
||||
)
|
||||
---
|
||||
|
||||
<section
|
||||
|
@ -180,12 +180,12 @@ const descriptions = Object.values(features.featureTabs).map(
|
|||
|
||||
<script>
|
||||
const features = document.querySelectorAll(
|
||||
'.feature, .feature-tab'
|
||||
'.feature, .feature-tab',
|
||||
) as NodeListOf<HTMLElement>
|
||||
|
||||
// Set initial description
|
||||
const descriptionEl = document.querySelector(
|
||||
'.feature-description'
|
||||
'.feature-description',
|
||||
) as HTMLDivElement
|
||||
const descriptions = descriptionEl?.dataset.descriptions?.split(',')
|
||||
if (descriptionEl && descriptions) {
|
||||
|
@ -219,7 +219,7 @@ const descriptions = Object.values(features.featureTabs).map(
|
|||
}
|
||||
|
||||
const videos = document.querySelectorAll(
|
||||
'.feature-video'
|
||||
'.feature-video',
|
||||
) as NodeListOf<HTMLVideoElement>
|
||||
videos.forEach((vid, i) => {
|
||||
const yOffset = (i - index) * 20
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: { footer },
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<footer
|
||||
|
@ -24,7 +24,9 @@ const {
|
|||
class="w-full text-center lg:w-1/2 lg:text-left"
|
||||
aria-labelledby="footer-title"
|
||||
>
|
||||
<Description id="footer-title" class="!text-paper text-6xl font-bold">{footer.title}</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">
|
||||
{footer.description}
|
||||
</Description>
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
---
|
||||
import { ArrowRight } from "lucide-astro";
|
||||
import { motion } from "motion/react";
|
||||
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";
|
||||
import { ArrowRight } from 'lucide-astro'
|
||||
import { motion } from 'motion/react'
|
||||
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;
|
||||
let titleAnimationCounter = 0
|
||||
function getNewAnimationDelay() {
|
||||
titleAnimationCounter++;
|
||||
return titleAnimationCounter * 0.15;
|
||||
titleAnimationCounter++
|
||||
return titleAnimationCounter * 0.15
|
||||
}
|
||||
|
||||
function getHeroTitleAnimation() {
|
||||
return getTitleAnimation(getNewAnimationDelay());
|
||||
return getTitleAnimation(getNewAnimationDelay())
|
||||
}
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const getLocalePath = getPath(locale);
|
||||
const getLocalePath = getPath(locale)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { hero },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<header
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
import { getLocale, getPath, getUI } from "~/utils/i18n";
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const getLocalePath = getPath(locale);
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: {
|
||||
nav: { menu },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<!-- Hidden checkbox for menu toggle -->
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
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";
|
||||
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);
|
||||
library.add(faSort, faSortUp, faSortDown)
|
||||
|
||||
// Create icon objects
|
||||
const defaultSortIcon = icon({ prefix: "fas", iconName: "sort" });
|
||||
const ascSortIcon = icon({ prefix: "fas", iconName: "sort-up" });
|
||||
const descSortIcon = icon({ prefix: "fas", iconName: "sort-down" });
|
||||
const defaultSortIcon = icon({ prefix: 'fas', iconName: 'sort' })
|
||||
const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' })
|
||||
const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' })
|
||||
|
||||
interface ModsListProps {
|
||||
allMods: ZenTheme[];
|
||||
locale: Locale;
|
||||
allMods: ZenTheme[]
|
||||
locale: Locale
|
||||
}
|
||||
|
||||
export default function ModsList({ allMods, locale }: ModsListProps) {
|
||||
|
@ -38,58 +34,58 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
setLimit,
|
||||
mods: paginatedMods,
|
||||
// searchParams,
|
||||
} = useModsSearch(allMods);
|
||||
} = useModsSearch(allMods)
|
||||
|
||||
const [pageInput, setPageInput] = useState(page.toString());
|
||||
const [pageInput, setPageInput] = useState(page.toString())
|
||||
|
||||
// Keep page input in sync with actual page
|
||||
useEffect(() => {
|
||||
setPageInput(page.toString());
|
||||
}, [page]);
|
||||
setPageInput(page.toString())
|
||||
}, [page])
|
||||
|
||||
function getSortIcon(state: "default" | "asc" | "desc") {
|
||||
if (state === "asc") return ascSortIcon;
|
||||
if (state === "desc") return descSortIcon;
|
||||
return defaultSortIcon;
|
||||
function getSortIcon(state: 'default' | 'asc' | 'desc') {
|
||||
if (state === 'asc') return ascSortIcon
|
||||
if (state === 'desc') return descSortIcon
|
||||
return defaultSortIcon
|
||||
}
|
||||
|
||||
function handleSearch(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
setSearch(target.value);
|
||||
const target = e.target as HTMLInputElement
|
||||
setSearch(target.value)
|
||||
}
|
||||
|
||||
function handleLimitChange(e: Event) {
|
||||
const target = e.target as HTMLSelectElement;
|
||||
setLimit(Number.parseInt(target.value, 10));
|
||||
const target = e.target as HTMLSelectElement
|
||||
setLimit(Number.parseInt(target.value, 10))
|
||||
}
|
||||
|
||||
function handlePageSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
const newPage = Number.parseInt(pageInput, 10);
|
||||
e.preventDefault()
|
||||
const newPage = Number.parseInt(pageInput, 10)
|
||||
if (!Number.isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {
|
||||
setPage(newPage);
|
||||
window.scrollTo(0, 0);
|
||||
setPage(newPage)
|
||||
window.scrollTo(0, 0)
|
||||
} else {
|
||||
setPageInput(page.toString());
|
||||
setPageInput(page.toString())
|
||||
}
|
||||
}
|
||||
|
||||
function handlePageInputChange(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
setPageInput(target.value);
|
||||
const target = e.target as HTMLInputElement
|
||||
setPageInput(target.value)
|
||||
}
|
||||
|
||||
function navigatePage(pageNum: number) {
|
||||
setPage(pageNum);
|
||||
window.scrollTo(0, 0);
|
||||
setPage(pageNum)
|
||||
window.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
const {
|
||||
routes: { mods },
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
function renderPagination() {
|
||||
if (totalPages <= 1) return null;
|
||||
if (totalPages <= 1) return null
|
||||
return (
|
||||
<div className="mx-auto mb-12 flex items-center justify-center gap-4 px-8">
|
||||
<button
|
||||
|
@ -97,14 +93,14 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
onClick={() => navigatePage(page - 1)}
|
||||
className={`px-3 py-2 ${
|
||||
page === 1
|
||||
? "pointer-events-none text-gray-400"
|
||||
: "text-dark hover:text-gray-600"
|
||||
? 'pointer-events-none text-gray-400'
|
||||
: 'text-dark hover:text-gray-600'
|
||||
}`}
|
||||
>
|
||||
<
|
||||
</button>
|
||||
<form onSubmit={handlePageSubmit} className="flex items-center gap-2">
|
||||
{mods.pagination.pagination.split("{input}").map((value, index) => {
|
||||
{mods.pagination.pagination.split('{input}').map((value, index) => {
|
||||
if (index === 0) {
|
||||
return (
|
||||
<input
|
||||
|
@ -114,15 +110,15 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
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())}
|
||||
.replace('{totalPages}', totalPages.toString())
|
||||
.replace('{totalItems}', totalItems.toString())}
|
||||
</span>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</form>
|
||||
<button
|
||||
|
@ -130,14 +126,14 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
onClick={() => navigatePage(page + 1)}
|
||||
className={`px-3 py-2 ${
|
||||
page === totalPages
|
||||
? "pointer-events-none text-gray-400"
|
||||
: "text-dark hover:text-gray-600"
|
||||
? 'pointer-events-none text-gray-400'
|
||||
: 'text-dark hover:text-gray-600'
|
||||
}`}
|
||||
>
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -222,7 +218,7 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-bold">
|
||||
{mod.name}{" "}
|
||||
{mod.name}{' '}
|
||||
<span className="ml-1 text-sm font-normal">
|
||||
by @{mod.author}
|
||||
</span>
|
||||
|
@ -241,5 +237,5 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
|||
|
||||
{renderPagination()}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
---
|
||||
import { Astronav, Dropdown, DropdownItems, MenuItems } from "astro-navbar";
|
||||
import { ArrowRight, ChevronDown, Download, Menu } from "lucide-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 Logo from "./Logo.astro";
|
||||
import MobileMenu from "./MobileMenu.astro";
|
||||
import ThemeSwitch from "./ThemeSwitch.astro";
|
||||
import { Astronav, Dropdown, DropdownItems, MenuItems } from 'astro-navbar'
|
||||
import { ArrowRight, ChevronDown, Download, Menu } from 'lucide-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 Logo from './Logo.astro'
|
||||
import MobileMenu from './MobileMenu.astro'
|
||||
import ThemeSwitch from './ThemeSwitch.astro'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const getLocalePath = getPath(locale);
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
components: {
|
||||
nav: { brand, menu },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
---
|
||||
import { Accordion, AccordionItem } from "free-astro-components";
|
||||
import { Info } from "lucide-astro";
|
||||
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 { releaseNotes as releaseNotesData } from '~/release-notes'
|
||||
import { getLocale, getPath, getUI } from '~/utils/i18n'
|
||||
import {
|
||||
type BreakingChange,
|
||||
type ReleaseNote,
|
||||
getReleaseNoteFirefoxVersion,
|
||||
} from "../release-notes";
|
||||
export type Props = ReleaseNote;
|
||||
const { isTwilight, ...props } = Astro.props;
|
||||
} from '../release-notes'
|
||||
export type Props = ReleaseNote
|
||||
const { isTwilight, ...props } = Astro.props
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const getLocalePath = getPath(locale);
|
||||
const locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
routes: {
|
||||
releaseNotes: {
|
||||
components: { releaseNoteItem },
|
||||
},
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
let date;
|
||||
let date
|
||||
if (props.date) {
|
||||
const [day, month, year] = props.date.split("/");
|
||||
date = new Date(Date.parse(`${year}-${month}-${day}`));
|
||||
const [day, month, year] = props.date.split('/')
|
||||
date = new Date(Date.parse(`${year}-${month}-${day}`))
|
||||
}
|
||||
|
||||
const ffVersion = getReleaseNoteFirefoxVersion(props);
|
||||
const ffVersion = getReleaseNoteFirefoxVersion(props)
|
||||
const currentReleaseIndex = releaseNotesData.findIndex(
|
||||
(releaseNote: ReleaseNote) => releaseNote.version === props.version,
|
||||
);
|
||||
const prevReleaseNote = releaseNotesData[currentReleaseIndex + 1];
|
||||
let compareLink = "";
|
||||
)
|
||||
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}`
|
||||
}
|
||||
---
|
||||
|
||||
|
@ -62,7 +62,10 @@ if (prevReleaseNote && !isTwilight) {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
{releaseNoteItem.releaseChanges.replaceAll("{version}", props.version)}
|
||||
{releaseNoteItem.releaseChanges.replaceAll(
|
||||
'{version}',
|
||||
props.version,
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -152,7 +155,7 @@ if (prevReleaseNote && !isTwilight) {
|
|||
target="_blank"
|
||||
aria-label={releaseNoteItem.viewIssue.replace(
|
||||
'{issue}',
|
||||
fix.issue
|
||||
fix.issue,
|
||||
)}
|
||||
>
|
||||
#{fix.issue}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
---
|
||||
const { gap = 4 } = Astro.props;
|
||||
const { gap = 4 } = Astro.props
|
||||
|
||||
import { icon, library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faBluesky,
|
||||
faGithub,
|
||||
faMastodon,
|
||||
faReddit,
|
||||
faXTwitter,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
} from '@fortawesome/free-brands-svg-icons'
|
||||
|
||||
library.add(faMastodon, faBluesky, faGithub, faXTwitter, faReddit);
|
||||
const Mastodon = icon({ prefix: "fab", iconName: "mastodon" });
|
||||
const Bluesky = icon({ prefix: "fab", iconName: "bluesky" });
|
||||
const Github = icon({ prefix: "fab", iconName: "github" });
|
||||
const XTwitter = icon({ prefix: "fab", iconName: "x-twitter" });
|
||||
const Reddit = icon({ prefix: "fab", iconName: "reddit" });
|
||||
library.add(faMastodon, faBluesky, faGithub, faXTwitter, faReddit)
|
||||
const Mastodon = icon({ prefix: 'fab', iconName: 'mastodon' })
|
||||
const Bluesky = icon({ prefix: 'fab', iconName: 'bluesky' })
|
||||
const Github = icon({ prefix: 'fab', iconName: 'github' })
|
||||
const XTwitter = icon({ prefix: 'fab', iconName: 'x-twitter' })
|
||||
const Reddit = icon({ prefix: 'fab', iconName: 'reddit' })
|
||||
---
|
||||
|
||||
<ul class={`flex items-center opacity-80 gap-${gap}`}>
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
---
|
||||
import { motion } from "motion/react";
|
||||
import { getTitleAnimation } from "~/animations";
|
||||
import Description from "~/components/Description.astro";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
import { motion } from 'motion/react'
|
||||
import { getTitleAnimation } from '~/animations'
|
||||
import Description from '~/components/Description.astro'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
import tutaLogo from "~/assets/tuta-logo.png";
|
||||
import tutaLogo from '~/assets/tuta-logo.png'
|
||||
|
||||
import Image from "astro/components/Image.astro";
|
||||
const { showSponsors = true } = Astro.props;
|
||||
import Image from 'astro/components/Image.astro'
|
||||
const { showSponsors = true } = Astro.props
|
||||
|
||||
const {
|
||||
routes: {
|
||||
index: { sponsors },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<section id="sponsors" class:list={['mb-32 px-4', !showSponsors && 'hidden']}>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
interface Props {
|
||||
label?: string;
|
||||
className?: string;
|
||||
label?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const { label, className = "" } = Astro.props;
|
||||
const { label, className = '' } = Astro.props
|
||||
---
|
||||
|
||||
<button
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
const { class: className } = Astro.props;
|
||||
const { class: className } = Astro.props
|
||||
---
|
||||
|
||||
<h1 class:list={['title text-dark', className]}>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
const { src, class: className, ...rest } = Astro.props;
|
||||
const type = src.split(".").pop() || "webm";
|
||||
const { src, class: className, ...rest } = Astro.props
|
||||
const type = src.split('.').pop() || 'webm'
|
||||
---
|
||||
|
||||
<video
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const I18N = {
|
||||
DEFAULT_LOCALE: "en",
|
||||
LOCALES: [{ label: "English", value: "en" }],
|
||||
} as const;
|
||||
DEFAULT_LOCALE: 'en',
|
||||
LOCALES: [{ label: 'English', value: 'en' }],
|
||||
} as const
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { I18N } from "./i18n";
|
||||
import { I18N } from './i18n'
|
||||
|
||||
export const CONSTANT = {
|
||||
I18N,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import NotFound from "./[...locale]/404.astro";
|
||||
import NotFound from './[...locale]/404.astro'
|
||||
---
|
||||
|
||||
<NotFound />
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
const getLocalePath = getPath(locale)
|
||||
const {
|
||||
routes: { notFound },
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={notFound.title}>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
const {
|
||||
routes: { donate },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={layout.donate.title} description={layout.donate.description}>
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
---
|
||||
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 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 { icon, library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faApple,
|
||||
faGithub,
|
||||
faLinux,
|
||||
faWindows,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
import { ExternalLink, Lock } from "lucide-astro";
|
||||
} from '@fortawesome/free-brands-svg-icons'
|
||||
import { ExternalLink, Lock } from 'lucide-astro'
|
||||
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
const {
|
||||
routes: { download },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
library.add(faWindows, faLinux, faApple, faGithub);
|
||||
const windowsIcon = icon({ prefix: "fab", iconName: "windows" });
|
||||
const linuxIcon = icon({ prefix: "fab", iconName: "linux" });
|
||||
const appleIcon = icon({ prefix: "fab", iconName: "apple" });
|
||||
const githubIcon = icon({ prefix: "fab", iconName: "github" });
|
||||
library.add(faWindows, faLinux, faApple, faGithub)
|
||||
const windowsIcon = icon({ prefix: 'fab', iconName: 'windows' })
|
||||
const linuxIcon = icon({ prefix: 'fab', iconName: 'linux' })
|
||||
const appleIcon = icon({ prefix: 'fab', iconName: 'apple' })
|
||||
const githubIcon = icon({ prefix: 'fab', iconName: 'github' })
|
||||
|
||||
const checksums = await getChecksums();
|
||||
const releases = getReleasesWithChecksums(checksums);
|
||||
const checksums = await getChecksums()
|
||||
const releases = getReleasesWithChecksums(checksums)
|
||||
|
||||
const platformNames = download.platformNames;
|
||||
const platformDescriptions = download.platformDescriptions;
|
||||
const platformNames = download.platformNames
|
||||
const platformDescriptions = download.platformDescriptions
|
||||
---
|
||||
|
||||
<DownloadScript />
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import rss, { type RSSOptions } from "@astrojs/rss";
|
||||
import { releaseNotes } from "~/release-notes";
|
||||
import type { ReleaseNote } from "~/release-notes";
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
import rss, { type RSSOptions } from '@astrojs/rss'
|
||||
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;
|
||||
const RSS_ENTRY_LIMIT = 20
|
||||
|
||||
/**
|
||||
* Handles the GET request for the `feed.xml` endpoint.
|
||||
|
@ -15,11 +15,11 @@ export function GET(context: any) {
|
|||
const latestDate =
|
||||
releaseNotes.length > 0
|
||||
? formatRssDate(releaseNotes[0].date as string)
|
||||
: new Date();
|
||||
: new Date()
|
||||
|
||||
const rssData: RSSOptions = {
|
||||
title: "Zen Browser Release Notes",
|
||||
description: "Release Notes for the Zen Browser",
|
||||
title: 'Zen Browser Release Notes',
|
||||
description: 'Release Notes for the Zen Browser',
|
||||
site: context.url,
|
||||
items: [],
|
||||
customData: `
|
||||
|
@ -33,7 +33,7 @@ export function GET(context: any) {
|
|||
<link>https://www.zen-browser.app</link>
|
||||
</image>
|
||||
`,
|
||||
};
|
||||
}
|
||||
|
||||
for (const releaseNote of releaseNotes.slice(0, RSS_ENTRY_LIMIT)) {
|
||||
rssData.items.push({
|
||||
|
@ -42,10 +42,10 @@ export function GET(context: any) {
|
|||
pubDate: formatRssDate(releaseNote.date as string),
|
||||
description: releaseNote.extra,
|
||||
content: formatReleaseNote(releaseNote),
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return rss(rssData);
|
||||
return rss(rssData)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,15 +56,15 @@ export function GET(context: any) {
|
|||
* @returns The passed in date string as a Date object.
|
||||
*/
|
||||
function formatRssDate(dateStr: string) {
|
||||
const splitDate = dateStr.split("/");
|
||||
const splitDate = dateStr.split('/')
|
||||
if (splitDate.length !== 3) {
|
||||
throw new Error("Invalid date format");
|
||||
throw new Error('Invalid date format')
|
||||
}
|
||||
|
||||
const day = Number(splitDate[0]);
|
||||
const month = Number(splitDate[1]) - 1;
|
||||
const year = Number(splitDate[2]);
|
||||
return new Date(year, month, day);
|
||||
const day = Number(splitDate[0])
|
||||
const month = Number(splitDate[1]) - 1
|
||||
const year = Number(splitDate[2])
|
||||
return new Date(year, month, day)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,72 +76,72 @@ 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>.
|
||||
Thanks everyone for your feedback! ❤️
|
||||
</p>`;
|
||||
</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;"
|
||||
/>`;
|
||||
/>`
|
||||
}
|
||||
|
||||
if (releaseNote.extra) {
|
||||
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`;
|
||||
content += `<p>${releaseNote.extra.replace(/(\n)/g, '<br />')}</p>`
|
||||
}
|
||||
|
||||
content += addReleaseNoteSection(
|
||||
"⚠️ Breaking changes",
|
||||
'⚠️ Breaking changes',
|
||||
releaseNote.breakingChanges?.map(breakingChangeToReleaseNote),
|
||||
);
|
||||
)
|
||||
content += addReleaseNoteSection(
|
||||
"✓ Fixes",
|
||||
'✓ Fixes',
|
||||
releaseNote.fixes?.map(fixToReleaseNote),
|
||||
);
|
||||
content += addReleaseNoteSection("🖌 Theme Changes", releaseNote.themeChanges);
|
||||
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
|
||||
)
|
||||
content += addReleaseNoteSection('🖌 Theme Changes', releaseNote.themeChanges)
|
||||
content += addReleaseNoteSection('⭐ Features', releaseNote.features)
|
||||
|
||||
return content;
|
||||
return content
|
||||
}
|
||||
|
||||
function addReleaseNoteSection(title: string, items?: string[]): string {
|
||||
if (!items) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
let content = `<h2>${title}</h2>`;
|
||||
content += `<ul>`;
|
||||
let content = `<h2>${title}</h2>`
|
||||
content += `<ul>`
|
||||
for (const item of items) {
|
||||
if (item && item.length > 0) {
|
||||
content += `<li>${item}</li>`;
|
||||
content += `<li>${item}</li>`
|
||||
}
|
||||
}
|
||||
content += `</ul>`;
|
||||
return content;
|
||||
content += `</ul>`
|
||||
return content
|
||||
}
|
||||
|
||||
function fixToReleaseNote(
|
||||
fix?: Exclude<ReleaseNote["fixes"], undefined>[number],
|
||||
fix?: Exclude<ReleaseNote['fixes'], undefined>[number],
|
||||
) {
|
||||
if (typeof fix === "string") {
|
||||
return fix;
|
||||
if (typeof fix === 'string') {
|
||||
return fix
|
||||
}
|
||||
|
||||
if (!fix || !fix.description || fix.description.length === 0) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
let note = fix.description;
|
||||
let note = fix.description
|
||||
if (fix.issue) {
|
||||
note += ` (<a href="https://github.com/zen-browser/desktop/issues/${fix.issue}" target="_blank">#${fix.issue}</a>)`;
|
||||
note += ` (<a href="https://github.com/zen-browser/desktop/issues/${fix.issue}" target="_blank">#${fix.issue}</a>)`
|
||||
}
|
||||
return note;
|
||||
return note
|
||||
}
|
||||
|
||||
function breakingChangeToReleaseNote(
|
||||
breakingChange?: Exclude<ReleaseNote["breakingChanges"], undefined>[number],
|
||||
breakingChange?: Exclude<ReleaseNote['breakingChanges'], undefined>[number],
|
||||
) {
|
||||
if (typeof breakingChange === "string") {
|
||||
return breakingChange;
|
||||
if (typeof breakingChange === 'string') {
|
||||
return breakingChange
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -149,26 +149,26 @@ function breakingChangeToReleaseNote(
|
|||
!breakingChange.description ||
|
||||
breakingChange.description.length === 0
|
||||
) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
return `${breakingChange.description} (<a href="${breakingChange.link}" target="_blank">Learn more</a>)`;
|
||||
return `${breakingChange.description} (<a href="${breakingChange.link}" target="_blank">Learn more</a>)`
|
||||
}
|
||||
|
||||
function pubDate(date?: Date) {
|
||||
date ??= new Date();
|
||||
date ??= new Date()
|
||||
|
||||
const pieces = date.toString().split(" ");
|
||||
const offsetTime = pieces[5].match(/[-+]\d{4}/);
|
||||
const offset = offsetTime ? offsetTime : pieces[5];
|
||||
const pieces = date.toString().split(' ')
|
||||
const offsetTime = pieces[5].match(/[-+]\d{4}/)
|
||||
const offset = offsetTime ? offsetTime : pieces[5]
|
||||
const parts = [
|
||||
pieces[0] + ",",
|
||||
pieces[0] + ',',
|
||||
pieces[2],
|
||||
pieces[1],
|
||||
pieces[3],
|
||||
pieces[4],
|
||||
offset,
|
||||
];
|
||||
]
|
||||
|
||||
return parts.join(" ");
|
||||
return parts.join(' ')
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const { layout } = getUI(locale);
|
||||
const { layout } = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
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";
|
||||
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();
|
||||
const mods = await getAllMods()
|
||||
return mods.flatMap((mod) => [
|
||||
...getOtherLocales().map((locale) => ({
|
||||
params: {
|
||||
|
@ -31,25 +31,25 @@ export async function getStaticPaths() {
|
|||
locale: undefined,
|
||||
},
|
||||
},
|
||||
]);
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/TeaClientMC/Website/blob/7faacc9f8b2c79c74f711d413b155c84faafc00d/src/pages/news/%5B...slug%5D.astro
|
||||
|
||||
const mod = Astro.props;
|
||||
const mod = Astro.props
|
||||
|
||||
const dates = {
|
||||
createdAt: getLocalizedDate(mod.createdAt),
|
||||
updatedAt: getLocalizedDate(mod.updatedAt),
|
||||
};
|
||||
}
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
mods: { slug },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
|
@ -104,7 +104,7 @@ const {
|
|||
<p
|
||||
set:html={slug.latestUpdate.replace(
|
||||
'{updatedAt}',
|
||||
dates.updatedAt
|
||||
dates.updatedAt,
|
||||
)}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
---
|
||||
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";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { mods },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
const allMods = (await getAllMods()) || [];
|
||||
const allMods = (await getAllMods()) || []
|
||||
---
|
||||
|
||||
<Layout title={layout.mods.title}>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
import Title from "~/components/Title.astro";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { privacyPolicy },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
---
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import { releaseNotes } from "~/release-notes";
|
||||
import { getStaticPaths as getI18nPaths, getLocale, getUI } from "~/utils/i18n";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: {
|
||||
releaseNotes: { slug },
|
||||
},
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const i18nPaths = getI18nPaths();
|
||||
const i18nPaths = getI18nPaths()
|
||||
|
||||
return i18nPaths.flatMap(({ params: { locale } }) => [
|
||||
...releaseNotes.map((release: any) => ({
|
||||
|
@ -20,13 +20,13 @@ export async function getStaticPaths() {
|
|||
props: { ...release },
|
||||
})),
|
||||
{
|
||||
params: { slug: "latest", locale },
|
||||
params: { slug: 'latest', locale },
|
||||
props: { ...releaseNotes[0] },
|
||||
},
|
||||
]);
|
||||
])
|
||||
}
|
||||
|
||||
const release = Astro.props;
|
||||
const release = Astro.props
|
||||
---
|
||||
|
||||
<Layout title={slug.title} redirect={`/release-notes#${release.version}`}>
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
---
|
||||
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 { 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";
|
||||
} from '~/release-notes'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { releaseNotes },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={layout.releaseNotes.title}>
|
||||
|
@ -33,7 +33,7 @@ const {
|
|||
class="text-base opacity-55"
|
||||
set:html={releaseNotes.topSection.description.replaceAll(
|
||||
'{latestVersion}',
|
||||
releaseNotesData[0].version
|
||||
releaseNotesData[0].version,
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
import Features from "~/components/Features.astro";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
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 locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { welcome },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
---
|
||||
|
||||
<Layout title={layout.welcome.title} description={layout.welcome.description}>
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
---
|
||||
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 { 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 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";
|
||||
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 latestVersion = releaseNotes[0]
|
||||
|
||||
const locale = getLocale(Astro);
|
||||
const locale = getLocale(Astro)
|
||||
|
||||
const {
|
||||
routes: { whatsNew },
|
||||
layout,
|
||||
} = getUI(locale);
|
||||
} = getUI(locale)
|
||||
|
||||
// Just redirect to the release notes if we are in a patch version
|
||||
if (
|
||||
latestVersion.version.split(".").length > 2 &&
|
||||
latestVersion.version.split('.').length > 2 &&
|
||||
whatsNewText[1] !== latestVersion.version
|
||||
) {
|
||||
return Astro.redirect(`/release-notes#${latestVersion.version}`);
|
||||
return Astro.redirect(`/release-notes#${latestVersion.version}`)
|
||||
}
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={layout.whatsNew.title.replace(
|
||||
'{latestVersion.version}',
|
||||
latestVersion.version
|
||||
latestVersion.version,
|
||||
)}
|
||||
>
|
||||
<main
|
||||
|
@ -45,7 +45,7 @@ if (
|
|||
>{
|
||||
whatsNew.title.replace(
|
||||
'{latestVersion.version}',
|
||||
latestVersion.version
|
||||
latestVersion.version,
|
||||
)
|
||||
}</Description
|
||||
>
|
||||
|
|
|
@ -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', {
|
||||
const res = await fetch(
|
||||
'https://api.github.com/repos/zen-browser/desktop/releases/latest',
|
||||
{
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github+json',
|
||||
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
|
||||
}
|
|
@ -1,67 +1,67 @@
|
|||
import type { GetStaticPaths } from "astro";
|
||||
import { CONSTANT } from "~/constants";
|
||||
import UI_EN from "~/i18n/en/translation.json";
|
||||
import type { GetStaticPaths } from 'astro'
|
||||
import { CONSTANT } from '~/constants'
|
||||
import UI_EN from '~/i18n/en/translation.json'
|
||||
|
||||
export type Locale = (typeof locales)[number];
|
||||
export type Locale = (typeof locales)[number]
|
||||
|
||||
export const getPath = (locale?: Locale) => (path: string) => {
|
||||
if (locale && !path.startsWith(`/${locale}`)) {
|
||||
return `/${locale}${path.startsWith("/") ? "" : "/"}${path}`;
|
||||
return `/${locale}${path.startsWith('/') ? '' : '/'}${path}`
|
||||
}
|
||||
return path
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
export const getLocale = (Astro: any) => {
|
||||
if (Astro.params.locale) {
|
||||
return Astro.params.locale as Locale;
|
||||
return Astro.params.locale as Locale
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const locales = CONSTANT.I18N.LOCALES.map(({ value }) => value);
|
||||
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 const getOtherLocales = () => otherLocales
|
||||
|
||||
export type UI = typeof UI_EN;
|
||||
export type UI = typeof UI_EN
|
||||
|
||||
export const ui = { en: 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];
|
||||
: 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;
|
||||
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 };
|
||||
: { ...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];
|
||||
result[key] = (overrideObj as any)[key]
|
||||
}
|
||||
}
|
||||
return result as T;
|
||||
return result as T
|
||||
}
|
||||
|
||||
return deepMerge<UI>(defaultUI, localeUI);
|
||||
};
|
||||
return deepMerge<UI>(defaultUI, localeUI)
|
||||
}
|
||||
|
||||
export const getStaticPaths = (() => {
|
||||
return [
|
||||
|
@ -77,9 +77,9 @@ export const getStaticPaths = (() => {
|
|||
locale: value,
|
||||
},
|
||||
})),
|
||||
];
|
||||
}) satisfies GetStaticPaths;
|
||||
]
|
||||
}) satisfies GetStaticPaths
|
||||
|
||||
export const getLocales = () => {
|
||||
return [...locales, ...otherLocales];
|
||||
};
|
||||
return [...locales, ...otherLocales]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue