Skip to content
Draft
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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ gp-sphinx (`gp_sphinx`) is a shared Sphinx documentation platform for Python pro

Key features:
- `merge_sphinx_config()` API for shared defaults with per-project overrides
- Shared extension list (autodoc, intersphinx, myst_parser, sphinx_design, etc.)
- Shared extension list (autodoc, intersphinx, myst_parser, sphinx_ux_*, etc.)
- Shared Furo theme configuration (CSS variables, fonts, sidebar, footer)
- Bundled workarounds (tabs.js removal, spa-nav.js injection)
- Bundled workarounds (spa-nav.js injection)
- Shared font configuration (IBM Plex via Fontsource)

## Development Environment
Expand Down
5 changes: 4 additions & 1 deletion docs/_ext/package_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ class PackageDocsRecord:
"@gp-sphinx/serene-tokens": "tokens",
"sphinx-fonts": "tokens",
"sphinx-ux-badges": "ux",
"sphinx-ux-octicons": "ux",
"sphinx-ux-grid": "ux",
"sphinx-ux-tabs": "ux",
"sphinx-ux-autodoc-layout": "ux",
"sphinx-vite-builder": "build-seo",
"sphinx-gp-opengraph": "build-seo",
Expand Down Expand Up @@ -902,7 +905,7 @@ def package_reference_markdown(package_name: str) -> str:


def maturity_badge(maturity: str) -> str:
"""Return a sphinx-design badge role for use in grid markdown output.
"""Return a badge role (MyST ``{bdg-*}`` syntax) for use in grid markdown output.

Used only in :func:`workspace_package_grid_markdown` which produces raw
MyST markdown strings. Per-page package headers use the ``gp-sphinx-package-meta``
Expand Down
245 changes: 0 additions & 245 deletions docs/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -286,251 +286,6 @@ img[src*="codecov.io"] {
line-height: 1.5;
}

/* ── Package page metadata strip ────────────────────────────
* Selects the first <p> inside the top-level section that
* contains ONLY sphinx-design badges (no non-badge children).
*
* MyST renders {bdg-*} roles as <span class="sd-badge …"> inside
* a bare <p> that is a direct child of <section>, which is a
* direct child of <article>.
*
* :has() requires CSS Level 4 (all evergreen browsers ≥ 2024).
* Falls back gracefully: badges render inline without the flex strip.
*
* Overrides `article h1 { margin-bottom: 0.75rem }` (line 38)
* via equal specificity (0,0,2) and later source order.
* ────────────────────────────────────────────────────────── */

/* Tighten h1 → badge strip gap so they read as a unit */
article > section > h1 {
margin-bottom: 0.2rem;
}

/* Convert badge-only paragraph into a flex metadata strip */
article > section > p:first-of-type:has(> .sd-badge:first-child):not(:has(*:not(.sd-badge))) {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0;
margin-bottom: 1.5rem;
padding: 0;
line-height: 1;
}

/* ── Base badge reset ────────────────────────────────────── */
.sd-badge {
display: inline-flex !important;
align-items: center;
vertical-align: middle;
font-size: 0.67rem;
font-weight: 600;
line-height: 1;
letter-spacing: 0.02em;
padding: 0.16rem 0.4rem;
border-radius: 0.22rem;
user-select: none;
-webkit-user-select: none;
}

/* ── Maturity palette ────────────────────────────────────────
* Subtle fill: Radix steps 12 (text), 11 (border), 3 (bg).
* Step-12 text passes WCAG AAA on step-3 tinted backgrounds.
* Step-11 border passes WCAG 1.4.11 (non-text contrast ≥ 3:1).
*
* !important matches sphinx-design's own !important on
* .sd-text-warning / .sd-text-success and .sd-outline-*.
* Without it, color and border-color are silently overridden.
* background-color does not need !important — sphinx-design
* does not set background on these badge variants.
* ─────────────────────────────────────────────────────────── */
:root {
--badge-alpha-color: #4e2009; /* Radix amber-12 — 11.62:1 on amber-3 (AAA) */
--badge-alpha-border: #ab6400; /* Radix amber-11 — 4.11:1 on card footer (WCAG 1.4.11 ✓) */
--badge-alpha-bg: #ffedc6; /* Radix amber-3 — opaque tint, no color-mix */

--badge-beta-color: #193b2d; /* Radix green-12 — 10.55:1 on green-3 (AAA) */
--badge-beta-border: #218358; /* Radix green-11 — 4.22:1 on card footer (WCAG 1.4.11 ✓) */
--badge-beta-bg: #ddf3e4; /* Radix green-3 */
}

