Skip to content

Commit 687d69e

Browse files
authored
Merge branch 'main' into main
2 parents 5819191 + 7f51e4e commit 687d69e

55 files changed

Lines changed: 4653 additions & 2790 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ jobs:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- name: Checkout
14-
uses: actions/checkout@v4
14+
uses: actions/checkout@v6
1515

1616
- name: Setup Node
17-
uses: actions/setup-node@v4
17+
uses: actions/setup-node@v6
1818
with:
19-
node-version: "18"
19+
node-version: "24"
2020
cache: npm
2121
cache-dependency-path: ./package-lock.json
2222

.github/workflows/cf_pages.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ jobs:
1717
name: Build
1818
if: ${{ github.repository_owner == 'vtbag' }}
1919
runs-on: ubuntu-latest
20+
env:
21+
npm_config_legacy_peer_deps: "true"
2022
steps:
2123
- name: Checkout
22-
uses: actions/checkout@v4
24+
uses: actions/checkout@v6
2325
with:
2426
fetch-depth: 0
2527

2628
- name: Setup Node
27-
uses: actions/setup-node@v4
29+
uses: actions/setup-node@v6
2830
with:
29-
node-version: "18"
31+
node-version: "24"
3032
cache: npm
3133
cache-dependency-path: ./package-lock.json
3234

@@ -38,7 +40,7 @@ jobs:
3840
restore-keys: astro-cache
3941

4042
- name: Install dependencies
41-
run: npm install
43+
run: npm ci
4244

4345
- name: Build with Astro
4446
run: npm run build

astro.config.ts

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,13 @@ import d2 from "astro-d2";
1313
import inoxToolsPortalGun from "@inox-tools/portal-gun";
1414
import type { Badge } from "node_modules/@astrojs/starlight/schemas/badge";
1515
import sitemap from '@astrojs/sitemap';
16-
import og from "astro-og";
1716

