--- import { getCollection, render } from "astro:content"; import Layout from "../../layouts/Layout.astro"; import { Shield, ChevronLeft, List, PanelRight } from "@lucide/astro"; import Author from "../../components/Author.astro"; export async function getStaticPaths() { const notes = await getCollection("notes"); return notes.map((entry) => ({ params: { slug: entry.id }, props: { entry }, })); } const { entry } = Astro.props; const { Content } = await render(entry); const allNotes = await getCollection("notes"); const sortedNotes = allNotes.sort((a, b) => a.data.title.localeCompare(b.data.title)); function getCategory(n: { id: string; data: { category?: string } }): string { if (n.data.category) return n.data.category; const parts = n.id.split("/"); return parts.length > 1 ? parts[0] : "General"; } const categories = [...new Set(allNotes.map(getCategory))].sort(); function formatDate(date: Date) { return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }); } function extractLinks(body: string): string[] { const re = /\(\/notes\/([^)#\s]+)\)/g; const ids: string[] = []; let m; while ((m = re.exec(body)) !== null) ids.push(m[1]); return [...new Set(ids)]; } const allLinks = Object.fromEntries(allNotes.map((n) => [n.id, extractLinks(n.body ?? "")])); const forwardLinks = (allLinks[entry.id] ?? []) .map((id) => allNotes.find((n) => n.id === id)) .filter(Boolean) as typeof allNotes; const backlinks = allNotes.filter( (n) => n.id !== entry.id && (allLinks[n.id] ?? []).includes(entry.id) ); const graphNodes = [ { id: entry.id, title: entry.data.title, current: true }, ...forwardLinks.map((n) => ({ id: n.id, title: n.data.title, current: false })), ...backlinks .filter((n) => !forwardLinks.some((f) => f.id === n.id)) .map((n) => ({ id: n.id, title: n.data.title, current: false })), ]; const graphEdges = [ ...forwardLinks.map((n) => ({ from: entry.id, to: n.id })), ...backlinks.map((n) => ({ from: n.id, to: entry.id })), ]; function extractInlineHashtags(body: string): string[] { const re = /#(\w+)/g; const tags: string[] = []; let m; while ((m = re.exec(body)) !== null) tags.push(m[1].toLowerCase()); return [...new Set(tags)]; } function slugify(text: string) { return text.toLowerCase().replace(/`[^`]*`/g, "").replace(/[^\w\s-]/g, "").trim().replace(/[\s_]+/g, "-"); } const headings: { depth: number; text: string; id: string }[] = []; const headingRe = /^(#{2,4}) (.+)$/gm; let hm; while ((hm = headingRe.exec(entry.body ?? "")) !== null) { const raw = hm[2].trim().replace(/\*\*|__|\*|_|`/g, ""); headings.push({ depth: hm[1].length, text: raw, id: slugify(raw) }); } --- Notes nav graph /{getCategory(entry)} · {formatDate(entry.data.publishDate)} {entry.data.title} {entry.data.description} {entry.data.tags.length > 0 && ( {entry.data.tags.map((tag) => ( {tag} ))} )} {headings.length > 0 && ( § table of contents + − {headings.map((h) => ( {"#".repeat(h.depth)}{h.text} ))} )} ← all notes ~/hadi
{entry.data.description}