/* Furo explicit dark theme */
body[data-theme="dark"] {
--badge-alpha-color: #ffca16; /* Radix amber-11 dark — 9.13:1 on #3f2700 (AAA) */
--badge-alpha-border: #8f6424; /* Radix amber-8 dark */
--badge-alpha-bg: #3f2700; /* Radix amber-3 dark */

--badge-beta-color: #3dd68c; /* Radix green-11 dark — 6.66:1 on #113b29 (AA) */
--badge-beta-border: #2f7c57; /* Radix green-8 dark */
--badge-beta-bg: #113b29; /* Radix green-3 dark */
}

/* Furo auto mode: system dark when not explicitly set to light */
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--badge-alpha-color: #ffca16;
--badge-alpha-border: #8f6424;
--badge-alpha-bg: #3f2700;
--badge-beta-color: #3dd68c;
--badge-beta-border: #2f7c57;
--badge-beta-bg: #113b29;
}
}

/* {bdg-warning-line} → .sd-badge.sd-outline-warning.sd-text-warning */
.sd-badge.sd-outline-warning {
color: var(--badge-alpha-color) !important;
border-color: var(--badge-alpha-border) !important;
background-color: var(--badge-alpha-bg);
}

/* {bdg-success-line} → .sd-badge.sd-outline-success.sd-text-success */
.sd-badge.sd-outline-success {
color: var(--badge-beta-color) !important;
border-color: var(--badge-beta-border) !important;
background-color: var(--badge-beta-bg);
}

/* ── Safety badge compatibility ─────────────────────────────
* Downstream projects like libtmux-mcp emit safety badges via
* a custom extension. Keep the docs-site copy aligned with the
* packaged theme CSS so previews match downstream builds.
* ────────────────────────────────────────────────────────── */
:root {
--gp-sphinx-fastmcp-safety-readonly-bg: #1f7a3f;
--gp-sphinx-fastmcp-safety-readonly-border: #2a8d4d;
--gp-sphinx-fastmcp-safety-readonly-text: #f3fff7;
--gp-sphinx-fastmcp-safety-mutating-bg: #b96a1a;
--gp-sphinx-fastmcp-safety-mutating-border: #cf7a23;
--gp-sphinx-fastmcp-safety-mutating-text: #fff8ef;
--gp-sphinx-fastmcp-safety-destructive-bg: #b4232c;
--gp-sphinx-fastmcp-safety-destructive-border: #cb3640;
--gp-sphinx-fastmcp-safety-destructive-text: #fff5f5;
}

h2:has(> .sd-badge[role="note"][aria-label^="Safety tier:"]),
h3:has(> .sd-badge[role="note"][aria-label^="Safety tier:"]),
h4:has(> .sd-badge[role="note"][aria-label^="Safety tier:"]) {
display: inline-flex;
align-items: center;
gap: 0.45rem;
}

.sd-badge[role="note"][aria-label^="Safety tier:"] {
gap: 0.28rem;
font-weight: 700;
letter-spacing: 0.01em;
border: 1px solid transparent;
}

.sd-badge[role="note"][aria-label^="Safety tier:"]::before {
font-style: normal;
font-weight: normal;
font-size: 1em;
line-height: 1;
flex-shrink: 0;
}

.sd-badge.sd-bg-success[role="note"][aria-label^="Safety tier:"] {
background-color: var(--gp-sphinx-fastmcp-safety-readonly-bg) !important;
color: var(--gp-sphinx-fastmcp-safety-readonly-text) !important;
border-color: var(--gp-sphinx-fastmcp-safety-readonly-border);
}

.sd-badge.sd-bg-warning[role="note"][aria-label^="Safety tier:"] {
background-color: var(--gp-sphinx-fastmcp-safety-mutating-bg) !important;
color: var(--gp-sphinx-fastmcp-safety-mutating-text) !important;
border-color: var(--gp-sphinx-fastmcp-safety-mutating-border);
}

