Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "robostack-site",
"runtimeExecutable": "env",
"runtimeArgs": ["ASTRO_DEV_BACKGROUND=1", "pixi", "run", "serve"],
"port": 4321
}
]
}
41 changes: 29 additions & 12 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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(),
Expand Down
146 changes: 146 additions & 0 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -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;
---

<div class="stacked">
<div class="header">
<div class="title-wrapper sl-flex">
<SiteTitle />
</div>
<div class="search-wrapper sl-flex print:hidden">
{shouldRenderSearch && <Search />}
</div>
<div class="sl-hidden md:sl-flex print:hidden right-group">
<div class="sl-flex social-icons">
<SocialIcons />
</div>
<ThemeSelect />
<LanguageSelect />
</div>
</div>
<nav class="top-nav print:hidden" aria-label="Main">
{
tabs.map((tab) => (
<a
href={tab.href}
aria-current={tab.match.test(pathname) ? "page" : undefined}
>
{tab.label}
</a>
))
}
</nav>
</div>

<script>
// On narrow screens the tab row scrolls; keep the active tab in view.
document
.querySelector('.top-nav a[aria-current="page"]')
?.scrollIntoView({ inline: "center", block: "nearest" });
</script>

{
/* 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. */
}
<style>
.stacked {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}

.header {
display: flex;
gap: var(--sl-nav-gap);
justify-content: space-between;
align-items: center;
height: calc(var(--rs-nav-row) - 2 * var(--sl-nav-pad-y));
}

.title-wrapper {
/* Prevent long titles overflowing and covering the search and menu buttons on narrow viewports. */
overflow: clip;
/* Avoid clipping focus ring around link inside title wrapper. */
padding: 0.25rem;
margin: -0.25rem;
min-width: 0;
}

.right-group,
.social-icons {
gap: 1rem;
align-items: center;
}
.social-icons::after {
content: "";
height: 2rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}

.top-nav {
display: flex;
gap: 1.5rem;
overflow-x: auto;
scrollbar-width: none;
font-size: var(--sl-text-sm);
/* Sit on the header's bottom border, zensical-style: the active tab's
underline touches the border, and the space freed up moves between
the logo row and the tabs. */
margin-block-end: calc(-1 * var(--sl-nav-pad-y));
}
.top-nav a {
color: var(--sl-color-gray-2);
text-decoration: none;
white-space: nowrap;
padding-block: 0.25rem 0.4rem;
border-bottom: 2px solid transparent;
}
.top-nav a:hover {
color: var(--sl-color-white);
}
.top-nav a[aria-current="page"] {
color: var(--sl-color-white);
border-bottom-color: var(--sl-color-accent);
}

@media (min-width: 50rem) {
.header {
display: grid;
/* Starlight's own grid sizes the first column off the sidebar and TOC
widths, so the search box shifts from page to page. Anchoring the
search to the right edge, next to the other controls, keeps it in
the same place everywhere. */
grid-template-columns: auto 1fr auto;
align-content: center;
}
.search-wrapper {
justify-content: flex-end;
}
}
</style>
35 changes: 35 additions & 0 deletions src/components/Sidebar.astro
Original file line number Diff line number Diff line change
@@ -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;
---

<SidebarPersister>
<SidebarSublist sublist={entries} />
</SidebarPersister>

<div class="md:sl-hidden">
<MobileMenuFooter />
</div>
5 changes: 4 additions & 1 deletion src/components/SiteTitle.astro
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
</style>
52 changes: 52 additions & 0 deletions src/content/docs/CommunityMeeting.mdx
Original file line number Diff line number Diff line change
@@ -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:

<LinkButton
href="https://calendar.google.com/calendar/event?action=TEMPLATE&tmeid=MDU1bHFrbzdlN3EzdHBjbWtxZ2poMTF1aHNfMjAyNjA4MjBUMTQwMDAwWiBydWJlbkBwcmVmaXguZGV2&tmsrc=ruben%40prefix.dev&scp=ALL"
icon="external"
>
Add the meeting to your calendar
</LinkButton>

## 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!
1 change: 1 addition & 0 deletions src/content/docs/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!

Expand Down
34 changes: 34 additions & 0 deletions src/data/nav.ts
Original file line number Diff line number Diff line change
@@ -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)/,
},
];
1 change: 1 addition & 0 deletions src/pages/[distro].astro
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ const packagesHref = `/${newestRelease().name}.html`;

{/* Page backdrop and measure: the cream paper tone, wider than the docs. */}
<style is:global>
/* Outranks Starlight's own `html:not([data-has-sidebar])` width. */
:root:not([data-has-sidebar]) {
:root {
--sl-content-width: 76rem;
}

.main-pane,
main {
background: var(--bg-page);
Expand Down
Loading