brainx-sphinx-header 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brainx_sphinx_header-0.1.0/PKG-INFO +73 -0
- brainx_sphinx_header-0.1.0/README.md +56 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header/__init__.py +238 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header.egg-info/PKG-INFO +73 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header.egg-info/SOURCES.txt +8 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header.egg-info/dependency_links.txt +1 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header.egg-info/requires.txt +1 -0
- brainx_sphinx_header-0.1.0/brainx_sphinx_header.egg-info/top_level.txt +1 -0
- brainx_sphinx_header-0.1.0/pyproject.toml +27 -0
- brainx_sphinx_header-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brainx-sphinx-header
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sphinx extension that injects the canonical BrainX brand header into any docs site, fetched live from brainx.chaobrain.com.
|
|
5
|
+
Author: BrainX Developers
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://brainx.chaobrain.com/
|
|
8
|
+
Project-URL: Source, https://github.com/chaobrain/brainx.chaobrain.com/tree/main/sphinx-ext
|
|
9
|
+
Keywords: sphinx,extension,brainx,documentation,header
|
|
10
|
+
Classifier: Framework :: Sphinx :: Extension
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Documentation :: Sphinx
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: sphinx>=4
|
|
17
|
+
|
|
18
|
+
# brainx-sphinx-header
|
|
19
|
+
|
|
20
|
+
Sphinx extension that injects the canonical [BrainX](https://brainx.chaobrain.com/) brand header into any docs site, fetched live from the landing site so every package's docs stays in visual sync.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install brainx-sphinx-header
|
|
26
|
+
# or, before publishing:
|
|
27
|
+
pip install "git+https://github.com/chaobrain/brainx.chaobrain.com.git#subdirectory=sphinx-ext"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Use
|
|
31
|
+
|
|
32
|
+
In your `docs/conf.py`:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
extensions = [
|
|
36
|
+
# ...
|
|
37
|
+
"brainx_sphinx_header",
|
|
38
|
+
]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
That's it. On the next build, the BrainX header is fetched from `https://brainx.chaobrain.com/shared-header`, cached at `<docs>/_brand/`, and emitted as `_static/css/brainx-header.css` + `_static/js/brainx-header.js`.
|
|
42
|
+
|
|
43
|
+
## Configuration (optional)
|
|
44
|
+
|
|
45
|
+
All settings have sensible defaults. Override in `conf.py` only if you need to.
|
|
46
|
+
|
|
47
|
+
| Setting | Default | Purpose |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `brainx_header_url` | `"https://brainx.chaobrain.com/shared-header"` | Where to fetch the canonical header |
|
|
50
|
+
| `brainx_header_ttl` | `3600` | Cache TTL in seconds |
|
|
51
|
+
| `brainx_header_offline` | `False` | Use cache only, never fetch |
|
|
52
|
+
| `brainx_header_local` | `None` | Path to a local shared-header dir for live preview |
|
|
53
|
+
|
|
54
|
+
Each setting also honors an environment variable (`BRAINX_HEADER_URL`, `BRAINX_HEADER_TTL`, `BRAINX_HEADER_OFFLINE=1`, `BRAINX_HEADER_LOCAL`) which takes precedence — handy for CI.
|
|
55
|
+
|
|
56
|
+
## What it does
|
|
57
|
+
|
|
58
|
+
- Fetches `header.html` and `header.css` from the BrainX landing site (with TTL cache + stale fallback).
|
|
59
|
+
- Emits them as Sphinx static assets and registers them via `add_css_file` / `add_js_file`.
|
|
60
|
+
- Appends CSS overrides that hide `sphinx_book_theme` / `pydata_sphinx_theme` native top bars (`header.bd-header`, `.bd-header-article`, `.header-article-items.header-article__inner`).
|
|
61
|
+
- Wires the BrainX header's burger and theme button to the theme's hidden originals (`.primary-toggle`, `.theme-switch-button`) so sidebar toggle and theme cycling keep working — no template overrides needed.
|
|
62
|
+
|
|
63
|
+
## Local development
|
|
64
|
+
|
|
65
|
+
To preview a header change against your local landing-site build before pushing:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
BRAINX_HEADER_LOCAL=/path/to/brainx.chaobrain.com/dist/shared-header sphinx-build -b html docs docs/_build/html
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Supported themes
|
|
72
|
+
|
|
73
|
+
`sphinx_book_theme`, `pydata_sphinx_theme` (the `bd-*` selector family). Other themes will still render the BrainX header but without button delegation; their native header is unaffected.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# brainx-sphinx-header
|
|
2
|
+
|
|
3
|
+
Sphinx extension that injects the canonical [BrainX](https://brainx.chaobrain.com/) brand header into any docs site, fetched live from the landing site so every package's docs stays in visual sync.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install brainx-sphinx-header
|
|
9
|
+
# or, before publishing:
|
|
10
|
+
pip install "git+https://github.com/chaobrain/brainx.chaobrain.com.git#subdirectory=sphinx-ext"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
In your `docs/conf.py`:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
extensions = [
|
|
19
|
+
# ...
|
|
20
|
+
"brainx_sphinx_header",
|
|
21
|
+
]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That's it. On the next build, the BrainX header is fetched from `https://brainx.chaobrain.com/shared-header`, cached at `<docs>/_brand/`, and emitted as `_static/css/brainx-header.css` + `_static/js/brainx-header.js`.
|
|
25
|
+
|
|
26
|
+
## Configuration (optional)
|
|
27
|
+
|
|
28
|
+
All settings have sensible defaults. Override in `conf.py` only if you need to.
|
|
29
|
+
|
|
30
|
+
| Setting | Default | Purpose |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `brainx_header_url` | `"https://brainx.chaobrain.com/shared-header"` | Where to fetch the canonical header |
|
|
33
|
+
| `brainx_header_ttl` | `3600` | Cache TTL in seconds |
|
|
34
|
+
| `brainx_header_offline` | `False` | Use cache only, never fetch |
|
|
35
|
+
| `brainx_header_local` | `None` | Path to a local shared-header dir for live preview |
|
|
36
|
+
|
|
37
|
+
Each setting also honors an environment variable (`BRAINX_HEADER_URL`, `BRAINX_HEADER_TTL`, `BRAINX_HEADER_OFFLINE=1`, `BRAINX_HEADER_LOCAL`) which takes precedence — handy for CI.
|
|
38
|
+
|
|
39
|
+
## What it does
|
|
40
|
+
|
|
41
|
+
- Fetches `header.html` and `header.css` from the BrainX landing site (with TTL cache + stale fallback).
|
|
42
|
+
- Emits them as Sphinx static assets and registers them via `add_css_file` / `add_js_file`.
|
|
43
|
+
- Appends CSS overrides that hide `sphinx_book_theme` / `pydata_sphinx_theme` native top bars (`header.bd-header`, `.bd-header-article`, `.header-article-items.header-article__inner`).
|
|
44
|
+
- Wires the BrainX header's burger and theme button to the theme's hidden originals (`.primary-toggle`, `.theme-switch-button`) so sidebar toggle and theme cycling keep working — no template overrides needed.
|
|
45
|
+
|
|
46
|
+
## Local development
|
|
47
|
+
|
|
48
|
+
To preview a header change against your local landing-site build before pushing:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
BRAINX_HEADER_LOCAL=/path/to/brainx.chaobrain.com/dist/shared-header sphinx-build -b html docs docs/_build/html
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Supported themes
|
|
55
|
+
|
|
56
|
+
`sphinx_book_theme`, `pydata_sphinx_theme` (the `bd-*` selector family). Other themes will still render the BrainX header but without button delegation; their native header is unaffected.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""Inject the canonical BrainX brand header into a Sphinx docs site.
|
|
2
|
+
|
|
3
|
+
The header is fetched live from https://brainx.chaobrain.com/shared-header so
|
|
4
|
+
every package's docs stay in sync with the landing site without copy-paste.
|
|
5
|
+
|
|
6
|
+
Usage in conf.py
|
|
7
|
+
----------------
|
|
8
|
+
|
|
9
|
+
extensions = [
|
|
10
|
+
...,
|
|
11
|
+
"brainx_sphinx_header",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
Optional configuration (all have sensible defaults):
|
|
15
|
+
|
|
16
|
+
brainx_header_url = "https://brainx.chaobrain.com/shared-header"
|
|
17
|
+
brainx_header_ttl = 3600 # cache TTL in seconds
|
|
18
|
+
brainx_header_offline = False # use cache only, never fetch
|
|
19
|
+
brainx_header_local = None # str path to a local shared-header dir
|
|
20
|
+
# (e.g. ".../brainx.chaobrain.com/dist/shared-header")
|
|
21
|
+
# for live-preview against an unpushed change
|
|
22
|
+
|
|
23
|
+
Environment variable overrides (handy in CI):
|
|
24
|
+
|
|
25
|
+
BRAINX_HEADER_URL, BRAINX_HEADER_TTL, BRAINX_HEADER_OFFLINE=1, BRAINX_HEADER_LOCAL
|
|
26
|
+
|
|
27
|
+
What this extension does
|
|
28
|
+
------------------------
|
|
29
|
+
|
|
30
|
+
1. On ``builder-inited``, fetches header.html + header.css from the BrainX
|
|
31
|
+
landing site (with TTL cache at ``<confdir>/_brand/``).
|
|
32
|
+
2. Writes them to ``_static/css/brainx-header.css`` and
|
|
33
|
+
``_static/js/brainx-header.js`` (the JS embeds the HTML and prepends it to
|
|
34
|
+
``<body>`` on DOM ready).
|
|
35
|
+
3. Registers both files via ``add_css_file`` / ``add_js_file``.
|
|
36
|
+
4. The CSS appends overrides that hide ``sphinx_book_theme`` /
|
|
37
|
+
``pydata_sphinx_theme`` top bars (``header.bd-header``,
|
|
38
|
+
``.bd-header-article``, ``.header-article-items.header-article__inner``) so
|
|
39
|
+
the BrainX header is the only one visible.
|
|
40
|
+
5. The JS rewires the BrainX header's burger and theme-toggle buttons to the
|
|
41
|
+
theme's hidden originals (``.primary-toggle`` and ``.theme-switch-button``)
|
|
42
|
+
via capture-phase ``stopImmediatePropagation``, so sidebar toggle and
|
|
43
|
+
theme-cycle keep working without touching theme templates.
|
|
44
|
+
|
|
45
|
+
Supported themes: ``sphinx_book_theme``, ``pydata_sphinx_theme`` (the
|
|
46
|
+
``bd-*`` family). Other themes will still show the BrainX header but won't get
|
|
47
|
+
button delegation; functionality of the theme's own header is unaffected.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
from __future__ import annotations
|
|
51
|
+
|
|
52
|
+
import json
|
|
53
|
+
import os
|
|
54
|
+
import time
|
|
55
|
+
from pathlib import Path
|
|
56
|
+
from urllib.request import Request, urlopen
|
|
57
|
+
|
|
58
|
+
from sphinx.application import Sphinx
|
|
59
|
+
|
|
60
|
+
__version__ = "0.1.0"
|
|
61
|
+
|
|
62
|
+
DEFAULT_BASE = "https://brainx.chaobrain.com/shared-header"
|
|
63
|
+
DEFAULT_TTL = 3600
|
|
64
|
+
ARTIFACT_CSS = "css/brainx-header.css"
|
|
65
|
+
ARTIFACT_JS = "js/brainx-header.js"
|
|
66
|
+
CACHE_DIR_NAME = "_brand"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------------------------
|
|
70
|
+
# fetch / cache
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
def _fetch(url: str, timeout: int = 10) -> str:
|
|
74
|
+
req = Request(url, headers={"User-Agent": "brainx-sphinx-header"})
|
|
75
|
+
with urlopen(req, timeout=timeout) as r:
|
|
76
|
+
return r.read().decode("utf-8")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
_ASSETS = ("header.html", "header.css", "header.js")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _read_local(local_dir: Path) -> dict:
|
|
83
|
+
return {name: (local_dir / name).read_text(encoding="utf-8") for name in _ASSETS}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _load_with_cache(base_url: str, cache_dir: Path, ttl: int, offline: bool) -> dict:
|
|
87
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
88
|
+
paths = {name: cache_dir / name for name in _ASSETS}
|
|
89
|
+
meta_path = cache_dir / "meta.json"
|
|
90
|
+
|
|
91
|
+
fresh = False
|
|
92
|
+
if meta_path.exists() and all(p.exists() for p in paths.values()):
|
|
93
|
+
try:
|
|
94
|
+
meta = json.loads(meta_path.read_text())
|
|
95
|
+
fresh = (time.time() - meta.get("ts", 0)) < ttl
|
|
96
|
+
except Exception:
|
|
97
|
+
fresh = False
|
|
98
|
+
|
|
99
|
+
if not fresh and not offline:
|
|
100
|
+
try:
|
|
101
|
+
fetched = {name: _fetch(f"{base_url}/{name}") for name in _ASSETS}
|
|
102
|
+
for name, content in fetched.items():
|
|
103
|
+
paths[name].write_text(content, encoding="utf-8")
|
|
104
|
+
meta_path.write_text(json.dumps({"ts": time.time(), "src": base_url}))
|
|
105
|
+
return fetched
|
|
106
|
+
except Exception as e:
|
|
107
|
+
if not all(p.exists() for p in paths.values()):
|
|
108
|
+
raise RuntimeError(
|
|
109
|
+
f"[brainx-sphinx-header] fetch failed for {base_url} "
|
|
110
|
+
f"and no complete cache exists: {e}"
|
|
111
|
+
) from e
|
|
112
|
+
print(f"[brainx-sphinx-header] fetch failed ({e}); using stale cache at {cache_dir}")
|
|
113
|
+
|
|
114
|
+
if not all(p.exists() for p in paths.values()):
|
|
115
|
+
raise RuntimeError(
|
|
116
|
+
f"[brainx-sphinx-header] offline=True but cache at {cache_dir} is incomplete. "
|
|
117
|
+
f"Run once online first."
|
|
118
|
+
)
|
|
119
|
+
return {name: paths[name].read_text(encoding="utf-8") for name in _ASSETS}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
# artifact emission (CSS + JS)
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
_THEME_OVERRIDES = """
|
|
127
|
+
|
|
128
|
+
/* --- brainx-sphinx-header docs-site overrides --- */
|
|
129
|
+
/* Hide pydata_sphinx_theme / sphinx_book_theme native top bars. The
|
|
130
|
+
BrainX header replaces them visually; their functional buttons remain
|
|
131
|
+
in the DOM (display: none) so the JS below can still click them. */
|
|
132
|
+
header.bd-header,
|
|
133
|
+
.bd-header-article,
|
|
134
|
+
.header-article-items.header-article__inner {
|
|
135
|
+
display: none !important;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
body {
|
|
139
|
+
padding-top: 0 !important;
|
|
140
|
+
}
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _build_js(html_payload: str, behavior_js: str, source_label: str) -> str:
|
|
145
|
+
"""Return the bundle the docs site loads.
|
|
146
|
+
|
|
147
|
+
Bundle = injection preamble + canonical header.js. The preamble prepends
|
|
148
|
+
the markup to <body> on DOM ready (Astro doesn't need this — it SSRs the
|
|
149
|
+
markup). All actual behavior (theme, burger, sphinx delegation) lives in
|
|
150
|
+
`behavior_js`, fetched verbatim from shared-header/header.js so every host
|
|
151
|
+
converges on the same logic.
|
|
152
|
+
"""
|
|
153
|
+
payload = json.dumps(html_payload)
|
|
154
|
+
preamble = f"""// Auto-generated by brainx-sphinx-header from {source_label}
|
|
155
|
+
(function () {{
|
|
156
|
+
var HTML = {payload};
|
|
157
|
+
function inject() {{
|
|
158
|
+
if (document.querySelector('[data-bx-header]')) return;
|
|
159
|
+
var holder = document.createElement('div');
|
|
160
|
+
holder.innerHTML = HTML;
|
|
161
|
+
var node = holder.firstElementChild;
|
|
162
|
+
if (node) document.body.insertBefore(node, document.body.firstChild);
|
|
163
|
+
}}
|
|
164
|
+
if (document.readyState === 'loading') {{
|
|
165
|
+
document.addEventListener('DOMContentLoaded', inject);
|
|
166
|
+
}} else {{
|
|
167
|
+
inject();
|
|
168
|
+
}}
|
|
169
|
+
}})();
|
|
170
|
+
"""
|
|
171
|
+
return preamble + "\n/* --- canonical header.js (shared-header) --- */\n" + behavior_js
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# ---------------------------------------------------------------------------
|
|
175
|
+
# Sphinx hooks
|
|
176
|
+
# ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
def _resolve_config(app: Sphinx) -> dict:
|
|
179
|
+
cfg = app.config
|
|
180
|
+
return {
|
|
181
|
+
"url": os.environ.get("BRAINX_HEADER_URL", cfg.brainx_header_url).rstrip("/"),
|
|
182
|
+
"ttl": int(os.environ.get("BRAINX_HEADER_TTL", cfg.brainx_header_ttl)),
|
|
183
|
+
"offline": (os.environ.get("BRAINX_HEADER_OFFLINE") == "1") or bool(cfg.brainx_header_offline),
|
|
184
|
+
"local": os.environ.get("BRAINX_HEADER_LOCAL", cfg.brainx_header_local),
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _on_builder_inited(app: Sphinx) -> None:
|
|
189
|
+
cfg = _resolve_config(app)
|
|
190
|
+
confdir = Path(app.confdir)
|
|
191
|
+
|
|
192
|
+
static_dirs = list(getattr(app.config, "html_static_path", []) or [])
|
|
193
|
+
if not static_dirs:
|
|
194
|
+
static_dirs = ["_static"]
|
|
195
|
+
app.config.html_static_path = static_dirs
|
|
196
|
+
primary_static = confdir / static_dirs[0]
|
|
197
|
+
|
|
198
|
+
css_out = primary_static / ARTIFACT_CSS
|
|
199
|
+
js_out = primary_static / ARTIFACT_JS
|
|
200
|
+
css_out.parent.mkdir(parents=True, exist_ok=True)
|
|
201
|
+
js_out.parent.mkdir(parents=True, exist_ok=True)
|
|
202
|
+
|
|
203
|
+
if cfg["local"]:
|
|
204
|
+
assets = _read_local(Path(cfg["local"]))
|
|
205
|
+
source_label = f"local:{cfg['local']}"
|
|
206
|
+
print(f"[brainx-sphinx-header] using local source: {cfg['local']}")
|
|
207
|
+
else:
|
|
208
|
+
assets = _load_with_cache(
|
|
209
|
+
cfg["url"],
|
|
210
|
+
confdir / CACHE_DIR_NAME,
|
|
211
|
+
cfg["ttl"],
|
|
212
|
+
cfg["offline"],
|
|
213
|
+
)
|
|
214
|
+
source_label = cfg["url"]
|
|
215
|
+
print(f"[brainx-sphinx-header] source={cfg['url']} offline={cfg['offline']} ttl={cfg['ttl']}")
|
|
216
|
+
|
|
217
|
+
css_out.write_text(assets["header.css"] + _THEME_OVERRIDES, encoding="utf-8")
|
|
218
|
+
js_out.write_text(
|
|
219
|
+
_build_js(assets["header.html"], assets["header.js"], source_label),
|
|
220
|
+
encoding="utf-8",
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def setup(app: Sphinx) -> dict:
|
|
225
|
+
app.add_config_value("brainx_header_url", DEFAULT_BASE, "html")
|
|
226
|
+
app.add_config_value("brainx_header_ttl", DEFAULT_TTL, "html")
|
|
227
|
+
app.add_config_value("brainx_header_offline", False, "html")
|
|
228
|
+
app.add_config_value("brainx_header_local", None, "html")
|
|
229
|
+
|
|
230
|
+
app.connect("builder-inited", _on_builder_inited)
|
|
231
|
+
app.add_css_file(ARTIFACT_CSS)
|
|
232
|
+
app.add_js_file(ARTIFACT_JS)
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
"version": __version__,
|
|
236
|
+
"parallel_read_safe": True,
|
|
237
|
+
"parallel_write_safe": True,
|
|
238
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brainx-sphinx-header
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sphinx extension that injects the canonical BrainX brand header into any docs site, fetched live from brainx.chaobrain.com.
|
|
5
|
+
Author: BrainX Developers
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://brainx.chaobrain.com/
|
|
8
|
+
Project-URL: Source, https://github.com/chaobrain/brainx.chaobrain.com/tree/main/sphinx-ext
|
|
9
|
+
Keywords: sphinx,extension,brainx,documentation,header
|
|
10
|
+
Classifier: Framework :: Sphinx :: Extension
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Documentation :: Sphinx
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: sphinx>=4
|
|
17
|
+
|
|
18
|
+
# brainx-sphinx-header
|
|
19
|
+
|
|
20
|
+
Sphinx extension that injects the canonical [BrainX](https://brainx.chaobrain.com/) brand header into any docs site, fetched live from the landing site so every package's docs stays in visual sync.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install brainx-sphinx-header
|
|
26
|
+
# or, before publishing:
|
|
27
|
+
pip install "git+https://github.com/chaobrain/brainx.chaobrain.com.git#subdirectory=sphinx-ext"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Use
|
|
31
|
+
|
|
32
|
+
In your `docs/conf.py`:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
extensions = [
|
|
36
|
+
# ...
|
|
37
|
+
"brainx_sphinx_header",
|
|
38
|
+
]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
That's it. On the next build, the BrainX header is fetched from `https://brainx.chaobrain.com/shared-header`, cached at `<docs>/_brand/`, and emitted as `_static/css/brainx-header.css` + `_static/js/brainx-header.js`.
|
|
42
|
+
|
|
43
|
+
## Configuration (optional)
|
|
44
|
+
|
|
45
|
+
All settings have sensible defaults. Override in `conf.py` only if you need to.
|
|
46
|
+
|
|
47
|
+
| Setting | Default | Purpose |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `brainx_header_url` | `"https://brainx.chaobrain.com/shared-header"` | Where to fetch the canonical header |
|
|
50
|
+
| `brainx_header_ttl` | `3600` | Cache TTL in seconds |
|
|
51
|
+
| `brainx_header_offline` | `False` | Use cache only, never fetch |
|
|
52
|
+
| `brainx_header_local` | `None` | Path to a local shared-header dir for live preview |
|
|
53
|
+
|
|
54
|
+
Each setting also honors an environment variable (`BRAINX_HEADER_URL`, `BRAINX_HEADER_TTL`, `BRAINX_HEADER_OFFLINE=1`, `BRAINX_HEADER_LOCAL`) which takes precedence — handy for CI.
|
|
55
|
+
|
|
56
|
+
## What it does
|
|
57
|
+
|
|
58
|
+
- Fetches `header.html` and `header.css` from the BrainX landing site (with TTL cache + stale fallback).
|
|
59
|
+
- Emits them as Sphinx static assets and registers them via `add_css_file` / `add_js_file`.
|
|
60
|
+
- Appends CSS overrides that hide `sphinx_book_theme` / `pydata_sphinx_theme` native top bars (`header.bd-header`, `.bd-header-article`, `.header-article-items.header-article__inner`).
|
|
61
|
+
- Wires the BrainX header's burger and theme button to the theme's hidden originals (`.primary-toggle`, `.theme-switch-button`) so sidebar toggle and theme cycling keep working — no template overrides needed.
|
|
62
|
+
|
|
63
|
+
## Local development
|
|
64
|
+
|
|
65
|
+
To preview a header change against your local landing-site build before pushing:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
BRAINX_HEADER_LOCAL=/path/to/brainx.chaobrain.com/dist/shared-header sphinx-build -b html docs docs/_build/html
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Supported themes
|
|
72
|
+
|
|
73
|
+
`sphinx_book_theme`, `pydata_sphinx_theme` (the `bd-*` selector family). Other themes will still render the BrainX header but without button delegation; their native header is unaffected.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
brainx_sphinx_header/__init__.py
|
|
4
|
+
brainx_sphinx_header.egg-info/PKG-INFO
|
|
5
|
+
brainx_sphinx_header.egg-info/SOURCES.txt
|
|
6
|
+
brainx_sphinx_header.egg-info/dependency_links.txt
|
|
7
|
+
brainx_sphinx_header.egg-info/requires.txt
|
|
8
|
+
brainx_sphinx_header.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sphinx>=4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
brainx_sphinx_header
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "brainx-sphinx-header"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Sphinx extension that injects the canonical BrainX brand header into any docs site, fetched live from brainx.chaobrain.com."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "BrainX Developers" }]
|
|
13
|
+
keywords = ["sphinx", "extension", "brainx", "documentation", "header"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Framework :: Sphinx :: Extension",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Documentation :: Sphinx",
|
|
19
|
+
]
|
|
20
|
+
dependencies = ["sphinx>=4"]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://brainx.chaobrain.com/"
|
|
24
|
+
Source = "https://github.com/chaobrain/brainx.chaobrain.com/tree/main/sphinx-ext"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
include = ["brainx_sphinx_header*"]
|