.sd-badge.sd-bg-danger[role="note"][aria-label^="Safety tier:"] {
background-color: var(--gp-sphinx-fastmcp-safety-destructive-bg) !important;
color: var(--gp-sphinx-fastmcp-safety-destructive-text) !important;
border-color: var(--gp-sphinx-fastmcp-safety-destructive-border);
}

.sd-badge.sd-bg-success[role="note"][aria-label^="Safety tier:"]::before {
content: "🔍";
}

.sd-badge.sd-bg-warning[role="note"][aria-label^="Safety tier:"]::before {
content: "✏️";
}

.sd-badge.sd-bg-danger[role="note"][aria-label^="Safety tier:"]::before {
content: "💣";
}

h2 .sd-badge[role="note"][aria-label^="Safety tier:"],
h3 .sd-badge[role="note"][aria-label^="Safety tier:"] {
font-size: 0.68rem;
padding: 0.17rem 0.4rem;
}

p .sd-badge[role="note"][aria-label^="Safety tier:"],
li .sd-badge[role="note"][aria-label^="Safety tier:"],
td .sd-badge[role="note"][aria-label^="Safety tier:"],
a .sd-badge[role="note"][aria-label^="Safety tier:"] {
font-size: 0.62rem;
padding: 0.12rem 0.32rem;
}

code.docutils + .sd-badge[role="note"][aria-label^="Safety tier:"],
.sd-badge[role="note"][aria-label^="Safety tier:"] + code.docutils {
margin-left: 0.4em;
}

/* ── Safety badge link behavior ────────────────────────────
* Keep docs-site previews aligned with the packaged theme:
* tool links underline only the code token, not the gap or
* the attached safety badge.
* ────────────────────────────────────────────────────────── */
a.reference:has(.sd-badge[role="note"][aria-label^="Safety tier:"]) {
text-decoration: none;
}

a.reference:has(.sd-badge[role="note"][aria-label^="Safety tier:"])
.sd-badge[role="note"][aria-label^="Safety tier:"] {
text-decoration: none;
vertical-align: middle;
}

a.reference:has(.sd-badge[role="note"][aria-label^="Safety tier:"]) code {
text-decoration: none;
vertical-align: middle;
}

a.reference:has(.sd-badge[role="note"][aria-label^="Safety tier:"]):hover code {
text-decoration: underline;
}

/* Type badges (solid fills) — muted gray, scoped to metadata strip only.
* extension: {bdg-primary} → .sd-badge.sd-bg-primary
* coordinator: {bdg-success} → .sd-badge.sd-bg-success (solid fill)
* theme: {bdg-info} → .sd-badge.sd-bg-info
* .sd-bg-success and .sd-outline-success are mutually exclusive in sphinx-design. */
article > section > p:first-of-type > .sd-badge.sd-bg-primary,
article > section > p:first-of-type > .sd-badge.sd-bg-success,
article > section > p:first-of-type > .sd-badge.sd-bg-info {
font-size: 0.6rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
opacity: 0.65;
background-color: var(--color-background-border) !important;
color: var(--color-foreground-secondary) !important;
border: 1px solid var(--color-foreground-border);
}

/* Card footer badges — compact and scannable in the grid index */
.sd-card-footer .sd-badge {
font-size: 0.6rem;
font-weight: 500;
padding: 0.13rem 0.35rem;
letter-spacing: 0.03em;
text-transform: uppercase;
vertical-align: middle;
}

