Add types and don't show unlisted posts in HTML, feeds and sitemap. Fix JSON feed URLs.

This commit is contained in:
Jade Ellis
2025-01-06 19:17:57 +00:00
parent d6a648b6e7
commit 8dabe60322
7 changed files with 72 additions and 31 deletions
+28
View File
@@ -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[]
}
@@ -3,6 +3,6 @@ import { pages } from './posts'
export async function load({ params }) { export async function load({ params }) {
return { return {
pages pages: pages.filter((page) => page.listed !== "false")
} }
} }
@@ -4,12 +4,11 @@
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
import type { WithContext, Thing } from "schema-dts"; import type { WithContext, Thing } from "schema-dts";
interface Props { import type { BlogPage } from "./posts";
data: any;
}
let { data }: Props = $props(); const { data }: { data: { pages: BlogPage[] } } = $props();
const { pages } = data; const { pages } = data;
console.log(data)
const jsonLd = { const jsonLd = {
"@context": "https://schema.org", "@context": "https://schema.org",
@@ -23,15 +22,15 @@
"@type": "ListItem", "@type": "ListItem",
position: 1, position: 1,
name: "Blog", name: "Blog",
item: SITE_URL + "/blog", item: `${SITE_URL}/blog`,
}, },
], ],
}, },
mainEntity: { mainEntity: {
"@type": "Blog", "@type": "Blog",
"@id": SITE_URL + "/blog", "@id": `${SITE_URL}/blog`,
name: "Jade's Blog", name: "Jade's Blog",
mainEntityOfPage: SITE_URL + "/blog", mainEntityOfPage: `${SITE_URL}/blog`,
}, },
} as WithContext<Thing>; } as WithContext<Thing>;
</script> </script>
@@ -1,4 +1,4 @@
import { pages } from '../posts' import { pages, type BlogPage } from '../posts'
import type Feed from '@json-feed-types/1_1' import type Feed from '@json-feed-types/1_1'
import { import {
@@ -23,9 +23,9 @@ export async function GET({ params, url}) {
.filter((post) => { .filter((post) => {
const date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() === dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) && (!dateParts[1] || date.getMonth()+1 === dateParts[1]) &&
(!dateParts[2] || date.getDate() == dateParts[2]) (!dateParts[2] || date.getDate() === dateParts[2])
) )
}) : pages; }) : pages;
const headers = { const headers = {
@@ -37,7 +37,7 @@ export async function GET({ params, url}) {
const AUTHOR = "Jade Ellis" const AUTHOR = "Jade Ellis"
// prettier-ignore // prettier-ignore
async function getJsonFeed(selfUrl: string, pages: any[]): Promise<string> { async function getJsonFeed(selfUrl: string, pages: BlogPage[]): Promise<string> {
const feed: Feed = { const feed: Feed = {
version: 'https://jsonfeed.org/version/1.1', version: 'https://jsonfeed.org/version/1.1',
@@ -51,14 +51,16 @@ async function getJsonFeed(selfUrl: string, pages: any[]): Promise<string> {
], ],
} }
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 title = post.title;
const pubDate = post.date const pubDate = post.date
const postUrl = SITE_URL + "/blog/" + post.canonical const postUrl = `${SITE_URL}/blog/${post.canonical}`
// const postHtml = // const postHtml =
const summary = post.description; const summary = post.description;
const item: typeof feed.items[number] = { const item: typeof feed.items[number] = {
id: post.postUrl, id: postUrl,
title, title,
url: postUrl, url: postUrl,
date_published: pubDate, date_published: pubDate,
+17 -7
View File
@@ -2,11 +2,12 @@ import { browser } from '$app/environment'
// import { format } from 'date-fns' // import { format } from 'date-fns'
import slugify from 'slugify'; 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 // we require some server-side APIs to parse all metadata
if (browser) { 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 { browser } from '$app/environment'
// import { format } from 'date-fns' // import { format } from 'date-fns'
@@ -66,7 +67,17 @@ if (browser) {
// })) // }))
const dateRegex = /^((?<year>\d{4})-(?<month>[0][1-9]|1[0-2])-(?<day>[0][1-9]|[1-2]\d|3[01]))\s*/ const dateRegex = /^((?<year>\d{4})-(?<month>[0][1-9]|1[0-2])-(?<day>[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]) => { .map(async ([filepath, post]) => {
const path = parse(filepath); const path = parse(filepath);
const title = path.name.replace(dateRegex, "") 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 datePath = date.replaceAll("-", "/")
const slug = slugify(title, { lower: true }) const slug = slugify(title, { lower: true })
return { return {
title, title,
date, date,
canonical: datePath + "/" + slug, canonical: `${datePath}/${slug}`,
slug,
// @ts-ignore // @ts-ignore
...post.metadata, ...post.metadata,
slug,
filepath: path filepath: path
} }
}))) })))
@@ -99,8 +111,6 @@ export const pages = (await Promise.all(Object.entries(import.meta.glob('$notes/
// next: allPosts[index - 1], // next: allPosts[index - 1],
// previous: allPosts[index + 1] // previous: allPosts[index + 1]
// })) // }))
// function addTimezoneOffset(date) { // function addTimezoneOffset(date) {
// const offsetInMilliseconds = new Date().getTimezoneOffset() * 60 * 1000 // const offsetInMilliseconds = new Date().getTimezoneOffset() * 60 * 1000
// return new Date(new Date(date).getTime() + offsetInMilliseconds) // return new Date(new Date(date).getTime() + offsetInMilliseconds)
@@ -1,4 +1,4 @@
import { pages } from '../posts' import { pages, type BlogPage } from '../posts'
import { import {
SITE_DEFAULT_DESCRIPTION, SITE_DEFAULT_DESCRIPTION,
@@ -25,9 +25,9 @@ export async function GET({ url, params }) {
.filter((post) => { .filter((post) => {
const date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() === dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) && (!dateParts[1] || date.getMonth()+1 === dateParts[1]) &&
(!dateParts[2] || date.getDate() == dateParts[2]) (!dateParts[2] || date.getDate() === dateParts[2])
) )
}) : pages; }) : pages;
const headers = { const headers = {
@@ -40,7 +40,7 @@ export async function GET({ url, params }) {
const AUTHOR = "Jade Ellis" const AUTHOR = "Jade Ellis"
// prettier-ignore // prettier-ignore
async function getRssXml(selfUrl: string, pages: any[]): Promise<string> { async function getRssXml(selfUrl: string, pages: BlogPage[]): Promise<string> {
// const rssUrl = `${SITE_URL}/rss.xml`; // const rssUrl = `${SITE_URL}/rss.xml`;
const root = create({ version: '1.0', encoding: 'utf-8' }) const root = create({ version: '1.0', encoding: 'utf-8' })
.ins('xml-stylesheet', `type="text/xsl" href="${rssStyle}"`) .ins('xml-stylesheet', `type="text/xsl" href="${rssStyle}"`)
@@ -59,10 +59,12 @@ async function getRssXml(selfUrl: string, pages: any[]): Promise<string> {
.up() .up()
.ele('subtitle').txt(SITE_DEFAULT_DESCRIPTION).up() .ele('subtitle').txt(SITE_DEFAULT_DESCRIPTION).up()
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 title = post.title;
const pubDate = post.date const pubDate = post.date
const postUrl = SITE_URL + "/blog/" + post.canonical const postUrl = `${SITE_URL}/blog/${post.canonical}`
// const postHtml = // const postHtml =
const summary = post.description; const summary = post.description;
@@ -28,7 +28,7 @@ export const GET: RequestHandler = async ({ params }) => {
page: params.page, page: params.page,
paramValues: { paramValues: {
'/projects/[slug]': projects, '/projects/[slug]': projects,
'/blog/[...date]/[slug]': blogPosts.map((post) => post.canonical) '/blog/[...date]/[slug]': blogPosts.filter((page) => page.listed !== "false").map((post) => post.canonical)
} }
}); });
}; };