Adds notes.
This commit is contained in:
2153
package-lock.json
generated
2153
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
||||
"@types/react": "^19.1.7",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"astro": "^5.9.2",
|
||||
"astro-loader-obsidian": "^0.10.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"sharp": "^0.34.2"
|
||||
|
||||
@@ -18,6 +18,5 @@ const { date } = Astro.props;
|
||||
<style>
|
||||
time {
|
||||
font-family: "Fira Code", monospace;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -33,7 +33,7 @@ import Blazestar from './Blazestar.astro';
|
||||
</div>
|
||||
</nav>
|
||||
<div class="h-card">
|
||||
<img class="u-photo" src="/public/photos/Bingley Business.jpg" />
|
||||
<img class="u-photo" src="/photos/Bingley Business.jpg" />
|
||||
<a class="p-name u-url" href="https://www.blazestar.net">Drew Haven</a>
|
||||
a.k.a. <span class="p-nickname">Periodic</span>
|
||||
</div>
|
||||
|
||||
65
src/components/NoteHierarchy.astro
Normal file
65
src/components/NoteHierarchy.astro
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
import { type Hierarchy } from "../lib/hierarchy.ts";
|
||||
|
||||
interface Props {
|
||||
prefix: string;
|
||||
hierarchy: Hierarchy;
|
||||
}
|
||||
|
||||
const { prefix, hierarchy } = Astro.props;
|
||||
|
||||
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '/');
|
||||
|
||||
---
|
||||
{
|
||||
Object.entries(hierarchy).map(([leader, node]) => {
|
||||
const notePath = `${prefix}/${leader}`;
|
||||
const isActive = pathname === notePath;
|
||||
const linkClasses = isActive ? "active" : "";
|
||||
|
||||
if (node.children) {
|
||||
return (
|
||||
<details open={pathname.startsWith(notePath) && "true"}>
|
||||
<summary>
|
||||
{ node.id
|
||||
? <a href={notePath} class={linkClasses}>{node.title || leader}</a>
|
||||
: <span class="header-only">{node.title || leader}</span>
|
||||
}
|
||||
</summary>
|
||||
<div class="child-notes">
|
||||
{ <Astro.self prefix={notePath} hierarchy={node.children} /> }
|
||||
</div>
|
||||
</details>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<a href={notePath} class={linkClasses}>
|
||||
{node.title || leader}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
<style>
|
||||
.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.child-notes {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
summary {
|
||||
.header-only {
|
||||
color: var(--color-gray)
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--color-gold);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
29
src/components/NotesLinks.astro
Normal file
29
src/components/NotesLinks.astro
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import { makeHierarchy } from '../lib/hierarchy';
|
||||
import { getCollection } from 'astro:content';
|
||||
import NotchedBox from './NotchedBox.astro';
|
||||
import NoteHierarchy from './NoteHierarchy.astro';
|
||||
|
||||
const notes = await getCollection('notes');
|
||||
|
||||
const hierarchy = makeHierarchy(notes.map(note => [note.id, note.data.title]));
|
||||
|
||||
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
|
||||
const isActive = pathname.startsWith("notes");
|
||||
---
|
||||
<NotchedBox fillNotches={isActive ? 'left' : 'none'}>
|
||||
<div class="notes-header">Notes</div>
|
||||
<div class="note-links">
|
||||
<NoteHierarchy prefix="/notes" hierarchy={hierarchy} />
|
||||
</div>
|
||||
</NotchedBox>
|
||||
|
||||
<style>
|
||||
.notes-header {
|
||||
color: var(--color-light-text);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
.note-links {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
import SidebarLink from './SidebarLink.astro';
|
||||
import Blazestar from './Blazestar.astro';
|
||||
import NotesLinks from './NotesLinks.astro';
|
||||
---
|
||||
|
||||
<header>
|
||||
@@ -10,6 +11,7 @@ import Blazestar from './Blazestar.astro';
|
||||
<SidebarLink href="/">Home</SidebarLink>
|
||||
<SidebarLink href="/blog">Blog</SidebarLink>
|
||||
<SidebarLink href="/about">About</SidebarLink>
|
||||
<NotesLinks />
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://mastodon.social/@periodic" target="_blank" rel="me">
|
||||
@@ -57,13 +59,12 @@ import Blazestar from './Blazestar.astro';
|
||||
gap: 16px;
|
||||
a {
|
||||
color: var(--color-light-text);
|
||||
border-bottom: 4px solid transparent;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent);
|
||||
border-bottom: 4px solid transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
ObsidianDocumentSchema,
|
||||
ObsidianMdLoader,
|
||||
} from "astro-loader-obsidian";
|
||||
import { glob } from "astro/loaders";
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
@@ -26,4 +30,15 @@ const page = defineCollection({
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { blog, page };
|
||||
const notes = defineCollection({
|
||||
loader: ObsidianMdLoader({
|
||||
base: "src/content/notes",
|
||||
url: "notes",
|
||||
}),
|
||||
schema: ({ image }) =>
|
||||
ObsidianDocumentSchema.extend({
|
||||
image: image().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { blog, page, notes };
|
||||
|
||||
@@ -62,6 +62,7 @@ const posts = await getPublishedPosts( selectedTag );
|
||||
}
|
||||
.date {
|
||||
color: var(--color-gray);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
.entry {
|
||||
padding: 0.5em;
|
||||
|
||||
@@ -26,6 +26,10 @@ const { slug, title, description, pubDate, updatedDate, heroImage, tags } = Astr
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.dt-published {
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
37
src/lib/hierarchy.ts
Normal file
37
src/lib/hierarchy.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
export interface HierarchyNode {
|
||||
id: string | null;
|
||||
title: string | null;
|
||||
children: Hierarchy | null;
|
||||
}
|
||||
export interface Hierarchy extends Record<string, HierarchyNode> {}
|
||||
|
||||
function addToHierarchy(
|
||||
tree: Hierarchy,
|
||||
[noteId, title]: [string, string],
|
||||
): Hierarchy {
|
||||
const path = noteId.split("/");
|
||||
if (path.length === 0) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
if (!tree[path[0]]) {
|
||||
tree[path[0]] = { id: null, title: null, children: null };
|
||||
}
|
||||
let curr = tree[path[0]];
|
||||
|
||||
for (const node of path.slice(1)) {
|
||||
curr.children ||= {};
|
||||
if (!curr.children[node]) {
|
||||
curr.children[node] = { id: null, title: null, children: null };
|
||||
}
|
||||
curr = curr.children[node];
|
||||
}
|
||||
|
||||
curr.id = noteId;
|
||||
curr.title = title;
|
||||
return tree;
|
||||
}
|
||||
|
||||
export function makeHierarchy(notes: Array<[string, string]>): Hierarchy {
|
||||
return notes.reduce(addToHierarchy, {});
|
||||
}
|
||||
36
src/pages/notes/[...slug].astro
Normal file
36
src/pages/notes/[...slug].astro
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
import RootLayout from '../../layouts/RootLayout.astro';
|
||||
import NotchedBox from '../../components/NotchedBox.astro';
|
||||
import FormattedDate from '../../components/FormattedDate.astro';
|
||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||
import { render } from 'astro:content';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const notes = await getCollection('notes');
|
||||
return notes.map((note) => ({
|
||||
params: { slug: note.id },
|
||||
props: note,
|
||||
}));
|
||||
}
|
||||
type Props = CollectionEntry<'notes'>;
|
||||
|
||||
const note = Astro.props;
|
||||
const { Content } = await render(note);
|
||||
---
|
||||
|
||||
<RootLayout>
|
||||
<NotchedBox fillNotches="left">
|
||||
<h1>{note.data.title}</h1>
|
||||
<div class="last-updated">
|
||||
Last updated <FormattedDate date={note.data.updated} />
|
||||
</div>
|
||||
<Content />
|
||||
</NotchedBox>
|
||||
</RootLayout>
|
||||
|
||||
<style>
|
||||
.last-updated {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-gray);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user