Add MDsveX and projects page

This commit is contained in:
Jade Ellis
2024-05-01 18:34:30 +01:00
parent bc3ae9cd81
commit e26f653a46
12 changed files with 1568 additions and 124 deletions
+117
View File
@@ -0,0 +1,117 @@
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 { parse, format } from "node:path";
import slugify from 'slugify';
export const NOTE_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="2" x2="22" y2="6"></line><path d="M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"></path></svg>';
export const QUOTE_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"></path><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"></path></svg>';
export const INFO_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>';
export const ICONS = {
note: NOTE_ICON,
quote: QUOTE_ICON,
info: INFO_ICON,
};
import { globSync } from 'glob'
const projects = globSync('/node_modules/Notes/Projects/*.md')
.map((filepath) => {
return parse(filepath)
})
.map((path) => {
return format({
// ...path,
name: slugify(path.name, { lower: true }),
// base: undefined,
// root: "",
// ext: undefined,
// dir: path.dir.replace("/node_modules/Notes/Projects", "")
})
})
/**
* @type {string[]}
*/
const permalinks = projects.map((p) => "/projects/" + p)
/**
* @param {string} pageName
* @returns {string[]}
*/
function pageResolver(pageName) {
const slug = slugify(pageName, { lower: true });
return ["/", "/projects/"].map((p) => p + slug);
}
const hrefTemplate = (/** @type {string} */ permalink) => `#${permalink}`
const config = defineConfig({
extensions: [".svelte.md", ".md", ".svx"],
fences: true,
ruleSpaces: false,
smartypants: {
dashes: "oldschool",
},
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
],
});
export default config;
+13
View File
@@ -11,11 +11,20 @@
"devDependencies": { "devDependencies": {
"@fontsource/fira-mono": "^5.0.13", "@fontsource/fira-mono": "^5.0.13",
"@json-feed-types/1_1": "^1.0.2", "@json-feed-types/1_1": "^1.0.2",
"@rollup/plugin-dynamic-import-vars": "^2.1.2",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@sveltejs/adapter-auto": "^3.2.0", "@sveltejs/adapter-auto": "^3.2.0",
"@sveltejs/adapter-node": "^5.0.1", "@sveltejs/adapter-node": "^5.0.1",
"@sveltejs/kit": "^2.5.7", "@sveltejs/kit": "^2.5.7",
"@sveltejs/vite-plugin-svelte": "^3.1.0", "@sveltejs/vite-plugin-svelte": "^3.1.0",
"@types/node": "^20.12.7",
"glob": "^10.3.12",
"mdsvex": "^0.11.0",
"rehype-slug": "^6.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"remark-math": "^6.0.0",
"remark-wiki-link": "^2.0.1",
"rollup": "^4.17.0", "rollup": "^4.17.0",
"rollup-plugin-type-as-json-schema": "^0.2.6", "rollup-plugin-type-as-json-schema": "^0.2.6",
"sharp": "^0.33.3", "sharp": "^0.33.3",
@@ -26,7 +35,9 @@
"svgo": "^3.2.0", "svgo": "^3.2.0",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"unified": "^11.0.4",
"vite": "^5.2.10", "vite": "^5.2.10",
"vite-plugin-dynamic-import": "^1.5.0",
"vite-plugin-image-optimizer": "^1.1.7" "vite-plugin-image-optimizer": "^1.1.7"
}, },
"type": "module", "type": "module",
@@ -39,8 +50,10 @@
"@lezer/highlight": "^1.2.0", "@lezer/highlight": "^1.2.0",
"@steeze-ui/svelte-icon": "^1.5.0", "@steeze-ui/svelte-icon": "^1.5.0",
"@uiw/codemirror-theme-github": "^4.21.25", "@uiw/codemirror-theme-github": "^4.21.25",
"Notes": "link:~/Documents/Notes/",
"acorn": "^8.11.3", "acorn": "^8.11.3",
"magic-string": "^0.30.10", "magic-string": "^0.30.10",
"slugify": "^1.6.6",
"super-sitemap": "^0.14.14", "super-sitemap": "^0.14.14",
"svelte-codemirror-editor": "^1.3.0", "svelte-codemirror-editor": "^1.3.0",
"terser": "^5.30.4", "terser": "^5.30.4",
@@ -4,6 +4,8 @@
import { bookmarkify, parseMeta } from "./bookmarklets"; import { bookmarkify, parseMeta } from "./bookmarklets";
import type { Config } from "./config"; import type { Config } from "./config";
import { SITE_URL } from '$lib/metadata';
/** @type {import('./$types').Snapshot<string>} */ /** @type {import('./$types').Snapshot<string>} */
export const snapshot = { export const snapshot = {
capture: () => value, capture: () => value,
@@ -29,7 +31,7 @@
<SvelteSeo <SvelteSeo
title="Bookmarklet Maker" title="Bookmarklet Maker"
description="Make booklets in your browser with this tool. Make handy shortcuts to save time." description="Make booklets in your browser with this tool. Make handy shortcuts to save time."
canonical="https://jade.ellis.link/bookmarklets" canonical={SITE_URL + "/bookmarklets"}
/> />
<h1>Bookmarklet Maker</h1> <h1>Bookmarklet Maker</h1>
<Editor <Editor
@@ -0,0 +1,18 @@
import { pages } from './projects'
import { error } from '@sveltejs/kit'
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const { slug } = params
// get post with metadata
const page = pages.find((post) => slug === post.slug)
if (!page) {
throw error(404, 'Post not found')
}
return {
page
}
}
@@ -0,0 +1,14 @@
<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';
</script>
<SvelteSeo
title={data.post.title}
canonical={SITE_URL + "/projects/" + data.post.slug}
/>
<h1>{data.post.title}</h1>
<svelte:component this={data.component} />
@@ -0,0 +1,21 @@
// import { pages } from './projects'
import { error } from '@sveltejs/kit'
/** @type {import('./$types').PageServerLoad} */
export async function load({ data }) {
// if (!post) {
// throw error(404, 'Post not found')
// }
// load the markdown file based on slug
const component =
// await import(data.page.filepath)
await import("Notes/Projects/" + data.page.filepath.name + ".md")
// console.log(data.page.filepath)
return {
post: data.page,
component: component.default
}
}
@@ -0,0 +1,61 @@
// 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]
// }))
// function addTimezoneOffset(date) {
// const offsetInMilliseconds = new Date().getTimezoneOffset() * 60 * 1000
// return new Date(new Date(date).getTime() + offsetInMilliseconds)
// }
@@ -0,0 +1,33 @@
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`)
}
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true }))
.map(([filepath, post]) => {
let path = parse(filepath);
let slug = slugify(path.name, { lower: true })
return {
title: path.name,
// @ts-ignore
...post.metadata,
slug,
// filepath: relative(import.meta.dirname, filepath)
filepath: path
}
})
// Get all posts and add metadata
// 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]
// }))
@@ -3,9 +3,31 @@ import * as sitemap from 'super-sitemap';
import { SITE_URL } from '$lib/metadata'; import { SITE_URL } from '$lib/metadata';
import type { RequestHandler } from '@sveltejs/kit'; 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 }))
.map(([filepath, post]) => {
return parse(filepath)
})
.map((path) => {
return format({
// ...path,
name: slugify(path.name, { lower: true }),
// base: undefined,
// root: "",
// ext: undefined,
// dir: path.dir.replace("/node_modules/Notes/Projects", "")
})
})
export const GET: RequestHandler = async ({ params }) => { export const GET: RequestHandler = async ({ params }) => {
return await sitemap.response({ return await sitemap.response({
origin: SITE_URL, origin: SITE_URL,
page: params.page, page: params.page,
paramValues: {
'/projects/[slug]': pages
}
}); });
}; };
+9 -6
View File
@@ -1,15 +1,18 @@
import adapter from '@sveltejs/adapter-node'; import { mdsvex } from "mdsvex";
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import mdsvexConfig from "./mdsvex.config.js";
import adapter from "@sveltejs/adapter-node";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import htmlMinifierAdaptor from "sveltekit-html-minifier"; import htmlMinifierAdaptor from "sveltekit-html-minifier";
import cspDirectives from './csp.js'; import cspDirectives from "./csp.js";
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
extensions: [".svelte", ".md"],
// Consult https://kit.svelte.dev/docs/integrations#preprocessors // Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: [mdsvex(mdsvexConfig), vitePreprocess()],
kit: { kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
@@ -36,7 +39,7 @@ const config = {
mode: "auto", mode: "auto",
directives: cspDirectives, directives: cspDirectives,
}, },
} },
}; };
export default config; export default config;
+39 -8
View File
@@ -1,20 +1,50 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from 'vite'; import { defineConfig } from "vite";
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'; import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
import typeAsJsonSchemaPlugin from 'rollup-plugin-type-as-json-schema'; import dynamicImport from 'vite-plugin-dynamic-import'
import typeAsJsonSchemaPlugin from "rollup-plugin-type-as-json-schema";
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
import { mdsvex } from 'mdsvex';
import mdsvexConfig from "./mdsvex.config.js";
import { extname } from 'node:path';
function mdsvex_transform() {
return {
name: "Mdsvex transformer",
async transform(code: string, id: string) {
if (extname(id) !== ".md") return;
const c = (
await mdsvex(mdsvexConfig).markup({ content: code, filename: id })
)?.code;
return c;
// return `export default \`${c.replace(/`/g, "\\`").trim()}\`;`;
}
};
}
export default defineConfig({ export default defineConfig({
resolve: {
alias: {
"Notes": "node_modules/Notes"
}
},
plugins: [ plugins: [
typeAsJsonSchemaPlugin(), typeAsJsonSchemaPlugin(),
ViteImageOptimizer({ ViteImageOptimizer({
/* pass your config */ /* pass your config */
}), }),
sveltekit() // mdsvex_transform(),
sveltekit(),
dynamicImport({
}),
// dynamicImportVars({
// // options
// })
], ],
build: { build: {
assetsInlineLimit: 0 assetsInlineLimit: 0,
}, },
optimizeDeps: { optimizeDeps: {
exclude: [ exclude: [
@@ -25,6 +55,7 @@ export default defineConfig({
// "@codemirror/autocomplete", // "@codemirror/autocomplete",
// "@codemirror/language", // "@codemirror/language",
// "thememirror" // "thememirror"
/* ... */], /* ... */
],
}, },
}); });
+1117 -8
View File
File diff suppressed because it is too large Load Diff