1817
export default defineConfig({
1918
image: { remotePatterns: [{ protocol: "https" }] },
2019
devToolbar: { enabled: true },
2120
site: "https://vtbag.dev",
2221
compressHTML: false,
2322

24-
redirects: {
25-
"/inspection-chamber/": "/tools/inspection-chamber/",
26-
},
27-
28-
experimental: {
29-
preserveScriptOrder: true,
30-
headingIdCompat: true,
31-
},
3223
prefetch: false,
3324

3425
markdown: {
@@ -83,12 +74,12 @@ export default defineConfig({
8374
},
8475
head: [
8576
{
86-
tag: "meta",
87-
attrs: {
88-
property: "og:image",
89-
content: "https://vtbag.dev/social.png",
90-
},
77+
tag: "meta", attrs: { property: "og:image", content: "https://vtbag.dev/social.png", }
9178
},
79+
{ tag: "meta", attrs: { property: "article:publisher", content: "https://bsky.app/profile/vtbag.dev" } },
80+
{ tag: "meta", attrs: { property: "article:author", content: "https://bsky.app/profile/martr.app" } },
81+
{ tag: "meta", attrs: { property: "article:tag", content: "view transitions" } },
82+
{ tag: "meta", attrs: { property: "article:section", content: "Articles" } },
9283
{
9384
tag: "meta",
9485
attrs: {
@@ -128,12 +119,18 @@ export default defineConfig({
128119
],
129120
lastUpdated: true,
130121
pagination: true,
131-
favicon: "/bag4.png",
122+
favicon: "/bag4.ico",
132123
logo: {
133124
src: "./src/assets/mini-bag.webp",
125+
alt: "vtbag logo",
134126
},
135127

136128
social: [
129+
{
130+
icon: "rss",
131+
label: "RSS",
132+
href: "/rss.xml",
133+
},
137134
{
138135
icon: "github",
139136
label: "GitHub",
@@ -153,10 +150,12 @@ export default defineConfig({
153150
}),
154151
d2({
155152
skipGeneration: process.env.GITHUB_ACTIONS === "true",
153+
theme: {
154+
default: "0",
155+
},
156156
}),
157157
vtbot({ autoLint: false, loadingIndicator: false }),
158158
inoxToolsPortalGun(),
159-
og(),
160159
sitemap({
161160
filter: (page) =>
162161
/**/!page.startsWith('https://vtbag.dev/auto/')
@@ -199,7 +198,7 @@ function sidebar() {
199198
link: "/vtbag/",
200199
},
201200
{
202-
label: "Basics",
201+
label: "Basic Information",
203202
items: [
204203
{ label: "Test Your Browser", link: "/basics/test-page/" },
205204
{ label: "View Transition API", link: "/basics/api/" },
@@ -214,17 +213,17 @@ function sidebar() {
214213
},
215214
{ label: "Styling View Transitions", link: "/basics/styling/" },
216215
{ label: "JavaScript API", link: "/basics/javascript/" },
217-
{ label: "Playing Hide & Seek", link: "/basics/hide-and-seek/" },
216+
{ label: "Playing Hide & Seek", link: "/basics/hide-and-seek/",
217+
badge: { text: "Updated!", variant: "success" } as Badge },
218218
{
219219
label: "API Levels and Implications",
220-
link: "/basics/levels/",
221-
badge: { text: "New!", variant: "success" } as Badge,
220+
link: "/basics/levels/"
222221
},
223222
{ label: "Web Framework Support", link: "/basics/frameworks/" },
224223
],
225224
},
226225
{
227-
label: "Tools",
226+
label: "Tools & Libraries",
228227
items: [
229228
{ label: "Inspection Chamber", link: "/tools/inspection-chamber/" },
230229
{ label: "Element Crossing", link: "/tools/element-crossing/" },
@@ -233,8 +232,7 @@ function sidebar() {
233232
{
234233
label: "Utensil Drawer",
235234
link: "/tools/utensil-drawer/",
236-
badge: { text: "Updated!", variant: "success" } as Badge,
237-
},
235+
},
238236
],
239237
},
240238
{
@@ -250,7 +248,6 @@ function sidebar() {
250248
{
251249
label: "Playing",
252250
link: "/fwvt/playing/",
253-
badge: { text: "New!", variant: "success" } as Badge,
254251
},
255252
],
256253
},
@@ -275,13 +272,12 @@ function sidebar() {
275272
{
276273
label: "Why View Transitions Might Fail",
277274
link: "tips/view-transition-fails-and-fixes/",
278-
badge: { text: "Updated!", variant: "success" } as Badge
279275
},
280276
],
281277
},
282278
{ label: "BagLog", link: "/baglog" },
283279
{
284-
label: "All Demos",
280+
label: "All Tech Demos",
285281
collapsed: false,
286282
items: [
287283
{

bin/rss-update.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
import { parse } from 'node-html-parser';
5+
6+
const SITE_URL = 'https://vtbag.dev/';
7+
const OUTPUT = 'public/rss.xml';
8+
9+
const CONTENT_DIRS = [
10+
'dist/basics',
11+
'dist/fwvt',
12+
'dist/tips',
13+
'dist/tools',
14+
'dist/vtbag',
15+
];
16+
17+
type FeedItem = {
18+
title: string;
19+
link: string;
20+
guid: string;
21+
author: string | undefined;
22+
lastModifiedStr: string | undefined;
23+
lastModified: Date | null;
24+
description?: string;
25+
image?: string;
26+
};
27+
28+
function walk(dir: string): string[] {
29+
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
30+
const fullPath = path.join(dir, entry.name);
31+
if (entry.isDirectory()) return walk(fullPath);
32+
if (entry.isFile() && entry.name.endsWith('.html')) {
33+
return [fullPath];
34+
}
35+
return [];
36+
});
37+
}
38+
39+
function readHtml(file: string) {
40+
return parse(fs.readFileSync(file, 'utf8'));
41+
}
42+
43+
function meta(root: ReturnType<typeof parse>, prop: string): string | undefined {
44+
return root
45+
.querySelector(`meta[property="${prop}"]`)
46+
?.getAttribute('content');
47+
}
48+
49+
function toUrl(file: string): string {
50+
const rel = file.replace(/^dist/, '');
51+
return SITE_URL + rel.replace(/index\.html$/, '');
52+
}
53+
54+
function cdata(value: string): string {
55+
return `<![CDATA[${value.replaceAll(']]>', ']]]]><![CDATA[>')}]]>`;
56+
}
57+
58+
function rfc822(date: Date): string {
59+
return date.toUTCString();
60+
}
61+
62+
const files = CONTENT_DIRS.flatMap(dir => walk(dir));
63+
64+
const items: FeedItem[] = [];
65+
66+
for (const file of files) {
67+
const root = readHtml(file);
68+
69+
const draft = meta(root, 'draft');
70+
if (draft) continue;
71+
72+
const title = meta(root, 'og:title') ?? root.querySelector('title')?.text;
73+
const link = toUrl(file);
74+
const author = meta(root, 'author');
75+
76+
const lastModifiedStr = meta(root, 'og:updated_time') || meta(root, 'article:modified_time');
77+
const lastModified = lastModifiedStr ? new Date(lastModifiedStr) : null;
78+
79+
if (!title || !lastModified) continue;
80+
81+
items.push({
82+
title,
83+
link,
84+
guid: link,
85+
author,
86+
lastModifiedStr,
87+
lastModified,
88+
description: meta(root, 'og:description') ?? "Missing Description",
89+
image: meta(root, 'og:image') ?? "/social.png",
90+
});
91+
}
92+
93+
items.sort((a, b) => b.lastModified!.getTime() - a.lastModified!.getTime());
94+
95+
const rssItems = items.map(item => `
96+
<item>
97+
<title>${cdata(item.title)}</title>
98+
<link>${item.link}</link>
99+
<guid isPermaLink="true">${item.guid}</guid>
100+
${item.author ? `<dc:creator>${cdata(item.author)}</dc:creator>` : ''}
101+
<pubDate>${rfc822(item.lastModified!)}</pubDate>
102+
${item.description ? `<description>${cdata(item.description)}</description>` : ''}
103+
${item.image ? `<enclosure
104+
url="${item.image}"
105+
type="image/jpeg"
106+
/>` : ''}
107+
</item>
108+
`).join('');
109+
110+
const rss = `<?xml version="1.0" encoding="UTF-8"?>
111+
<rss
112+
version="2.0"
113+
xmlns:dc="http://purl.org/dc/elements/1.1/"
114+
>
115+
<channel>
116+
<title>@vtbag: The Bag of Tricks for View Transitions</title>
117+
<link>${SITE_URL}</link>
118+
<description>Tools, Tips, and Tricks to Enhance your Dev Skills with the View Transition API!</description>
119+
<language>en-us</language>
120+
<lastBuildDate>${rfc822(new Date())}</lastBuildDate>
121+
${rssItems}
122+
</channel>
123+
</rss>
124+
`;
125+
126+
fs.writeFileSync(OUTPUT, rss.trim() + '\n');
127+
128+
console.log(`RSS written to ${OUTPUT}`);

0 commit comments

Comments
 (0)