From 8dabe603228fe14487b98bf7ce4b8a2689fa68f2 Mon Sep 17 00:00:00 2001 From: Jade Ellis Date: Mon, 6 Jan 2025 19:17:57 +0000 Subject: [PATCH] Add types and don't show unlisted posts in HTML, feeds and sitemap. Fix JSON feed URLs. --- packages/website/src/lib/pageTypes.d.ts | 28 +++++++++++++++++++ .../website/src/routes/blog/+page.server.ts | 2 +- packages/website/src/routes/blog/+page.svelte | 13 ++++----- .../src/routes/blog/feed.json/+server.ts | 18 ++++++------ packages/website/src/routes/blog/posts.ts | 24 +++++++++++----- .../src/routes/blog/rss.xml/+server.ts | 16 ++++++----- .../src/routes/sitemap[[page]].xml/+server.ts | 2 +- 7 files changed, 72 insertions(+), 31 deletions(-) create mode 100644 packages/website/src/lib/pageTypes.d.ts diff --git a/packages/website/src/lib/pageTypes.d.ts b/packages/website/src/lib/pageTypes.d.ts new file mode 100644 index 00000000..1563d447 --- /dev/null +++ b/packages/website/src/lib/pageTypes.d.ts @@ -0,0 +1,28 @@ + +export interface MdsvexPage { + readingTime: ReadingTime + flattenedHeadings: FlattenedHeading[] + headings: NestedHeading[] + [key: string]: unknown +} + + +export interface ReadingTime { + text: string + minutes: number + time: number + words: number +} + +export interface FlattenedHeading { + level: number + title: string + id: string +} + +export interface NestedHeading { + level: number + title: string + id: string + children: NestedHeading[] +} diff --git a/packages/website/src/routes/blog/+page.server.ts b/packages/website/src/routes/blog/+page.server.ts index e5b3919d..3b61b914 100644 --- a/packages/website/src/routes/blog/+page.server.ts +++ b/packages/website/src/routes/blog/+page.server.ts @@ -3,6 +3,6 @@ import { pages } from './posts' export async function load({ params }) { return { - pages + pages: pages.filter((page) => page.listed !== "false") } } \ No newline at end of file diff --git a/packages/website/src/routes/blog/+page.svelte b/packages/website/src/routes/blog/+page.svelte index 28e9e281..4b4708a4 100644 --- a/packages/website/src/routes/blog/+page.svelte +++ b/packages/website/src/routes/blog/+page.svelte @@ -4,12 +4,11 @@ import SvelteSeo from "svelte-seo"; import type { WithContext, Thing } from "schema-dts"; - interface Props { - data: any; - } + import type { BlogPage } from "./posts"; - let { data }: Props = $props(); + const { data }: { data: { pages: BlogPage[] } } = $props(); const { pages } = data; + console.log(data) const jsonLd = { "@context": "https://schema.org", @@ -23,15 +22,15 @@ "@type": "ListItem", position: 1, name: "Blog", - item: SITE_URL + "/blog", + item: `${SITE_URL}/blog`, }, ], }, mainEntity: { "@type": "Blog", - "@id": SITE_URL + "/blog", + "@id": `${SITE_URL}/blog`, name: "Jade's Blog", - mainEntityOfPage: SITE_URL + "/blog", + mainEntityOfPage: `${SITE_URL}/blog`, }, } as WithContext; diff --git a/packages/website/src/routes/blog/feed.json/+server.ts b/packages/website/src/routes/blog/feed.json/+server.ts index 62b08694..1bb0a8ed 100644 --- a/packages/website/src/routes/blog/feed.json/+server.ts +++ b/packages/website/src/routes/blog/feed.json/+server.ts @@ -1,4 +1,4 @@ -import { pages } from '../posts' +import { pages, type BlogPage } from '../posts' import type Feed from '@json-feed-types/1_1' import { @@ -23,9 +23,9 @@ export async function GET({ params, url}) { .filter((post) => { const date = new Date(post.date) return ( - (!dateParts[0] || date.getFullYear() == dateParts[0]) && - (!dateParts[1] || date.getMonth()+1 == dateParts[1]) && - (!dateParts[2] || date.getDate() == dateParts[2]) + (!dateParts[0] || date.getFullYear() === dateParts[0]) && + (!dateParts[1] || date.getMonth()+1 === dateParts[1]) && + (!dateParts[2] || date.getDate() === dateParts[2]) ) }) : pages; const headers = { @@ -37,7 +37,7 @@ export async function GET({ params, url}) { const AUTHOR = "Jade Ellis" // prettier-ignore -async function getJsonFeed(selfUrl: string, pages: any[]): Promise { +async function getJsonFeed(selfUrl: string, pages: BlogPage[]): Promise { const feed: Feed = { version: 'https://jsonfeed.org/version/1.1', @@ -51,14 +51,16 @@ async function getJsonFeed(selfUrl: string, pages: any[]): Promise { ], } - for await (const post of pages) { + const shownPages = pages.filter((page) => page.listed !== "false") + + for await (const post of shownPages) { const title = post.title; const pubDate = post.date - const postUrl = SITE_URL + "/blog/" + post.canonical + const postUrl = `${SITE_URL}/blog/${post.canonical}` // const postHtml = const summary = post.description; const item: typeof feed.items[number] = { - id: post.postUrl, + id: postUrl, title, url: postUrl, date_published: pubDate, diff --git a/packages/website/src/routes/blog/posts.ts b/packages/website/src/routes/blog/posts.ts index a1571932..42800292 100644 --- a/packages/website/src/routes/blog/posts.ts +++ b/packages/website/src/routes/blog/posts.ts @@ -2,11 +2,12 @@ import { browser } from '$app/environment' // import { format } from 'date-fns' import slugify from 'slugify'; -import { parse, format, relative } from "node:path"; +import { parse, type ParsedPath } from "node:path"; +import type { MdsvexPage } from '$lib/pageTypes'; // we require some server-side APIs to parse all metadata if (browser) { - throw new Error(`posts can only be imported server-side`) + throw new Error("posts can only be imported server-side") } // import { browser } from '$app/environment' // import { format } from 'date-fns' @@ -66,7 +67,17 @@ if (browser) { // })) const dateRegex = /^((?\d{4})-(?[0][1-9]|1[0-2])-(?[0][1-9]|[1-2]\d|3[01]))\s*/ -export const pages = (await Promise.all(Object.entries(import.meta.glob('$notes/Blogs/*.md', { eager: true})) +export interface BlogPage extends MdsvexPage { + title: string + date: string + canonical: string + slug: string + description: string + filepath: ParsedPath + syndication?: string[] + listed?: string +} +export const pages: BlogPage[] = (await Promise.all(Object.entries(import.meta.glob('$notes/Blogs/*.md', { eager: true })) .map(async ([filepath, post]) => { const path = parse(filepath); const title = path.name.replace(dateRegex, "") @@ -79,14 +90,15 @@ export const pages = (await Promise.all(Object.entries(import.meta.glob('$notes/ const datePath = date.replaceAll("-", "/") const slug = slugify(title, { lower: true }) + return { title, date, - canonical: datePath + "/" + slug, + canonical: `${datePath}/${slug}`, + slug, // @ts-ignore ...post.metadata, - slug, filepath: path } }))) @@ -99,8 +111,6 @@ export const pages = (await Promise.all(Object.entries(import.meta.glob('$notes/ // next: allPosts[index - 1], // previous: allPosts[index + 1] // })) - - // function addTimezoneOffset(date) { // const offsetInMilliseconds = new Date().getTimezoneOffset() * 60 * 1000 // return new Date(new Date(date).getTime() + offsetInMilliseconds) diff --git a/packages/website/src/routes/blog/rss.xml/+server.ts b/packages/website/src/routes/blog/rss.xml/+server.ts index 506ae080..a7fa42df 100644 --- a/packages/website/src/routes/blog/rss.xml/+server.ts +++ b/packages/website/src/routes/blog/rss.xml/+server.ts @@ -1,4 +1,4 @@ -import { pages } from '../posts' +import { pages, type BlogPage } from '../posts' import { SITE_DEFAULT_DESCRIPTION, @@ -25,9 +25,9 @@ export async function GET({ url, params }) { .filter((post) => { const date = new Date(post.date) return ( - (!dateParts[0] || date.getFullYear() == dateParts[0]) && - (!dateParts[1] || date.getMonth()+1 == dateParts[1]) && - (!dateParts[2] || date.getDate() == dateParts[2]) + (!dateParts[0] || date.getFullYear() === dateParts[0]) && + (!dateParts[1] || date.getMonth()+1 === dateParts[1]) && + (!dateParts[2] || date.getDate() === dateParts[2]) ) }) : pages; const headers = { @@ -40,7 +40,7 @@ export async function GET({ url, params }) { const AUTHOR = "Jade Ellis" // prettier-ignore -async function getRssXml(selfUrl: string, pages: any[]): Promise { +async function getRssXml(selfUrl: string, pages: BlogPage[]): Promise { // const rssUrl = `${SITE_URL}/rss.xml`; const root = create({ version: '1.0', encoding: 'utf-8' }) .ins('xml-stylesheet', `type="text/xsl" href="${rssStyle}"`) @@ -58,11 +58,13 @@ async function getRssXml(selfUrl: string, pages: any[]): Promise { .ele('name').txt(AUTHOR).up() .up() .ele('subtitle').txt(SITE_DEFAULT_DESCRIPTION).up() + + const shownPages = pages.filter((page) => page.listed !== "false") - for await (const post of pages) { + for await (const post of shownPages) { const title = post.title; const pubDate = post.date - const postUrl = SITE_URL + "/blog/" + post.canonical + const postUrl = `${SITE_URL}/blog/${post.canonical}` // const postHtml = const summary = post.description; diff --git a/packages/website/src/routes/sitemap[[page]].xml/+server.ts b/packages/website/src/routes/sitemap[[page]].xml/+server.ts index f3fe4df1..7052ece3 100644 --- a/packages/website/src/routes/sitemap[[page]].xml/+server.ts +++ b/packages/website/src/routes/sitemap[[page]].xml/+server.ts @@ -28,7 +28,7 @@ export const GET: RequestHandler = async ({ params }) => { page: params.page, paramValues: { '/projects/[slug]': projects, - '/blog/[...date]/[slug]': blogPosts.map((post) => post.canonical) + '/blog/[...date]/[slug]': blogPosts.filter((page) => page.listed !== "false").map((post) => post.canonical) } }); }; \ No newline at end of file