/* Per-package landing layout — rendered by PackageLandingDirective.
*
* The directive emits :class-container: gp-sphinx-package__landing-grid
Expand Down
13 changes: 12 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
0,
str(project_root / "packages" / "sphinx-ux-badges" / "src"),
)
sys.path.insert(
0,
str(project_root / "packages" / "sphinx-ux-octicons" / "src"),
)
sys.path.insert(
0,
str(project_root / "packages" / "sphinx-ux-grid" / "src"),
)
sys.path.insert(
0,
str(project_root / "packages" / "sphinx-ux-tabs" / "src"),
)
sys.path.insert(
0,
str(project_root / "packages" / "sphinx-autodoc-fastmcp" / "src"),
Expand Down Expand Up @@ -92,7 +104,6 @@
"package_reference",
"sab_demo",
"sab_meta",
"sphinx_ux_badges",
"sphinx_autodoc_api_style",
"sphinx_autodoc_pytest_fixtures",
"sphinx_autodoc_docutils",
Expand Down
11 changes: 7 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,15 @@ already present.
## Injected `setup(app)`

The returned config includes a `setup(app)` function from
{py:func}`gp_sphinx.config.setup`. It does two things:
{py:func}`gp_sphinx.config.setup`. It wires the runtime hooks that the
shared config depends on:

| Action | Effect |
| --- | --- |
| `app.add_js_file("js/spa-nav.js", loading_method="defer")` | Registers the bundled SPA navigation script from `sphinx-gp-theme` |
| `app.connect("build-finished", remove_tabs_js)` | Removes `_static/tabs.js` after HTML builds as a `sphinx-inline-tabs` workaround |
| `app.connect("html-page-context", _inject_copybutton_bridge)` | Exposes `copybutton_selector` as a window global for `spa-nav.js` |
| `app.connect("html-page-context", _inject_fowt_prevention)` | Injects the FOWT-prevention head snippet to suppress flash-of-wrong-theme |
| `app.add_lexer("myst", MystLexer)` / `("myst-md", MystLexer)` | Registers the MyST source-block lexer aliases |

## Always-set coordinator values

Expand All @@ -111,7 +114,7 @@ These are injected even though they are not exposed as `DEFAULT_*` constants:

| Constant | Value |
| --- | --- |
| `DEFAULT_EXTENSIONS` | `["sphinx.ext.autodoc", "sphinx_fonts", "sphinx.ext.intersphinx", "sphinx_autodoc_typehints_gp", "sphinx.ext.todo", "sphinx_inline_tabs", "sphinx_copybutton", "sphinx_gp_opengraph", "sphinx_gp_sitemap", "sphinxext.rediraffe", "sphinx_design", "myst_parser", "linkify_issues"]` |
| `DEFAULT_EXTENSIONS` | `["sphinx.ext.autodoc", "sphinx_fonts", "sphinx.ext.intersphinx", "sphinx_autodoc_typehints_gp", "sphinx.ext.todo", "sphinx_ux_tabs", "sphinx_copybutton", "sphinx_gp_opengraph", "sphinx_gp_sitemap", "sphinxext.rediraffe", "sphinx_ux_grid", "sphinx_ux_octicons", "sphinx_ux_badges", "myst_parser", "linkify_issues"]` |
| `DEFAULT_SOURCE_SUFFIX` | `{".rst": "restructuredtext", ".md": "markdown"}` |
| `DEFAULT_MYST_EXTENSIONS` | `["colon_fence", "substitution", "replacements", "strikethrough", "linkify"]` |
| `DEFAULT_MYST_HEADING_ANCHORS` | `4` |
Expand All @@ -138,7 +141,7 @@ These are injected even though they are not exposed as `DEFAULT_*` constants:

| Constant | Value |
| --- | --- |
| `DEFAULT_PYGMENTS_STYLE` | `"monokai"` |
| `DEFAULT_PYGMENTS_STYLE` | `"gp-sphinx-light"` |
| `DEFAULT_PYGMENTS_DARK_STYLE` | `"monokai"` |
| `DEFAULT_COPYBUTTON_PROMPT_TEXT` | regex matching Python, shell, and IPython prompts |
| `DEFAULT_COPYBUTTON_PROMPT_IS_REGEXP` | `True` |
Expand Down
3 changes: 3 additions & 0 deletions docs/packages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ and independently installable.
The rendering pipeline every autodoc extension consumes:

- [`sphinx-ux-badges`](sphinx-ux-badges/index.md) — badge primitives and colour palette
- [`sphinx-ux-octicons`](sphinx-ux-octicons/index.md) — curated GitHub Octicons as a Sphinx `{octicon}` role
- [`sphinx-ux-grid`](sphinx-ux-grid/index.md) — CSS-Grid `{grid}` and `{grid-item-card}` directives
- [`sphinx-ux-tabs`](sphinx-ux-tabs/index.md) — drop-in tabs replacement for sphinx-inline-tabs and sphinx-design
- [`sphinx-ux-autodoc-layout`](sphinx-ux-autodoc-layout/index.md) — structural presenter for `api-*` entry components
- [`sphinx-autodoc-typehints-gp`](sphinx-autodoc-typehints-gp/index.md) — annotation normalization and type rendering
- [`sphinx-fonts`](sphinx-fonts/index.md) — IBM Plex font preloading
Expand Down
Loading
Loading