diff --git a/.claude/launch.json b/.claude/launch.json
new file mode 100644
index 00000000..069b1adf
--- /dev/null
+++ b/.claude/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.0.1",
+ "configurations": [
+ {
+ "name": "robostack-site",
+ "runtimeExecutable": "env",
+ "runtimeArgs": ["ASTRO_DEV_BACKGROUND=1", "pixi", "run", "serve"],
+ "port": 4321
+ }
+ ]
+}
diff --git a/astro.config.mjs b/astro.config.mjs
index c5b956ee..b4018733 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -2,7 +2,6 @@
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import svelte from "@astrojs/svelte";
-import { newestRelease } from "./src/data/distros.ts";
export default defineConfig({
site: "https://robostack.github.io",
@@ -33,25 +32,43 @@ export default defineConfig({
customCss: ["./src/styles/custom.css"],
routeMiddleware: "./src/routeData.ts",
components: {
+ Header: "./src/components/Header.astro",
+ Sidebar: "./src/components/Sidebar.astro",
SiteTitle: "./src/components/SiteTitle.astro",
PageTitle: "./src/components/PageTitle.astro",
},
sidebar: [
- // Slugs are set explicitly in each page's frontmatter to keep the
- // published mixed-case URLs (`GettingStarted.html`, `FAQ.html`, ...).
- { label: "Getting Started", slug: "GettingStarted" },
+ // One top-level group per header tab (src/components/Header.astro);
+ // the Sidebar override shows only the current page's group, so these
+ // group labels never render. Slugs are set explicitly in each page's
+ // frontmatter to keep the published mixed-case URLs
+ // (`GettingStarted.html`, `FAQ.html`, ...).
{
- label: "Alternative to Pixi",
+ label: "Docs",
items: [
- { label: "Micromamba", slug: "micromamba" },
- { label: "Conda", slug: "conda" },
+ { label: "Getting Started", slug: "GettingStarted" },
+ {
+ label: "Alternative to Pixi",
+ items: [
+ { label: "Micromamba", slug: "micromamba" },
+ { label: "Conda", slug: "conda" },
+ ],
+ },
+ { label: "JupyterRos", slug: "JupyterRos" },
+ { label: "FAQ", slug: "FAQ" },
+ // Cross-listed; its primary section is Community (the last
+ // group containing a page wins in the Sidebar override).
+ { label: "Contributing", slug: "Contributing" },
+ ],
+ },
+ {
+ label: "Community",
+ items: [
+ { label: "Community Meeting", slug: "CommunityMeeting" },
+ { label: "Support", slug: "support" },
+ { label: "Contributing", slug: "Contributing" },
],
},
- { label: "Packages", link: `/${newestRelease().name}.html` },
- { label: "JupyterRos", slug: "JupyterRos" },
- { label: "Support", slug: "support" },
- { label: "Contributing", slug: "Contributing" },
- { label: "FAQ", slug: "FAQ" },
],
}),
svelte(),
diff --git a/src/components/Header.astro b/src/components/Header.astro
new file mode 100644
index 00000000..98b15a15
--- /dev/null
+++ b/src/components/Header.astro
@@ -0,0 +1,146 @@
+---
+import config from "virtual:starlight/user-config";
+
+import LanguageSelect from "virtual:starlight/components/LanguageSelect";
+import Search from "virtual:starlight/components/Search";
+import SiteTitle from "virtual:starlight/components/SiteTitle";
+import SocialIcons from "virtual:starlight/components/SocialIcons";
+import ThemeSelect from "virtual:starlight/components/ThemeSelect";
+
+import { NAV_TABS as tabs } from "../data/nav";
+
+/**
+ * Override of Starlight's Header: the original row plus a tab row underneath
+ * (the zensical.org pattern), so the main sections stay reachable from every
+ * page - the splash homepage has no sidebar. The row's extra height comes
+ * from `--sl-nav-height`, raised in custom.css; the first row keeps the
+ * original height via `--rs-nav-row`. The tabs live in src/data/nav.ts,
+ * shared with the Sidebar override.
+ */
+
+const shouldRenderSearch =
+ config.pagefind ||
+ config.components.Search !== "@astrojs/starlight/components/Search.astro";
+
+const pathname = Astro.url.pathname;
+---
+
+
+
+
+
+{
+ /* The first-row styles are copied from Starlight's Header.astro so the
+ original layout survives the override; only `.stacked` and `.top-nav`
+ are new. */
+}
+
diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro
new file mode 100644
index 00000000..cceaeb0f
--- /dev/null
+++ b/src/components/Sidebar.astro
@@ -0,0 +1,35 @@
+---
+import MobileMenuFooter from "virtual:starlight/components/MobileMenuFooter";
+import SidebarPersister from "@astrojs/starlight/components/SidebarPersister.astro";
+import SidebarSublist from "@astrojs/starlight/components/SidebarSublist.astro";
+
+import { NAV_TABS } from "../data/nav";
+
+/**
+ * Override of Starlight's Sidebar: the header tabs are the top level of the
+ * navigation, so the sidebar only shows the pages of the current section.
+ * The section comes from the shared nav.ts patterns - the same ones that
+ * pick the active header tab - and names the matching top-level group in
+ * `astro.config.mjs`. Pages outside any section fall back to the full
+ * sidebar. The distro table pages opt out of the sidebar entirely; their
+ * in-page distro tabs are the sub-navigation.
+ */
+
+const { sidebar } = Astro.locals.starlightRoute;
+const pathname = Astro.url.pathname;
+
+const tab = NAV_TABS.find((t) => t.match.test(pathname));
+const section = sidebar.find(
+ (entry) => entry.type === "group" && entry.label === tab?.label,
+);
+
+const entries = section && section.type === "group" ? section.entries : sidebar;
+---
+
+
+
+
+
+
+
+
diff --git a/src/components/SiteTitle.astro b/src/components/SiteTitle.astro
index ec716170..64e3a811 100644
--- a/src/components/SiteTitle.astro
+++ b/src/components/SiteTitle.astro
@@ -24,7 +24,10 @@ const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute;
min-width: 0;
}
.site-title :global(svg) {
- height: calc(var(--sl-nav-height) - 2.4 * var(--sl-nav-pad-y));
+ /* Sized against the header's first row, not the full two-row header. */
+ height: calc(
+ var(--rs-nav-row, var(--sl-nav-height)) - 2.4 * var(--sl-nav-pad-y)
+ );
width: auto;
}
diff --git a/src/content/docs/CommunityMeeting.mdx b/src/content/docs/CommunityMeeting.mdx
new file mode 100644
index 00000000..14b09b70
--- /dev/null
+++ b/src/content/docs/CommunityMeeting.mdx
@@ -0,0 +1,52 @@
+---
+title: Community Meeting
+slug: CommunityMeeting
+---
+
+import { LinkButton } from "@astrojs/starlight/components";
+
+RoboStack has multiple stakeholders, so once a month we host an online meeting to discuss changes and potential user questions.
+Join in to understand or influence the project.
+
+:::note[Everyone is welcome]
+You don't have to be a maintainer or contributor.
+Using RoboStack, or just curious about it, is reason enough to join.
+:::
+
+## When
+
+- **Every third Thursday of the month, 16:00 Amsterdam time (CET/CEST)**
+- That is 14:00 UTC, 10:00 in New York and 7:00 in San Francisco during summer time.
+
+## How to join
+
+Add the recurring event to your calendar, the Google Meet link is attached to it:
+
+
+ Add the meeting to your calendar
+
+
+## Agenda and notes
+
+The agenda and notes live in [one shared document](https://docs.google.com/document/d/11zfgoNtyu1I55EHNk42vEWgFMPT_QGaI5XehcdU_ttc/edit), one running doc with the newest meeting on top.
+
+Want something discussed?
+Add a comment to the doc with your topic, or bring it up at the start of the call.
+Notes from past meetings stay in the same doc, so that is also the place to catch up on what you missed.
+
+## What we talk about
+
+- The state of the distros we package and the potential coming packages.
+- New features in [Pixi](https://pixi.sh) and [Vinca](https://github.com/RoboStack/vinca) that make using RoboStack easier or more feature-full.
+- Ongoing work, like migrations, CI and new platforms.
+- Your questions, issues and use cases.
+- Anything you bring to the agenda.
+
+## Between meetings
+
+For quicker async feedback or support, contact the team in the [robotics channel on the prefix.dev Discord](https://discord.gg/kKV8ZxyzY4).
+
+See you there!
diff --git a/src/content/docs/support.md b/src/content/docs/support.md
index ccf0dc76..a8e56bc8 100644
--- a/src/content/docs/support.md
+++ b/src/content/docs/support.md
@@ -9,6 +9,7 @@ How to help improve our documentation:
- For typos, grammar, or other errors, we'd appreciate your support! Simply [fork](https://github.com/RoboStack/robostack.github.io/fork) our repo, make the necessary changes, and submit a pull request.
- If you have questions or need help, feel free to create an [issue](https://github.com/RoboStack/robostack.github.io/issues) or join the community in the [robotics channel on the prefix.dev Discord](https://discord.gg/kKV8ZxyzY4).
+- Prefer talking to us live? Join the monthly [community meeting](/CommunityMeeting.html).
We're always eager to improve, and your input is valuable to us. Thank you for being part of the RoboStack community!
diff --git a/src/data/nav.ts b/src/data/nav.ts
new file mode 100644
index 00000000..ca38d256
--- /dev/null
+++ b/src/data/nav.ts
@@ -0,0 +1,34 @@
+import { DISTROS, newestRelease } from "./distros";
+
+/**
+ * The site's top-level sections: one header tab each (Header.astro), and -
+ * for tabs whose label matches a top-level sidebar group in astro.config.mjs
+ * - the sidebar shows that group's pages (Sidebar.astro). `match` decides
+ * both the active tab and which section a page belongs to, so cross-listed
+ * pages (Contributing sits in Docs and Community) resolve consistently.
+ */
+export interface NavTab {
+ label: string;
+ href: string;
+ match: RegExp;
+}
+
+export const NAV_TABS: NavTab[] = [
+ { label: "Home", href: "/index.html", match: /^\/(index(\.html)?)?$/ },
+ {
+ label: "Docs",
+ href: "/GettingStarted.html",
+ match: /^\/(GettingStarted|micromamba|conda|JupyterRos|FAQ)/,
+ },
+ {
+ label: "Packages",
+ href: `/${newestRelease().name}.html`,
+ // Active on every distro table page (/noetic.html, /lyrical.html, ...).
+ match: new RegExp(`^/(${DISTROS.map((d) => d.name).join("|")})(\\.html)?$`),
+ },
+ {
+ label: "Community",
+ href: "/CommunityMeeting.html",
+ match: /^\/(CommunityMeeting|support|Contributing)/,
+ },
+];
diff --git a/src/pages/[distro].astro b/src/pages/[distro].astro
index 1267e9bb..af8e7e53 100644
--- a/src/pages/[distro].astro
+++ b/src/pages/[distro].astro
@@ -29,6 +29,7 @@ const install = [
title: `ROS ${distro.ros} ${title(distro)}`,
tableOfContents: false,
}}
+ hasSidebar={false}
>
{
/* Phrased about upstream, not about our rebuilds. Noetic is end of life
diff --git a/src/pages/index.astro b/src/pages/index.astro
index bdd7380e..cc46fd31 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -149,10 +149,10 @@ const packagesHref = `/${newestRelease().name}.html`;
{/* Page backdrop and measure: the cream paper tone, wider than the docs. */}