From f577cee93cc847e5d2f8885cddeed196d2ddd4cd Mon Sep 17 00:00:00 2001 From: Charles Howard <96023061+charlesrhoward@users.noreply.github.com> Date: Mon, 18 May 2026 15:37:38 -0400 Subject: [PATCH 1/3] Refine docs dark theme contrast --- src/app/global.css | 266 +++++++++++++++++++++++++++--- src/components/theme-switcher.tsx | 2 +- src/lib/layout.shared.tsx | 2 +- 3 files changed, 243 insertions(+), 27 deletions(-) diff --git a/src/app/global.css b/src/app/global.css index b558e4f..14d374f 100644 --- a/src/app/global.css +++ b/src/app/global.css @@ -2,38 +2,56 @@ @import 'fumadocs-ui/css/neutral.css'; @import 'fumadocs-ui/css/preset.css'; -/* Mogplex brand colors — monochrome theme, aligned with mogplex.com */ +/* Mogplex docs theme: quiet dark technical reference surface. */ :root { --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); - /* Light mode tokens — warm cream surface, neutral ink */ - --color-fd-background: #f6f5f1; - --color-fd-foreground: #171717; - --color-fd-card: #ffffff; - --color-fd-muted: #efede7; - --color-fd-muted-foreground: #78716c; - --color-fd-primary: #171717; - --color-fd-primary-foreground: #fafaf9; - --color-fd-accent: #ebe7dd; - --color-fd-accent-foreground: #171717; - --color-fd-border: #ddd7ca; - --color-fd-ring: #171717; + --bg-canvas: #0a0a0c; + --bg-surface: #111114; + --bg-sidebar: #0d0d10; + --bg-elevated: #16161a; + + --border-subtle: rgba(255, 255, 255, 0.05); + --border-default: rgba(255, 255, 255, 0.08); + --border-strong: rgba(255, 255, 255, 0.12); + + --text-primary: rgba(255, 255, 255, 0.92); + --text-body: rgba(255, 255, 255, 0.74); + --text-secondary: rgba(255, 255, 255, 0.55); + --text-tertiary: rgba(255, 255, 255, 0.38); + + --accent: #af71d2; + --accent-soft: rgba(175, 113, 210, 0.12); + --accent-underline: rgba(175, 113, 210, 0.4); } +:root, +.light, .dark { - /* Dark mode tokens — pure black surface, white ink */ - --color-fd-background: #0a0a0a; - --color-fd-foreground: #ededed; - --color-fd-card: #111111; - --color-fd-muted: #1a1a1a; - --color-fd-muted-foreground: #a1a1a1; - --color-fd-primary: #ffffff; - --color-fd-primary-foreground: #0a0a0a; - --color-fd-accent: #1e1e1e; - --color-fd-accent-foreground: #ededed; - --color-fd-border: #262626; - --color-fd-ring: #ffffff; + --color-fd-background: var(--bg-surface); + --color-fd-foreground: var(--text-body); + --color-fd-card: var(--bg-elevated); + --color-fd-card-foreground: var(--text-body); + --color-fd-muted: var(--bg-elevated); + --color-fd-muted-foreground: var(--text-secondary); + --color-fd-popover: var(--bg-elevated); + --color-fd-popover-foreground: var(--text-body); + --color-fd-primary: var(--accent); + --color-fd-primary-foreground: var(--text-primary); + --color-fd-secondary: var(--bg-elevated); + --color-fd-secondary-foreground: var(--text-body); + --color-fd-accent: var(--accent-soft); + --color-fd-accent-foreground: var(--text-primary); + --color-fd-border: var(--border-default); + --color-fd-ring: var(--border-strong); + --color-fd-overlay: rgba(0, 0, 0, 0.62); +} + +html, +body { + background: var(--bg-canvas); + color: var(--text-body); } html { @@ -45,6 +63,204 @@ html > body[data-scroll-locked] { --removed-body-scroll-bar-size: 0px !important; } +#nd-docs-layout { + position: relative; + z-index: 1; + background-color: var(--bg-canvas); + background-image: + linear-gradient(var(--border-subtle) 1px, transparent 1px), + linear-gradient(90deg, var(--border-subtle) 1px, transparent 1px); + background-size: 40px 40px; + color: var(--text-body); +} + +#nd-page { + min-height: 100dvh; + background: var(--bg-surface); + border-inline: 1px solid var(--border-subtle); + color: var(--text-body); +} + +#nd-page h1, +#nd-page h2, +#nd-page h3, +#nd-page h4, +#nd-page h5, +#nd-page h6 { + color: var(--text-primary); +} + +#nd-page > p { + color: var(--text-body); +} + +#nd-page > .border-b { + border-color: var(--border-subtle); +} + +#nd-sidebar, +#nd-sidebar-mobile { + background: var(--bg-sidebar) !important; + border-color: var(--border-default) !important; + color: var(--text-secondary); +} + +#nd-sidebar a, +#nd-sidebar button, +#nd-sidebar p, +#nd-sidebar-mobile a, +#nd-sidebar-mobile button, +#nd-sidebar-mobile p { + color: var(--text-secondary); +} + +#nd-sidebar a:not([data-active='true']):hover, +#nd-sidebar button:hover, +#nd-sidebar-mobile a:not([data-active='true']):hover, +#nd-sidebar-mobile button:hover { + background: rgba(255, 255, 255, 0.04); + color: var(--text-body); +} + +#nd-sidebar a[data-active='true'], +#nd-sidebar-mobile a[data-active='true'] { + background: var(--accent-soft) !important; + color: var(--text-primary) !important; +} + +#nd-sidebar a[data-active='true']::before, +#nd-sidebar-mobile a[data-active='true']::before { + display: none !important; +} + +#nd-sidebar a[data-active='true']::after, +#nd-sidebar-mobile a[data-active='true']::after { + content: ''; + position: absolute; + inset-block: 0.625rem; + inset-inline-start: 0; + width: 2px; + border-radius: 999px; + background: var(--accent); +} + +#nd-toc { + color: var(--text-tertiary); +} + +#nd-toc #toc-title, +#nd-toc a { + color: var(--text-tertiary) !important; +} + +#nd-toc a:hover { + color: var(--text-secondary) !important; +} + +#nd-toc a[data-active='true'] { + color: var(--text-primary) !important; +} + +#nd-toc [class*='border-fd-foreground'] { + border-color: var(--border-subtle) !important; +} + +#nd-page .prose { + --tw-prose-body: var(--text-body); + --tw-prose-headings: var(--text-primary); + --tw-prose-lead: var(--text-body); + --tw-prose-links: var(--text-body); + --tw-prose-bold: var(--text-primary); + --tw-prose-counters: var(--text-secondary); + --tw-prose-bullets: var(--text-secondary); + --tw-prose-hr: var(--border-subtle); + --tw-prose-quotes: var(--text-body); + --tw-prose-quote-borders: var(--border-default); + --tw-prose-captions: var(--text-secondary); + --tw-prose-code: var(--text-primary); + --tw-prose-th-borders: var(--border-subtle); + --tw-prose-td-borders: var(--border-subtle); + --tw-prose-kbd: var(--text-primary); +} + +#nd-page .prose :where(h1, h2, h3, h4, h5, h6, strong):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + color: var(--text-primary); +} + +#nd-page .prose :where(p, li):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + color: var(--text-body); +} + +#nd-page .prose :where(a:not([data-card])):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + color: var(--text-body); + text-decoration-color: var(--accent-underline); + text-decoration-thickness: 1px; + opacity: 1; +} + +#nd-page .prose :where(a:not([data-card]):hover):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + color: var(--accent); + opacity: 1; +} + +#nd-page .prose :where(table):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + background: var(--bg-elevated); + border-color: var(--border-subtle); +} + +#nd-page .prose :where(th):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + background: var(--bg-elevated); + border-color: var(--border-subtle); + color: var(--text-secondary); +} + +#nd-page .prose :where(td):not( + :where([class~='not-prose'], [class~='not-prose'] *) + ) { + border-color: var(--border-subtle); + color: var(--text-secondary); +} + +#nd-page .prose :where(code):not( + :where(pre code, [class~='not-prose'], [class~='not-prose'] *) + ) { + border: 1px solid var(--border-subtle); + border-radius: 0.25rem; + background: var(--bg-elevated); + padding: 0.125em 0.35em; + color: var(--text-primary); +} + +#nd-page figure.shiki, +#nd-page [data-card='true'], +#nd-page table, +#nd-page [role='alert'] { + background-color: var(--bg-elevated); + border-color: var(--border-default); +} + +#nd-page [data-card='true'] { + border-radius: 0.5rem; +} + +#nd-docs-layout .shadow-sm, +#nd-docs-layout .shadow-md, +#nd-docs-layout .shadow-lg { + box-shadow: none !important; +} + @media (min-width: 768px) { #nd-docs-layout { --fd-sidebar-width: 270px; diff --git a/src/components/theme-switcher.tsx b/src/components/theme-switcher.tsx index 9bece12..9e637b4 100644 --- a/src/components/theme-switcher.tsx +++ b/src/components/theme-switcher.tsx @@ -59,7 +59,7 @@ export function ThemeSwitcher(): React.JSX.Element { aria-label="Theme selection" > + Date: Mon, 18 May 2026 15:53:15 -0400 Subject: [PATCH 2/3] Address docs theme review feedback --- src/app/global.css | 43 +++++++++++++++++++++++++++------------ src/lib/layout.shared.tsx | 2 +- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/app/global.css b/src/app/global.css index 14d374f..963d4b0 100644 --- a/src/app/global.css +++ b/src/app/global.css @@ -7,10 +7,11 @@ --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); - --bg-canvas: #0a0a0c; - --bg-surface: #111114; - --bg-sidebar: #0d0d10; + --bg-canvas: hsl(0 0% 2%); + --bg-surface: hsl(0 0% 2%); + --bg-sidebar: hsl(0 0% 8%); --bg-elevated: #16161a; + --bg-hover: rgba(255, 255, 255, 0.04); --border-subtle: rgba(255, 255, 255, 0.05); --border-default: rgba(255, 255, 255, 0.08); @@ -19,13 +20,36 @@ --text-primary: rgba(255, 255, 255, 0.92); --text-body: rgba(255, 255, 255, 0.74); --text-secondary: rgba(255, 255, 255, 0.55); - --text-tertiary: rgba(255, 255, 255, 0.38); + --text-tertiary: rgba(255, 255, 255, 0.5); + --text-logo: rgba(255, 255, 255, 0.96); --accent: #af71d2; --accent-soft: rgba(175, 113, 210, 0.12); --accent-underline: rgba(175, 113, 210, 0.4); } +.light { + --bg-canvas: #f6f5f1; + --bg-surface: #ffffff; + --bg-sidebar: #efede7; + --bg-elevated: #faf9f5; + --bg-hover: rgba(23, 23, 23, 0.05); + + --border-subtle: rgba(23, 23, 23, 0.08); + --border-default: rgba(23, 23, 23, 0.12); + --border-strong: rgba(23, 23, 23, 0.18); + + --text-primary: rgba(23, 23, 23, 0.92); + --text-body: rgba(23, 23, 23, 0.78); + --text-secondary: rgba(23, 23, 23, 0.7); + --text-tertiary: rgba(23, 23, 23, 0.64); + --text-logo: rgba(23, 23, 23, 0.96); + + --accent: #7d3fa2; + --accent-soft: rgba(125, 63, 162, 0.11); + --accent-underline: rgba(125, 63, 162, 0.42); +} + :root, .light, .dark { @@ -67,10 +91,6 @@ html > body[data-scroll-locked] { position: relative; z-index: 1; background-color: var(--bg-canvas); - background-image: - linear-gradient(var(--border-subtle) 1px, transparent 1px), - linear-gradient(90deg, var(--border-subtle) 1px, transparent 1px); - background-size: 40px 40px; color: var(--text-body); } @@ -90,10 +110,6 @@ html > body[data-scroll-locked] { color: var(--text-primary); } -#nd-page > p { - color: var(--text-body); -} - #nd-page > .border-b { border-color: var(--border-subtle); } @@ -118,12 +134,13 @@ html > body[data-scroll-locked] { #nd-sidebar button:hover, #nd-sidebar-mobile a:not([data-active='true']):hover, #nd-sidebar-mobile button:hover { - background: rgba(255, 255, 255, 0.04); + background: var(--bg-hover); color: var(--text-body); } #nd-sidebar a[data-active='true'], #nd-sidebar-mobile a[data-active='true'] { + position: relative; background: var(--accent-soft) !important; color: var(--text-primary) !important; } diff --git a/src/lib/layout.shared.tsx b/src/lib/layout.shared.tsx index ff5dcf8..c8ef1d7 100644 --- a/src/lib/layout.shared.tsx +++ b/src/lib/layout.shared.tsx @@ -5,7 +5,7 @@ export function baseOptions(): BaseLayoutProps { return { nav: { title: ( - + Date: Mon, 18 May 2026 16:29:52 -0400 Subject: [PATCH 3/3] Add agent-friendly markdown URLs and address PR review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump --text-secondary 0.55 → 0.62 to clear WCAG AA on sidebar - Add --bg-overlay token so the Fumadocs overlay is themeable - Move Copy Markdown + View Options into the TOC footer - Expose /.md (and /index.md) via rewrite for agent curl access - Emit for auto-discovery --- next.config.mjs | 7 ++++++ src/app/(docs)/[[...slug]]/page.tsx | 33 ++++++++++++++++++----------- src/app/global.css | 6 ++++-- src/lib/source.ts | 9 ++++---- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/next.config.mjs b/next.config.mjs index bbd0688..3caadd9 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -14,6 +14,13 @@ const config = { turbopack: { root: __dirname, }, + async rewrites() { + // Agent-friendly: `curl https://docs/.md` returns raw markdown. + return [ + { source: '/index.md', destination: '/llms.mdx/docs/content.md' }, + { source: '/:path*.md', destination: '/llms.mdx/docs/:path*/content.md' }, + ]; + }, }; export default withMDX(config); diff --git a/src/app/(docs)/[[...slug]]/page.tsx b/src/app/(docs)/[[...slug]]/page.tsx index 9c5482c..9eec9ab 100644 --- a/src/app/(docs)/[[...slug]]/page.tsx +++ b/src/app/(docs)/[[...slug]]/page.tsx @@ -22,17 +22,23 @@ export default async function Page(props: PageProps<'/[[...slug]]'>) { const MDX = page.data.body; const markdownUrl = getPageMarkdownUrl(page).url; + const githubUrl = `https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`; + return ( - + + + + + ), + }} + > {page.data.title} - {page.data.description} -
- - -
+ {page.data.description} ) { })} /> - + ); } @@ -60,6 +64,11 @@ export async function generateMetadata(props: PageProps<'/[[...slug]]'>): Promis return { title: page.data.title, description: page.data.description, + alternates: { + types: { + 'text/markdown': getPageMarkdownUrl(page).url, + }, + }, openGraph: { images: getPageImage(page).url, }, diff --git a/src/app/global.css b/src/app/global.css index 963d4b0..5c5b8bb 100644 --- a/src/app/global.css +++ b/src/app/global.css @@ -12,6 +12,7 @@ --bg-sidebar: hsl(0 0% 8%); --bg-elevated: #16161a; --bg-hover: rgba(255, 255, 255, 0.04); + --bg-overlay: rgba(0, 0, 0, 0.62); --border-subtle: rgba(255, 255, 255, 0.05); --border-default: rgba(255, 255, 255, 0.08); @@ -19,7 +20,7 @@ --text-primary: rgba(255, 255, 255, 0.92); --text-body: rgba(255, 255, 255, 0.74); - --text-secondary: rgba(255, 255, 255, 0.55); + --text-secondary: rgba(255, 255, 255, 0.62); --text-tertiary: rgba(255, 255, 255, 0.5); --text-logo: rgba(255, 255, 255, 0.96); @@ -34,6 +35,7 @@ --bg-sidebar: #efede7; --bg-elevated: #faf9f5; --bg-hover: rgba(23, 23, 23, 0.05); + --bg-overlay: rgba(23, 23, 23, 0.4); --border-subtle: rgba(23, 23, 23, 0.08); --border-default: rgba(23, 23, 23, 0.12); @@ -69,7 +71,7 @@ --color-fd-accent-foreground: var(--text-primary); --color-fd-border: var(--border-default); --color-fd-ring: var(--border-strong); - --color-fd-overlay: rgba(0, 0, 0, 0.62); + --color-fd-overlay: var(--bg-overlay); } html, diff --git a/src/lib/source.ts b/src/lib/source.ts index 46262ae..582e8da 100644 --- a/src/lib/source.ts +++ b/src/lib/source.ts @@ -20,12 +20,13 @@ export function getPageImage(page: InferPageType) { } export function getPageMarkdownUrl(page: InferPageType) { + // Static route still pre-renders at /llms.mdx/docs//content.md. const segments = [...page.slugs, 'content.md']; - return { - segments, - url: `${docsContentRoute}/${segments.join('/')}`, - }; + // Agent-friendly URL (via next.config rewrite): /.md or /index.md for root. + const url = page.slugs.length === 0 ? '/index.md' : `/${page.slugs.join('/')}.md`; + + return { segments, url }; } export async function getLLMText(page: InferPageType) {