add markdown rendering, copy in old posts

rewrite
Ashelyn Dawn 10 months ago
parent 6cddfdf8fe
commit d89d92d393

@ -10,18 +10,18 @@ export default function Contact() {
const [submitting, setSubmitting] = useState(false)
const [status, setStatus] = useState('')
const nameRef = useRef()
const emailRef = useRef()
const messageRef = useRef()
const nameRef = useRef<HTMLInputElement>()
const emailRef = useRef<HTMLInputElement>()
const messageRef = useRef<HTMLTextAreaElement>()
const submit = async (ev: FormEvent<HTMLFormElement>) => {
ev.preventDefault()
setStatus('')
const name: string = nameRef.current?.value ?? ''
const email: string = emailRef.current?.value ?? ''
const message: string = messageRef.current?.value ?? ''
const name = nameRef.current.value
const email = emailRef.current.value
const message = messageRef.current.value
if (!name) setStatus(s => s + ' Name required.')
if (!email) setStatus(s => s + ' Email required.')

@ -39,7 +39,7 @@ export default function Index() {
<p>
<em>Note:</em> This is the information for our system in aggregate,
for individual info see our <a href="/system">about</a> page
for individual info see our <a href="/about">about</a> page
</p>
</main>
)

@ -0,0 +1,28 @@
import { notFound } from 'next/navigation'
import Markdown from 'markdown-to-jsx'
import InfoBar from '~/components/InfoBar'
import { getPostSlugs, loadSinglePage } from '~/utils/post'
export async function generateStaticParams() {
const slugs = await getPostSlugs()
return slugs.map((slug: string) => ({ slug }))
}
export default async function Post({ params: { slug } }) {
const post = await loadSinglePage(slug)
if (!post) notFound()
return (
<>
<h1 className="pageTitle">
{post.title}
</h1>
<main className="mainColumn">
<InfoBar authorName={post.author} publishedDate={post.date} />
<Markdown>{post.body}</Markdown>
</main>
</>
)
}

@ -1,11 +1,26 @@
export default function Posts() {
import InfoBar from "~/components/InfoBar"
import { Post, getPostSlugs, loadSinglePage } from "~/utils/post"
export default async function Posts() {
const slugs = await getPostSlugs()
const posts = await Promise.all(slugs.map(loadSinglePage))
const sortedPosts = posts.sort((a: Post, b: Post) => b.date.valueOf() - a.date.valueOf())
return (
<>
<h1 className="pageTitle">
Posts
</h1>
<main className="mainColumn">
<p>This will have posts here eventually we promise</p>
<main>
{sortedPosts.map((post: Post) => (
<div className="mainColumn">
<InfoBar authorName={post.author} publishedDate={post.date} />
<h2>{post.title}</h2>
<p>{post.subtitle}</p>
<a href={`/posts/${post.slug}`}>Read Post =&gt;</a>
</div>
))}
</main>
</>
)

58
package-lock.json generated

@ -9,6 +9,8 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"front-matter": "^4.0.2",
"markdown-to-jsx": "^7.2.0",
"next": "^13.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@ -224,6 +226,14 @@
"resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.1.tgz",
"integrity": "sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A=="
},
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/async-validator": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz",
@ -469,6 +479,18 @@
"once": "^1.4.0"
}
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
@ -477,6 +499,14 @@
"node": ">=6"
}
},
"node_modules/front-matter": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz",
"integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==",
"dependencies": {
"js-yaml": "^3.13.1"
}
},
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@ -531,6 +561,18 @@
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -553,6 +595,17 @@
"node": ">=10"
}
},
"node_modules/markdown-to-jsx": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.2.0.tgz",
"integrity": "sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg==",
"engines": {
"node": ">= 10"
},
"peerDependencies": {
"react": ">= 0.14.0"
}
},
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@ -933,6 +986,11 @@
"node": ">=0.10.0"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",

