diff --git a/src/app/[[...slug]]/page.tsx b/src/app/[[...slug]]/page.tsx index 5efba49..7f029e7 100644 --- a/src/app/[[...slug]]/page.tsx +++ b/src/app/[[...slug]]/page.tsx @@ -33,7 +33,7 @@ export default async function Page(props: PageProps<"/[[...slug]]">) { return ( {page.data.title} - + {page.data.description}
diff --git a/src/app/global.css b/src/app/global.css index 79d1558..3ebd230 100644 --- a/src/app/global.css +++ b/src/app/global.css @@ -72,6 +72,41 @@ } } +/* ── Body copy ── */ + +/* Fumadocs sets prose body text to `--color-fd-foreground` at 90%, and renders + the page description (DocsDescription, the standfirst under the H1) muted. + We want the reverse: the standfirst leads at full contrast, and the body + copy sits back. Only `--tw-prose-body` moves — headings, links, bold, code, + quotes and captions keep their own variables, so they stay prominent + against the softer paragraph text. + + Both values are theme tokens, so light and dark follow the same rule with + no per-mode override. The description's colour is set at the call site in + the two page routes. + + Deliberately unlayered. Fumadocs declares `.prose` in `@layer utilities`, + and layer order beats both specificity and source order — the same rule + inside `@layer components` below is silently ignored. Unlayered + declarations outrank every layer, so this wins without `!important`. */ +.prose { + --tw-prose-body: var(--color-fd-muted-foreground); +} + +/* Callout body sits one step above the muted paragraphs around it: the colour + prose body copy had before the rule above. A callout is already set apart by + its card background, border, accent bar and icon; matching the body copy + exactly made it read flat, and full foreground read as shouting. + + Fumadocs puts `text-fd-muted-foreground` directly on the description div, so + inheritance can't reach it — this has to select the element. `data-callout` + is ours (see mdx-components.tsx); `prose-no-margin` is what Fumadocs marks + the description's prose block with. Unlayered for the same reason as the + rule above: the utility class it overrides lives in `@layer utilities`. */ +[data-callout] .prose-no-margin { + color: color-mix(in oklab, var(--color-fd-foreground) 90%, transparent); +} + /* ── Fumadocs component overrides ── */ @layer components { diff --git a/src/app/stack/[[...slug]]/page.tsx b/src/app/stack/[[...slug]]/page.tsx index ef050ee..992bf75 100644 --- a/src/app/stack/[[...slug]]/page.tsx +++ b/src/app/stack/[[...slug]]/page.tsx @@ -22,7 +22,7 @@ export default async function Page(props: PageProps<"/stack/[[...slug]]">) { return ( {page.data.title} - + {page.data.description}
diff --git a/src/mdx-components.tsx b/src/mdx-components.tsx index 57411a1..e8b9bd4 100644 --- a/src/mdx-components.tsx +++ b/src/mdx-components.tsx @@ -1,13 +1,42 @@ -import { Callout } from "fumadocs-ui/components/callout"; +import { Callout as FumaCallout } from "fumadocs-ui/components/callout"; import { Step, Steps } from "fumadocs-ui/components/steps"; import defaultMdxComponents from "fumadocs-ui/mdx"; import type { MDXComponents } from "mdx/types"; +import type { ComponentProps } from "react"; import { BadExample } from "@/components/bad-example"; import { TrackedCodeBlock } from "@/components/code-block"; import { EqlFn } from "@/components/eql-fn"; import { EqlVersion } from "@/components/eql-version"; import { ZeroKmsRegions } from "@/components/zerokms-regions"; +/** + * Callouts keep Fumadocs' own body colour — `text-fd-muted-foreground`, the + * same token the sidebar's resting nav items use — so they sit at the same + * weight as the rest of the chrome rather than shouting. This wrapper only: + * + * - doubles the padding, `p-3 ps-1` → `p-6 ps-2`. `ps` stays proportionally + * small because the accent bar is the container's first child and sits + * near the edge; + * - adds a `data-callout` attribute, which Fumadocs does not emit. global.css + * has had a `[data-callout]` rule since the theme work that consequently + * matched nothing. + * + * Fumadocs' `Callout` still resolves the `warn`/`tip` aliases, picks the icon + * and renders the title, and it spreads unknown props onto the container, so + * there is nothing here to reimplement. + */ +function Callout({ className, ...props }: ComponentProps) { + // CalloutContainer runs its own `cn`, so these merge against its defaults; + // a caller's className comes last and still wins. + return ( + + ); +} + export function getMDXComponents(components?: MDXComponents): MDXComponents { return { ...defaultMdxComponents,