Compare commits

..

13 Commits

20 changed files with 358 additions and 12 deletions

15
TODO.md Normal file
View File

@@ -0,0 +1,15 @@
## UI
- [ ] Outline mode on documents
- [ ] Improve table rendering
- [ ] More image-flow options
- [ ] Fix capitalization in notes values/headers. Only the first letter is capitalized, but it should follow the capitalization of the folder. E.g. "NixOS" not "Nixos"
- [x] Code Highlighting
## Interaction
- [ ] Web Mentions
- [ ] Comments
- [ ] Guest Book
## Content

View File

@@ -13,4 +13,8 @@ export default defineConfig({
vite: { vite: {
plugins: [], plugins: [],
}, },
redirects: {
"/now": "/notes/now",
},
}); });

View File

@@ -41,7 +41,7 @@ const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '/');
return ( return (
<div> <div>
<a href={notePath} class={linkClasses}> <a href={`/notes/${node.id}`} class={linkClasses}>
{node.title || leader} {node.title || leader}
</a> </a>
</div> </div>

View File

@@ -1,5 +1,5 @@
<div class="social-links"> <div class="social-links">
<a href="https://m.webtoo.ls/@astro" target="_blank"> <a href="https://mastodon.social/@periodic" target="_blank" rel="me">
<span class="sr-only">Follow Periodic on Mastodon</span> <span class="sr-only">Follow Periodic on Mastodon</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32"
><path ><path
@@ -7,7 +7,7 @@
d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z" d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z"
></path></svg> ></path></svg>
</a> </a>
<a href="https://github.com/periodic" target="_blank"> <a href="https://github.com/periodic" target="_blank" rel="me">
<span class="sr-only">Go to Periodic's GitHub repo</span> <span class="sr-only">Go to Periodic's GitHub repo</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32"
><path ><path
@@ -16,6 +16,18 @@
></path></svg ></path></svg
> >
</a> </a>
<a href="/rss.xml">
<span class="sr-only">Subscribe to Periodic's RSS feed</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" aria-hidden="true" width="32" height="32">
<!--!Font Awesome Free v7.2.0 by @fontawesome - https://fontawesome.com
License - CC BY 4.0 - https://fontawesome.com/license/free
Copyright 2026 Fonticons, Inc.-->
<path
fill="currentColor"
d="M96 128C96 110.3 110.3 96 128 96C357.8 96 544 282.2 544 512C544 529.7 529.7 544 512 544C494.3 544 480 529.7 480 512C480 317.6 322.4 160 128 160C110.3 160 96 145.7 96 128zM96 480C96 444.7 124.7 416 160 416C195.3 416 224 444.7 224 480C224 515.3 195.3 544 160 544C124.7 544 96 515.3 96 480zM128 224C287.1 224 416 352.9 416 512C416 529.7 401.7 544 384 544C366.3 544 352 529.7 352 512C352 388.3 251.7 288 128 288C110.3 288 96 273.7 96 256C96 238.3 110.3 224 128 224z"/>
cial
</svg>
</a>
</div> </div>
<style> <style>
@@ -23,6 +35,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 16px; gap: 16px;
justify-content: center;
a { a {
color: var(--color-light-text); color: var(--color-light-text);

View File

@@ -0,0 +1,31 @@
---
import TableOfContentsTree from "./TableOfContentsTree.astro";
import type { MarkdownHeading } from "astro";
import { makeHeadingsTree, removeEmptyLevels } from "../lib/headings";
type Props = {
headings: Array<MarkdownHeading>;
};
const {headings} = Astro.props;
const headingsTree = removeEmptyLevels(makeHeadingsTree(headings));
---
<div class="table-of-contents">
<TableOfContentsTree headingsTree={headingsTree}></TableOfContentsTree>
</div>
<style>
.table-of-contents {
border: 1px solid var(--color-space-blue-light);
ul {
list-style: none;
}
& > ul {
padding: 0;
margin: 8px 16px;
}
}
</style>

View File

@@ -0,0 +1,15 @@
---
type Props = {
headingsTree: HeadingsTree;
};
const {headingsTree} = Astro.props;
---
<ul>
{headingsTree.map(node =>
Array.isArray(node)
? <Astro.self headingsTree={node} />
: <li><a href={`#${node.slug}`}>{node.text}</a></li>
)}
</ul>

View File

@@ -26,7 +26,7 @@ So now that I had these notes, I needed to rebuild the structure so I could rend
I created a type like the following. Note that TypeScript does not support self-referential recursive types! It does allow self-referential interfaces though. Hence the odd syntax. I created a type like the following. Note that TypeScript does not support self-referential recursive types! It does allow self-referential interfaces though. Hence the odd syntax.
```TypeScript ```typescript
interface Hierarchy extends Record<string, Hierarchy> {} interface Hierarchy extends Record<string, Hierarchy> {}
``` ```
@@ -34,7 +34,7 @@ However, after messing around with it for a while I realized I needed a little m
This lead me to create the following data structure. Some nodes would have children, others not, and they may or may not have an ID or title. (I could write both of these as `type` declarations because they are _mutually recursive_ types. TypeScript is weird.) This lead me to create the following data structure. Some nodes would have children, others not, and they may or may not have an ID or title. (I could write both of these as `type` declarations because they are _mutually recursive_ types. TypeScript is weird.)
```TypeScript ```typescript
interface HierarchyNode { interface HierarchyNode {
id: string | null; id: string | null;
title: string | null; title: string | null;
@@ -45,7 +45,7 @@ type Hierarchy = Record<string, HierarchyNode>;
I started with algorithm of splitting all the paths into their parts, then going through and recursively grouping. However, I found this would be much simpler if I just did this as a fold/reduce so I could just focus on adding one path at a time. This gave me the following simple algorithm. Please ignore the repetition, it didn't seem worth cleaning up at the time. I started with algorithm of splitting all the paths into their parts, then going through and recursively grouping. However, I found this would be much simpler if I just did this as a fold/reduce so I could just focus on adding one path at a time. This gave me the following simple algorithm. Please ignore the repetition, it didn't seem worth cleaning up at the time.
```TypeScript ```typescript
function addToHierarchy( function addToHierarchy(
tree: Hierarchy, tree: Hierarchy,
[noteId, title]: [string, string], [noteId, title]: [string, string],
@@ -82,7 +82,7 @@ export function makeHierarchy(notes: Array<[string, string]>): Hierarchy {
So now I had to render the links. Astro thankfully _does_ support recursive components through `Astro.self`, so I was able to write a single component to render the hierarchy. So now I had to render the links. Astro thankfully _does_ support recursive components through `Astro.self`, so I was able to write a single component to render the hierarchy.
```Astro ```astro
--- ---
import { type Hierarchy } from "../lib/hierarchy.ts"; import { type Hierarchy } from "../lib/hierarchy.ts";

View File

@@ -0,0 +1,31 @@
---
title: Favorite Albums
---
I'm an album listener. I really prefer to listen to a coherent set of songs that are narratively linked and have a cohesive them and tone. The algorithmic feeds never seem to quite leave me happy with the results. Though there is the one exception of 90s rock because that's what I grew up listening to on the radio.
As I remember them and listen to them, I'll add more albums here under various genres.
## Metal
### Unleash the Archers
I've been following this Canadian band since their third album, Time Stands Still. It has some catchy tracks like Test Your Metal.
All their following albums are built around a narrative, which progresses throughout the album. There are a few recurring characters and themes between them such as The Matriarch. I listened to Apex many times, but didn't find myself drawn to Abyss as much initially. However, later I came back to the album and listened to it a dozen times on repeat.
Their latest, Phantoma, didn't have the strength of execution and I've struggled to like it as much as many of the others, even though I enjoy the story. The sand out track for me is Ghost in the Mist, but sometimes I just want to listen to Buried in Code when I'm coding.
### Elevation by We are the Catalyst
This Swedish alt-metal band got my attention with the track Askja. I was fed it by some algorithm or list and it's stuck with me. I've enjoyed that album, Elevation, but never really picked up their others.Their lead singer, Cat Fey, infuses a lot of emotion into her vocals. Their music is melodic and relatively heavy. The singing never quite loses it's clarity, but has the force of screaming.
## Electronic / Synthwave
### Unicorn by GUNSHIP
I've been really liking this album lately. It seems like a collection of concept pieces because GUNSHIP got various guest artists to join for single tracks. The overall album is more on hopeful and nostalgic side of retro-futurism. Bonus points for the Blood for the Blood God reference.
### Scandroid by Scandroid
I'm a sucker for robots. This was actually one of the first albums I encountered that started to embrace the retro-futuristic aesthetic, with a little bit of cyberpunk mixed it. It introduced me to two terms I hope will someday become common: "probots" vs "robophobes".

View File

@@ -0,0 +1,91 @@
---
title: Deploying NixOS on the cloud
tags:
- NixOS
- cloud
---
There are two major things to consider when deploying NixOS systems into the cloud. The first is where to host, the other is how to set it up.
As always, if you have any input such as suggestions, corrections or more data, please [ping me on Mastodon](https://mastodon.social/@periodic) and I'd love to hear from you.
## Providers
There is a list of [NixOS friendly hosters](https://wiki.nixos.org/wiki/NixOS_friendly_hosters) on the wiki, but I have no idea how up-to-date it is.
My criteria are all skewed by the fact that I am an English speaker based on the west coast of the United States. That means additional latency to Europe and I'm subject to a lot of US laws.
- Location
- Local laws and juristictions
- Latency
- Ease of installation
- How easy it is it to install NixOS on their systems? Is it a native option, require a custom image, or a more specialized option?
- Speed
- How much latency is in the network?
- Price
- How much does a box cost? VPS instances are fairly commodified at this point, so prices should be fairly comparable. My benchmark is 2 vCPU with 4 GB of RAM because that will serve most small sites well with overhead for other tasks.
- Support
- How easy is it to contact support?
- Do they speak my language?
- Other offerings
- What other services do they offer if I should choose to expand or require more specialized services? Database hosting, CDN, file hosting, etc.
- Company Values
- I want a company that matches my values and isn't just an autonomous extractive entity.
### Providers I've investigated
| Provider | Location | NixOS Support | Notes |
| ----------------------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------- |
| [Gandi.net](https://www.gandi.net/) | France | Native | Had some billing, latency and packet loss issues. |
| Linode/Akamai | US/Global | Custom ISO | Still setting up |
| Hetzner | Germany/US | Custom ISO | I got blocked here because they do not accept credit-card payment without contacting support. |
| [vpsFree.cz](https://vpsfree.org/) | Czech Republic | Native | They operate as a "community" more than a company. |
| [Crocuda.com](https://crocuda.com/) | France | Native | Only accept payment in crypto. IPv6 only. They pride themselves on having no KYC. |
#### Gandi.net
Last tried: May 2026
I was drawn to them initially because they are based in France and seem relatively professional. I've also heard their name come up positively in discussions of domain registrars, so I thought I'd give them a try.
I was able to set up an account fairly quickly, though initially my billing didn't go through and my account got stuck in a state of pending a charge to fund a pre-paid account. I tried initiating payment for that order, but that just resulted in a new order being created and paid, leaving my account hanging and pending billing verification. Eventually I figured out that I could cancel that first order, putting my account back into the initial state and allowing me to set up billing again which worked.
Setting up a NixOS system was trivial. It is an option in the provisioning flow. I was able to have the system up and running within minutes. They provide a very minimal Nix config whihc is mostly just hardware settings. It was a simple matter to integrate that into a new host configuration, checking that out on the host, building and reboot.
The major issue that I had with this provider was latency. I had a minimum latency of about 150ms, which is just enough to create a noticeable lag when typing. There were occasional spikes in latency and dropped packets which were far more annoying. These would happen for about 1% of pings that I measured and could result in dropped packets for a few seconds at a time.
#### Linode
TODO
#### Hetzner
TODO
#### Crocuda
They have a pretty slick terminal UI that you can access over SSH. It labels itself as being alpha status.
However, only accepting crypto for payments is a bit of a non-started for me. It's a bit odd since their pricing is all listed in dollars. They'll give you about $1 in credits, which is enough for about 5 days of usage.
They also pride themselves on no KYC. That's maybe nice from a privacy standpoint, but they can still access everything on the systems, so your data isn't private. This makes me think my neighbors on the boxes will not be the most savory folks. I would be wary of my data getting wrapped up in some criminal activity or having my capacity impacted by the actions of my neighbors. A company like this may attract clients who are prone to activities that would get them in trouble with other providers. That could include using exploits to break out of their VMs and affect my data or the stability of the system.
They seem to only support IPv6, which makes it hard to use as a web server.
Prices seem very competitive, at about $10/month for my target system.
Latency is around 180ms.
## Installation
If a provider doesn't support native NixOS then there are a few options. If they support a custom ISO then I can create a NixOS image and load that. Another option is to use one of the tools that allow you to convert an existing system into NixOS, such as [nixos-anywhere](https://github.com/nix-community/nixos-anywhere/tree/main) or [nixos-infect](https://github.com/elitak/nixos-infect).
TODO
## Deployments and management
TODO
- [morph](https://github.com/DBCDK/morph) - Morph is a tool for managing existing NixOS hosts - basically a fancy wrapper around nix-build, nix copy, nix-env, /nix/store/.../bin/switch-to-configuration, scp and more. Morph supports updating multiple hosts in a row, and with support for health checks makes it fairly safe to do so.
- [colmena](https://github.com/zhaofengli/colmena) - Colmena is a simple, stateless NixOS deployment tool modeled after NixOps and morph, written in Rust. It's a thin wrapper over Nix commands like nix-instantiate and nix-copy-closure, and supports parallel deployment.
- [NixOps](https://github.com/NixOS/nixops) - NixOps is a tool for deploying to NixOS machines in a network or the cloud.

View File

@@ -0,0 +1,40 @@
---
title: Running Untrusted Code
---
What is untrusted code? It's any code for which you cannot vouch for the entire chain of custody. Any code you don't trust should be in a sandbox with as little privilege as possible.
This includes a lot of scripts that you might get from the internet. Some scripts are small enough to review yourself, but honestly, who wants to do that every time? There are tons of small scripts and utilities I might want to run that I don't trust.
Another case is LLM output. Who knows what the LLM might output? They hallucinate and make many mistakes. No one wants to accidentally run `rm -rf /` or anything like it.
There's also the case of supply chain attacks. We trust a lot of code that we download implicitly. A lot of code dependencies are downloaded and executed as part of programming. Sometimes these have malicious code slipped in.
However, you have to draw the line somewhere. For example, it's hard to trust every package on your OS. If someone slipped malicious code into my window manager I would be pretty fucked.
## Using Docker
My favorite trick for running untrusted code is to run it in a small one-time container.
Here's an example for running a python script.
```bash
docker run --rm \
-v ~/src/repo:/repo:ro \ # Mount this RO unless it needs to do something like NPM builds or VENV installs
-v ~/data:/data:ro \ # Mount RO to prevent modification.
--network none \ # No network
--cap-drop ALL \ # Drop other capabilities
--security-opt no-new-privileges \ # Make sure it gets no new ones
python:3.12-slim python3 /repo/untrusted_script.py
```
Some additional optional arguments if you are concerned:
```bash
--read-only \ # Make the container RO
--tmpfs /tmp \ # Give it some dedicated scratch space
--memory 512m \ # Limit memory
--cpus 1 \ # Limit CPU
--pids-limit 100 \ # Prevent fork bombing
--user 1000:1000 # Run as a non-root user to further limit capabilities and prevent root access to whatever you do give it
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 KiB

50
src/content/notes/now.md Normal file
View File

@@ -0,0 +1,50 @@
---
title: Now
---
This is my [Now Page](https://nownownow.com/about). It hopes to answer the question, **"what are you doing these days?"**
## Pets
| Rosie | Bingley | Clover |
| --------------------- | ----------------------------------- | --------------------------------- |
| ![[images/rosie.jpg]] | ![[images/bingley.jpg]] | ![[images/clover.jpg]] |
| 8 yeas old | 8 years old | 3 years old |
| GSD / Husky / AmStaff | Husky / AmStaff | Terrier / Chihuahua / many others |
| Loves sun, her ball | Loves food, wrestling, being a lump | Loves barking, chasing |
## Projects
- Creating and improving my personal site, Blazestar.net
- Comments
- [Webmentions](https://webmention.io/)
- More content
- Exploring ways to use Haskell for various projects, particularly the web
- Maintaining our forest of timber bamboo
- Logging observations of all the [Messier Objects](https://en.wikipedia.org/wiki/Messier_object)
## Hobbies
- Playing miniature war games, mostly Warhammer 40k
- Weekly games and monthly tournaments at [Great Escape Games](https://greatescapegames.com/)
- T'au Empire: Printed and painted around 3,000 points of [FishMech](https://pipermakes.art/collections/fishmech) proxies
- Blood Angels: Printed and painted 2,000 points of various proxies
- Enjoying World of Warcraft: Midnight
- [Main Tank](https://raider.io/characters/us/tichondrius/Ironsoul) for &lt;Mitsakes Were Made&gt;
- Hiking and camping in the High Sierras
- Star Gazing with the [Sacramento Valley Astronomical Society](https://www.svas.org/)
- Current equipment:
- Meade 2160 254mm SCT
- Stellarview ST102 102mm refractor
- iOptron AX Mount Pro
## Media
- Re-reading Lord of the Rings
- Listening to [Marketplace](https://www.marketplace.org/) for economic news
- Reading many blogs I'll get around to listing some time
## Personal
- Developing my physical health and mental health
- Finding my place in swiftly changing culture, economy and technology

View File

@@ -8,6 +8,8 @@ I do full stack web-development: A little front-end, a little back-end, database
I have been a software developer from a young age and have spent two decades in the tech industry. I've done freelance, start-ups (Asana, Fossa) and some big corps (Google, Visa). I have been a software developer from a young age and have spent two decades in the tech industry. I've done freelance, start-ups (Asana, Fossa) and some big corps (Google, Visa).
See my [now page](/now) for more about what I'm focused on right now.
## What is "Blaze Star"? ## What is "Blaze Star"?
I picked up this domain about a year ago. I was looking for some places to host some of my own things. There's a domain I've had for over a decade but never really liked. I wanted something memorable, a bit obscure, but easy to describe. I picked up this domain about a year ago. I was looking for some places to host some of my own things. There's a domain I've had for over a decade but never really liked. I wanted something memorable, a bit obscure, but easy to describe.

View File

@@ -1,13 +1,15 @@
--- ---
import type { MarkdownHeading } from "astro";
import type { CollectionEntry } from 'astro:content'; import type { CollectionEntry } from 'astro:content';
import RootLayout from '../layouts/RootLayout.astro'; import RootLayout from '../layouts/RootLayout.astro';
import FormattedDate from '../components/FormattedDate.astro'; import FormattedDate from '../components/FormattedDate.astro';
import NotchedBox from '../components/NotchedBox.astro'; import NotchedBox from '../components/NotchedBox.astro';
import TableOfContents from '../components/TableOfContents.astro';
import { Image } from 'astro:assets'; import { Image } from 'astro:assets';
type Props = CollectionEntry<'blog'>['data'] & { slug: string; }; type Props = CollectionEntry<'blog'>['data'] & { slug: string; headings: MarkdownHeading[] };
const { slug, title, description, pubDate, updatedDate, heroImage, tags } = Astro.props; const { slug, title, description, pubDate, updatedDate, heroImage, tags, headings } = Astro.props;
--- ---
<style> <style>
@@ -77,6 +79,7 @@ const { slug, title, description, pubDate, updatedDate, heroImage, tags } = Astr
</div> </div>
} }
<hr /> <hr />
<TableOfContents headings={headings} />
<div class="e-content"> <div class="e-content">
<slot /> <slot />
</div> </div>

49
src/lib/headings.ts Normal file
View File

@@ -0,0 +1,49 @@
import type { MarkdownHeading } from "astro";
export type HeadingsTree = Array<MarkdownHeading | HeadingsTree>;
// could take a list like [5, 1, 2, 2, 3, 5, 1] and should return
// [ [ [ [ [ 5 ] ] ] ], 1, [ 2, 2, [3, [[5]]]], 1]
export function makeHeadingsTree(headings: MarkdownHeading[]): HeadingsTree {
let index = 0;
let currDepth = 1;
const treeStack = [[]] as Array<HeadingsTree>;
while (index < headings.length) {
const currHeading = headings[index];
// If the next heading is at the current depth, push it into the tree
if (currHeading.depth == currDepth) {
treeStack[treeStack.length - 1].push(currHeading);
index += 1;
}
// If the next heading is deeper, go deeper
if (currHeading.depth > currDepth) {
const nextLevel = [] as HeadingsTree;
treeStack[treeStack.length - 1].push(nextLevel);
treeStack.push(nextLevel);
currDepth += 1;
}
// If the next heading is shallower, back out
if (currHeading.depth < currDepth) {
treeStack.pop();
currDepth -= 1;
}
}
return treeStack[0];
}
export function removeEmptyLevels(tree: HeadingsTree): HeadingsTree {
const newLevel = tree.map((node) =>
Array.isArray(node) ? removeEmptyLevels(node) : node,
);
if (tree.every(Array.isArray)) {
return tree.flatMap((node) => node);
}
return tree;
}

View File

@@ -14,9 +14,9 @@ type Props = CollectionEntry<'blog'>;
const post = Astro.props; const post = Astro.props;
const { slug } = Astro.params; const { slug } = Astro.params;
const { Content } = await render(post); const { Content, headings } = await render(post);
--- ---
<BlogPost slug={slug} {...post.data} > <BlogPost slug={slug} headings={headings} {...post.data} >
<Content /> <Content />
</BlogPost> </BlogPost>

View File

@@ -2,6 +2,7 @@
import RootLayout from '../../layouts/RootLayout.astro'; import RootLayout from '../../layouts/RootLayout.astro';
import NotchedBox from '../../components/NotchedBox.astro'; import NotchedBox from '../../components/NotchedBox.astro';
import FormattedDate from '../../components/FormattedDate.astro'; import FormattedDate from '../../components/FormattedDate.astro';
import TableOfContents from '../../components/TableOfContents.astro';
import { type CollectionEntry, getCollection } from 'astro:content'; import { type CollectionEntry, getCollection } from 'astro:content';
import { render } from 'astro:content'; import { render } from 'astro:content';
@@ -15,7 +16,7 @@ export async function getStaticPaths() {
type Props = CollectionEntry<'notes'>; type Props = CollectionEntry<'notes'>;
const note = Astro.props; const note = Astro.props;
const { Content } = await render(note); const { Content, headings } = await render(note);
--- ---
<RootLayout> <RootLayout>
@@ -24,6 +25,7 @@ const { Content } = await render(note);
<div class="last-updated"> <div class="last-updated">
Last updated <FormattedDate date={note.data.updated} /> Last updated <FormattedDate date={note.data.updated} />
</div> </div>
<TableOfContents headings={headings}/>
<Content /> <Content />
</NotchedBox> </NotchedBox>
</RootLayout> </RootLayout>