From 94222bfb8e1fcfb43acd903146377c20f0bb9c23 Mon Sep 17 00:00:00 2001 From: Xevion Date: Sun, 10 Mar 2024 08:44:50 -0500 Subject: [PATCH] Continue work on sidebar generation/styling --- CHANGELOG.md | 5 +++ src/components/Sidebar.astro | 8 ++-- src/content/sidebar.ts | 74 +++++++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76c62ea..24b3afa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.0.3 + +- Continued dark mode work +- Added sidebar with content collection query for dynamic navigation + # 0.0.2 - Added version/commit hash to the footer diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro index 32f6804..b701ad5 100644 --- a/src/components/Sidebar.astro +++ b/src/components/Sidebar.astro @@ -12,12 +12,14 @@ const isCurrentPage = (item): boolean => { }; const getLinkClasses = (link) => { - const baseClasses = "block py-2 px-6 my-1 transition-colors border-l dark:border-l-zinc-600 hover:border-zinc-400 hover:text-slate-900" + const baseClasses = "block py-2 px-6 my-1 transition-colors border-l hover:border-zinc-400 hover:text-slate-900" const isCurrent = isCurrentPage(link); return clsx(baseClasses, { - "border-slate-500 text-slate-900": isCurrent, - "dark:text-slate-200 text-slate-500": !isCurrent, + // Classes for when the link is not the current page + "dark:border-l-zinc-600 text-zinc-500 dark:text-zinc-400": !isCurrent, + // Classes for when the link is the current page + "dark:border-l-zinc-500 text-zinc-900 dark:text-zinc-200": isCurrent, }); } diff --git a/src/content/sidebar.ts b/src/content/sidebar.ts index cb64676..8379aca 100644 --- a/src/content/sidebar.ts +++ b/src/content/sidebar.ts @@ -1,4 +1,4 @@ -import { getCollection, getEntries } from 'astro:content'; +import { getCollection, getEntries, type CollectionEntry } from 'astro:content'; export type Link = { @@ -7,37 +7,65 @@ export type Link = { header?: boolean; }; +const headerOrder: Record = { + root: 0, + learning: 1, + living: 2, + improving: 3, + default: 999 +} + +function toTitleCase(s: string): string { + return s.replace( + /\w\S*/g, + function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + } + ); +} + /** * Queries the content collection to build the sidebar dynamically * @returns {Link[]} - An array of links to be used in the sidebar */ -const get = async (): Link[] => { +const get = async (): Promise => { const entries = await getCollection('handbook'); - return entries.map((entry) => { - return { - text: entry.data.title, - link: `/handbook/${entry.slug}`, - header: entry.slug.endsWith('index.md') || entry.data.header, - }; + const entriesByHeader: Record[]> = {}; + + entries.forEach((entry) => { + // Acquire the header using the first part of the slug (otherwise, use 'root' as the header) + const header = entry.slug.indexOf('/') !== -1 ? entry.slug.split('/')[0] : 'root'; + + if (entriesByHeader[header]) + entriesByHeader[header].push(entry); + else + entriesByHeader[header] = [entry]; }); - // Fake data - return [ - { text: "Core", header: true }, - { text: "Introduction", link: "/core/introduction" }, - { text: "Colors", link: "/core/colors" }, - { text: "Typography", link: "/core/typography" }, - { text: "Shadows", link: "/core/shadows" }, + // Begin building the links array (root level first, then the rest of the entries) + const links: Link[] = entriesByHeader.root.map((entry) => ({ + text: entry.data.title, + link: `/handbook/${entry.slug}`, + })); - { text: "Components", header: true }, - { text: "Buttons", link: "/components/buttons" }, - { text: "Input", link: "/components/input" }, - { text: "Status pills", link: "/components/status-pill" }, - { text: "Table", link: "/components/table" }, + delete entriesByHeader.root; - { text: "Patterns", header: true }, - { text: "Introduction", link: "/patterns/introduction" }, - ]; + const sortedHeaders = Object.keys(entriesByHeader).sort((a, b) => { + return (headerOrder[a] || headerOrder.default) - (headerOrder[b] || headerOrder.default); + }); + + sortedHeaders.forEach((header) => { + links.push({ text: toTitleCase(header), header: true }); + entriesByHeader[header].forEach((entry) => { + links.push({ + text: entry.data.title, + link: `/handbook/${entry.slug}`, + }); + }); + }); + + + return links; }; export default get;