diff --git a/src/components/navigation.ts b/src/components/navigation.ts index ef8b9a2..232ce8f 100644 --- a/src/components/navigation.ts +++ b/src/components/navigation.ts @@ -27,7 +27,7 @@ export const navigation = [ label: "Mentorship Programme Terms and Conditions", link: "/about/mentorship", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Legal Information", @@ -46,7 +46,7 @@ export const navigation = [ link: "/legal/privacy", }, { - label: "Naomi's Public License", + label: "Naomi's Public Licence", link: "/legal/license", }, { @@ -93,7 +93,7 @@ export const navigation = [ label: "Crisis and Mental Health Management Policy", link: "/legal/crisis-mental-health", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Community Policies", @@ -123,14 +123,14 @@ export const navigation = [ label: "Community Feedback and Participation Policy", link: "/community/feedback", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Development Documentation", collapsed: true, items: [ { - label: "Contributing Guide", + label: "Contributing Documentation", link: "/dev/contributing", }, { @@ -154,10 +154,14 @@ export const navigation = [ link: "/dev/servers", }, { - label: "VTubing Setup", + label: "Naomi's VTubing Setup", link: "/dev/vtubing", }, - ], + { + label: "Security Hall of Fame", + link: "/dev/hall-of-fame", + } + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Project Documentation", @@ -224,7 +228,7 @@ export const navigation = [ badge: { text: "v0.0.0", variant: "danger" }, }, { - label: "NHCarrigan Portfolio", + label: "Portfolio", link: "/projects/portfolio", badge: { text: "unversioned", variant: "success" }, }, @@ -304,7 +308,7 @@ export const navigation = [ badge: { text: "v1.0.0", variant: "tip" }, }, { - label: "Documentation Site", + label: "NHCarrigan Documentation", link: "/projects/docs", badge: { text: "v1.0.0", variant: "tip" }, }, @@ -519,7 +523,7 @@ export const navigation = [ badge: { text: "v1.0.0", variant: "tip" }, }, { - label: "Art4Palestine Bot", + label: "Artists4Palestine Bot", link: "/projects/a4p-bot", badge: { text: "v1.0.0", variant: "tip" }, }, @@ -624,13 +628,13 @@ export const navigation = [ label: "Technical Contributor Training for Staff", link: "/staff/training/technical-contributor", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Staff Policy Self-Assessment", link: "/staff/policy-self-assessment", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Miscellaneous Documents", @@ -640,7 +644,7 @@ export const navigation = [ label: "Managing Local Music", link: "/misc/music", }, - ], + ].sort((a, b) => a.label.localeCompare(b.label)), }, { label: "Sitemap", diff --git a/src/content/docs/dev/covenant.md b/src/content/docs/dev/covenant.md index c0cc384..3394320 100644 --- a/src/content/docs/dev/covenant.md +++ b/src/content/docs/dev/covenant.md @@ -1,5 +1,5 @@ --- -title: nhcarrigan Contributor Covenant +title: Contributor Covenant --- Copyright (C) 2024 nhcarrigan and its contributors. diff --git a/src/content/docs/dev/labels.md b/src/content/docs/dev/labels.md index 113df97..8e6e905 100644 --- a/src/content/docs/dev/labels.md +++ b/src/content/docs/dev/labels.md @@ -1,5 +1,5 @@ --- -title: Labels +title: "Issue/PR Labels" --- We use very specific labels to help categorise our issues. This page explains what each label means. diff --git a/src/content/docs/misc/music.md b/src/content/docs/misc/music.md index 7a4b21b..89b3c71 100644 --- a/src/content/docs/misc/music.md +++ b/src/content/docs/misc/music.md @@ -1,5 +1,5 @@ --- -title: Downloading and Editing Music +title: Managing Local Music --- This serves as our documentation for how we manage our local music libraries on Linux. diff --git a/test/nav.spec.ts b/test/nav.spec.ts new file mode 100644 index 0000000..dc9cac7 --- /dev/null +++ b/test/nav.spec.ts @@ -0,0 +1,79 @@ +/** + * @copyright NHCarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { readFile } from "node:fs/promises"; +import { readdir } from "node:fs/promises"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { navigation } from "../src/components/navigation.ts"; +import matter from "gray-matter"; + +type Navigation = typeof navigation; +type NavigationItem = Array<{ + label: string + link: string + items?: Array<{ + label: string + link: string + }> + }> + +const excludedFiles = ["intro.mdx", "projects/_template.md"]; + +// this should recursively walk the specified directory and return a list of all files, prefixing them with nested paths. +// For example, calling walkDirectory() should return "/about/contact.md", "/about/mission.md", "/about/sustainability.md", etc. +const walkDirectory = async (directory = join(__dirname, "..", "src", "content", "docs"), prefix = ""): Promise> => { + const filesAndDirectories = await readdir(directory, { withFileTypes: true }); + const pages = []; + for (const fileOrDirectory of filesAndDirectories) { + if (fileOrDirectory.isDirectory()) { + pages.push(...(await walkDirectory(join(directory, fileOrDirectory.name), join(prefix, fileOrDirectory.name)))); + } else { + pages.push(join(prefix, fileOrDirectory.name)); + } + } + return pages; +} + +const flattenNavigation = (navigation: Navigation | NavigationItem): Array<{ label: string; link: string }> => { + const items: Array<{ label: string; link: string }> = []; + for (const item of navigation) { + if ("items" in item && item.items) { + items.push(...flattenNavigation(item.items as NavigationItem)); + } else { + items.push({ label: item.label, link: item.link }); + } + } + return items; +} + +describe("navigation", () => { + it("should include all pages", async () => { + expect.hasAssertions(); + let pages = await walkDirectory(); + pages = pages.filter((page) => !excludedFiles.includes(page)); + const flattenedNavigation = flattenNavigation(navigation); + for (const page of pages) { + const pageName = page.split(".")[0]; + const navItem = flattenedNavigation.find((item) => item.link === `/${pageName}`); + expect(navItem, `Navigation item not found for page ${page}`).toBeDefined(); + } + }); + + it("should use page titles as navigation item labels", async () => { + expect.hasAssertions(); + let pages = await walkDirectory(); + pages = pages.filter((page) => !excludedFiles.includes(page)); + const flattenedNavigation = flattenNavigation(navigation); + for (const page of pages) { + const pageName = page.split(".")[0]; + const navItem = flattenedNavigation.find((item) => item.link === `/${pageName}`); + const pageContent = await readFile(join(__dirname, "..", "src", "content", "docs", page), "utf-8"); + const { data } = matter(pageContent); + expect(navItem?.label, `Navigation item label for ${pageName} is not correct`).toBe(data.title); + } + }); +}); diff --git a/test/projects.spec.ts b/test/projects.spec.ts index db7ac86..d4ea3eb 100644 --- a/test/projects.spec.ts +++ b/test/projects.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention -- We are dealing with repository names, which are in kebab-case */ /** * @copyright NHCarrigan * @license Naomi's Public License