From adf64e59e38adb05c7511a14a01be54b16cea27a Mon Sep 17 00:00:00 2001 From: Zach Harel Date: Wed, 29 Jul 2026 21:39:32 -0400 Subject: [PATCH 1/4] replace weird header thing with sidebar topics --- astro.config.mjs | 12 +- package.json | 6 +- pnpm-lock.yaml | 43 ++- src/config/sidebarConfig.ts | 72 ---- src/config/sidebarTopics.ts | 56 +++ src/starlightOverrides/Header.astro | 549 --------------------------- src/starlightOverrides/Sidebar.astro | 294 +------------- src/styles/global.css | 13 +- 8 files changed, 117 insertions(+), 928 deletions(-) create mode 100644 src/config/sidebarTopics.ts diff --git a/astro.config.mjs b/astro.config.mjs index 5931855a..dbe7e048 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,6 +1,8 @@ import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import starlightLinksValidator from 'starlight-links-validator'; +import starlightSidebarTopics from 'starlight-sidebar-topics'; +import { sidebarTopics } from './src/config/sidebarTopics'; import remarkGlossary from './src/plugins/remark-glossary'; import remarkCenter from './src/plugins/remark-center'; import remarkFigure from './src/plugins/remark-figure'; @@ -70,9 +72,13 @@ export default defineConfig({ // TOC is disabled globally but can be enabled per-directory in src/config/tocConfig.ts // or per-page via frontmatter (tableOfContents: true) tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 3 }, - // Sidebar configuration is now managed in src/config/sidebarConfig.ts - // This allows different sidebars per top-level navigation section - plugins: [starlightLinksValidator()], + plugins: [ + // Separates sidebar into topics that are switchable with a dropdown + starlightSidebarTopics(sidebarTopics, { + exclude: ['/', '/test-content-figure'], + }), + starlightLinksValidator(), + ], }), ], }); diff --git a/package.json b/package.json index 31979789..9d3b8077 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "@mdi/js": "^7.4.47", "astro": "^7.1.3", "sharp": "^0.34.5", + "starlight-sidebar-topics": "^0.8.0", + "starlight-sidebar-topics-dropdown": "^0.6.0", "unist-util-visit": "^5.1.0" }, "devDependencies": { @@ -43,9 +45,10 @@ "astro-eslint-parser": "^1.4.0", "eslint": "^10.5.0", "eslint-plugin-astro": "^1.7.0", - "mdast-util-mdx": "^3.0.0", + "globals": "^16.5.0", "husky": "^9.1.7", "lint-staged": "^17.0.8", + "mdast-util-mdx": "^3.0.0", "mdast-util-mdx-jsx": "^3.2.0", "mdx2vast": "^0.3.1", "prettier": "^3.8.4", @@ -55,7 +58,6 @@ "remark-frontmatter": "^5.0.0", "remark-lint-no-dead-urls": "^2.0.1", "remark-mdx": "^3.1.1", - "globals": "^16.5.0", "remark-preset-lint-recommended": "^7.0.1", "starlight-links-validator": "^0.20.0", "tsx": "^4.22.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5ba09bc2..b2c9153e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,12 @@ importers: sharp: specifier: ^0.34.5 version: 0.34.5 + starlight-sidebar-topics: + specifier: ^0.8.0 + version: 0.8.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3)) + starlight-sidebar-topics-dropdown: + specifier: ^0.6.0 + version: 0.6.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3))(starlight-sidebar-topics@0.8.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3))) unist-util-visit: specifier: ^5.1.0 version: 5.1.0 @@ -3335,6 +3341,19 @@ packages: '@astrojs/starlight': '>=0.38.0' astro: '>=6.0.0' + starlight-sidebar-topics-dropdown@0.6.0: + resolution: {integrity: sha512-V9a31xML6B28Eo/EZU84AqE8sjhPLjmRpo0buYtRyugRAp2vH7ZKJQDzQwpjSZen7MVb3hgYTNqBus0pdDr+XQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/starlight': '>=0.38' + starlight-sidebar-topics: '>=0.7' + + starlight-sidebar-topics@0.8.0: + resolution: {integrity: sha512-hE8+w2vNL13h6cq3UJGl05milJQ3+1BSlhaV5V4a993YzYczU6uLAj6jfUDKQ2mmgkdVWp8/UNDF4Je/rQXNQw==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/starlight': '>=0.38.0' + stream-replace-string@2.0.0: resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} @@ -4745,7 +4764,7 @@ snapshots: dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.4 + picomatch: 4.0.5 optionalDependencies: rollup: 4.59.0 @@ -5810,9 +5829,9 @@ snapshots: dependencies: format: 0.2.2 - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: @@ -8183,6 +8202,16 @@ snapshots: transitivePeerDependencies: - supports-color + starlight-sidebar-topics-dropdown@0.6.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3))(starlight-sidebar-topics@0.8.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3))): + dependencies: + '@astrojs/starlight': 0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3) + starlight-sidebar-topics: 0.8.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3)) + + starlight-sidebar-topics@0.8.0(@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3)): + dependencies: + '@astrojs/starlight': 0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(rollup@4.59.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@6.0.3) + picomatch: 4.0.5 + stream-replace-string@2.0.0: {} string-argv@0.3.2: {} @@ -8297,13 +8326,13 @@ snapshots: tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 to-regex-range@5.0.1: dependencies: diff --git a/src/config/sidebarConfig.ts b/src/config/sidebarConfig.ts index bc56f1ed..b87ba2a1 100644 --- a/src/config/sidebarConfig.ts +++ b/src/config/sidebarConfig.ts @@ -21,17 +21,6 @@ export type Item = { // Define which URL paths belong to which sidebar section export const sidebarSections: Record = { - // Home page - minimal sidebar or none - '/': [], - - // Feature Guide section - '/feature-guide': [ - { - label: 'Website Feature Guide', - items: [{ label: 'Overview', slug: 'feature-guide' }], - }, - ], - // Learning Course section '/learning-course': [ { @@ -257,67 +246,6 @@ export const sidebarSections: Record = { ], }, ], - - // Getting Started section - '/getting-started': [ - { - label: 'Getting Started', - items: [ - { - label: 'Website Feature Guide', - slug: 'learning-course/getting-started/website-feature-guide', - }, - { - label: 'Required Tools', - slug: 'learning-course/getting-started/required-tools', - }, - { - label: 'VS Code Overview', - slug: 'learning-course/getting-started/vscode-overview', - }, - { - label: 'Forking and Cloning', - slug: 'learning-course/getting-started/forking-and-cloning', - }, - { - label: 'Intro to Java', - slug: 'learning-course/stage0/stage-overview', - }, - ], - }, - ], - - // Intro To Java section - '/intro-to-java': [ - { - label: 'Intro to Java', - items: [ - { - label: 'Stage Overview', - slug: 'learning-course/stage0/stage-overview', - }, - { - label: 'Java fundamentals', - slug: 'learning-course/stage0/java-fundamentals', - }, - { - label: 'operators', - slug: 'learning-course/stage0/operators', - }, - ], - }, - ], - - // Resources section (content lives at /resources but navbar says "Other Resources") - // '/resources': [ - // { - // label: 'Resources', - // items: [ - // { label: 'Overview', slug: 'resources' }, - // { label: 'Glossary', slug: 'resources/glossary' }, - // ], - // }, - // ], }; /** diff --git a/src/config/sidebarTopics.ts b/src/config/sidebarTopics.ts new file mode 100644 index 00000000..6874f26b --- /dev/null +++ b/src/config/sidebarTopics.ts @@ -0,0 +1,56 @@ +import type { StarlightUserConfig } from '@astrojs/starlight/types'; +import { sidebarSections, type SidebarItem } from './sidebarConfig'; + +type StarlightSidebarItem = NonNullable[number]; + +function convertItem(item: SidebarItem): StarlightSidebarItem { + if (item.items) { + return { + label: item.label, + collapsed: item.collapsed ?? false, + items: item.items.map(convertItem), + }; + } + return { label: item.label, link: '/' + item.slug + '/' }; +} + +export const sidebarTopics = [ + { + label: 'Learning Course', + id: 'learning-course', + link: '/learning-course/', + icon: 'notes', + items: sidebarSections['/learning-course']![0]!.items.map(convertItem), + }, + { + label: "Educator's Guide", + id: 'educators-guide', + link: '/educators-guide/introduction/', + icon: 'open-book', + items: sidebarSections['/educators-guide']![0]!.items.map(convertItem), + }, + { + label: 'Best Practices', + id: 'best-practices', + link: '/best-practices/overview/', + icon: 'approve-check-circle', + items: sidebarSections['/best-practices']![0]!.items.map(convertItem), + }, + { + label: 'Resources', + id: 'resources', + link: '/resources/', + icon: 'document', + items: sidebarSections['/other-resources']![0]!.items.map(convertItem), + }, + { + label: 'Contribution', + id: 'contribution', + link: '/contribution/', + icon: 'code-branch', + items: [ + { label: 'Overview', link: '/contribution/' }, + ...sidebarSections['/contribution']![0]!.items.map(convertItem), + ], + }, +]; diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro index 1ceca959..c6e18366 100644 --- a/src/starlightOverrides/Header.astro +++ b/src/starlightOverrides/Header.astro @@ -4,88 +4,7 @@ import Search from '@astrojs/starlight/components/Search.astro'; import { mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js'; import MdiIcon from '../components/MdiIcon.astro'; -import { getSidebarForPath, type SidebarItem } from '../config/sidebarConfig'; - const props = Astro.props; - -const navLinks = [ - { href: '/', label: 'Home' }, - { href: '/learning-course/', label: 'Learning Course' }, - { href: '/educators-guide/introduction/', label: "Educator's Guide" }, - { href: '/best-practices/overview', label: 'Best Practices' }, - { href: '/contribution/', label: 'Contribution' }, -]; - -const currentPath = Astro.url.pathname; - -function isActive(href: string): boolean { - if (href === '/') { - return currentPath === '/' || currentPath === ''; - } - - // Special case: Changelog is a specific page under /resources/ - // Only mark it active if we're exactly on the changelog page - if (href === '/resources/site-changelog/') { - return ( - currentPath === '/resources/site-changelog/' || - currentPath === '/resources/site-changelog' - ); - } - - // Special case: "Other Resources" should NOT be active when on Changelog - if (href === '/resources/') { - return ( - currentPath.startsWith('/resources/') && - !currentPath.startsWith('/resources/site-changelog') - ); - } - - // For nested paths like /educators-guide/introduction/, check the base section - const baseSection = '/' + href.split('/')[1] + '/'; - return currentPath.startsWith(baseSection); -} - -// Get sidebar items for current page -const sidebarSections = getSidebarForPath(currentPath); - -// Build nested structure for mobile menu -type MobileNavItem = { - label: string; - href?: string; - items?: MobileNavItem[]; - depth: number; -}; - -function buildMobileNavItems( - items: SidebarItem[], - depth: number = 0, -): MobileNavItem[] { - const result: MobileNavItem[] = []; - - for (const item of items) { - if (item.slug) { - result.push({ - label: item.label, - href: '/' + item.slug + '/', - depth, - }); - } else if (item.items) { - result.push({ - label: item.label, - items: buildMobileNavItems(item.items, depth + 1), - depth, - }); - } - } - - return result; -} - -// Get all items from all sections -const mobileSidebarItems: MobileNavItem[] = []; -for (const section of sidebarSections) { - mobileSidebarItems.push(...buildMobileNavItems(section.items, 0)); -} ---
@@ -95,19 +14,6 @@ for (const section of sidebarSections) {
- - -
- - - -
- - - - +{hasSidebar && isPageWithTopic && } + diff --git a/src/styles/global.css b/src/styles/global.css index b10c5136..f4e61d7b 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -7,7 +7,7 @@ :root { /* Layout */ --sl-content-width: 85rem !important; - --sl-nav-height: 5.5rem !important; + --sl-nav-height: 3.5rem !important; /* Typography */ --sl-font: 'Inter', system-ui, sans-serif !important; @@ -195,17 +195,6 @@ section[class*='hero'] a:hover svg { drop-shadow(0 0 50px rgba(255, 255, 255, 0.15)) !important; } -/* ========================================================================== - Mobile Sidebar Toggle (Hide Starlight's default - we use unified menu) - ========================================================================== */ - -@media (max-width: 1350px) { - /* Hide Starlight's default sidebar toggle - we merged it into header menu */ - starlight-menu-button { - display: none !important; - } -} - /* ========================================================================== Sidebar ========================================================================== */ From 271e038437ab14df035905c1c5f7bed8a0e787b9 Mon Sep 17 00:00:00 2001 From: Zach Harel Date: Wed, 29 Jul 2026 22:04:54 -0400 Subject: [PATCH 2/4] fix mobile header formatting --- src/starlightOverrides/Header.astro | 130 +++++++++++++++++++++++++++- src/styles/global.css | 16 +++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro index c6e18366..0ea563f5 100644 --- a/src/starlightOverrides/Header.astro +++ b/src/starlightOverrides/Header.astro @@ -14,6 +14,20 @@ const props = Astro.props;
+ + +