@ -9,6 +9,8 @@
"author": "",
"license": "ISC",
"dependencies": {
"front-matter": "^4.0.2",
"markdown-to-jsx": "^7.2.0",
"next": "^13.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",

@ -0,0 +1,65 @@
---
title: Thoughts on Neovim
subtitle: Who even needs an IDE anyways?
author: rose
---
## Why I'm using Neovim
When I first started coding in high school and then later in early
college I used to jump around between editors a lot more than I do today.
I used Notepad++, then Visual Studio, briefly Netbeans, then Atom.
But since settling into frontend web development I've stayed with VSCode
for a very long time. I liked it because it was straightforward to get
started with, but versatile enough to extend for other languages.
Between various jobs and projects I used it for Javascript, Java, C#,
Rust, and C - and it did admirably at pretty much all of these.
But about a year ago I saw that VSCode had a Neovim plugin, and I was
intrigued. I'd wanted to get more familiar with Vim beyond the basic
hjkl navigation, and this seemed like a great way to do that!
So for the last year and change I've had the
<a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=asvetliakov.vscode-neovim">vscode-neovim</a> plugin
plugin installed, and I've been really enjoying it!
I quickly fell in love with visual block mode, or the "delete N words"
commands. They're just so handy I suddenly felt like they were missing
if I needed to edit code any other way!
But over the weekend I made the jump from using Neovim inside VSCode to
using it more or less on its own. I saw a video that mentioned the
AstroNvim configuration framework and Neovide, and decided "yeah, I think
I want to try that", and a few days later . . . here we are.
## How is it going?
Overall, surprisingly well.
The AstroNvim config I'm using already had NeoTree set up which is
very nice. I've figured out how to get ESLint and Prettier configured
for work, rust-analyzer installed for my own projects, I've been poking
at themes over and over again, and honestly . . . I'm really liking this.
Getting Neovide to connect to a VM over the network was relatively
straightforward, I love how easy it is to drop my config into git and
keep it synced between computers, and finally having proper mouse support
(which I never could get sorted out with my terminal) is a pretty big
game changer for when I'm just reading code.
Also, I'd be lying if I said that I didn't love the smooth scrolling and
cursor animation. I am a simple girl after all.
## Should you try replacing your IDE?
That is a tricky question to answer.
I was comfortable spending some time experimenting with this because I
already had decent familiarity with Vim and had been using Neovim
specifically for a while. If you don't have any similar experience,
the learning curve is going to be pretty steep.
But hey - if you're looking for a challenge, you'll definitely learn
a lot.

@ -0,0 +1,75 @@
---
title: Advent of Wasm
subtitle: Now with 87% more pain
author: rose
---
So the last few years I have done Advent of Code off and on. Sometimes
I have tried to learn a new language, other times I was just trying to
beat my dad each evening. This year though, this year I don't know what
I was thinking.
It was several weeks after everyone else had started, I had largely written
it off for the year - I was not up for it. Until a terrible idea crossed
my mind.
Like an intrusive thought, my mind asked: "Well you've been wanting to do
something in web assembly for a while right? How bad could it be?"
<br/>
Turns out I was definitely not ready for this.
## So what was so hard about it?
More than anything else, I forgot how much you need to do by hand to do
any sort of assembly. The first day saw me spending several hours just
on some loader code to pass the puzzle input in from JS, call a wasm
function, and then read back the result.
Next was a few functions for reading numbers out of the wasm memory buffer,
parsing them from ascii, etc. The core read loop was not too tricky, but
the bit that took far longer than it had any reason to was converting my
answer back to ascii and shoving it into an output area.
Really none of it was surprising, and none of it <em><strong>*should*</strong></em> have
been that hard ... it's just been a while since this Javascript girl
has written truly low-level code.
To make matters worse I got hard-core distracted by the non-wasm part of
my wasm project. After the first day I returned to my stub JS loader and
expanded it into a little wasm explorer.
I added a code view, syntax highlighting, auto-loaded my puzzle inputs,
even made a janky little dynamic list that would automatically pick up
new days' solutions as I added them to the repo without needing me to
touch the loader page each day.
In the end I'm really quite proud of it, I will absolutely be reusing
this setup for future years, and you should
<a href="https://aoc2022.tempest.dev/" target="_blank">check it out</a>
if you haven't already ... but for wanting to challenge myself with
something new I was doing a lot of the same-old.
Ultimately I got through 3 days before giving up jusst because every
step along the way involved <em><strong>*so much*</strong></em> extra
code. I may come back to some of the puzzles later, but for now I'm
kind of happy with what I did, and I don't feel like I need to prove
myself by doing more. I was doing it for fun, and so I stopped when
it stopped being fun.
## Tips if you want to get into writing wasm by hand?
Uhh ... maybe consider don't?
Jokes aside: do a throwaway project or two so you get used to passing
data into and out of wasm, whatever parsing you're going to do, etc.
Do everything in your power to make sure you can focus on the actual
wasm part of your project, because (at least if you're anything like
me) it's easy to get sidetracked with all that.
With that said: I had fun. Doing new things is always a treat, so if
you're looking for something new to try definitely consider giving
webassembly a look.

@ -33,7 +33,7 @@ header {
padding: var(--text-padding);
padding-bottom: 0;
box-sizing: border-box;
align-items: start;
align-items: flex-start;
justify-items: flex-start;
}
@ -125,12 +125,15 @@ header:not(.homepage) ~ h1.pageTitle {
}
main.mainColumn {
min-height: calc(var(--header-overlap) + var(--min-main-overhang));
}
.mainColumn {
width: var(--main-width);
box-sizing: border-box;
padding: var(--text-padding);
margin: 0 auto;
background: var(--main-background);
min-height: calc(var(--header-overlap) + var(--min-main-overhang));
box-shadow: 0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12);
}
@ -138,13 +141,17 @@ header.homepage ~ .mainColumn {
min-height: calc(var(--header-overlap) + var(--min-main-overhang) - var(--header-bar-height));
}
.mainColumn ~ .mainColumn {
margin-top: calc(2 * var(--text-padding));
}
main.mainColumn > p:first-child {
margin-top: 0;
}
footer {
flex: 1;
align-items: end;
align-items: flex-end;
box-sizing: border-box;
width: var(--main-width);
margin: 0 auto;

@ -0,0 +1,56 @@
import { promises as fs } from 'fs'
import path from 'path'
import frontmatter from 'front-matter'
export interface Post {
slug: string,
date: Date,
title: string,
subtitle?: string,
author: string,
body: string
}
const POST_FILE_PATTERN = /^(?<date>[0-9]{4}-[0-9]{2}-[0-9]{2}(-[0-9]{1,2})?)_(?<slug>[^\.]+)\.md$/
export async function getPostSlugs(): Promise<string[]> {
const postsDir = path.join(process.cwd(), 'posts')
const postPaths = await fs.readdir(postsDir)
return postPaths.map(getSlugFromFilePath).filter(slug => slug !== null)
}
export function getSlugFromFilePath(postPath: string): string | null {
const regexResult = POST_FILE_PATTERN.exec(postPath)
if (!regexResult) return null
return regexResult.groups.slug
}
export async function loadSinglePage(slug: string): Promise<Post | null> {
const postsDir = path.join(process.cwd(), 'posts')
const postPaths = await fs.readdir(postsDir)
const postMatch: RegExpExecArray | null = postPaths
.map((postFile: string) => POST_FILE_PATTERN.exec(postFile))
.filter((regexResult: RegExpExecArray | null) => regexResult !== null)
.find((regexResult: RegExpExecArray) => regexResult.groups.slug === slug)
if (!postMatch) return null;
const fileName = `${postMatch.groups.date}_${postMatch.groups.slug}.md`
const fileContents = (await fs.readFile(path.join(process.cwd(), 'posts', fileName))).toString('utf8')
const { attributes, body } = frontmatter(fileContents)
type Attributes = { [key: string]: string }
const data: Attributes = attributes as Attributes
if (!data.title) return null;
return {
slug: postMatch.groups.slug,
date: new Date(postMatch.groups.date),
title: data.title,
subtitle: data.subtitle,
author: data.author,
body
}
}
Loading…
Cancel
Save