refactor: bookmarks becomes a content collection with auto-id
This commit is contained in:
parent
23a267a242
commit
1d8ef601bc
6 changed files with 33 additions and 57 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { defineCollection } from 'astro:content';
|
import { defineCollection } from 'astro:content';
|
||||||
import { glob } from 'astro/loaders';
|
import { glob, file } from 'astro/loaders';
|
||||||
import { z } from 'astro/zod';
|
import { z } from 'astro/zod';
|
||||||
|
import yaml from 'js-yaml';
|
||||||
|
|
||||||
const posts = defineCollection({
|
const posts = defineCollection({
|
||||||
loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
|
loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
|
||||||
|
|
@ -13,4 +14,18 @@ const posts = defineCollection({
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collections = { posts };
|
const bookmarks = defineCollection({
|
||||||
|
loader: file('./src/content/bookmarks.yaml', {
|
||||||
|
parser: (text) => {
|
||||||
|
const data = yaml.load(text) as Array<Record<string, unknown>>;
|
||||||
|
return data.map((item, i) => ({ id: String(i), ...item }));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
url: z.string().url(),
|
||||||
|
date: z.coerce.date(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = { posts, bookmarks };
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
---
|
---
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
import Layout from '../../layouts/Layout.astro';
|
import Layout from '../../layouts/Layout.astro';
|
||||||
import yaml from 'js-yaml';
|
|
||||||
import bookmarksRaw from '../../content/bookmarks.yaml?raw';
|
|
||||||
|
|
||||||
interface Bookmark {
|
const bookmarksCollection = await getCollection('bookmarks');
|
||||||
date: string;
|
const bookmarks = bookmarksCollection
|
||||||
title: string;
|
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bookmarks = (yaml.load(bookmarksRaw) as Bookmark[])
|
|
||||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
||||||
|
|
||||||
function formatDate(date: Date): string {
|
function formatDate(date: Date): string {
|
||||||
const d = String(date.getDate()).padStart(2, '0');
|
const d = String(date.getDate()).padStart(2, '0');
|
||||||
|
|
@ -19,11 +13,6 @@ function formatDate(date: Date): string {
|
||||||
return `${d}/${m}/${y}`;
|
return `${d}/${m}/${y}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBookmarkDate(dateStr: string): string {
|
|
||||||
const date = new Date(dateStr);
|
|
||||||
return formatDate(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractDomain(url: string): string {
|
function extractDomain(url: string): string {
|
||||||
try {
|
try {
|
||||||
const parsed = new URL(url);
|
const parsed = new URL(url);
|
||||||
|
|
@ -37,6 +26,6 @@ function extractDomain(url: string): string {
|
||||||
|
|
||||||
<details open>
|
<details open>
|
||||||
<summary>bookmarks</summary>
|
<summary>bookmarks</summary>
|
||||||
<pre set:html={bookmarks.map(b => `<span class="muted">${formatBookmarkDate(b.date)}</span> <a href="${b.url}">${b.title}</a> <span class="muted">(${extractDomain(b.url)})</span>`).join('\n')} />
|
<pre set:html={bookmarks.map(b => `<span class="muted">${formatDate(b.data.date)}</span> <a href="${b.data.url}">${b.data.title}</a> <span class="muted">(${extractDomain(b.data.url)})</span>`).join('\n')} />
|
||||||
</details>
|
</details>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ function formatDate(date: Date): string {
|
||||||
<Layout title={`${post.data.title} - lewis m.w.`}>
|
<Layout title={`${post.data.title} - lewis m.w.`}>
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
<p class="muted">[DRAFT] <a href="/draft/">back to drafts</a></p>
|
|
||||||
<h1>{post.data.title}</h1>
|
<h1>{post.data.title}</h1>
|
||||||
<p class="muted" style="margin-top: 0;">{formatDate(post.data.date)}</p>
|
<p class="muted" style="margin-top: 0;">{formatDate(post.data.date)}</p>
|
||||||
<Content />
|
<Content />
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,10 @@
|
||||||
import rss from '@astrojs/rss';
|
import rss from '@astrojs/rss';
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import yaml from 'js-yaml';
|
|
||||||
import bookmarksRaw from '../content/bookmarks.yaml?raw';
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import type { APIContext } from 'astro';
|
import type { APIContext } from 'astro';
|
||||||
import { getGitDate } from '../utils';
|
import { getGitDate } from '../utils';
|
||||||
|
|
||||||
interface Bookmark {
|
|
||||||
date: string;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TxtFile {
|
interface TxtFile {
|
||||||
name: string;
|
name: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
|
|
@ -20,7 +12,7 @@ interface TxtFile {
|
||||||
|
|
||||||
export async function GET(context: APIContext) {
|
export async function GET(context: APIContext) {
|
||||||
const posts = await getCollection('posts', ({ data }) => data.draft !== true);
|
const posts = await getCollection('posts', ({ data }) => data.draft !== true);
|
||||||
const bookmarks = yaml.load(bookmarksRaw) as Bookmark[];
|
const bookmarks = await getCollection('bookmarks');
|
||||||
|
|
||||||
const txtDir = path.join(process.cwd(), 'public/txt');
|
const txtDir = path.join(process.cwd(), 'public/txt');
|
||||||
const txtFiles: TxtFile[] = fs.existsSync(txtDir)
|
const txtFiles: TxtFile[] = fs.existsSync(txtDir)
|
||||||
|
|
@ -46,10 +38,10 @@ export async function GET(context: APIContext) {
|
||||||
description: txt.name,
|
description: txt.name,
|
||||||
})),
|
})),
|
||||||
...bookmarks.map(b => ({
|
...bookmarks.map(b => ({
|
||||||
title: b.title,
|
title: b.data.title,
|
||||||
pubDate: new Date(b.date),
|
pubDate: b.data.date,
|
||||||
link: b.url,
|
link: b.data.url,
|
||||||
description: b.title,
|
description: b.data.title,
|
||||||
})),
|
})),
|
||||||
].sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime());
|
].sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,11 @@
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import Layout from '../layouts/Layout.astro';
|
import Layout from '../layouts/Layout.astro';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import bookmarksRaw from '../content/bookmarks.yaml?raw';
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { getApprovedEntries, type GuestbookEntry } from '../lib/db';
|
import { getApprovedEntries, type GuestbookEntry } from '../lib/db';
|
||||||
import { getGitDate } from '../utils';
|
import { getGitDate } from '../utils';
|
||||||
|
|
||||||
interface Bookmark {
|
|
||||||
date: string;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TxtFile {
|
interface TxtFile {
|
||||||
name: string;
|
name: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
|
|
@ -50,8 +43,9 @@ for (const category of sortedCategories) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const bookmarks = (yaml.load(bookmarksRaw) as Bookmark[])
|
const bookmarksCollection = await getCollection('bookmarks');
|
||||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
const bookmarks = bookmarksCollection
|
||||||
|
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||||
|
|
||||||
// Auto-discover txt files from public/txt/
|
// Auto-discover txt files from public/txt/
|
||||||
const txtDir = path.join(process.cwd(), 'public/txt');
|
const txtDir = path.join(process.cwd(), 'public/txt');
|
||||||
|
|
@ -89,11 +83,6 @@ function formatDate(date: Date): string {
|
||||||
return `${d}/${m}/${y}`;
|
return `${d}/${m}/${y}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBookmarkDate(dateStr: string): string {
|
|
||||||
const date = new Date(dateStr);
|
|
||||||
return formatDate(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractDomain(url: string): string {
|
function extractDomain(url: string): string {
|
||||||
try {
|
try {
|
||||||
const parsed = new URL(url);
|
const parsed = new URL(url);
|
||||||
|
|
@ -129,7 +118,7 @@ function extractDomain(url: string): string {
|
||||||
<details open>
|
<details open>
|
||||||
<summary>bookmarks</summary>
|
<summary>bookmarks</summary>
|
||||||
<pre set:html={[
|
<pre set:html={[
|
||||||
...bookmarks.slice(0, 10).map(b => `<span class="muted">${formatBookmarkDate(b.date)}</span> <a href="${b.url}">${b.title}</a> <span class="muted">(${extractDomain(b.url)})</span>`),
|
...bookmarks.slice(0, 10).map(b => `<span class="muted">${formatDate(b.data.date)}</span> <a href="${b.data.url}">${b.data.title}</a> <span class="muted">(${extractDomain(b.data.url)})</span>`),
|
||||||
...(bookmarks.length > 10 ? [`<a href="/bookmarks/">+${bookmarks.length - 10} more</a>`] : [])
|
...(bookmarks.length > 10 ? [`<a href="/bookmarks/">+${bookmarks.length - 10} more</a>`] : [])
|
||||||
].join('\n')} />
|
].join('\n')} />
|
||||||
</details>
|
</details>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,14 @@
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import yaml from 'js-yaml';
|
|
||||||
import bookmarksRaw from '../content/bookmarks.yaml?raw';
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import type { APIContext } from 'astro';
|
import type { APIContext } from 'astro';
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
interface Bookmark {
|
|
||||||
date: string;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function GET(context: APIContext) {
|
export async function GET(context: APIContext) {
|
||||||
const site = context.site?.origin ?? 'https://wynne.rs';
|
const site = context.site?.origin ?? 'https://wynne.rs';
|
||||||
const posts = await getCollection('posts', ({ data }) => data.draft !== true);
|
const posts = await getCollection('posts', ({ data }) => data.draft !== true);
|
||||||
const bookmarks = yaml.load(bookmarksRaw) as Bookmark[];
|
const bookmarks = await getCollection('bookmarks');
|
||||||
|
|
||||||
const txtDir = path.join(process.cwd(), 'public/txt');
|
const txtDir = path.join(process.cwd(), 'public/txt');
|
||||||
const txtFiles = fs.existsSync(txtDir)
|
const txtFiles = fs.existsSync(txtDir)
|
||||||
|
|
@ -26,7 +18,7 @@ export async function GET(context: APIContext) {
|
||||||
const urls = [
|
const urls = [
|
||||||
...posts.map(post => `/md/${post.id}`),
|
...posts.map(post => `/md/${post.id}`),
|
||||||
...txtFiles.map(txt => `/txt/${txt}`),
|
...txtFiles.map(txt => `/txt/${txt}`),
|
||||||
...bookmarks.map(b => b.url),
|
...bookmarks.map(b => b.data.url),
|
||||||
];
|
];
|
||||||
|
|
||||||
const random = urls[Math.floor(Math.random() * urls.length)];
|
const random = urls[Math.floor(Math.random() * urls.length)];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue