mirror of
https://github.com/zen-browser/www.git
synced 2025-07-08 01:10:02 +02:00
feat(rss): port RSS feed from old Next.JS site to Astro
This commit is contained in:
parent
19a38982b8
commit
0102dc66fd
4 changed files with 172 additions and 4 deletions
|
@ -14,6 +14,7 @@
|
|||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/cloudflare": "^12.0.1",
|
||||
"@astrojs/react": "^4.1.0",
|
||||
"@astrojs/rss": "^4.0.10",
|
||||
"@astrojs/tailwind": "^5.1.2",
|
||||
"@fontsource/bricolage-grotesque": "^5.1.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.1",
|
||||
|
|
24
pnpm-lock.yaml
generated
24
pnpm-lock.yaml
generated
|
@ -17,6 +17,9 @@ importers:
|
|||
'@astrojs/react':
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(@types/node@22.10.2)(@types/react-dom@19.0.2(@types/react@19.0.1))(@types/react@19.0.1)(jiti@1.21.6)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yaml@2.6.1)
|
||||
'@astrojs/rss':
|
||||
specifier: ^4.0.10
|
||||
version: 4.0.10
|
||||
'@astrojs/tailwind':
|
||||
specifier: ^5.1.2
|
||||
version: 5.1.3(astro@5.0.5(@types/node@22.10.2)(jiti@1.21.6)(rollup@4.28.1)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16)
|
||||
|
@ -159,6 +162,9 @@ packages:
|
|||
react: ^17.0.2 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.2 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@astrojs/rss@4.0.10':
|
||||
resolution: {integrity: sha512-2gFdHM763uUAySkdwPYrpi6dppOBJr9ddg5VbkKXctWze8d1JHgIBBY78zWIYs7KBJT58zxadsObVAVt55RDaw==}
|
||||
|
||||
'@astrojs/tailwind@5.1.3':
|
||||
resolution: {integrity: sha512-XF7WhXRhqEHGvADqc0kDtF7Yv/g4wAWTaj91jBBTBaYnc4+MQLH94duFfFa4NlTkRG40VQd012eF3MhO3Kk+bg==}
|
||||
peerDependencies:
|
||||
|
@ -1528,6 +1534,10 @@ packages:
|
|||
fast-uri@3.0.3:
|
||||
resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==}
|
||||
|
||||
fast-xml-parser@4.5.1:
|
||||
resolution: {integrity: sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.17.1:
|
||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
||||
|
||||
|
@ -2532,6 +2542,9 @@ packages:
|
|||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
strnum@1.0.5:
|
||||
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
|
||||
|
||||
sucrase@3.35.0:
|
||||
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
@ -3149,6 +3162,11 @@ snapshots:
|
|||
- tsx
|
||||
- yaml
|
||||
|
||||
'@astrojs/rss@4.0.10':
|
||||
dependencies:
|
||||
fast-xml-parser: 4.5.1
|
||||
kleur: 4.1.5
|
||||
|
||||
'@astrojs/tailwind@5.1.3(astro@5.0.5(@types/node@22.10.2)(jiti@1.21.6)(rollup@4.28.1)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16)':
|
||||
dependencies:
|
||||
astro: 5.0.5(@types/node@22.10.2)(jiti@1.21.6)(rollup@4.28.1)(typescript@5.7.2)(yaml@2.6.1)
|
||||
|
@ -4502,6 +4520,10 @@ snapshots:
|
|||
|
||||
fast-uri@3.0.3: {}
|
||||
|
||||
fast-xml-parser@4.5.1:
|
||||
dependencies:
|
||||
strnum: 1.0.5
|
||||
|
||||
fastq@1.17.1:
|
||||
dependencies:
|
||||
reusify: 1.0.4
|
||||
|
@ -5721,6 +5743,8 @@ snapshots:
|
|||
|
||||
strip-bom@3.0.0: {}
|
||||
|
||||
strnum@1.0.5: {}
|
||||
|
||||
sucrase@3.35.0:
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
|
|
|
@ -29,11 +29,12 @@ import Footer from "../components/Footer.astro";
|
|||
<meta property="og:color" content="#da755b3" />
|
||||
<!-- twitter card -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=bricolage-grotesque:200,300,400,500,600,700,800|instrument-serif:400,400i" rel="stylesheet" />
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=bricolage-grotesque:200,300,400,500,600,700,800|instrument-serif:400,400i" rel="stylesheet" />
|
||||
<link rel="alternate" type="application/rss+xml" title="Zen Browser Release Notes" href={`${Astro.url.origin}/feed.xml`} />
|
||||
</head>
|
||||
<body class="bg-paper font-['bricolage-grotesque'] text-dark overflow-x-hidden">
|
||||
<body class="bg-paper font-['bricolage-grotesque'] text-dark overflow-x-hidden">
|
||||
<slot />
|
||||
<Footer />
|
||||
<NavBar />
|
||||
|
|
142
src/pages/feed.xml.ts
Normal file
142
src/pages/feed.xml.ts
Normal file
|
@ -0,0 +1,142 @@
|
|||
import rss, { type RSSOptions } from '@astrojs/rss';
|
||||
import { releaseNotes } from '../release-notes';
|
||||
import type { ReleaseNote } from '../release-notes';
|
||||
|
||||
/** The default number of entries to include in the RSS feed. */
|
||||
const RSS_ENTRY_LIMIT = 20;
|
||||
|
||||
/**
|
||||
* Handles the GET request for the `feed.xml` endpoint.
|
||||
* @returns The RSS feed for the Zen Browser release notes.
|
||||
*/
|
||||
export function GET(context: any) {
|
||||
// Just in case the release notes array is empty for whatever reason.
|
||||
const latestDate = releaseNotes.length > 0
|
||||
? formatRssDate(releaseNotes[0].date)
|
||||
: new Date();
|
||||
|
||||
const rssData: RSSOptions = {
|
||||
title: "Zen Browser Release Notes",
|
||||
description: "Release Notes for the Zen Browser",
|
||||
site: context.url,
|
||||
items: [],
|
||||
customData: `
|
||||
<language>en</language>
|
||||
<link>https://www.zen-browser.app/release-notes</link>
|
||||
<copyright>Zen Browser © ${new Date().getFullYear()} - Made with ❤️ by the Zen team.</copyright>
|
||||
<pubDate>${pubDate(latestDate)}</pubDate>
|
||||
<image>
|
||||
<url>https://www.zen-browser.app/favicon.ico</url>
|
||||
<title>Zen Browser</title>
|
||||
<link>https://www.zen-browser.app</link>
|
||||
</image>
|
||||
`
|
||||
};
|
||||
|
||||
for (const releaseNote of releaseNotes.slice(0, RSS_ENTRY_LIMIT)) {
|
||||
rssData.items.push({
|
||||
title: `Release notes for version ${releaseNote.version}`,
|
||||
link: `https://www.zen-browser.app/release-notes/${releaseNote.version}`,
|
||||
pubDate: formatRssDate(releaseNote.date),
|
||||
description: releaseNote.extra,
|
||||
content: formatReleaseNote(releaseNote),
|
||||
});
|
||||
}
|
||||
|
||||
return rss(rssData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date string in the format day/month/year.
|
||||
*
|
||||
* Note: If release notes change to ISO format, this will need to be updated.
|
||||
* @param dateStr The date string to format.
|
||||
* @returns The passed in date string as a Date object.
|
||||
*/
|
||||
function formatRssDate(dateStr: string) {
|
||||
const splitDate = dateStr.split("/");
|
||||
if (splitDate.length !== 3) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the release note entry for use as the content of the RSS feed.
|
||||
* @param releaseNote The release note to format.
|
||||
* @returns The formatted release note as a HTML 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>.
|
||||
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;"
|
||||
/>`;
|
||||
}
|
||||
|
||||
if (releaseNote.extra) {
|
||||
content += `<p>${releaseNote.extra.replace(/(\n)/g, "<br />")}</p>`;
|
||||
}
|
||||
|
||||
content += addReleaseNoteSection("⚠️ Breaking changes", releaseNote.breakingChanges);
|
||||
content += addReleaseNoteSection("✓ Fixes", releaseNote.fixes?.map(fixToReleaseNote));
|
||||
content += addReleaseNoteSection("🖌 Theme Changes", releaseNote.themeChanges)
|
||||
content += addReleaseNoteSection("⭐ Features", releaseNote.features);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function addReleaseNoteSection(title: string, items?: string[]): string {
|
||||
if (!items) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let content = `<h2>${title}</h2>`;
|
||||
content += `<ul>`;
|
||||
for (const item of items) {
|
||||
if (item && item.length > 0) {
|
||||
content += `<li>${item}</li>`;
|
||||
}
|
||||
}
|
||||
content += `</ul>`;
|
||||
return content;
|
||||
}
|
||||
|
||||
function fixToReleaseNote(fix?: Exclude<ReleaseNote['fixes'], undefined>[number]) {
|
||||
if (!fix || !fix.description || fix.description.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let note = fix.description;
|
||||
if (fix.issue) {
|
||||
note += ` (<a href="https://github.com/zen-browser/desktop/issues/${fix.issue}" target="_blank">#${fix.issue}</a>)`;
|
||||
}
|
||||
return note;
|
||||
}
|
||||
|
||||
function pubDate(date?: Date) {
|
||||
date ??= new Date();
|
||||
|
||||
const pieces = date.toString().split(' ');
|
||||
const offsetTime = pieces[5].match(/[-+]\d{4}/);
|
||||
const offset = (offsetTime) ? offsetTime : pieces[5];
|
||||
const parts = [
|
||||
pieces[0] + ',',
|
||||
pieces[2],
|
||||
pieces[1],
|
||||
pieces[3],
|
||||
pieces[4],
|
||||
offset
|
||||
];
|
||||
|
||||
return parts.join(' ');
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue