Add blog post system to load from markdown files with mdsvex and marked
This commit is contained in:
parent
71e6fb0fab
commit
53313ea02c
|
|
@ -8,3 +8,4 @@ node_modules
|
|||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
/pagesjson
|
||||
|
|
|
|||
|
|
@ -4,18 +4,22 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"build": "node pages/pages.js && vite build",
|
||||
"preview": "vite preview",
|
||||
"buildview": "vite build && vite preview",
|
||||
"buildview": "node pages/pages.js && vite build && vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"md": "node pages/pages.js",
|
||||
"lint": "prettier --plugin-search-dir . --check .",
|
||||
"format": "prettier --plugin-search-dir . --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^2.1.0",
|
||||
"@sveltejs/kit": "^1.21.0",
|
||||
"@types/marked": "^5.0.0",
|
||||
"@unocss/transformer-directives": "^0.53.4",
|
||||
"marked": "^5.1.0",
|
||||
"mdsvex": "^0.11.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"sass": "^1.63.6",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
First blog post
|
||||
2023-06-07
|
||||
|
||||
I'm baby portland cred tote bag ethical glossier etsy fixie edison bulb retro irony. Helvetica beard humblebrag before they sold out photo booth yr cloud bread iceland ennui yes plz cold-pressed solarpunk tacos marxism. Yr occupy squid pug helvetica crucifix enamel pin subway tile bruh jean shorts fanny pack. Meditation gluten-free butcher PBR&B twee. Hammock selfies asymmetrical fixie before they sold out.
|
||||
|
||||
Grailed iceland austin chicharrones sriracha 8-bit praxis kinfolk blog everyday carry trust fund DIY pour-over. Sriracha disrupt PBR&B fam gorpcore bodega boys adaptogen butcher. Master cleanse tumeric slow-carb activated charcoal jean shorts freegan artisan poke trust fund poutine paleo marxism viral sartorial. Wayfarers neutral milk hotel unicorn art party skateboard. Actually williamsburg chicharrones palo santo direct trade seitan kickstarter humblebrag church-key air plant tacos sriracha. Vape blackbird spyplane kickstarter +1 hexagon PBR&B. Organic copper mug aesthetic, XOXO marxism quinoa subway tile irony lumbersexual authentic disrupt kitsch solarpunk.
|
||||
|
||||
Whatever JOMO organic artisan photo booth marfa, wayfarers yes plz cray. Keffiyeh gentrify thundercats affogato small batch retro you probably haven't heard of them drinking vinegar try-hard vibecession enamel pin. Tbh crucifix seitan, ennui jawn vice lo-fi DSA franzen fingerstache chillwave vape. Sartorial subway tile forage vaporware organic, XOXO letterpress.
|
||||
|
||||
Mustache bicycle rights copper mug pitchfork af typewriter. Vinyl copper mug bitters sus brunch. Biodiesel copper mug vexillologist, butcher asymmetrical seitan man bun everyday carry. Cray humblebrag lumbersexual Brooklyn chambray vice. Taxidermy viral keytar XOXO hell of intelligentsia next level.
|
||||
|
||||
Squid polaroid cold-pressed bitters, tousled enamel pin succulents. Seitan semiotics tumblr shabby chic heirloom salvia, beard gorpcore narwhal williamsburg forage. Austin synth locavore XOXO succulents artisan. Bodega boys bespoke bicycle rights shaman, mukbang leggings selvage irony yuccie polaroid kale chips activated charcoal chambray. Deep v migas pour-over edison bulb tilde chia vinyl, letterpress umami wolf hot chicken franzen taxidermy health goth tonx. Post-ironic gastropub heirloom, plaid literally dreamcatcher pop-up YOLO migas shoreditch brunch. Lo-fi glossier single-origin coffee, tattooed vegan hexagon kinfolk actually YOLO prism.
|
||||
|
||||
Dummy text? More like dummy thicc text, amirite?
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Second blog post
|
||||
2023-06-07
|
||||
|
||||
I'm baby portland cred tote bag ethical glossier etsy fixie edison bulb retro irony. Helvetica beard humblebrag before they sold out photo booth yr cloud bread iceland ennui yes plz cold-pressed solarpunk tacos marxism. Yr occupy squid pug helvetica crucifix enamel pin subway tile bruh jean shorts fanny pack. Meditation gluten-free butcher PBR&B twee. Hammock selfies asymmetrical fixie before they sold out.
|
||||
|
||||
Grailed iceland austin chicharrones sriracha 8-bit praxis kinfolk blog everyday carry trust fund DIY pour-over. Sriracha disrupt PBR&B fam gorpcore bodega boys adaptogen butcher. Master cleanse tumeric slow-carb activated charcoal jean shorts freegan artisan poke trust fund poutine paleo marxism viral sartorial. Wayfarers neutral milk hotel unicorn art party skateboard. Actually williamsburg chicharrones palo santo direct trade seitan kickstarter humblebrag church-key air plant tacos sriracha. Vape blackbird spyplane kickstarter +1 hexagon PBR&B. Organic copper mug aesthetic, XOXO marxism quinoa subway tile irony lumbersexual authentic disrupt kitsch solarpunk.
|
||||
|
||||
Whatever JOMO organic artisan photo booth marfa, wayfarers yes plz cray. Keffiyeh gentrify thundercats affogato small batch retro you probably haven't heard of them drinking vinegar try-hard vibecession enamel pin. Tbh crucifix seitan, ennui jawn vice lo-fi DSA franzen fingerstache chillwave vape. Sartorial subway tile forage vaporware organic, XOXO letterpress.
|
||||
|
||||
Mustache bicycle rights copper mug pitchfork af typewriter. Vinyl copper mug bitters sus brunch. Biodiesel copper mug vexillologist, butcher asymmetrical seitan man bun everyday carry. Cray humblebrag lumbersexual Brooklyn chambray vice. Taxidermy viral keytar XOXO hell of intelligentsia next level.
|
||||
|
||||
Squid polaroid cold-pressed bitters, tousled enamel pin succulents. Seitan semiotics tumblr shabby chic heirloom salvia, beard gorpcore narwhal williamsburg forage. Austin synth locavore XOXO succulents artisan. Bodega boys bespoke bicycle rights shaman, mukbang leggings selvage irony yuccie polaroid kale chips activated charcoal chambray. Deep v migas pour-over edison bulb tilde chia vinyl, letterpress umami wolf hot chicken franzen taxidermy health goth tonx. Post-ironic gastropub heirloom, plaid literally dreamcatcher pop-up YOLO migas shoreditch brunch. Lo-fi glossier single-origin coffee, tattooed vegan hexagon kinfolk actually YOLO prism.
|
||||
|
||||
Dummy text? More like dummy thicc text, amirite?
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import { marked } from "marked"
|
||||
import fs from "fs"
|
||||
|
||||
// Convert all markdown files in the pages directory and all subdirectories
|
||||
// to HTML, and output as JSON files in the pagesjson directory.
|
||||
|
||||
function walk(dir) {
|
||||
let results = []
|
||||
|
||||
for (const file of fs.readdirSync(dir)) {
|
||||
const name = `${dir}/${file}`
|
||||
const stat = fs.statSync(name)
|
||||
|
||||
if (stat && stat.isDirectory())
|
||||
// Recurse into a subdirectory
|
||||
results = results.concat(walk(name))
|
||||
else if (file.endsWith(".md"))
|
||||
// Is a file
|
||||
results.push({ name })
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
const allMdFiles = walk("./pages")
|
||||
|
||||
fs.rmSync("./pagesjson", { recursive: true })
|
||||
|
||||
allMdFiles.forEach(file => {
|
||||
let md = fs.readFileSync(file.name, "utf8")
|
||||
|
||||
const lines = md.split("\n")
|
||||
|
||||
// Remove the first line of the file
|
||||
const title = lines.shift()
|
||||
const date = new Date(lines.shift())
|
||||
lines.shift() // Remove the empty line
|
||||
|
||||
md = lines.join("\n")
|
||||
|
||||
const html = marked.parse(md, {
|
||||
mangle: false,
|
||||
headerIds: false,
|
||||
})
|
||||
|
||||
const obj = { title, date, html }
|
||||
|
||||
fs.mkdirSync(
|
||||
file.name
|
||||
.replace("/pages/", "/pagesjson/")
|
||||
.replace(file.name.split("/").pop(), ""),
|
||||
{ recursive: true }
|
||||
)
|
||||
|
||||
console.log(`Writing ${file.name.replace(".md", ".json")}`)
|
||||
|
||||
fs.writeFileSync(
|
||||
file.name.replace("/pages/", "/pagesjson/").replace(".md", ".json"),
|
||||
JSON.stringify(obj)
|
||||
)
|
||||
})
|
||||
|
||||
console.log("~ Done! ~")
|
||||
|
|
@ -19,9 +19,18 @@ devDependencies:
|
|||
'@sveltejs/kit':
|
||||
specifier: ^1.21.0
|
||||
version: 1.21.0(svelte@4.0.3)(vite@4.3.9)
|
||||
'@types/marked':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
'@unocss/transformer-directives':
|
||||
specifier: ^0.53.4
|
||||
version: 0.53.4
|
||||
marked:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0
|
||||
mdsvex:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(svelte@4.0.3)
|
||||
prettier:
|
||||
specifier: ^2.8.8
|
||||
version: 2.8.8
|
||||
|
|
@ -413,10 +422,18 @@ packages:
|
|||
/@types/estree@1.0.1:
|
||||
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
|
||||
|
||||
/@types/marked@5.0.0:
|
||||
resolution: {integrity: sha512-YcZe50jhltsCq7rc9MNZC/4QB/OnA2Pd6hrOSTOFajtabN+38slqgDDCeE/0F83SjkKBQcsZUj7VLWR0H5cKRA==}
|
||||
dev: true
|
||||
|
||||
/@types/pug@2.0.6:
|
||||
resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
|
||||
dev: true
|
||||
|
||||
/@types/unist@2.0.6:
|
||||
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
|
||||
dev: true
|
||||
|
||||
/@unocss/astro@0.53.4(vite@4.3.9):
|
||||
resolution: {integrity: sha512-fR1F0mNktoN79R+t4GD4y3cvfHUVxtV0+9/6vraZTw3SOXTOMdHeisdxDLjJb3N1yer7XoKX+2GHrKCt873IUA==}
|
||||
dependencies:
|
||||
|
|
@ -1025,9 +1042,27 @@ packages:
|
|||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/marked@5.1.0:
|
||||
resolution: {integrity: sha512-z3/nBe7aTI8JDszlYLk7dDVNpngjw0o1ZJtrA9kIfkkHcIF+xH7mO23aISl4WxP83elU+MFROgahqdpd05lMEQ==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
|
||||
/mdsvex@0.11.0(svelte@4.0.3):
|
||||
resolution: {integrity: sha512-gJF1s0N2nCmdxcKn8HDn0LKrN8poStqAicp6bBcsKFd/zkUBGLP5e7vnxu+g0pjBbDFOscUyI1mtHz+YK2TCDw==}
|
||||
peerDependencies:
|
||||
svelte: '>=3 <5'
|
||||
dependencies:
|
||||
'@types/unist': 2.0.6
|
||||
prism-svelte: 0.4.7
|
||||
prismjs: 1.29.0
|
||||
svelte: 4.0.3
|
||||
vfile-message: 2.0.4
|
||||
dev: true
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
dev: false
|
||||
|
|
@ -1212,6 +1247,15 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/prism-svelte@0.4.7:
|
||||
resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==}
|
||||
dev: true
|
||||
|
||||
/prismjs@1.29.0:
|
||||
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
|
|
@ -1495,6 +1539,12 @@ packages:
|
|||
busboy: 1.6.0
|
||||
dev: true
|
||||
|
||||
/unist-util-stringify-position@2.0.3:
|
||||
resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==}
|
||||
dependencies:
|
||||
'@types/unist': 2.0.6
|
||||
dev: true
|
||||
|
||||
/unocss@0.53.4(postcss@8.4.24)(vite@4.3.9):
|
||||
resolution: {integrity: sha512-UUEi+oh1rngHHP0DVESRS+ScoKMRF8q6GIQrElHb67gqG7GDEGpy3oocIA/6+1t71I4FFvnnxLMGIo9qAD0TEw==}
|
||||
engines: {node: '>=14'}
|
||||
|
|
@ -1531,6 +1581,13 @@ packages:
|
|||
- vite
|
||||
dev: false
|
||||
|
||||
/vfile-message@2.0.4:
|
||||
resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==}
|
||||
dependencies:
|
||||
'@types/unist': 2.0.6
|
||||
unist-util-stringify-position: 2.0.3
|
||||
dev: true
|
||||
|
||||
/vite@4.3.9(sass@1.63.6):
|
||||
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="bg-#282726 px-6">
|
||||
<div class="bg-#282625 px-6">
|
||||
<span class="inline-block pt-3 pb-3">
|
||||
<a href="/" class="text-light hover:text-#aaa text-xl font-light mb-5">
|
||||
Revival Archive
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
<nav class="inline-block ps-4">
|
||||
<a class="navlink" href="/">Home</a>
|
||||
<a class="navlink" href="/about">About</a>
|
||||
<a class="navlink" href="/blog">Blog</a>
|
||||
</nav>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/stores"
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col justify-center items-center h-72vh">
|
||||
<div class="bg-#1f1c1d p-8 px-22 rounded-4 light-text text-center">
|
||||
<h1 class="light-text m-0 mb-5 text-2.2rem">Error {$page.status}</h1>
|
||||
{$page.error?.message}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<Navbar />
|
||||
|
||||
<main
|
||||
class="box-border px-5 sm:mx-auto w-full
|
||||
class="box-border px-5 pt-12 sm:mx-auto w-full
|
||||
sm:w-140 md:w-180 lg:w-220 xl:w-270 2xl:w-300">
|
||||
<slot />
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<svelte:head>
|
||||
<title>Revival Archive</title>
|
||||
</svelte:head>
|
||||
|
||||
# Revival Archive
|
||||
|
||||
Visit [kit.svelte.dev](https://kit.svelte.dev)
|
||||
to read the documentation
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<svelte:head>
|
||||
<title>Revival Archive</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>
|
||||
Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a>
|
||||
to read the documentation
|
||||
</p>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts">
|
||||
export let data
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Blog • Revival Archive</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Posts</h1>
|
||||
|
||||
{#each data.posts as post}
|
||||
<a href="/blog/{post.path}" class="text-white hover:text-#aaa">
|
||||
<article class="bg-#1f1c1d py-3 px-6 rounded-5 mb-4">
|
||||
<h2 class="my-2">{post.title}</h2>
|
||||
<p class="my-2">
|
||||
Published {new Date(post.date).toLocaleDateString("en-GB", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
</p>
|
||||
</article>
|
||||
</a>
|
||||
{/each}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
export async function load() {
|
||||
const allPostFiles = import.meta.glob("../../../pagesjson/blog/*.json")
|
||||
|
||||
return {
|
||||
posts: Promise.all(
|
||||
Object.entries(allPostFiles).map(async ([path, resolver]) => {
|
||||
const { title, date, html } = await resolver()
|
||||
|
||||
return {
|
||||
title,
|
||||
date,
|
||||
html,
|
||||
path: path.match(/(\w+)\.json/)[1],
|
||||
}
|
||||
})
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { error } from "@sveltejs/kit"
|
||||
|
||||
export async function load({ params }) {
|
||||
try {
|
||||
const { title, date, html } = await import(
|
||||
`../../../../pagesjson/blog/${params.page}.json`
|
||||
)
|
||||
return {
|
||||
html,
|
||||
title,
|
||||
date,
|
||||
}
|
||||
} catch (e) {
|
||||
throw error(404, "Post not found")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
export let data
|
||||
</script>
|
||||
|
||||
<article class="w-full sm:w-140 mx-auto">
|
||||
<span class="flex my-10">
|
||||
<h1 class="m-0">{data.title}</h1>
|
||||
<span class="mt-auto ms-3">
|
||||
Published {new Date(data.date).toLocaleDateString("en-GB", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div class="text-justify">
|
||||
{@html data.html}
|
||||
</div>
|
||||
</article>
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
import adapter from "@sveltejs/adapter-auto"
|
||||
import { vitePreprocess } from "@sveltejs/kit/vite"
|
||||
import autoImport from "sveltekit-autoimport"
|
||||
import { mdsvex } from "mdsvex"
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
export default {
|
||||
extensions: [".svelte", ".svelte.md", ".md", ".svx"],
|
||||
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: [
|
||||
|
|
@ -12,6 +15,16 @@ export default {
|
|||
components: ["./src/lib/components"],
|
||||
flat: true,
|
||||
}),
|
||||
mdsvex({
|
||||
extensions: [".svelte.md", ".md", ".svx"],
|
||||
|
||||
smartypants: {
|
||||
dashes: "oldschool",
|
||||
},
|
||||
|
||||
remarkPlugins: [],
|
||||
rehypePlugins: [],
|
||||
}),
|
||||
],
|
||||
|
||||
kit: {
|
||||
|
|
|
|||
|
|
@ -10,4 +10,9 @@ export default defineConfig({
|
|||
}),
|
||||
sveltekit(),
|
||||
],
|
||||
server: {
|
||||
fs: {
|
||||
allow: ["./pagesjson"],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue