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
2 changes: 2 additions & 0 deletions blume.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export default defineConfig({
title: "Spacefast Docs",
variables: pricingVariables(await loadPricing({ fixture: new URL("./content/_pricing/document.json", import.meta.url) })),
description: "Publish and host the sites your agents build.",
// Two links (components/Logo.astro): the mark goes to the Website home at the
// origin root, outside the /docs base; "Docs" goes to the Docs home.
logo: { href: "/", image: { light: "/spacefast-wordmark.svg", alt: "Spacefast" }, text: "Docs" },
// The 2026-10 brand: neutral greys, one green, dark first like the Website.
// The green is a ground with ink on it, never type on white, so light mode
Expand Down
3 changes: 2 additions & 1 deletion components.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { defineComponents } from "blume";

import Breadcrumbs from "./components/Breadcrumbs.astro";
import Logo from "./components/Logo.astro";
import Pagination from "./components/Pagination.astro";
import Sidebar from "./components/Sidebar.astro";
import PricingTable from "./components/PricingTable.astro";
import WpCloudDocs from "./components/WpCloudDocs.astro";

export default defineComponents({
layout: { Breadcrumbs, Pagination, Sidebar },
layout: { Breadcrumbs, Logo, Pagination, Sidebar },
mdx: { PricingTable, WpCloudDocs },
});
41 changes: 41 additions & 0 deletions components/Logo.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
// The brand lockup: the Spacefast mark links to the Website home, "Docs" links
// to the Docs home. Docs are always served inside the Website artifact at
// /docs, so the configured root-relative `logo.href` ("/") is emitted as is,
// without the deployment base, and reaches the Website home on whatever origin
// serves the page. The Website is not part of the Docs' client router, so the
// mark's link does a plain page load instead of a router fetch first.
import { withBase } from "blume/components/islands/base-path.ts";
import type { BlumeLogo } from "blume/core/data.ts";

interface Props {
site: { title: string };
logo?: BlumeLogo | null;
locale?: string;
}

const { site, logo } = Astro.props;
const label = logo?.text ?? site.title;
const link = "inline-flex items-center transition-opacity hover:opacity-80";
// The config inlines the wordmark so it follows the theme. Fail the build
// rather than ship a header whose mark silently disappeared.
if (!logo?.svg) throw new Error("components/Logo.astro needs blume.config.ts `logo` to resolve to an inline SVG.");
---

<div class="flex min-w-0 items-center gap-2" data-sf-brand>
<a
aria-label={`${logo.alt || "Spacefast"} home`}
class:list={[link, "shrink-0 text-foreground"]}
data-astro-reload
href={logo.href}
>
<span aria-hidden="true" class="inline-flex h-5 items-center [&>svg]:h-5 [&>svg]:w-auto" set:html={logo.svg} />
</a>
{
label && (
<a class:list={[link, "min-w-0 font-semibold text-base text-foreground"]} href={withBase("/")}>
<span class="truncate">{label}</span>
</a>
)
}
</div>
18 changes: 17 additions & 1 deletion scripts/verify-routes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from "./redirect-rules.mjs";
import { discoveryFileForUrl } from "./build-llms-index.mjs";
import { readSidebarRoutes } from "./sidebar-routes.mjs";
import { websiteDependencies } from "./website-dependencies.mjs";

const root = path.resolve(process.cwd());
const dist = path.join(root, "dist");
Expand Down Expand Up @@ -289,6 +290,21 @@ for (const [file, present, absent] of sidebarExpectations) {
);
}
}
// The header lockup (components/Logo.astro) is two links: the mark to the
// Website home at the origin root, the label to the Docs home.
for (const file of ["index.html", "quickstart/index.html", "api/reference/index.html"]) {
const html = await readBuilt(file);
const start = html.indexOf("data-sf-brand");
const brand = start < 0 ? "" : html.slice(start, html.indexOf("</div>", start));
const links = [...brand.matchAll(/<a\b([^>]*)>([\s\S]*?)<\/a>/gu)].map(([, attributes, body]) => ({
href: /\bhref="([^"]*)"/u.exec(attributes)?.[1],
name: /\baria-label="([^"]*)"/u.exec(attributes)?.[1] ?? body.replace(/<[^>]*>/gu, "").trim(),
}));
const want = [{ href: "/", name: "Spacefast home" }, { href: `${deploymentBase}/`, name: "Docs" }];
if (JSON.stringify(links) !== JSON.stringify(want)) {
throw new Error(`dist/${file} header lockup is wrong: ${JSON.stringify(links)}.`);
}
}
// Docs previous/next skip the generated /setup pages; /setup keeps Blume's order.
for (const [file, prev, next] of [
["troubleshooting/index.html", "/quickstart", "/spaces"],
Expand Down Expand Up @@ -555,7 +571,7 @@ for (const file of htmlFiles) {
const html = await readFile(path.join(dist, file), "utf8");
for (const match of html.matchAll(/\b(?:action|href|src)=["'](\/[^"']*)["']/giu)) {
const url = match[1];
if (url.startsWith("//")) continue;
if (url.startsWith("//") || websiteDependencies.includes(url)) continue;
if (url !== deploymentBase && !url.startsWith(`${deploymentBase}/`)) {
throw new Error(`Built URL misses the ${deploymentBase} base in dist/${file}: ${url}`);
}
Expand Down
11 changes: 0 additions & 11 deletions theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,6 @@
color: var(--sf-ink);
}

/* The wordmark beside the mark reads as part of the logo, not a link. */
[data-blume-header] > a:first-of-type {
gap: 0.625rem;
font-weight: 500;
letter-spacing: -0.02em;
}

[data-blume-header] > a:first-of-type > span:last-child {
color: var(--blume-muted-foreground);
}

/*
* Headings follow the brand's type scale: Medium for display sizes, slight
* negative tracking, no serif.
Expand Down
Loading