This commit is contained in:
Brad Treloar 2025-11-01 21:33:17 +10:30
parent 9a65be07e4
commit d17cb3509a
9 changed files with 89 additions and 34 deletions

View file

@ -1,17 +1,20 @@
// @ts-check // @ts-check
import { defineConfig } from "astro/config"; import { defineConfig } from "astro/config";
const setLayout = () => { //const setLayout = () => {
return function (_, file) { // return function (_, file) {
if (file.data.astro.frontmatter.layout === undefined) { // if (file.data.astro.frontmatter.layout === undefined) {
file.data.astro.frontmatter.layout = "@layouts/BaseLayout.astro"; // file.data.astro.frontmatter.layout = "@layouts/BaseLayout.astro";
} // }
}; // };
}; //};
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
markdown: { markdown: {
remarkPlugins: [setLayout], //remarkPlugins: [setLayout],
shikiConfig: {
theme: "catppuccin-latte",
},
}, },
}); });

View file

@ -0,0 +1,18 @@
---
import { getDocumentPath, getDocumentTitle, getAncestorDocuments } from "@utils/docs";
const { document } = Astro.props;
const ancestorDocuments = await getAncestorDocuments(document);
---
<div class="breadcrumbs">
<a href="/">Home</a>
{ancestorDocuments.map(document => {
const title = getDocumentTitle(document);
const path = getDocumentPath(document);
return (
<span>⟩</span>
<a href={path}>{title}</a>
);
})}
</div>

View file

@ -4,14 +4,14 @@ import { getDocumentPath, getDocumentTitle, getChildDocuments } from "@utils/doc
const { document } = Astro.props; const { document } = Astro.props;
const childDocuments = await getChildDocuments(document); const childDocuments = await getChildDocuments(document);
--- ---
<ul> <ul class="menu">
{childDocuments.map(document => { {childDocuments.map(document => {
const title = getDocumentTitle(document); const title = getDocumentTitle(document);
const path = getDocumentPath(document); const path = getDocumentPath(document);
return ( return (
<li> <li>
<a href={path}>{title}</a> <a href={path}>{title}</a>
</li> </li>
); );
})} })}

View file

@ -1,5 +1,6 @@
--- ---
const { pageTitle } = Astro.props; const { pageTitle } = Astro.props;
import "@styles/main.css";
--- ---
<html lang="en"> <html lang="en">
<head> <head>

View file

@ -1,12 +0,0 @@
---
import BaseLayout from "@layouts/BaseLayout.astro";
import DocumentMenu from "@components/DocumentMenu.astro";
import { getDocumentPath, getDocumentTitle } from "@utils/docs";
const { document } = Astro.props;
const pageTitle = getDocumentTitle(document);
---
<BaseLayout pageTitle={pageTitle}>
<slot />
<DocumentMenu document={document} />
</BaseLayout>

View file

@ -1,7 +1,9 @@
--- ---
import { getCollection, render } from 'astro:content'; import { getCollection, render } from 'astro:content';
import DocumentLayout from "@layouts/DocumentLayout.astro"; import BaseLayout from "@layouts/BaseLayout.astro";
import DocumentMenu from "@components/DocumentMenu.astro";
import DocumentBreadcrumbs from "@components/DocumentBreadcrumbs.astro";
import { getDocumentPath, getDocumentTitle, getChildDocuments } from "@utils/docs"; import { getDocumentPath, getDocumentTitle, getChildDocuments } from "@utils/docs";
export async function getStaticPaths() { export async function getStaticPaths() {
@ -14,9 +16,11 @@ export async function getStaticPaths() {
} }
const { document } = Astro.props; const { document } = Astro.props;
const paths = await getStaticPaths(); const pageTitle = getDocumentTitle(document);
const { Content } = await render(document); const { Content } = await render(document);
--- ---
<DocumentLayout document={document}> <BaseLayout pageTitle={pageTitle}>
<DocumentBreadcrumbs document={document} />
<Content /> <Content />
</DocumentLayout> <DocumentMenu document={document} />
</BaseLayout>

18
astro/src/styles/main.css Normal file
View file

@ -0,0 +1,18 @@
html, body {
font-family: sans-serif;
}
main {
margin: 0 auto;
max-width: 600px;
line-height: 1.35;
}
.astro-code {
padding: 1rem;
}
ul.menu {
list-style: none;
padding: 0;
}

View file

@ -1,11 +1,13 @@
import type { MarkdownHeading } from "astro"; import type { MarkdownHeading } from "astro";
import { getCollection, type CollectionEntry } from "astro:content"; import { getCollection, type CollectionEntry } from "astro:content";
export function getDocumentPath(document: CollectionEntry<"documents">) { export type Document = CollectionEntry<"docs">;
export function getDocumentPath(document: Document) {
return "/" + document.id.replace(/\/_index$/, ""); return "/" + document.id.replace(/\/_index$/, "");
} }
export function getDocumentTitle(document: CollectionEntry<"documents">) { export function getDocumentTitle(document: Document) {
const headings: MarkdownHeading[] = const headings: MarkdownHeading[] =
(document.rendered?.metadata?.headings as MarkdownHeading[]) || []; (document.rendered?.metadata?.headings as MarkdownHeading[]) || [];
const firstHeading = headings[0]; const firstHeading = headings[0];
@ -17,17 +19,37 @@ export function getDocumentTitle(document: CollectionEntry<"documents">) {
return null; return null;
} }
export async function getChildDocuments( export async function getChildDocuments(parentDocument: Document | undefined) {
parentDocument: CollectionEntry<"documents"> | undefined,
) {
const documents = await getCollection("docs"); const documents = await getCollection("docs");
const basePath = const basePath =
parentDocument !== undefined ? getDocumentPath(parentDocument) : ""; parentDocument !== undefined ? getDocumentPath(parentDocument) : "";
const pathPattern = new RegExp(`^${basePath}/[^/]+$`); const pathPattern = new RegExp(`^${basePath}/[^/]+$`);
return documents.filter((document) => { const childDocuments = documents.filter((document) => {
const documentPath = getDocumentPath(document); const path = getDocumentPath(document);
return pathPattern.test(documentPath) && documentPath !== basePath; return pathPattern.test(path) && path !== basePath;
});
return childDocuments.sort((a, b) => {
const aWeight = a.data.weight || 0;
const bWeight = b.data.weight || 0;
return aWeight - bWeight;
});
}
export async function getAncestorDocuments(document: Document) {
const documents = await getCollection("docs");
const descendantPath = getDocumentPath(document);
const ancestorDocuments = documents.filter((document) => {
const path = getDocumentPath(document);
return descendantPath.startsWith(path) && path !== descendantPath;
});
return ancestorDocuments.sort((a, b) => {
return getDocumentPath(a).length - getDocumentPath(b).length;
}); });
} }

View file

@ -7,6 +7,7 @@
"@components/*": ["src/components/*"], "@components/*": ["src/components/*"],
"@layouts/*": ["src/layouts/*"], "@layouts/*": ["src/layouts/*"],
"@pages/*": ["src/pages/*"], "@pages/*": ["src/pages/*"],
"@styles/*": ["src/styles/*"],
"@utils/*": ["src/utils/*"] "@utils/*": ["src/utils/*"]
} }
} }