From 36bb02cf64f7be3bb5f2f0c3b2baa1c91f3affb1 Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Sun, 7 Jul 2024 22:14:24 +0100 Subject: [PATCH] md posts --- package.json | 5 ++++- src/App.tsx | 2 ++ src/components/Default.tsx | 5 ++--- src/components/Post.tsx | 29 +++++++++++++++++++++++++++++ src/posts/test.md | 10 ++++++++++ src/utils/markdownToHtml.ts | 20 ++++++++++++++++++++ tsconfig.node.json | 16 ++++++++-------- vite.config.ts | 20 ++++++++++++++++++-- 8 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 src/components/Post.tsx create mode 100644 src/posts/test.md create mode 100644 src/utils/markdownToHtml.ts diff --git a/package.json b/package.json index ac45d44..fe8f8af 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,13 @@ "dependencies": { "@dimforge/rapier2d": "^0.11.2", "@tldraw/tldraw": "2.0.2", + "@types/markdown-it": "^14.1.1", "@vercel/analytics": "^1.2.2", + "gray-matter": "^4.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3" + "react-router-dom": "^6.22.3", + "vite-plugin-md": "^0.21.5" }, "devDependencies": { "@biomejs/biome": "1.4.1", diff --git a/src/App.tsx b/src/App.tsx index 0885a60..ed14069 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import { useCanvas } from "@/hooks/useCanvas" import { createShapes } from "@/utils"; import { BrowserRouter, Route, Routes } from 'react-router-dom'; import { Contact } from "@/components/Contact"; +import { Post } from '@/components/Post'; inject(); ReactDOM.createRoot(document.getElementById("root")!).render(); @@ -23,6 +24,7 @@ function App() { } /> } /> + } /> diff --git a/src/components/Default.tsx b/src/components/Default.tsx index 67332e0..5c5022b 100644 --- a/src/components/Default.tsx +++ b/src/components/Default.tsx @@ -23,9 +23,8 @@ export function Default() {

My work

Alongside my independent work I am a researcher at Block Science building{' '} - knowledge organisation infrastructure and at ECSA working on{' '} - computational media. I am also part of the nascent Liberatory Computing{' '} - collective and a co-organiser of the OCWG. + knowledge organisation infrastructure and an engineer-in-residence at tldraw. I am also part of the nascent Liberatory Computing{' '} + collective, occasional collaborator with ECSA and a co-organiser of the OCWG.

Get in touch

diff --git a/src/components/Post.tsx b/src/components/Post.tsx new file mode 100644 index 0000000..d9f6754 --- /dev/null +++ b/src/components/Post.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; + +export function Post() { + const { slug } = useParams<{ slug: string }>(); + const [post, setPost] = React.useState<{ title: string, html: string } | null>(null); + + React.useEffect(() => { + import(`../posts/${slug}.md`) + .then((module) => { + setPost(module.default); + }) + .catch((error) => { + console.error('Failed to load post:', error); + setPost(null); + }); + }, [slug]); + + if (!post) { + return
Loading...
; + } + + return ( +
+

{post.title}

+
+
+ ); +} \ No newline at end of file diff --git a/src/posts/test.md b/src/posts/test.md new file mode 100644 index 0000000..11aaa28 --- /dev/null +++ b/src/posts/test.md @@ -0,0 +1,10 @@ +# This is a title +this is some text under the title + +here is an image: +![image](image.png) + +requirements: +- basic html (headings, quotes, italics, bold...) +- images and videos (easy authoring, what are the vercel limits too?) +- static gen, we don't want SPA pop-in, we want 100% prerendered html \ No newline at end of file diff --git a/src/utils/markdownToHtml.ts b/src/utils/markdownToHtml.ts new file mode 100644 index 0000000..857eabb --- /dev/null +++ b/src/utils/markdownToHtml.ts @@ -0,0 +1,20 @@ +import MarkdownIt from 'markdown-it'; + +const md = new MarkdownIt({ + html: true, + breaks: true, + linkify: true, +}); + +// Customize Markdown-to-HTML mapping here +md.renderer.rules.paragraph_open = () => '

'; +md.renderer.rules.image = (tokens, idx, options, env, self) => { + const token = tokens[idx]; + const src = token.attrGet('src'); + const alt = token.content; + return `${alt}`; +}; + +export function markdownToHtml(content: string): string { + return md.render(content); +} \ No newline at end of file diff --git a/tsconfig.node.json b/tsconfig.node.json index 42872c5..bf67dd4 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,10 +1,10 @@ { - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts", "src/utils/*"] } diff --git a/vite.config.ts b/vite.config.ts index 9b55a11..77bb315 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,13 +1,29 @@ -import { defineConfig } from 'vite' +import { defineConfig, Plugin } from 'vite' import react from '@vitejs/plugin-react' import wasm from "vite-plugin-wasm"; import topLevelAwait from "vite-plugin-top-level-await"; +import matter from 'gray-matter'; +import { markdownToHtml } from './src/utils/markdownToHtml'; + +const markdownPlugin: Plugin = { + name: 'markdown-plugin', + enforce: 'pre', + transform(code, id) { + if (id.endsWith('.md')) { + const { data, content } = matter(code); + const html = markdownToHtml(content); + const jsonContent = JSON.stringify({ ...data, html }); + return `export default ${jsonContent};`; + } + }, +}; export default defineConfig({ plugins: [ react(), wasm(), - topLevelAwait() + topLevelAwait(), + markdownPlugin ], build: { sourcemap: true, // Enable source maps for production