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.
@@ -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
+ 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*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+