Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1c157fa
Load Geist from Google Fonts and switch mono to Berkeley Mono
legions-developer Jul 30, 2026
abda527
Port the www adaptive color scales into the docs design system
legions-developer Jul 30, 2026
dbd66c4
Port www semantic tokens and typography utilities; steady active tab
legions-developer Jul 30, 2026
15136f8
Migrate component CSS from globals.css to Tailwind utilities in TSX
legions-developer Jul 30, 2026
7f04c3e
Faux-bold active nav links and finish the cn() sweep
legions-developer Jul 30, 2026
434b40e
Article chrome polish: brand breadcrumbs, body-size lede, simpler menus
legions-developer Jul 30, 2026
e53eca0
Landing redesign: icon quick-cards, integrations grid, article footer
legions-developer Jul 30, 2026
b0f911f
Finish the globals.css migration: rendered-content CSS moves into TSX
legions-developer Jul 30, 2026
0677e28
Article prose stylesheet: nested doc-prose.css, list rhythm, not-prose
legions-developer Jul 30, 2026
c29fcc1
Render mermaid fences as Axiom-themed diagrams
legions-developer Jul 30, 2026
333e92b
Port the www axiom code theme into the Shiki pipeline
legions-developer Jul 30, 2026
8771fcc
Sidebar and header polish: symmetric rails, slimmer drawer, 1px tab rule
legions-developer Jul 30, 2026
e6c1675
Focus rings follow the brand accent instead of blue
legions-developer Jul 30, 2026
20d5e04
Extensions catalog: brand-icon AppCards for docs/apps/introduction
legions-developer Jul 30, 2026
aca662b
Drop the --- separators before reference-architecture h2s
legions-developer Jul 30, 2026
f6a8161
Use www's raster favicon for the docs
legions-developer Jul 30, 2026
ba39fd7
Refresh stale e2e expectations to the shipped design
legions-developer Jul 30, 2026
4ee9ac2
Merge branch 'main' into feat/improve-docs-design
legions-developer Aug 4, 2026
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
187 changes: 187 additions & 0 deletions app/[...slug]/doc-prose.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/* Article reading-column typography for MDX-rendered content, applied via
`doc-prose` on DocsBody (alongside fumadocs' own `prose`). Deliberately
UNLAYERED: it must outrank `@layer utilities` on elements inside the
article exactly like the hand-written rules it replaces — components that
need to override it locally use `!` utilities. Declarations use @apply so
values stay in the design-token vocabulary. */
@reference "../globals.css";

