sphinx-oceanid 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,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, driller
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: sphinx-oceanid
3
+ Version: 0.1.0
4
+ Summary: High-quality Mermaid diagrams in Sphinx, powered by beautiful-mermaid
5
+ Keywords: sphinx,mermaid,diagrams,documentation,beautiful-mermaid
6
+ Author: driller
7
+ Author-email: driller <eleshis@gmail.com>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Framework :: Sphinx :: Extension
12
+ Classifier: License :: OSI Approved :: BSD License
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Documentation
16
+ Requires-Dist: sphinx>=7.4
17
+ Requires-Dist: sphinx-autobuild>=2024.0 ; extra == 'preview'
18
+ Requires-Python: >=3.13
19
+ Project-URL: Homepage, https://github.com/drillan/sphinx-oceanid
20
+ Project-URL: Documentation, https://drillan.github.io/sphinx-oceanid/
21
+ Project-URL: Repository, https://github.com/drillan/sphinx-oceanid
22
+ Project-URL: Bug Tracker, https://github.com/drillan/sphinx-oceanid/issues
23
+ Project-URL: Changelog, https://github.com/drillan/sphinx-oceanid/blob/main/CHANGELOG.md
24
+ Provides-Extra: preview
25
+ Description-Content-Type: text/markdown
26
+
27
+ # sphinx-oceanid
28
+
29
+ [![PyPI](https://img.shields.io/pypi/v/sphinx-oceanid)](https://pypi.org/project/sphinx-oceanid/)
30
+ [![Python](https://img.shields.io/pypi/pyversions/sphinx-oceanid)](https://pypi.org/project/sphinx-oceanid/)
31
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://drillan.github.io/sphinx-oceanid/)
32
+ [![日本語](https://img.shields.io/badge/lang-日本語-red)](README.ja.md)
33
+
34
+ High-quality Mermaid diagrams in Sphinx, powered by [beautiful-mermaid](https://github.com/niccolozy/beautiful-mermaid).
35
+
36
+ ## Features
37
+
38
+ - **beautiful-mermaid rendering** — Uses ELK.js-based layout engine for high-quality SVG output
39
+ - **CSS variable theming** — Automatic dark/light theme detection with instant switching (no re-render)
40
+ - **Zero-config** — Works out of the box with CDN-hosted beautiful-mermaid
41
+ - **sphinx-revealjs support** — Lazy rendering for hidden slides via IntersectionObserver ([example](https://drillan.github.io/sphinx-oceanid/slides/))
42
+ - **Pan & zoom** — Native Pointer Events + SVG transform (no d3.js dependency)
43
+ - **Fullscreen modal** — View diagrams in a viewport-sized overlay
44
+ - **External file support** — Reference `.mmd` files instead of inline code
45
+ - **Auto class diagrams** — Generate class hierarchy diagrams from Python code
46
+
47
+ ## Supported Diagram Types
48
+
49
+ | Type | Alias |
50
+ |------|-------|
51
+ | `flowchart` | `graph` |
52
+ | `sequenceDiagram` | |
53
+ | `classDiagram` | |
54
+ | `stateDiagram` | `stateDiagram-v2` |
55
+ | `erDiagram` | |
56
+ | `xychart-beta` | |
57
+
58
+ Unsupported diagram types produce explicit warnings (or errors), never silent degradation.
59
+
60
+ ## Installation
61
+
62
+ sphinx-oceanid requires Python 3.13+.
63
+
64
+ ```bash
65
+ pip install sphinx-oceanid
66
+ ```
67
+
68
+ From source:
69
+
70
+ ```bash
71
+ pip install git+https://github.com/drillan/sphinx-oceanid.git
72
+ ```
73
+
74
+ Or clone and install locally:
75
+
76
+ ```bash
77
+ git clone https://github.com/drillan/sphinx-oceanid.git
78
+ cd sphinx-oceanid
79
+ pip install .
80
+ ```
81
+
82
+ ## Quick Start
83
+
84
+ Add the extension to your `conf.py`:
85
+
86
+ ```python
87
+ extensions = ["sphinx_oceanid"]
88
+ ```
89
+
90
+ Then use the `mermaid` directive in your reStructuredText files:
91
+
92
+ ```rst
93
+ .. mermaid::
94
+
95
+ flowchart LR
96
+ A[Start] --> B[Process] --> C[End]
97
+ ```
98
+
99
+ Or in Markdown (MyST) files:
100
+
101
+ ````markdown
102
+ ```{mermaid}
103
+ sequenceDiagram
104
+ Alice->>Bob: Hello
105
+ Bob-->>Alice: Hi!
106
+ ```
107
+ ````
108
+
109
+ ## Configuration
110
+
111
+ All configuration options use the `oceanid_` prefix in `conf.py`:
112
+
113
+ ```python
114
+ # conf.py
115
+ extensions = ["sphinx_oceanid"]
116
+
117
+ # Theme (default: "auto" — detects dark/light from Sphinx theme)
118
+ oceanid_theme = "auto"
119
+ oceanid_theme_dark = "zinc-dark"
120
+ oceanid_theme_light = "zinc-light"
121
+
122
+ # Enable zoom on all diagrams (default: False)
123
+ oceanid_zoom = True
124
+
125
+ # Enable fullscreen modal (default: False)
126
+ oceanid_fullscreen = True
127
+
128
+ # Action for unsupported diagram types: "warning" or "error" (default: "warning")
129
+ oceanid_unsupported_action = "warning"
130
+ ```
131
+
132
+ ## Directive Options
133
+
134
+ ```rst
135
+ .. mermaid::
136
+ :name: my-diagram
137
+ :alt: Description for accessibility
138
+ :align: center
139
+ :caption: Diagram caption (rendered as <figcaption>)
140
+ :title: Mermaid native title (rendered inside the diagram)
141
+ :zoom:
142
+ :config: {"theme": "forest"}
143
+
144
+ flowchart LR
145
+ A --> B --> C
146
+ ```
147
+
148
+ ## Auto Class Diagrams
149
+
150
+ Generate class hierarchy diagrams from Python code:
151
+
152
+ ```rst
153
+ .. autoclasstree:: mypackage.MyClass
154
+ :full:
155
+ :namespace: mypackage
156
+ :caption: Class hierarchy
157
+ ```
158
+
159
+ ## Local Preview
160
+
161
+ Mermaid diagrams require HTTP serving — opening built HTML via `file://` will not render diagrams due to browser CORS restrictions.
162
+
163
+ ```bash
164
+ # Quick static server (no extra dependencies)
165
+ make -C docs serve
166
+
167
+ # Live reload (requires sphinx-autobuild)
168
+ pip install sphinx-oceanid[preview]
169
+ make -C docs livehtml
170
+ ```
171
+
172
+ See [docs/install.md](docs/install.md) for Makefile setup instructions.
173
+
174
+ ## Documentation
175
+
176
+ Full documentation is available at **[drillan.github.io/sphinx-oceanid](https://drillan.github.io/sphinx-oceanid/)** or in the [docs/](docs/) directory.
177
+
178
+ ## License
179
+
180
+ BSD-3-Clause. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,154 @@
1
+ # sphinx-oceanid
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/sphinx-oceanid)](https://pypi.org/project/sphinx-oceanid/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/sphinx-oceanid)](https://pypi.org/project/sphinx-oceanid/)
5
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://drillan.github.io/sphinx-oceanid/)
6
+ [![日本語](https://img.shields.io/badge/lang-日本語-red)](README.ja.md)
7
+
8
+ High-quality Mermaid diagrams in Sphinx, powered by [beautiful-mermaid](https://github.com/niccolozy/beautiful-mermaid).
9
+
10
+ ## Features
11
+
12
+ - **beautiful-mermaid rendering** — Uses ELK.js-based layout engine for high-quality SVG output
13
+ - **CSS variable theming** — Automatic dark/light theme detection with instant switching (no re-render)
14
+ - **Zero-config** — Works out of the box with CDN-hosted beautiful-mermaid
15
+ - **sphinx-revealjs support** — Lazy rendering for hidden slides via IntersectionObserver ([example](https://drillan.github.io/sphinx-oceanid/slides/))
16
+ - **Pan & zoom** — Native Pointer Events + SVG transform (no d3.js dependency)
17
+ - **Fullscreen modal** — View diagrams in a viewport-sized overlay
18
+ - **External file support** — Reference `.mmd` files instead of inline code
19
+ - **Auto class diagrams** — Generate class hierarchy diagrams from Python code
20
+
21
+ ## Supported Diagram Types
22
+
23
+ | Type | Alias |
24
+ |------|-------|
25
+ | `flowchart` | `graph` |
26
+ | `sequenceDiagram` | |
27
+ | `classDiagram` | |
28
+ | `stateDiagram` | `stateDiagram-v2` |
29
+ | `erDiagram` | |
30
+ | `xychart-beta` | |
31
+
32
+ Unsupported diagram types produce explicit warnings (or errors), never silent degradation.
33
+
34
+ ## Installation
35
+
36
+ sphinx-oceanid requires Python 3.13+.
37
+
38
+ ```bash
39
+ pip install sphinx-oceanid
40
+ ```
41
+
42
+ From source:
43
+
44
+ ```bash
45
+ pip install git+https://github.com/drillan/sphinx-oceanid.git
46
+ ```
47
+
48
+ Or clone and install locally:
49
+
50
+ ```bash
51
+ git clone https://github.com/drillan/sphinx-oceanid.git
52
+ cd sphinx-oceanid
53
+ pip install .
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ Add the extension to your `conf.py`:
59
+
60
+ ```python
61
+ extensions = ["sphinx_oceanid"]
62
+ ```
63
+
64
+ Then use the `mermaid` directive in your reStructuredText files:
65
+
66
+ ```rst
67
+ .. mermaid::
68
+
69
+ flowchart LR
70
+ A[Start] --> B[Process] --> C[End]
71
+ ```
72
+
73
+ Or in Markdown (MyST) files:
74
+
75
+ ````markdown
76
+ ```{mermaid}
77
+ sequenceDiagram
78
+ Alice->>Bob: Hello
79
+ Bob-->>Alice: Hi!
80
+ ```
81
+ ````
82
+
83
+ ## Configuration
84
+
85
+ All configuration options use the `oceanid_` prefix in `conf.py`:
86
+
87
+ ```python
88
+ # conf.py
89
+ extensions = ["sphinx_oceanid"]
90
+
91
+ # Theme (default: "auto" — detects dark/light from Sphinx theme)
92
+ oceanid_theme = "auto"
93
+ oceanid_theme_dark = "zinc-dark"
94
+ oceanid_theme_light = "zinc-light"
95
+
96
+ # Enable zoom on all diagrams (default: False)
97
+ oceanid_zoom = True
98
+
99
+ # Enable fullscreen modal (default: False)
100
+ oceanid_fullscreen = True
101
+
102
+ # Action for unsupported diagram types: "warning" or "error" (default: "warning")
103
+ oceanid_unsupported_action = "warning"
104
+ ```
105
+
106
+ ## Directive Options
107
+
108
+ ```rst
109
+ .. mermaid::
110
+ :name: my-diagram
111
+ :alt: Description for accessibility
112
+ :align: center
113
+ :caption: Diagram caption (rendered as <figcaption>)
114
+ :title: Mermaid native title (rendered inside the diagram)
115
+ :zoom:
116
+ :config: {"theme": "forest"}
117
+
118
+ flowchart LR
119
+ A --> B --> C
120
+ ```
121
+
122
+ ## Auto Class Diagrams
123
+
124
+ Generate class hierarchy diagrams from Python code:
125
+
126
+ ```rst
127
+ .. autoclasstree:: mypackage.MyClass
128
+ :full:
129
+ :namespace: mypackage
130
+ :caption: Class hierarchy
131
+ ```
132
+
133
+ ## Local Preview
134
+
135
+ Mermaid diagrams require HTTP serving — opening built HTML via `file://` will not render diagrams due to browser CORS restrictions.
136
+
137
+ ```bash
138
+ # Quick static server (no extra dependencies)
139
+ make -C docs serve
140
+
141
+ # Live reload (requires sphinx-autobuild)
142
+ pip install sphinx-oceanid[preview]
143
+ make -C docs livehtml
144
+ ```
145
+
146
+ See [docs/install.md](docs/install.md) for Makefile setup instructions.
147
+
148
+ ## Documentation
149
+
150
+ Full documentation is available at **[drillan.github.io/sphinx-oceanid](https://drillan.github.io/sphinx-oceanid/)** or in the [docs/](docs/) directory.
151
+
152
+ ## License
153
+
154
+ BSD-3-Clause. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,91 @@
1
+ [project]
2
+ name = "sphinx-oceanid"
3
+ version = "0.1.0"
4
+ description = "High-quality Mermaid diagrams in Sphinx, powered by beautiful-mermaid"
5
+ readme = "README.md"
6
+ license = "BSD-3-Clause"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.13"
9
+ keywords = ["sphinx", "mermaid", "diagrams", "documentation", "beautiful-mermaid"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Framework :: Sphinx :: Extension",
13
+ "License :: OSI Approved :: BSD License",
14
+ "Programming Language :: Python :: 3.13",
15
+ "Programming Language :: Python :: 3.14",
16
+ "Topic :: Documentation",
17
+ ]
18
+ authors = [
19
+ { name = "driller", email = "eleshis@gmail.com" },
20
+ ]
21
+ dependencies = [
22
+ "sphinx>=7.4",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/drillan/sphinx-oceanid"
27
+ Documentation = "https://drillan.github.io/sphinx-oceanid/"
28
+ Repository = "https://github.com/drillan/sphinx-oceanid"
29
+ "Bug Tracker" = "https://github.com/drillan/sphinx-oceanid/issues"
30
+ Changelog = "https://github.com/drillan/sphinx-oceanid/blob/main/CHANGELOG.md"
31
+
32
+ [build-system]
33
+ requires = ["uv_build>=0.10.0,<0.11.0"]
34
+ build-backend = "uv_build"
35
+
36
+ [project.optional-dependencies]
37
+ preview = ["sphinx-autobuild>=2024.0"]
38
+
39
+ [dependency-groups]
40
+ test = [
41
+ "pytest",
42
+ "myst-parser",
43
+ "sphinx-revealjs",
44
+ ]
45
+ dev = [
46
+ "ruff",
47
+ "mypy",
48
+ "types-docutils",
49
+ { include-group = "test" },
50
+ ]
51
+ docs = [
52
+ "myst-parser>=5.0.0",
53
+ "shibuya>=2026.1.9",
54
+ "sphinx>=9.1.0",
55
+ "sphinx-autobuild>=2024.0",
56
+ "sphinx-design>=0.6",
57
+ "sphinx-revealjs>=3.0",
58
+ ]
59
+
60
+ [tool.pytest.ini_options]
61
+ testpaths = ["tests"]
62
+
63
+ [tool.ruff]
64
+ line-length = 120
65
+ target-version = "py313"
66
+
67
+ [tool.ruff.lint]
68
+ extend-select = [
69
+ "I", # isort
70
+ "UP", # pyupgrade
71
+ "B", # flake8-bugbear
72
+ "SIM", # flake8-simplify
73
+ "TCH", # flake8-type-checking
74
+ "RUF", # Ruff-specific
75
+ "PIE", # flake8-pie
76
+ "PT", # flake8-pytest-style
77
+ "RSE", # flake8-raise
78
+ "C4", # flake8-comprehensions
79
+ "FURB", # refurb
80
+ "PERF", # perflint
81
+ ]
82
+
83
+ [tool.ruff.lint.isort]
84
+ known-first-party = ["sphinx_oceanid"]
85
+
86
+ [tool.mypy]
87
+ python_version = "3.13"
88
+ strict = true
89
+ warn_unreachable = true
90
+ enable_error_code = ["ignore-without-code", "redundant-cast", "truthy-bool"]
91
+ exclude = ["tests/roots/", "examples/"]
@@ -0,0 +1,42 @@
1
+ """sphinx-oceanid: High-quality Mermaid diagrams in Sphinx."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from sphinx.application import Sphinx
10
+
11
+ from importlib.metadata import version
12
+
13
+ __version__ = version("sphinx-oceanid")
14
+
15
+ _STATIC_DIR = str(Path(__file__).parent / "_static")
16
+
17
+
18
+ def setup(app: Sphinx) -> dict[str, bool | str]:
19
+ """Sphinx extension entry point.
20
+
21
+ Registers nodes, directives, config values, and event handlers.
22
+ """
23
+ from .assets import install_assets
24
+ from .config import register_config_values, validate_config
25
+ from .directives import Mermaid, MermaidClassDiagram
26
+ from .nodes import mermaid_node
27
+ from .visitors import html_depart_mermaid, html_visit_mermaid
28
+
29
+ register_config_values(app)
30
+ app.add_node(mermaid_node, html=(html_visit_mermaid, html_depart_mermaid))
31
+ app.add_directive("mermaid", Mermaid)
32
+ app.add_directive("autoclasstree", MermaidClassDiagram)
33
+ app.connect("config-inited", validate_config)
34
+ app.connect("html-page-context", install_assets)
35
+ app.connect("builder-inited", _register_static_path)
36
+
37
+ return {"version": __version__, "parallel_read_safe": True}
38
+
39
+
40
+ def _register_static_path(app: Sphinx) -> None:
41
+ """Register the extension's _static directory for file copying."""
42
+ app.config.html_static_path.append(_STATIC_DIR)
@@ -0,0 +1,127 @@
1
+ /**
2
+ * sphinx-oceanid: Fullscreen modal for Mermaid diagrams (FR-018).
3
+ *
4
+ * Creates a modal overlay, injects fullscreen buttons on rendered diagrams,
5
+ * and watches for newly rendered diagrams via MutationObserver.
6
+ */
7
+
8
+ /**
9
+ * Create the fullscreen modal DOM element and append to document body.
10
+ *
11
+ * @param {object} config - Oceanid config with fullscreenButton and fullscreenButtonOpacity
12
+ * @returns {{modal: HTMLElement, container: HTMLElement, close: Function}}
13
+ */
14
+ const createModal = (config) => {
15
+ const modal = document.createElement("div");
16
+ modal.className = "oceanid-fullscreen-modal";
17
+
18
+ const closeBtn = document.createElement("button");
19
+ closeBtn.className = "oceanid-fullscreen-close";
20
+ closeBtn.textContent = "\u00d7";
21
+ closeBtn.setAttribute("aria-label", "Close fullscreen");
22
+
23
+ const container = document.createElement("div");
24
+ container.className = "oceanid-container-fullscreen";
25
+
26
+ modal.appendChild(closeBtn);
27
+ modal.appendChild(container);
28
+ document.body.appendChild(modal);
29
+
30
+ const close = () => {
31
+ modal.classList.remove("active");
32
+ container.innerHTML = "";
33
+ };
34
+
35
+ closeBtn.addEventListener("click", close);
36
+
37
+ modal.addEventListener("click", (e) => {
38
+ if (e.target === modal) {
39
+ close();
40
+ }
41
+ });
42
+
43
+ document.addEventListener("keydown", (e) => {
44
+ if (e.key === "Escape" && modal.classList.contains("active")) {
45
+ close();
46
+ }
47
+ });
48
+
49
+ return { modal, container, close };
50
+ };
51
+
52
+ /**
53
+ * Inject a fullscreen button on a rendered diagram element.
54
+ *
55
+ * @param {Element} el - .oceanid-diagram element with data-oceanid-rendered="true"
56
+ * @param {object} config - Oceanid config
57
+ * @param {{modal: HTMLElement, container: HTMLElement}} modalCtx - Modal context
58
+ */
59
+ const addFullscreenButton = (el, config, modalCtx) => {
60
+ if (el.querySelector(".oceanid-fullscreen-btn")) {
61
+ return;
62
+ }
63
+
64
+ const wrapper = el.querySelector(".oceanid-svg-container");
65
+ if (!wrapper) {
66
+ return;
67
+ }
68
+
69
+ el.style.position = el.style.position || "relative";
70
+
71
+ const btn = document.createElement("button");
72
+ btn.className = "oceanid-fullscreen-btn";
73
+ btn.textContent = config.fullscreenButton;
74
+ btn.setAttribute("aria-label", "Open fullscreen");
75
+ btn.style.opacity = String(config.fullscreenButtonOpacity / 100);
76
+
77
+ btn.addEventListener("click", () => {
78
+ const svg = wrapper.querySelector("svg");
79
+ if (!svg) {
80
+ return;
81
+ }
82
+ modalCtx.container.innerHTML = "";
83
+ const clone = svg.cloneNode(true);
84
+ clone.style.width = "100%";
85
+ clone.style.height = "auto";
86
+ clone.style.maxHeight = "90vh";
87
+ modalCtx.container.appendChild(clone);
88
+ modalCtx.modal.classList.add("active");
89
+ });
90
+
91
+ el.appendChild(btn);
92
+ };
93
+
94
+ /**
95
+ * Set up fullscreen modal functionality.
96
+ *
97
+ * - Creates modal DOM and appends to body
98
+ * - Adds fullscreen button to already-rendered diagrams
99
+ * - Uses MutationObserver to add button to diagrams rendered later (lazy)
100
+ *
101
+ * @param {object} config - Oceanid config
102
+ */
103
+ export const setupFullscreen = (config) => {
104
+ const modalCtx = createModal(config);
105
+
106
+ document
107
+ .querySelectorAll('.oceanid-diagram[data-oceanid-rendered="true"]')
108
+ .forEach((el) => {
109
+ addFullscreenButton(el, config, modalCtx);
110
+ });
111
+
112
+ const observer = new MutationObserver((mutations) => {
113
+ mutations.forEach((mutation) => {
114
+ if (
115
+ mutation.type === "attributes" &&
116
+ mutation.attributeName === "data-oceanid-rendered" &&
117
+ mutation.target.getAttribute("data-oceanid-rendered") === "true"
118
+ ) {
119
+ addFullscreenButton(mutation.target, config, modalCtx);
120
+ }
121
+ });
122
+ });
123
+
124
+ document.querySelectorAll(".oceanid-diagram").forEach((el) => {
125
+ observer.observe(el, { attributes: true });
126
+ });
127
+ };