mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Add basic blog functionality
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
import { defineMDSveXConfig as defineConfig } from "mdsvex";
|
||||
// https://github.com/String10/Hakuba/blob/master/package.json
|
||||
// import { defineMDSveXConfig as defineConfig } from "mdsvex";
|
||||
// import type { Plugin, Settings } from 'unified';
|
||||
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkFrontmatter from "remark-frontmatter";
|
||||
import remarkMath from "remark-math";
|
||||
import remarkWikiLink, { } from "remark-wiki-link";
|
||||
|
||||
import slug from 'rehype-slug';
|
||||
import remarkMath from "remark-math"
|
||||
// @ts-ignore
|
||||
import remarkAbbr from "remark-abbr"
|
||||
import remarkFootnotes from 'remark-footnotes'
|
||||
|
||||
import rehypeKatexSvelte from 'rehype-katex-svelte';
|
||||
// import github from "remark-github";
|
||||
|
||||
import rehypeSlug from 'rehype-slug';
|
||||
|
||||
import { parse, format } from "node:path";
|
||||
|
||||
@@ -57,61 +65,68 @@ function pageResolver(pageName) {
|
||||
}
|
||||
|
||||
const hrefTemplate = (/** @type {string} */ permalink) => `#${permalink}`
|
||||
/**
|
||||
* @type {import("mdsvex").MdsvexOptions}
|
||||
*/
|
||||
const config = {
|
||||
extensions: [".svelte.md", ".md", ".svx"],
|
||||
|
||||
const config = defineConfig({
|
||||
extensions: [".svelte.md", ".md", ".svx"],
|
||||
// fences: true,
|
||||
// ruleSpaces: false,
|
||||
smartypants: {
|
||||
dashes: "oldschool",
|
||||
},
|
||||
|
||||
// fences: true,
|
||||
// ruleSpaces: false,
|
||||
smartypants: {
|
||||
dashes: "oldschool",
|
||||
},
|
||||
|
||||
highlight: {
|
||||
alias: {
|
||||
ts: "typescript",
|
||||
mdx: "markdown",
|
||||
svelte: "svelte",
|
||||
svx: "svx",
|
||||
mdsvex: "svx",
|
||||
sig: "ts",
|
||||
}
|
||||
},
|
||||
highlight: {
|
||||
alias: {
|
||||
ts: "typescript",
|
||||
mdx: "markdown",
|
||||
svelte: "svelte",
|
||||
svx: "svx",
|
||||
mdsvex: "svx",
|
||||
sig: "ts",
|
||||
}
|
||||
},
|
||||
|
||||
remarkPlugins: [
|
||||
remarkGfm,
|
||||
remarkFrontmatter,
|
||||
remarkMath,
|
||||
[remarkWikiLink, {
|
||||
// @ts-ignore
|
||||
aliasDivider: "|",
|
||||
permalinks: permalinks,
|
||||
pageResolver,
|
||||
hrefTemplate,
|
||||
|
||||
// wikiLinkClassName,
|
||||
// newClassName,
|
||||
}],
|
||||
// [citePlugin, {
|
||||
// syntax: {
|
||||
// // see micromark-extension-cite
|
||||
// enableAltSyntax: false,
|
||||
// enablePandocSyntax: true,
|
||||
// },
|
||||
// toMarkdown: {
|
||||
// // see mdast-util-cite
|
||||
// standardizeAltSyntax: false,
|
||||
// enableAuthorSuppression: true,
|
||||
// useNodeValue: false,
|
||||
// },
|
||||
// }],
|
||||
// [remarkBibliography, { bibliography }],
|
||||
// [remarkMermaid, {}]
|
||||
],
|
||||
rehypePlugins: [
|
||||
// @ts-ignore
|
||||
slug
|
||||
],
|
||||
});
|
||||
remarkPlugins: [
|
||||
// remarkFrontmatter,
|
||||
// [github, {repository}],
|
||||
remarkMath,
|
||||
remarkAbbr,
|
||||
[remarkFootnotes, { inlineNotes: true }],
|
||||
remarkGfm,
|
||||
[remarkWikiLink, {
|
||||
// @ts-ignore
|
||||
aliasDivider: "|",
|
||||
permalinks: permalinks,
|
||||
pageResolver,
|
||||
hrefTemplate,
|
||||
|
||||
// wikiLinkClassName,
|
||||
// newClassName,
|
||||
}],
|
||||
// [citePlugin, {
|
||||
// syntax: {
|
||||
// // see micromark-extension-cite
|
||||
// enableAltSyntax: false,
|
||||
// enablePandocSyntax: true,
|
||||
// },
|
||||
// toMarkdown: {
|
||||
// // see mdast-util-cite
|
||||
// standardizeAltSyntax: false,
|
||||
// enableAuthorSuppression: true,
|
||||
// useNodeValue: false,
|
||||
// },
|
||||
// }],
|
||||
// [remarkBibliography, { bibliography }],
|
||||
// [remarkMermaid, {}]
|
||||
],
|
||||
rehypePlugins: [
|
||||
// @ts-ignore
|
||||
rehypeKatexSvelte,
|
||||
// @ts-ignore
|
||||
rehypeSlug
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -22,10 +22,14 @@
|
||||
"@types/sharedworker": "^0.0.115",
|
||||
"glob": "^10.4.1",
|
||||
"mdsvex": "^0.11.2",
|
||||
"rehype-katex-svelte": "1.2",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-abbr": "^1.4.2",
|
||||
"remark-footnotes": "2",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-math": "^6.0.0",
|
||||
"remark-github": "^12.0.0",
|
||||
"remark-math": "^3.0.1",
|
||||
"remark-wiki-link": "^2.0.1",
|
||||
"rollup": "^4.18.0",
|
||||
"rollup-plugin-type-as-json-schema": "^0.2.6",
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
</a>
|
||||
</li>
|
||||
<!-- <li><a href="/about/" class="navbar-link">About</a></li>
|
||||
<li><a href="/art/" class="navbar-link">Art</a></li>
|
||||
<li><a href="/blog/" class="navbar-link">Blog</a></li> -->
|
||||
<li><a href="/art/" class="navbar-link">Art</a></li> -->
|
||||
<li><a href="/blog/" class="navbar-link">Blog</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function match(value) {
|
||||
return /^\d+$/.test(value);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { pages } from './posts'
|
||||
|
||||
export async function load({ params }) {
|
||||
|
||||
return {
|
||||
pages
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
|
||||
export let data;
|
||||
let { pages } = data;
|
||||
$: console.log(data);
|
||||
</script>
|
||||
|
||||
<section role="feed">
|
||||
<h1>Blog Posts</h1>
|
||||
{#each pages as post, index}
|
||||
<article aria-posinset={index + 1} aria-setsize={pages.length}>
|
||||
<div class="content" data-sveltekit-preload-data="hover">
|
||||
<h2>
|
||||
<a href="/blog/{post.canonical}" class="text-link">
|
||||
{post.title}
|
||||
</a>
|
||||
</h2>
|
||||
<span class="quiet">{post.date}</span>
|
||||
{#if post.description}
|
||||
<p>{post.description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</article>
|
||||
{:else}
|
||||
<p>No posts yet!</p>
|
||||
{/each}
|
||||
<!-- {#if showPosts < postCount}
|
||||
<button type="submit" on:click={handleClick}>See more {H_ELLIPSIS_ENTITY}</button>
|
||||
{/if} -->
|
||||
</section>
|
||||
@@ -0,0 +1,43 @@
|
||||
import { pages } from '../../posts'
|
||||
import { error } from '@sveltejs/kit'
|
||||
import TTLCache, { } from "@isaacs/ttlcache";
|
||||
import { parse } from "@tusbar/cache-control";
|
||||
const cache = new TTLCache({ max: 10000, ttl: 1000 })
|
||||
|
||||
import type { Endpoints } from "@octokit/types";
|
||||
|
||||
let repoRegex = new RegExp("https?://github\.com/(?<repo>[a-zA-Z0-9]+/[a-zA-Z0-9]+)/?")
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export async function load({ params }) {
|
||||
const { slug } = params
|
||||
let dateParts = params.date.split(/[\/-]/).map((p) => parseInt(p, 10))
|
||||
if (dateParts.length > 3) {
|
||||
throw error(404, 'Post not found (bad date)')
|
||||
}
|
||||
|
||||
// let start = new Date(dateParts[0] || 1, dateParts[1] || 0, dateParts[2] || 0);
|
||||
// // @ts-ignore
|
||||
// let end = new Date(...dateParts);
|
||||
// console.log(dateParts)
|
||||
|
||||
// get post with metadata
|
||||
const page = pages
|
||||
.filter((post) => slug === post.slug)
|
||||
.filter((post) => {
|
||||
let 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])
|
||||
)
|
||||
})[0]
|
||||
|
||||
if (!page) {
|
||||
throw error(404, 'Post not found')
|
||||
}
|
||||
|
||||
return {
|
||||
page
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
// https://github.com/mattjennings/sveltekit-blog-template/blob/main/src/routes/post/%5Bslug%5D/%2Bpage.svelte
|
||||
|
||||
import SvelteSeo from "svelte-seo";
|
||||
export let data;
|
||||
import { SITE_URL } from "$lib/metadata";
|
||||
// let GhReleasesDownload: Promise<any>;
|
||||
// if (data.ghReleaseData) {
|
||||
// GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default)
|
||||
// }
|
||||
|
||||
console.log(data)
|
||||
</script>
|
||||
|
||||
<SvelteSeo
|
||||
title={data.post.title}
|
||||
description={data.post.description}
|
||||
canonical={SITE_URL + "/blog/" + data.post.canonical}
|
||||
/>
|
||||
<h1>{data.post.title}</h1>
|
||||
<!-- {#await GhReleasesDownload}
|
||||
|
||||
{:then component}
|
||||
<svelte:component this={component} releaseData={data.ghReleaseData} />
|
||||
{/await} -->
|
||||
|
||||
<svelte:component this={data.component} />
|
||||
@@ -0,0 +1,22 @@
|
||||
// import { pages } from './projects'
|
||||
import { error } from '@sveltejs/kit'
|
||||
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export async function load({ data, params }) {
|
||||
// if (!post) {
|
||||
// throw error(404, 'Post not found')
|
||||
// }
|
||||
// load the markdown file based on slug
|
||||
console.log(data)
|
||||
const component =
|
||||
// await import(data.page.filepath)
|
||||
await import("Notes/Blogs/" + data.page.filepath.name + ".md")
|
||||
// console.log(data.page.filepath)
|
||||
|
||||
|
||||
return {
|
||||
post: data.page,
|
||||
component: component.default
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { browser } from '$app/environment'
|
||||
// import { format } from 'date-fns'
|
||||
|
||||
import slugify from 'slugify';
|
||||
import { parse, format, relative } from "node:path";
|
||||
|
||||
// we require some server-side APIs to parse all metadata
|
||||
if (browser) {
|
||||
throw new Error(`posts can only be imported server-side`)
|
||||
}
|
||||
// import { browser } from '$app/environment'
|
||||
// import { format } from 'date-fns'
|
||||
// import { parse } from 'node-html-parser'
|
||||
// import readingTime from 'reading-time/lib/reading-time.js'
|
||||
|
||||
// // we require some server-side APIs to parse all metadata
|
||||
// if (browser) {
|
||||
// throw new Error(`posts can only be imported server-side`)
|
||||
// }
|
||||
|
||||
// // Get all posts and add metadata
|
||||
// export const posts = Object.entries(import.meta.glob('/posts/**/*.md', { eager: true }))
|
||||
// .map(([filepath, post]) => {
|
||||
// const html = parse(post.default.render().html)
|
||||
// const preview = post.metadata.preview ? parse(post.metadata.preview) : html.querySelector('p')
|
||||
|
||||
// return {
|
||||
// ...post.metadata,
|
||||
|
||||
// // generate the slug from the file path
|
||||
// slug: filepath
|
||||
// .replace(/(\/index)?\.md/, '')
|
||||
// .split('/')
|
||||
// .pop(),
|
||||
|
||||
// // whether or not this file is `my-post.md` or `my-post/index.md`
|
||||
// // (needed to do correct dynamic import in posts/[slug].svelte)
|
||||
// isIndexFile: filepath.endsWith('/index.md'),
|
||||
|
||||
// // format date as yyyy-MM-dd
|
||||
// date: post.metadata.date
|
||||
// ? format(
|
||||
// // offset by timezone so that the date is correct
|
||||
// addTimezoneOffset(new Date(post.metadata.date)),
|
||||
// 'yyyy-MM-dd'
|
||||
// )
|
||||
// : undefined,
|
||||
|
||||
// preview: {
|
||||
// html: preview.toString(),
|
||||
// // text-only preview (i.e no html elements), used for SEO
|
||||
// text: preview.structuredText ?? preview.toString()
|
||||
// },
|
||||
|
||||
// // get estimated reading time for the post
|
||||
// readingTime: readingTime(html.structuredText).text
|
||||
// }
|
||||
// })
|
||||
// // sort by date
|
||||
// .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
// // add references to the next/previous post
|
||||
// .map((post, index, allPosts) => ({
|
||||
// ...post,
|
||||
// next: allPosts[index - 1],
|
||||
// previous: allPosts[index + 1]
|
||||
// }))
|
||||
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 = Object.entries(import.meta.glob('/node_modules/Notes/Blogs/*.md', { eager: true }))
|
||||
.map(([filepath, post]) => {
|
||||
let path = parse(filepath);
|
||||
let title = path.name.replace(dateRegex, "")
|
||||
|
||||
// @ts-ignore
|
||||
// let {year, month, day}: { year: string, month: string, day: string } = path.name.match(dateRegex)?.groups;
|
||||
|
||||
// console.log(year, month, day)
|
||||
let date = path.name.match(dateRegex)[1];
|
||||
let datePath = date.replaceAll("-", "/")
|
||||
let slug = slugify(title, { lower: true })
|
||||
return {
|
||||
title,
|
||||
date,
|
||||
canonical: datePath + "/" + slug,
|
||||
// @ts-ignore
|
||||
...post.metadata,
|
||||
|
||||
slug,
|
||||
// filepath: relative(import.meta.dirname, filepath)
|
||||
filepath: path
|
||||
}
|
||||
})
|
||||
// sort by date
|
||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
// Get all posts and add metadata
|
||||
// // add references to the next/previous post
|
||||
// .map((post, index, allPosts) => ({
|
||||
// ...post,
|
||||
// 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)
|
||||
// }
|
||||
@@ -6,8 +6,8 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import slugify from 'slugify';
|
||||
|
||||
import { parse, format } from "node:path";
|
||||
|
||||
const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true }))
|
||||
import { pages as blogPosts } from "../blog/posts"
|
||||
const projects = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true }))
|
||||
.map(([filepath, post]) => {
|
||||
return parse(filepath)
|
||||
})
|
||||
@@ -27,7 +27,8 @@ export const GET: RequestHandler = async ({ params }) => {
|
||||
origin: SITE_URL,
|
||||
page: params.page,
|
||||
paramValues: {
|
||||
'/projects/[slug]': pages
|
||||
'/projects/[slug]': projects,
|
||||
'/blog/[...date]/[slug]': blogPosts.map((post) => post.canonical)
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -8,7 +8,7 @@ import cspDirectives from "./csp.js";
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
|
||||
const config = {
|
||||
extensions: [".svelte", ".md"],
|
||||
extensions: ['.svelte', '.md', '.svelte.md'],
|
||||
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
|
||||
Reference in New Issue
Block a user