.doc-prose {
--docs-type-size: 16px;
--docs-type-leading: 1.75;
--docs-type-flow: 1.4em;
/* Body copy matches the lede's colour — the brighter gray-300 read as
bold against it. --text-tertiary is theme-aware (gray-400 dark /
gray-600 light). */
--docs-copy: var(--text-tertiary);
--tw-prose-body: var(--docs-copy);
--tw-prose-headings: var(--text-primary);
--tw-prose-links: var(--text-primary);
--tw-prose-bold: var(--text-primary);
--tw-prose-code: var(--text-primary);
--tw-prose-bullets: var(--text-quaternary);
@apply max-w-none font-normal text-(--docs-copy) text-(length:--docs-type-size) leading-(--docs-type-leading) tracking-[-.006em];

/* `:is` (not `:where`) so these outrank plain colour utilities on elements
inside the article. */
& :is(p, li, dd, td) {
@apply text-(--docs-copy);
}
& :is(strong, b) {
@apply text-(--text-primary);
}

/* Vertical rhythm: zero every block, then space adjacent flow siblings.
Reading-column measure applies to direct children. */
& :where(p, ul, ol, blockquote, table, figure, hr) {
@apply my-0;
}
& > :where(p, ul, ol, blockquote, dl) {
@apply max-w-[768px];
}
&
> :where(
p,
ul,
ol,
blockquote,
table,
figure,
hr,
.fd-codeblock
)
+ :where(
p,
ul,
ol,
blockquote,
table,
figure,
hr,
.fd-codeblock
) {
@apply mt-(--docs-type-flow);
}

/* Heading rules honour `.not-prose` — components like fumadocs' Card
render their own <h3> titles, which the article heading margins were
inflating (a 40px gap above every card title). */
& h2:not(:is(.not-prose, .not-prose *)) {
@apply mt-[58px] mb-[14px] p-0 font-sans text-[24px] leading-[31px] font-semibold tracking-[-.022em] text-balance;
}
& h3:not(:is(.not-prose, .not-prose *)) {
@apply mt-10 mb-[11px] font-sans text-[20px] leading-[27px] font-semibold tracking-[-.015em] text-balance;
}
& h4:not(:is(.not-prose, .not-prose *)) {
@apply mt-8 mb-[9px] font-sans text-[17px] leading-6 font-semibold tracking-[-.01em];
}
& h2 + h3:not(:is(.not-prose, .not-prose *)) {
@apply mt-[18px];
}
& h3 + h4:not(:is(.not-prose, .not-prose *)) {
@apply mt-4;
}
& :where(h2, h3, h4) + :where(p, ul, ol) {
@apply mt-0;
}

& :where(ul, ol) {
@apply ps-[1.35em];
}
& li {
@apply ps-[.25em];
}
& li + li {
@apply mt-[.55em];
}
& :is(li > ul, li > ol) {
@apply mt-[.55em];
}

& blockquote {
@apply mt-[calc(var(--docs-type-flow)*1.15)] py-0.5 ps-[18px] pe-0 border-l-2 border-l-(--border-strong) text-(--text-tertiary) not-italic;
}
& hr {
@apply mt-[calc(var(--docs-type-flow)*2)] border-(--border-primary);
}
& table {
@apply mt-[calc(var(--docs-type-flow)*1.25)] text-[.93em];
}

& a {
@apply decoration-(--border-strong) underline-offset-[3px];
}
& :where(p, li, td, dd) a:not(.playground-link) {
@apply text-(--text-primary) underline decoration-[color-mix(in_oklab,var(--text-primary)_30%,transparent)];
}
& :where(p, li, td, dd) a:not(.playground-link):hover {
@apply decoration-(--color-accent);
}
& a:focus-visible {
@apply rounded-[2px] outline-2 outline-(--color-accent) outline-offset-2;
}

& :not(pre) > code {
@apply py-px px-1 border border-(--border-primary) rounded-[3px] bg-(--bg-inert) font-mono text-[.84em];
}
/* Flatter, more legible keycaps than Tailwind Typography's default (tiny
.875em text, low contrast, heavy raised-key shadow). */
& kbd {
@apply py-px px-1.5 border border-(--border-primary) rounded-[4px] bg-(--bg-emph-tertiary) shadow-[0_1px_0_var(--border-strong)] text-(--text-secondary) font-mono text-[12px] leading-[18px] font-medium align-baseline;
}
/* Multi-line code in the reading column tracks the body bump: 12px -> 13px. */
& :is(pre, pre code) {
@apply text-[13px] leading-[21px];
}

&
:is(
figure[data-rehype-pretty-code-figure],
figure.shiki,
.fd-codeblock
) {
@apply border-(--border-primary) rounded-[4px]! bg-(--bg-inert) shadow-none!;
}
& figure:has(+ .placeholder-config) {
@apply rounded-b-none!;
}

/* Code-block copy button reveals on hover, or on keyboard focus only
(:focus-visible) — a mouse click copies without the button sticking on. */
& figure > div:has(> button[aria-label="Copy Text"]) {
@apply opacity-0 transition-opacity duration-[.12s] ease-[ease];
}
& figure:hover > div:has(> button[aria-label="Copy Text"]),
&
figure
> div:has(> button[aria-label="Copy Text"]:focus-visible) {
@apply opacity-100;
}

/* Markdown tables (fumadocs wraps them in div.relative.overflow-auto). */
& div.relative.overflow-auto:has(> table) {
@apply my-[18px]! overflow-auto border border-(--border-primary) rounded-[4px];

& > table {
@apply w-full m-0! border-0! border-collapse table-auto text-[12px]! rounded-none!;
}
& th {
@apply py-2 px-2.5 border-0 border-r border-r-(--border-primary) border-b border-b-(--border-primary) text-(--text-secondary) bg-(--bg-inert) font-mono text-[13px] leading-[18px] font-[550] text-left;
}
& td {
@apply py-[9px] px-2.5 border-0 border-r border-r-(--border-tertiary) border-b border-b-(--border-tertiary) text-(--docs-copy) font-sans text-[14px] leading-[22px] font-normal align-top;
}
& :is(th, td):last-child {
@apply border-r-0;
}
& tbody tr:last-child td {
@apply border-b-0;
}

/* Inline code in cells already reads as an identifier via the mono face;
drop the chip so dense tables stay calm — just monospace. */
& :is(th, td) code {
@apply p-0 border-0 rounded-none bg-transparent text-[length:inherit];
}
}
}
49 changes: 39 additions & 10 deletions app/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,38 @@ import { getAdjacentNavigation, getBreadcrumbs, getNavigation, getSection } from
import { ogImage } from '@/lib/og';
import { pageGraph, structuredDataProps } from '@/lib/structured-data';
import { source } from '@/lib/source';
import './doc-prose.css';
import { cn } from '@/lib/utils';

type PageProps = { params: Promise<{ slug?: string[] }> };

// The reading column is shifted left of centre so the fixed table of contents on the
// right does not push the measure off-axis; the shift is dropped once the sidebar
// collapses into a drawer at 1240px.
const DOC_ARTICLE_CLASS = 'doc-article w-[min(768px,100%)] my-0 mx-auto translate-x-[-130px] max-xl:translate-x-0';

// The trail renders in the brand orange, so hover signals with an underline
// instead of a colour change. `[&:hover]` rather than `hover:` — Tailwind v4
// wraps `hover:` in `@media (hover: hover)`, which would drop the state on touch.
// decoration-current: the base `a:hover` element default recolours underlines
// to --text-primary, which reads as a stray white line under the orange trail.
const BREADCRUMB_LINK_CLASS = '[&:hover]:underline [&:hover]:underline-offset-[3px] [&:hover]:decoration-current';

const DOC_TITLE_CLASS = 'm-0 text-(--text-primary) font-sans text-[34px] leading-[42px] font-semibold tracking-[-.03em] text-balance';
const QUERY_SYNTAX_TITLE_CLASS = 'query-syntax-title m-0 text-(--text-primary) font-(family-name:--font-query) text-[32px] leading-10 font-semibold tracking-normal text-balance [font-variant-ligatures:none]';

// Lede tracks the body text size (--docs-type-size 16px / 1.75); it stays
// distinct through colour and the wider margin, not scale.
const DOC_LEDE_CLASS = 'max-w-[640px] mt-1.5 mb-[34px] mx-0 text-(--text-tertiary) font-sans text-[16px] leading-7 font-normal tracking-[-.006em] text-pretty';

// Article typography lives in ./doc-prose.css — one nested, unlayered
// stylesheet scoped under .doc-prose (see that file for why it is unlayered).
const DOC_PROSE_CLASS = 'doc-prose';

// Function and operator links render in the query face on syntax pages.
const QUERY_SYNTAX_PROSE_CLASS =
"[&_a:is([href*='/scalar-functions/'],[href*='/aggregation-functions/'],[href*='/operators/'])]:font-(family-name:--font-query) [&_a:is([href*='/scalar-functions/'],[href*='/aggregation-functions/'],[href*='/operators/'])]:[font-variant-ligatures:none] [&_a:is([href*='/scalar-functions/'],[href*='/aggregation-functions/'],[href*='/operators/'])]:tracking-normal";

export default async function DocumentationPage({ params }: PageProps) {
const { slug } = await params;
const page = source.getPage(slug);
Expand Down Expand Up @@ -58,25 +87,25 @@ export default async function DocumentationPage({ params }: PageProps) {
}),
)}
/>
<div className="article-layout">
<article className={querySyntaxTitle ? 'doc-article query-syntax-article' : 'doc-article'}>
<div className="doc-topline">
<nav className="doc-breadcrumbs" aria-label="Breadcrumb">
<div className="article-layout relative min-h-[calc(100vh_-_56px)] pt-14 pb-24 px-[clamp(32px,6vw,96px)] max-md:px-9 max-sm:pt-9 max-sm:pb-18 max-sm:px-5">
<article className={querySyntaxTitle ? `${DOC_ARTICLE_CLASS} query-syntax-article` : DOC_ARTICLE_CLASS}>
<div className="doc-topline mt-0 mx-0 mb-5 flex items-start justify-between gap-x-4 gap-y-2">
<nav className="doc-breadcrumbs m-0 flex flex-wrap gap-x-2 gap-y-1 text-(--color-accent-text) font-mono text-[12px] leading-4 font-[450]" aria-label="Breadcrumb">
{visibleBreadcrumbs.map((item, index) => {
const last = index === visibleBreadcrumbs.length - 1;
return (
<span className="doc-breadcrumb" key={`${item.title}-${index}`}>
{item.href ? <Link href={item.href} prefetch={false}>{item.title}</Link> : <span>{item.title}</span>}
{!last && <b aria-hidden="true">/</b>}
<span className="doc-breadcrumb inline-flex gap-2 min-w-0" key={`${item.title}-${index}`}>
{item.href ? <Link href={item.href} prefetch={false} className={BREADCRUMB_LINK_CLASS}>{item.title}</Link> : <span>{item.title}</span>}
{!last && <b aria-hidden="true" className="text-(--border-strong) font-normal">/</b>}
</span>
);
})}
</nav>
{!page.data.openapi && <CopyPageMenu markdownPath={`${href}.md`} />}
</div>
<DocsTitle className={querySyntaxTitle ? 'query-syntax-title' : undefined}>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<DocsTitle className={querySyntaxTitle ? QUERY_SYNTAX_TITLE_CLASS : DOC_TITLE_CLASS}>{page.data.title}</DocsTitle>
<DocsDescription className={DOC_LEDE_CLASS}>{page.data.description}</DocsDescription>
<DocsBody className={cn(DOC_PROSE_CLASS, querySyntaxTitle && QUERY_SYNTAX_PROSE_CLASS)}>
{page.data.openapi ? <ApiOperation value={page.data.openapi}><Body components={mdxComponents} /></ApiOperation> : <Body components={mdxComponents} />}
</DocsBody>
<ArticleFooter
Expand Down
Binary file added app/fonts/Berkeley_Mono_Variable.woff2
Binary file not shown.
Binary file removed app/fonts/Geist-Variable.ttf
Binary file not shown.
Binary file removed app/fonts/GeistMono-Variable.ttf
Binary file not shown.
Loading
Loading