nadoc 0.1.0a1__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.
- nadoc-0.1.0a1/LICENSE +21 -0
- nadoc-0.1.0a1/PKG-INFO +107 -0
- nadoc-0.1.0a1/README.md +77 -0
- nadoc-0.1.0a1/pyproject.toml +48 -0
- nadoc-0.1.0a1/setup.cfg +4 -0
- nadoc-0.1.0a1/src/nadoc/__init__.py +8 -0
- nadoc-0.1.0a1/src/nadoc/__main__.py +3 -0
- nadoc-0.1.0a1/src/nadoc/api.py +60 -0
- nadoc-0.1.0a1/src/nadoc/assets/icons/curl.svg +7 -0
- nadoc-0.1.0a1/src/nadoc/assets/icons/go.svg +1 -0
- nadoc-0.1.0a1/src/nadoc/assets/icons/js.svg +1 -0
- nadoc-0.1.0a1/src/nadoc/assets/icons/python.svg +1 -0
- nadoc-0.1.0a1/src/nadoc/assets/nada.css +115 -0
- nadoc-0.1.0a1/src/nadoc/assets/nada.js +126 -0
- nadoc-0.1.0a1/src/nadoc/cli.py +49 -0
- nadoc-0.1.0a1/src/nadoc/errors.py +2 -0
- nadoc-0.1.0a1/src/nadoc/loader.py +40 -0
- nadoc-0.1.0a1/src/nadoc/model.py +82 -0
- nadoc-0.1.0a1/src/nadoc/normalize.py +296 -0
- nadoc-0.1.0a1/src/nadoc/overlay.py +68 -0
- nadoc-0.1.0a1/src/nadoc/render.py +96 -0
- nadoc-0.1.0a1/src/nadoc/templates/page.html.j2 +123 -0
- nadoc-0.1.0a1/src/nadoc/templates/schema.html.j2 +53 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/PKG-INFO +107 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/SOURCES.txt +28 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/dependency_links.txt +1 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/entry_points.txt +2 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/requires.txt +4 -0
- nadoc-0.1.0a1/src/nadoc.egg-info/top_level.txt +1 -0
- nadoc-0.1.0a1/tests/test_renderer.py +229 -0
nadoc-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ibudidi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
nadoc-0.1.0a1/PKG-INFO
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nadoc
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: A simple static documentation generator for OpenAPI 3.1 specs
|
|
5
|
+
Author-email: Ibudidi <ibudidi@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ibudidi/nadoc
|
|
8
|
+
Project-URL: Repository, https://github.com/ibudidi/nadoc
|
|
9
|
+
Project-URL: Issues, https://github.com/ibudidi/nadoc/issues
|
|
10
|
+
Keywords: openapi,documentation,static-site,api
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Documentation
|
|
21
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: Jinja2<4,>=3.1
|
|
26
|
+
Requires-Dist: markdown-it-py<5,>=3
|
|
27
|
+
Requires-Dist: Pygments<3,>=2.19
|
|
28
|
+
Requires-Dist: PyYAML<7,>=6
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Nadoc
|
|
32
|
+
|
|
33
|
+
Deterministic static documentation for OpenAPI.
|
|
34
|
+
|
|
35
|
+
Nadoc converts an OpenAPI 3.1 document and an optional OpenAPI Overlay 1.x document into a self-contained,
|
|
36
|
+
server-rendered API documentation site. CSS, JavaScript, and language icons are embedded in the generated HTML;
|
|
37
|
+
Python is only required at generation time.
|
|
38
|
+
|
|
39
|
+
> Nadoc is currently alpha software. It intentionally rejects unsupported OpenAPI constructs in strict mode rather
|
|
40
|
+
> than silently omitting them.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
From this source checkout:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python3 -m pip install .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For isolated command-line installation, use `pipx install .`.
|
|
51
|
+
|
|
52
|
+
## Use
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
nadoc openapi.yaml --output-dir api-docs
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Apply an optional overlay and minify the HTML shell:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
nadoc openapi.yaml \
|
|
62
|
+
--overlay documentation-overlay.yaml \
|
|
63
|
+
--output-dir api-docs \
|
|
64
|
+
--minify
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Generated files:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
api-docs/
|
|
71
|
+
├── index.html
|
|
72
|
+
└── openapi.yaml
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Use custom progressive-enhancement assets with `--css` and `--js`. Use `--check` to avoid writing and return exit
|
|
76
|
+
code `1` when generated files are missing or stale. Input and validation errors return exit code `2`.
|
|
77
|
+
|
|
78
|
+
Nadoc can also be used from Python:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from nadoc import render
|
|
82
|
+
|
|
83
|
+
result = render(
|
|
84
|
+
"openapi.yaml",
|
|
85
|
+
overlay="documentation-overlay.yaml",
|
|
86
|
+
output_dir="api-docs",
|
|
87
|
+
)
|
|
88
|
+
print(result.html_path)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Supported scope
|
|
92
|
+
|
|
93
|
+
Nadoc currently supports the OpenAPI 3.1 operation, parameter, request/response media, example, server, tag,
|
|
94
|
+
`x-codeSamples`, and local component-schema constructs used by its test suite. It supports exact-target OpenAPI
|
|
95
|
+
Overlay 1.x object merges and replacements.
|
|
96
|
+
|
|
97
|
+
Strict mode currently rejects schema composition (`allOf`, `oneOf`, and `anyOf`), remote/file references,
|
|
98
|
+
discriminators, conditionals, callbacks, webhooks, and other unsupported schema keywords. Use `--no-strict` only
|
|
99
|
+
when omission of unsupported semantics is acceptable.
|
|
100
|
+
|
|
101
|
+
## Develop
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python3 -m unittest discover -s tests -v
|
|
105
|
+
python3 -m compileall -q src tests
|
|
106
|
+
node --check src/nadoc/assets/nada.js
|
|
107
|
+
```
|
nadoc-0.1.0a1/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Nadoc
|
|
2
|
+
|
|
3
|
+
Deterministic static documentation for OpenAPI.
|
|
4
|
+
|
|
5
|
+
Nadoc converts an OpenAPI 3.1 document and an optional OpenAPI Overlay 1.x document into a self-contained,
|
|
6
|
+
server-rendered API documentation site. CSS, JavaScript, and language icons are embedded in the generated HTML;
|
|
7
|
+
Python is only required at generation time.
|
|
8
|
+
|
|
9
|
+
> Nadoc is currently alpha software. It intentionally rejects unsupported OpenAPI constructs in strict mode rather
|
|
10
|
+
> than silently omitting them.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
From this source checkout:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python3 -m pip install .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For isolated command-line installation, use `pipx install .`.
|
|
21
|
+
|
|
22
|
+
## Use
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
nadoc openapi.yaml --output-dir api-docs
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Apply an optional overlay and minify the HTML shell:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
nadoc openapi.yaml \
|
|
32
|
+
--overlay documentation-overlay.yaml \
|
|
33
|
+
--output-dir api-docs \
|
|
34
|
+
--minify
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Generated files:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
api-docs/
|
|
41
|
+
├── index.html
|
|
42
|
+
└── openapi.yaml
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use custom progressive-enhancement assets with `--css` and `--js`. Use `--check` to avoid writing and return exit
|
|
46
|
+
code `1` when generated files are missing or stale. Input and validation errors return exit code `2`.
|
|
47
|
+
|
|
48
|
+
Nadoc can also be used from Python:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from nadoc import render
|
|
52
|
+
|
|
53
|
+
result = render(
|
|
54
|
+
"openapi.yaml",
|
|
55
|
+
overlay="documentation-overlay.yaml",
|
|
56
|
+
output_dir="api-docs",
|
|
57
|
+
)
|
|
58
|
+
print(result.html_path)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Supported scope
|
|
62
|
+
|
|
63
|
+
Nadoc currently supports the OpenAPI 3.1 operation, parameter, request/response media, example, server, tag,
|
|
64
|
+
`x-codeSamples`, and local component-schema constructs used by its test suite. It supports exact-target OpenAPI
|
|
65
|
+
Overlay 1.x object merges and replacements.
|
|
66
|
+
|
|
67
|
+
Strict mode currently rejects schema composition (`allOf`, `oneOf`, and `anyOf`), remote/file references,
|
|
68
|
+
discriminators, conditionals, callbacks, webhooks, and other unsupported schema keywords. Use `--no-strict` only
|
|
69
|
+
when omission of unsupported semantics is acceptable.
|
|
70
|
+
|
|
71
|
+
## Develop
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python3 -m unittest discover -s tests -v
|
|
75
|
+
python3 -m compileall -q src tests
|
|
76
|
+
node --check src/nadoc/assets/nada.js
|
|
77
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nadoc"
|
|
7
|
+
version = "0.1.0a1"
|
|
8
|
+
description = "A simple static documentation generator for OpenAPI 3.1 specs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Ibudidi", email = "ibudidi@users.noreply.github.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["openapi", "documentation", "static-site", "api"]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"Jinja2>=3.1,<4",
|
|
18
|
+
"markdown-it-py>=3,<5",
|
|
19
|
+
"Pygments>=2.19,<3",
|
|
20
|
+
"PyYAML>=6,<7",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 3 - Alpha",
|
|
24
|
+
"Environment :: Console",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Topic :: Documentation",
|
|
33
|
+
"Topic :: Software Development :: Documentation",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/ibudidi/nadoc"
|
|
38
|
+
Repository = "https://github.com/ibudidi/nadoc"
|
|
39
|
+
Issues = "https://github.com/ibudidi/nadoc/issues"
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
nadoc = "nadoc.cli:main"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.package-data]
|
|
48
|
+
nadoc = ["templates/*.j2", "assets/*.css", "assets/*.js", "assets/icons/*.svg"]
|
nadoc-0.1.0a1/setup.cfg
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from importlib.resources import files
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .loader import load_yaml
|
|
6
|
+
from .normalize import Normalizer
|
|
7
|
+
from .overlay import apply_overlay
|
|
8
|
+
from .render import build_icons_css, render_html, write_outputs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class RenderResult:
|
|
13
|
+
html_path: Path
|
|
14
|
+
merged_spec_path: Path
|
|
15
|
+
operation_count: int
|
|
16
|
+
schema_count: int
|
|
17
|
+
changed_paths: tuple[Path, ...]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def render(
|
|
21
|
+
spec: str | Path,
|
|
22
|
+
*,
|
|
23
|
+
overlay: str | Path | None = None,
|
|
24
|
+
output_dir: str | Path = "openapi-docs",
|
|
25
|
+
css: str | Path | None = None,
|
|
26
|
+
javascript: str | Path | None = None,
|
|
27
|
+
strict: bool = True,
|
|
28
|
+
minify: bool = False,
|
|
29
|
+
check: bool = False,
|
|
30
|
+
) -> RenderResult:
|
|
31
|
+
"""Render an OpenAPI document and return details about the generated artifacts."""
|
|
32
|
+
document = load_yaml(Path(spec))
|
|
33
|
+
if overlay is not None:
|
|
34
|
+
document = apply_overlay(document, load_yaml(Path(overlay)))
|
|
35
|
+
|
|
36
|
+
package = files("nadoc")
|
|
37
|
+
css_text = (
|
|
38
|
+
Path(css).read_text(encoding="utf-8")
|
|
39
|
+
if css is not None
|
|
40
|
+
else package.joinpath("assets", "nada.css").read_text(encoding="utf-8")
|
|
41
|
+
)
|
|
42
|
+
javascript_text = (
|
|
43
|
+
Path(javascript).read_text(encoding="utf-8")
|
|
44
|
+
if javascript is not None
|
|
45
|
+
else package.joinpath("assets", "nada.js").read_text(encoding="utf-8")
|
|
46
|
+
)
|
|
47
|
+
view = Normalizer(document, strict=strict).build()
|
|
48
|
+
html = render_html(
|
|
49
|
+
view,
|
|
50
|
+
css_text,
|
|
51
|
+
build_icons_css(package.joinpath("assets", "icons")),
|
|
52
|
+
javascript_text,
|
|
53
|
+
minify=minify,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
output = Path(output_dir)
|
|
57
|
+
merged_path = output / "openapi.yaml"
|
|
58
|
+
html_path = output / "index.html"
|
|
59
|
+
changed = tuple(write_outputs(merged_path, html_path, document, html, check))
|
|
60
|
+
return RenderResult(html_path, merged_path, view.operation_count, view.schema_count, changed)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-prompt" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="#198754" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<path stroke="none" d="M0 0h24v24H0z"/>
|
|
3
|
+
<polyline points="5 7 10 12 5 17" />
|
|
4
|
+
<line x1="13" y1="17" x2="19" y2="17" />
|
|
5
|
+
</svg>
|
|
6
|
+
|
|
7
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px" fill-rule="nonzero"><g fill="#05a7d2" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M22.46289,15.00391c-0.59933,0.01306 -1.20777,0.07845 -1.82227,0.18945c-3.006,0.549 -5.46431,2.09144 -7.32031,4.52344c-1.725,2.248 -2.5607,4.81016 -2.2207,7.66016c0.288,2.405 1.38631,4.33874 3.32031,5.80273c2.091,1.569 4.46925,2.06461 7.03125,1.72461c3.111,-0.418 5.56817,-1.96036 7.45117,-4.44336c0.048,-0.063 0.08291,-0.13231 0.12891,-0.19531c0.485,0.9 1.13713,1.70906 1.95313,2.41406c1.847,1.583 4.0365,2.26927 6.4375,2.32227c0.686,-0.079 1.39637,-0.10533 2.10938,-0.23633c2.453,-0.501 4.59003,-1.60895 6.33203,-3.37695c2.453,-2.483 3.48316,-5.38627 3.03516,-8.94727c-0.343,-2.533 -1.6367,-4.45781 -3.7207,-5.88281c-2.295,-1.557 -4.82853,-1.81875 -7.51953,-1.34375c-3.122,0.551 -5.43351,1.86023 -7.35352,4.36523c-0.646,-1.252 -1.53633,-2.31247 -2.73633,-3.10547c-1.58775,-1.0785 -3.30748,-1.50989 -5.10547,-1.4707zM4,20c-0.36064,-0.0051 -0.69608,0.18438 -0.87789,0.49587c-0.18181,0.3115 -0.18181,0.69676 0,1.00825c0.18181,0.3115 0.51725,0.50097 0.87789,0.49587h4c0.36064,0.0051 0.69608,-0.18438 0.87789,-0.49587c0.18181,-0.3115 0.18181,-0.69676 0,-1.00825c-0.18181,-0.3115 -0.51725,-0.50097 -0.87789,-0.49587zM22.13477,20.01172c0.60021,0.02632 1.2105,0.1822 1.82813,0.48633c0.549,0.261 0.83652,0.55014 1.22852,0.99414c0.34,0.392 0.36581,0.36672 0.75781,0.26172c1.313,-0.339 2.31263,-0.61378 3.51563,-0.92578c-0.457,0.767 -0.70422,1.3273 -0.94922,2.1543h-6.7168c-0.392,0 -0.5753,0.26097 -0.6543,0.41797c-0.366,0.68 -0.99203,2.03961 -1.33203,2.84961c-0.182,0.445 -0.05291,0.78516 0.49609,0.78516h5.04492c-0.261,0.366 -0.58336,0.91317 -0.81836,1.20117c-1.176,1.333 -2.66636,1.96256 -4.44336,1.72656c-2.065,-0.288 -3.5033,-2.01447 -3.5293,-4.10547c-0.026,-2.118 0.88997,-3.8168 2.66797,-4.9668c0.93125,-0.60438 1.90395,-0.92277 2.9043,-0.87891zM39.41016,20.20703c2.09275,-0.06851 3.93667,1.31455 4.3418,3.54492c0.051,0.257 0.05017,0.51366 0.07617,0.84766c-0.129,2.214 -1.23358,3.86197 -3.26758,4.91797c-1.364,0.695 -2.78127,0.7723 -4.19727,0.1543c-1.853,-0.824 -2.83119,-2.85723 -2.36719,-4.86523c0.566,-2.42 2.11186,-3.93947 4.50586,-4.48047c0.30562,-0.07075 0.60924,-0.10935 0.9082,-0.11914zM1,24c-0.36064,-0.0051 -0.69608,0.18438 -0.87789,0.49587c-0.18181,0.3115 -0.18181,0.69676 0,1.00825c0.18181,0.3115 0.51725,0.50097 0.87789,0.49587h6c0.36064,0.0051 0.69608,-0.18438 0.87789,-0.49587c0.18181,-0.3115 0.18181,-0.69676 0,-1.00825c-0.18181,-0.3115 -0.51725,-0.50097 -0.87789,-0.49587zM4,28c-0.36064,-0.0051 -0.69608,0.18438 -0.87789,0.49587c-0.18181,0.3115 -0.18181,0.69676 0,1.00825c0.18181,0.3115 0.51725,0.50097 0.87789,0.49587h2c0.36064,0.0051 0.69608,-0.18438 0.87789,-0.49587c0.18181,-0.3115 0.18181,-0.69676 0,-1.00825c-0.18181,-0.3115 -0.51725,-0.50097 -0.87789,-0.49587z"></path></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#ffd600" d="M6,42V6h36v36H6z"/><path fill="#000001" d="M29.538 32.947c.692 1.124 1.444 2.201 3.037 2.201 1.338 0 2.04-.665 2.04-1.585 0-1.101-.726-1.492-2.198-2.133l-.807-.344c-2.329-.988-3.878-2.226-3.878-4.841 0-2.41 1.845-4.244 4.728-4.244 2.053 0 3.528.711 4.592 2.573l-2.514 1.607c-.553-.988-1.151-1.377-2.078-1.377-.946 0-1.545.597-1.545 1.377 0 .964.6 1.354 1.985 1.951l.807.344C36.452 29.645 38 30.839 38 33.523 38 36.415 35.716 38 32.65 38c-2.999 0-4.702-1.505-5.65-3.368L29.538 32.947zM17.952 33.029c.506.906 1.275 1.603 2.381 1.603 1.058 0 1.667-.418 1.667-2.043V22h3.333v11.101c0 3.367-1.953 4.899-4.805 4.899-2.577 0-4.437-1.746-5.195-3.368L17.952 33.029z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#0277BD" d="M24.047,5c-1.555,0.005-2.633,0.142-3.936,0.367c-3.848,0.67-4.549,2.077-4.549,4.67V14h9v2H15.22h-4.35c-2.636,0-4.943,1.242-5.674,4.219c-0.826,3.417-0.863,5.557,0,9.125C5.851,32.005,7.294,34,9.931,34h3.632v-5.104c0-2.966,2.686-5.896,5.764-5.896h7.236c2.523,0,5-1.862,5-4.377v-8.586c0-2.439-1.759-4.263-4.218-4.672C27.406,5.359,25.589,4.994,24.047,5z M19.063,9c0.821,0,1.5,0.677,1.5,1.502c0,0.833-0.679,1.498-1.5,1.498c-0.837,0-1.5-0.664-1.5-1.498C17.563,9.68,18.226,9,19.063,9z"/><path fill="#FFC107" d="M23.078,43c1.555-0.005,2.633-0.142,3.936-0.367c3.848-0.67,4.549-2.077,4.549-4.67V34h-9v-2h9.343h4.35c2.636,0,4.943-1.242,5.674-4.219c0.826-3.417,0.863-5.557,0-9.125C41.274,15.995,39.831,14,37.194,14h-3.632v5.104c0,2.966-2.686,5.896-5.764,5.896h-7.236c-2.523,0-5,1.862-5,4.377v8.586c0,2.439,1.759,4.263,4.218,4.672C19.719,42.641,21.536,43.006,23.078,43z M28.063,39c-0.821,0-1.5-0.677-1.5-1.502c0-0.833,0.679-1.498,1.5-1.498c0.837,0,1.5,0.664,1.5,1.498C29.563,38.32,28.899,39,28.063,39z"/></svg>
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
:root{--header:64px;--sidebar:306px;--text:#040316;--background:#fbfbfe;--surface:#f4f3fa;--raised:#fff;--border:#ded9ea;--muted:#68647a;--primary:#6a0af0;--accent:#d2b3ff;--code:#15131e;--code-text:#eae9fc;--get:#15966c;--post:#2563eb;--put:#b7791f;--patch:#7c3aed;--delete:#dc2626;--shadow:0 1px 2px rgba(106,10,240,.05),0 12px 32px rgba(4,3,22,.08);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color-scheme:light}
|
|
2
|
+
:root[data-theme=dark]{--text:#eae9fc;--background:#010104;--surface:#11101c;--raised:#19182b;--border:#322b48;--muted:#aaa6bb;--primary:#9d65f7;--accent:#ae80f2;--code:#09080f;--code-text:#f1efff;--get:#34d399;--post:#60a5fa;--put:#fbbf24;--patch:#c4b5fd;--delete:#f87171;color-scheme:dark}
|
|
3
|
+
*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:calc(var(--header) + 18px)}body{margin:0;background:var(--background);color:var(--text);font-size:14px;line-height:1.55}.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.skip-link{position:fixed;z-index:1000;top:8px;left:8px;padding:10px 14px;background:var(--primary);color:#fff;border-radius:8px;transform:translateY(-150%)}.skip-link:focus{transform:none}.portal-header{position:fixed;z-index:100;inset:0 0 auto;display:flex;height:var(--header);align-items:center;justify-content:space-between;padding:0 24px;background:color-mix(in srgb,var(--raised) 92%,transparent);border-bottom:1px solid var(--border);backdrop-filter:blur(14px)}.brand{display:flex;align-items:center;gap:10px;color:var(--text);font-weight:700;text-decoration:none}.brand-mark{display:grid;width:34px;height:34px;place-items:center;border-radius:10px;background:linear-gradient(145deg,var(--primary),var(--accent));color:#fff}.brand-product{padding:2px 7px;border-radius:999px;background:color-mix(in srgb,var(--primary) 12%,var(--background));color:var(--primary);font-size:11px}.header-actions{display:flex;gap:8px}.header-button,.icon-button{height:36px;border:1px solid var(--border);border-radius:9px;background:var(--raised);color:var(--text);cursor:pointer}.header-button{display:flex;align-items:center;gap:14px;padding:0 10px}.header-button kbd{color:var(--muted)}.icon-button{width:38px}.menu-toggle{display:none}.docs-layout{display:grid;grid-template-columns:var(--sidebar) minmax(0,1fr);padding-top:var(--header)}.docs-sidebar{position:fixed;z-index:50;top:var(--header);bottom:0;left:0;width:var(--sidebar);overflow:auto;padding:18px 14px;background:var(--surface);border-right:1px solid var(--border)}.sidebar-search input{width:100%;height:40px;padding:0 12px;border:1px solid var(--border);border-radius:9px;background:var(--raised);color:var(--text);outline:none}.sidebar-search input:focus{border-color:var(--primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 18%,transparent)}.search-status{min-height:20px;margin:5px 3px;color:var(--muted);font-size:12px}.tag-list,.tag-list ul{padding:0;margin:0;list-style:none}.tag-nav{margin:4px 0}.tag-nav summary{padding:9px 8px;border-radius:8px;cursor:pointer;font-weight:700}.tag-nav summary:hover{background:var(--raised)}.tag-nav ul{margin:2px 0 9px}.tag-nav a{display:flex;align-items:flex-start;gap:8px;padding:7px 8px;border-radius:7px;color:var(--muted);font-size:12px;line-height:1.35;text-decoration:none}.tag-nav a:hover,.tag-nav a.active{background:color-mix(in srgb,var(--primary) 11%,var(--raised));color:var(--text)}.nav-method{min-width:39px;font-size:9px;font-weight:800}.method-get{color:var(--get)}.method-post{color:var(--post)}.method-put{color:var(--put)}.method-patch{color:var(--patch)}.method-delete{color:var(--delete)}main{grid-column:2;min-width:0}.api-introduction{max-width:1040px;padding:64px 46px 42px;margin:auto}.eyebrow{color:var(--primary);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.08em}h1{margin:8px 0 14px;font-size:42px;line-height:1.08}h2{font-size:27px}h3{font-size:20px}h4{margin:27px 0 11px;font-size:14px}.prose p{max-width:760px;color:var(--muted)}.tag-header{max-width:1040px;padding:18px 46px 8px;margin:auto}.operation-card{max-width:1120px;margin:18px auto 28px;background:var(--raised);border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow);overflow:hidden}.operation-header{position:relative;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:12px;padding:20px 24px;border-bottom:1px solid var(--border)}.operation-header h3{grid-column:1/3;margin:4px 0 0}.http-method{font-size:12px;font-weight:800}.operation-path{overflow-wrap:anywhere;color:var(--text);font-size:14px}.anchor-link{grid-row:1/3;grid-column:3;color:var(--muted);text-decoration:none}.operation-body{display:grid;grid-template-columns:minmax(0,60%) minmax(320px,40%)}.operation-description{padding:24px}.code-panel{min-width:0;padding:24px;background:var(--code);color:var(--code-text)}.code-panel h4{margin-top:0}.servers{display:grid;grid-template-columns:auto 1fr;gap:6px 12px}.servers h4{grid-column:1/-1}.servers span{color:var(--muted)}.table-wrap{overflow:auto}table{width:100%;border-collapse:collapse}th,td{padding:11px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--border)}th{color:var(--muted);font-size:11px;text-transform:uppercase}.required{display:inline-block;margin-left:7px;color:var(--delete);font-size:9px;text-transform:uppercase}.media-type{display:inline-block;margin-bottom:8px;color:var(--muted);font-size:12px}.schema-tree{margin:7px 0 13px;border:1px solid var(--border);border-radius:9px;background:var(--surface)}.schema-tree summary{padding:10px 12px;cursor:pointer;font-weight:700}.schema-tree summary span{margin-left:7px;color:var(--muted);font-weight:400}.schema-tree ul{padding-left:24px;margin:0 10px 10px;list-style:none}.schema-tree li{position:relative;padding:6px 0;border-left:1px solid var(--border)}.schema-row{display:flex;flex-wrap:wrap;align-items:center;gap:7px;padding-left:10px}.schema-type,.schema-ref{color:var(--primary);font-size:11px}.schema-tree p{padding-left:10px;margin:3px 0;color:var(--muted);font-size:12px}.schema-recursive{font-style:italic}.tabs>.tab-list{display:flex;gap:3px;overflow:auto;border-bottom:1px solid var(--border)}[role=tab]{padding:8px 10px;border:0;border-bottom:2px solid transparent;background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:12px}[role=tab][aria-selected=true]{border-color:var(--primary);color:var(--primary)}[role=tabpanel]{position:relative;padding-top:12px}.code-panel .tab-list{border-color:#363243}.code-panel [role=tab][aria-selected=true]{color:#d8bdff}.copy-button{position:absolute;z-index:2;top:20px;right:7px;padding:5px 8px;border:1px solid #454052;border-radius:6px;background:#24212e;color:#fff;cursor:pointer}pre{overflow:auto;padding:14px;border-radius:8px;background:var(--code);color:var(--code-text);font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.code-panel pre{padding-top:40px;margin:0}.example{max-height:360px}.status-success{color:var(--get)}.status-error{color:var(--delete)}.hll{background:#49483e}.c,.cm,.c1{color:#8292a2}.k,.kd,.kn{color:#c792ea}.s,.s1,.s2{color:#c3e88d}.mi,.mf{color:#f78c6c}.nf,.nb{color:#82aaff}.o{color:#89ddff}[hidden]{display:none!important}.operation-card.search-hidden,.tag-section.search-hidden,.tag-nav.search-hidden{display:none}.copy-status{position:fixed}button:focus-visible,a:focus-visible,input:focus-visible,summary:focus-visible{outline:3px solid color-mix(in srgb,var(--primary) 45%,transparent);outline-offset:2px}
|
|
4
|
+
@media(max-width:1100px){.operation-card{margin-right:18px;margin-left:18px}.operation-body{grid-template-columns:1fr}.code-panel{min-width:0}}
|
|
5
|
+
@media(max-width:760px){:root{--header:58px}.portal-header{padding:0 12px}.search-shortcut{display:none}.menu-toggle{display:block}.docs-layout{display:block}.docs-sidebar{visibility:hidden;width:min(88vw,330px);transform:translateX(-100%);transition:.2s ease}.menu-open .docs-sidebar{visibility:visible;transform:none}.menu-open:after{position:fixed;z-index:40;inset:var(--header) 0 0;content:"";background:rgba(0,0,0,.35)}main{width:100%}.api-introduction,.tag-header{padding-right:18px;padding-left:18px}h1{font-size:34px}.operation-card{margin:14px 0;border-right:0;border-left:0;border-radius:0}.operation-header,.operation-description,.code-panel{padding:18px}.operation-body{display:block}}
|
|
6
|
+
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.docs-sidebar{transition:none}}@media print{.portal-header,.docs-sidebar,.copy-button{display:none!important}.docs-layout{display:block;padding:0}main{display:block}.operation-card{break-inside:avoid;box-shadow:none}.code-panel{background:#fff;color:#000}}
|
|
7
|
+
|
|
8
|
+
/* Iconography and environment controls. SVG paths follow Lucide's 24px outline conventions. */
|
|
9
|
+
.header-button svg,.icon-button svg,.server-picker svg,.server-context svg,.anchor-link svg,.copy-button svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
|
|
10
|
+
.moon,:root[data-theme=dark] .sun{display:none}:root[data-theme=dark] .moon{display:block}
|
|
11
|
+
.server-picker{position:relative;display:flex;height:36px;max-width:310px;align-items:center;gap:8px;padding:0 31px 0 10px;color:var(--muted);background:var(--raised);border:1px solid var(--border);border-radius:9px}
|
|
12
|
+
.server-picker:focus-within{border-color:var(--primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 18%,transparent)}
|
|
13
|
+
.server-picker>svg:first-child{flex:0 0 auto;color:var(--primary)}.server-picker .chevron{position:absolute;right:9px;width:14px;pointer-events:none}
|
|
14
|
+
.server-picker select{min-width:0;max-width:245px;appearance:none;color:var(--text);background:transparent;border:0;outline:0;font:inherit;font-size:12px;cursor:pointer;text-overflow:ellipsis}
|
|
15
|
+
.server-context{display:grid;grid-template-columns:20px auto minmax(0,1fr);align-items:center;gap:8px;margin:18px 0;padding:10px 12px;background:var(--surface);border:1px solid var(--border);border-radius:9px}
|
|
16
|
+
.server-context svg{color:var(--primary)}.server-context span{color:var(--muted);font-size:11px;font-weight:700;text-transform:uppercase}.server-context code{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
17
|
+
.anchor-link{display:grid;width:30px;height:30px;place-items:center;border-radius:7px}.anchor-link:hover{color:var(--primary);background:var(--surface)}
|
|
18
|
+
.copy-button{display:grid;width:32px;height:32px;place-items:center}.copy-button svg{width:16px;height:16px}.copy-button.copied{color:#86efac}
|
|
19
|
+
.code-panel [role=tab][data-language-icon]{display:inline-flex;align-items:center;gap:7px}.code-panel [role=tab][data-language-icon]::before{width:18px;height:18px;flex:0 0 18px;content:"";background-position:center;background-size:contain;background-repeat:no-repeat}
|
|
20
|
+
@media(max-width:900px){.server-picker{max-width:220px}.server-picker select{max-width:155px}}
|
|
21
|
+
@media(max-width:760px){.server-picker{max-width:155px}.server-picker select{max-width:92px}.server-picker>svg:first-child{display:none}.server-picker{padding-left:8px}.header-actions{gap:5px}}
|
|
22
|
+
|
|
23
|
+
/* Typography design system extracted from the approved Redoc + Nada cascade. */
|
|
24
|
+
:root{
|
|
25
|
+
--type-sans:Inter,ui-sans-serif,system-ui,sans-serif;
|
|
26
|
+
--type-mono:"JetBrains Mono",ui-monospace,monospace;
|
|
27
|
+
--type-display-size:clamp(32px,4vw,48px);
|
|
28
|
+
--type-display-leading:1.08;
|
|
29
|
+
--type-section-size:25px;
|
|
30
|
+
--type-section-leading:1.3;
|
|
31
|
+
--type-operation-size:20px;
|
|
32
|
+
--type-operation-leading:1.4;
|
|
33
|
+
--type-subheading-size:15px;
|
|
34
|
+
--type-subheading-leading:1.4;
|
|
35
|
+
--type-body-size:14px;
|
|
36
|
+
--type-body-leading:1.65;
|
|
37
|
+
--type-control-size:13px;
|
|
38
|
+
--type-control-leading:20px;
|
|
39
|
+
--type-meta-size:12px;
|
|
40
|
+
--type-meta-leading:1.5;
|
|
41
|
+
--type-label-size:11px;
|
|
42
|
+
--type-code-size:13px;
|
|
43
|
+
--type-code-leading:1.6;
|
|
44
|
+
--type-weight-regular:400;
|
|
45
|
+
--type-weight-medium:500;
|
|
46
|
+
--type-weight-semibold:600;
|
|
47
|
+
--type-weight-bold:700;
|
|
48
|
+
--type-heading-tracking:-.025em;
|
|
49
|
+
--type-label-tracking:.04em;
|
|
50
|
+
--type-method-tracking:.02em;
|
|
51
|
+
}
|
|
52
|
+
body{font-family:var(--type-sans);font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:var(--type-body-leading);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
|
53
|
+
button,input,select{font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit}code,pre{font-family:var(--type-mono)}
|
|
54
|
+
.brand{font-size:15px;font-weight:var(--type-weight-bold);line-height:1}.brand-mark{font-size:16px}.brand-product{font-weight:var(--type-weight-medium)}
|
|
55
|
+
.header-button,.server-picker select{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:1.4}.header-button kbd{font-size:var(--type-label-size);font-weight:var(--type-weight-regular)}
|
|
56
|
+
.tag-nav summary{font-size:var(--type-label-size);font-weight:var(--type-weight-bold);line-height:20px;letter-spacing:var(--type-label-tracking);text-transform:uppercase}.tag-nav a{font-size:var(--type-control-size);font-weight:var(--type-weight-regular);line-height:1.5}.tag-nav a.active{font-weight:var(--type-weight-bold)}.nav-method{font-size:10px;font-weight:var(--type-weight-bold);line-height:1.5;letter-spacing:var(--type-method-tracking)}
|
|
57
|
+
h1,h2,h3,h4{font-family:var(--type-sans);font-weight:var(--type-weight-regular);letter-spacing:var(--type-heading-tracking)}
|
|
58
|
+
h1{font-size:var(--type-display-size);line-height:var(--type-display-leading)}h2{font-size:var(--type-section-size);line-height:var(--type-section-leading)}h3,.operation-header h3{font-size:var(--type-operation-size);line-height:var(--type-operation-leading)}
|
|
59
|
+
.http-method{font-size:var(--type-meta-size);font-weight:var(--type-weight-bold);line-height:1.5;letter-spacing:var(--type-method-tracking)}.operation-path{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:1.5}
|
|
60
|
+
.prose,.operation-description p,.operation-description li,.operation-description td{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:var(--type-body-leading)}
|
|
61
|
+
.operation-description>section>h4,.responses>h4,.code-panel h4{font-size:var(--type-subheading-size);font-weight:var(--type-weight-regular);line-height:var(--type-subheading-leading)}
|
|
62
|
+
th{font-size:var(--type-label-size);font-weight:var(--type-weight-bold);line-height:1.5;letter-spacing:var(--type-label-tracking)}td{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:var(--type-body-leading)}
|
|
63
|
+
.required{font-size:10px;font-weight:var(--type-weight-bold);line-height:1.5;letter-spacing:var(--type-method-tracking)}.media-type,.schema-tree p{font-size:var(--type-meta-size);font-weight:var(--type-weight-regular);line-height:var(--type-meta-leading)}
|
|
64
|
+
.schema-tree summary{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:1.5}.schema-row{font-size:var(--type-body-size);font-weight:var(--type-weight-regular);line-height:1.5}.property-name{font-weight:var(--type-weight-semibold)}.schema-type,.schema-ref{font-size:var(--type-meta-size);font-weight:var(--type-weight-regular);line-height:var(--type-meta-leading)}
|
|
65
|
+
.tabs [role=tab]{font-size:var(--type-control-size);font-weight:var(--type-weight-semibold);line-height:var(--type-control-leading)}.code-panel pre{font-size:var(--type-code-size);font-weight:var(--type-weight-regular);line-height:var(--type-code-leading)}.copy-button{font-size:var(--type-control-size);font-weight:var(--type-weight-medium);line-height:var(--type-control-leading)}
|
|
66
|
+
@media(max-width:760px){:root{--type-display-size:32px}}
|
|
67
|
+
|
|
68
|
+
/* Recursive response-schema disclosure with Lucide chevron-right indicators. */
|
|
69
|
+
.schema-tree summary{display:flex;align-items:center;gap:6px;list-style:none;cursor:pointer}.schema-tree summary::-webkit-details-marker{display:none}.schema-tree summary::marker{content:""}
|
|
70
|
+
.schema-chevron{width:14px;height:14px;flex:0 0 14px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s ease}
|
|
71
|
+
.schema-tree details[open]>summary>.schema-chevron{transform:rotate(90deg)}
|
|
72
|
+
.schema-root-leaf{padding:10px 12px}.schema-root-label{display:inline-flex;align-items:center;gap:7px;font-weight:var(--type-weight-regular)}.schema-root-label>span{font-weight:var(--type-weight-regular)}.schema-root-content{padding-left:20px}
|
|
73
|
+
.schema-node>details>summary{padding:6px 0}.schema-node>details>summary>.schema-row{padding-left:0}.schema-node-content{padding-left:20px}.schema-leaf>.schema-row{padding-top:6px;padding-bottom:6px}
|
|
74
|
+
@media(prefers-reduced-motion:reduce){.schema-chevron{transition:none}}
|
|
75
|
+
|
|
76
|
+
/* Original portal glass surface and brand treatment, adapted to the fixed renderer shell. */
|
|
77
|
+
.portal-header{gap:36px;color:var(--text);background:rgba(255,255,255,.22);border:1px solid rgba(255,255,255,.42);border-radius:0;box-shadow:0 18px 48px -12px rgba(15,23,42,.28);backdrop-filter:blur(18px) saturate(190%);-webkit-backdrop-filter:blur(18px) saturate(190%)}
|
|
78
|
+
:root[data-theme=dark] .portal-header{background:rgba(25,24,43,.4);border-color:rgba(234,233,252,.16)}
|
|
79
|
+
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.portal-header{background:rgba(255,255,255,.48)}:root[data-theme=dark] .portal-header{background:rgba(25,24,43,.88)}}
|
|
80
|
+
.brand{gap:9px;color:inherit;white-space:nowrap}.brand-mark{width:30px;height:30px;color:#fbfbfe;background:linear-gradient(135deg,var(--primary),var(--accent));border-radius:9px;box-shadow:0 6px 18px color-mix(in srgb,var(--primary) 28%,transparent)}
|
|
81
|
+
.brand-product{padding:0 0 0 9px;color:var(--muted);background:transparent;border-left:1px solid var(--border);border-radius:0}
|
|
82
|
+
.header-actions{align-items:center;margin-left:auto}
|
|
83
|
+
|
|
84
|
+
/* Lucide chevron-right for sidebar group headers: right aligned and animated to down when open. */
|
|
85
|
+
.tag-nav summary{display:flex;align-items:center;justify-content:space-between;gap:8px;list-style:none}.tag-nav summary::-webkit-details-marker{display:none}.tag-nav summary::marker{content:""}
|
|
86
|
+
.menu-chevron{width:14px;height:14px;flex:0 0 14px;margin-left:auto;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .18s ease}
|
|
87
|
+
.tag-nav details[open]>summary .menu-chevron{transform:rotate(90deg)}
|
|
88
|
+
@media(prefers-reduced-motion:reduce){.menu-chevron{transition:none}}
|
|
89
|
+
|
|
90
|
+
/* Sidebar operation rows: summary left with ellipsis, HTTP method fixed and right aligned. */
|
|
91
|
+
.tag-nav a{min-width:0;align-items:center}.nav-operation-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nav-method{min-width:40px;margin-left:auto;flex:0 0 40px;text-align:right}
|
|
92
|
+
|
|
93
|
+
/* Low-glare code palette: a soft editor surface in light mode, dark canvas only in dark mode. */
|
|
94
|
+
:root{--code:#f6f4fa;--code-text:#29263a;--code-border:#ddd8e8;--code-header:#eeebf4;--code-control:#e8e3f0;--code-control-text:#3f3955}
|
|
95
|
+
:root[data-theme=dark]{--code:#09080f;--code-text:#f1efff;--code-border:#363243;--code-header:#191622;--code-control:#24212e;--code-control-text:#fff}
|
|
96
|
+
.code-panel{background:var(--code);color:var(--code-text);border-left:1px solid var(--code-border)}.code-panel .tab-list{background:var(--code-header);border-color:var(--code-border)}
|
|
97
|
+
.copy-button{color:var(--code-control-text);background:var(--code-control);border-color:var(--code-border)}.code-panel [role=tab][aria-selected=true]{color:var(--primary)}
|
|
98
|
+
.code-panel pre,pre.example{background:var(--code);color:var(--code-text)}
|
|
99
|
+
.code-panel .c,.code-panel .cm,.code-panel .c1{color:#64748b}.code-panel .k,.code-panel .kd,.code-panel .kn{color:#6d28d9}.code-panel .s,.code-panel .s1,.code-panel .s2{color:#15803d}.code-panel .mi,.code-panel .mf{color:#0369a1}.code-panel .nf,.code-panel .nb{color:#1d4ed8}.code-panel .o{color:#9a3412}
|
|
100
|
+
:root[data-theme=dark] .code-panel .c,:root[data-theme=dark] .code-panel .cm,:root[data-theme=dark] .code-panel .c1{color:#8292a2}:root[data-theme=dark] .code-panel .k,:root[data-theme=dark] .code-panel .kd,:root[data-theme=dark] .code-panel .kn{color:#c792ea}:root[data-theme=dark] .code-panel .s,:root[data-theme=dark] .code-panel .s1,:root[data-theme=dark] .code-panel .s2{color:#c3e88d}:root[data-theme=dark] .code-panel .mi,:root[data-theme=dark] .code-panel .mf{color:#f78c6c}:root[data-theme=dark] .code-panel .nf,:root[data-theme=dark] .code-panel .nb{color:#82aaff}:root[data-theme=dark] .code-panel .o{color:#89ddff}
|
|
101
|
+
|
|
102
|
+
/* Content-sized sticky request samples, bounded by the matching operation content column. */
|
|
103
|
+
.operation-card{overflow:visible}.operation-header{border-radius:14px 14px 0 0}.operation-body{align-items:start}.operation-description{min-width:0}
|
|
104
|
+
.code-panel{position:sticky;top:calc(var(--header) + 16px);align-self:start;width:100%;height:max-content;max-height:calc(100vh - var(--header) - 32px);overflow:auto;border-radius:0 0 14px 0}
|
|
105
|
+
@media(max-width:1100px){.operation-card{overflow:hidden}.code-panel{position:static;max-height:none;overflow:visible;border-radius:0 0 14px 14px}}
|
|
106
|
+
@media(max-width:760px){.portal-header{gap:8px}.brand>span:not(.brand-mark){display:none}.server-picker{width:auto;height:44px;max-width:108px;padding-right:24px}.server-picker select{width:74px;max-width:74px}.server-picker .chevron{right:6px}.icon-button{width:44px;height:44px}.header-actions{min-width:0}.theme-toggle,.menu-toggle{flex:0 0 44px}}
|
|
107
|
+
:root{--get:#0f7654;--delete:#b91c1c;--danger:#b91c1c;--danger-soft:#fef2f2}
|
|
108
|
+
:root[data-theme=dark]{--get:#34d399;--danger:#f87171;--danger-soft:#2b1117}
|
|
109
|
+
.environment-warning{padding:4px 7px;color:var(--danger);background:var(--danger-soft);border:1px solid color-mix(in srgb,var(--danger) 30%,transparent);border-radius:7px;font-size:11px;font-weight:700;text-transform:uppercase}
|
|
110
|
+
.server-picker.is-production{color:var(--danger);background:var(--danger-soft);border-color:var(--danger)}.server-picker.is-production>svg:first-child{color:var(--danger)}
|
|
111
|
+
.operation-header{grid-template-columns:auto minmax(0,1fr) auto auto}.operation-header h3{grid-column:1/3}.operation-toggle{display:grid;width:40px;height:40px;padding:0;place-items:center;color:var(--muted);background:transparent;border:0;border-radius:8px;cursor:pointer}.operation-toggle:hover{color:var(--primary);background:var(--surface)}.operation-toggle svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s ease}.operation-toggle[aria-expanded=true] svg{transform:rotate(90deg)}
|
|
112
|
+
.operation-body[hidden]{display:none}.operation-card:has(.operation-body[hidden]){margin-bottom:12px;box-shadow:none}.operation-card:has(.operation-body[hidden]) .operation-header{border-bottom:0;border-radius:14px}
|
|
113
|
+
.anchor-link,.copy-button{width:40px;height:40px}.status-success,.method-get,.nav-method.method-get{color:var(--get)}
|
|
114
|
+
@media(max-width:760px){.environment-warning{display:none}.operation-header{grid-template-columns:auto minmax(0,1fr) auto auto;padding:16px 12px;gap:8px}.operation-header h3{grid-column:1/5}.anchor-link,.operation-toggle,.copy-button{width:44px;height:44px}}
|
|
115
|
+
@media(prefers-reduced-motion:reduce){.operation-toggle svg{transition:none}}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
'use strict';
|
|
3
|
+
const root = document.documentElement;
|
|
4
|
+
const themeButton = document.querySelector('.theme-toggle');
|
|
5
|
+
const themeMeta = document.querySelector('meta[name="theme-color"]');
|
|
6
|
+
const storageKey = 'nadoc-theme';
|
|
7
|
+
const storedTheme = () => { try { return localStorage.getItem(storageKey); } catch (_) { return null; } };
|
|
8
|
+
const preferredTheme = () => storedTheme() || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
|
9
|
+
const setTheme = (theme, persist = false) => {
|
|
10
|
+
root.dataset.theme = theme; root.style.colorScheme = theme;
|
|
11
|
+
themeButton?.setAttribute('aria-label', `Use ${theme === 'dark' ? 'light' : 'dark'} mode`);
|
|
12
|
+
themeMeta?.setAttribute('content', theme === 'dark' ? '#010104' : '#fbfbfe');
|
|
13
|
+
if (persist) try { localStorage.setItem(storageKey, theme); } catch (_) { /* storage disabled */ }
|
|
14
|
+
};
|
|
15
|
+
setTheme(preferredTheme());
|
|
16
|
+
themeButton?.addEventListener('click', () => setTheme(root.dataset.theme === 'dark' ? 'light' : 'dark', true));
|
|
17
|
+
matchMedia('(prefers-color-scheme: dark)').addEventListener?.('change', event => { if (!storedTheme()) setTheme(event.matches ? 'dark' : 'light'); });
|
|
18
|
+
|
|
19
|
+
const search = document.getElementById('operation-search');
|
|
20
|
+
const searchStatus = document.querySelector('.search-status');
|
|
21
|
+
const operations = Array.from(document.querySelectorAll('.operation-card'));
|
|
22
|
+
const searchStorageKey = 'nadoc-search';
|
|
23
|
+
const applySearch = () => {
|
|
24
|
+
const query = (search?.value || '').trim().toLowerCase(); let visible = 0;
|
|
25
|
+
operations.forEach(operation => { const matches = !query || operation.dataset.search.toLowerCase().includes(query) || operation.textContent.toLowerCase().includes(query); operation.classList.toggle('search-hidden', !matches); if (matches) visible += 1; });
|
|
26
|
+
document.querySelectorAll('.tag-section').forEach(section => section.classList.toggle('search-hidden', !section.querySelector('.operation-card:not(.search-hidden)')));
|
|
27
|
+
document.querySelectorAll('.tag-nav').forEach(tag => { const shown = Array.from(tag.querySelectorAll('[data-operation-link]')).some(item => !document.getElementById(item.dataset.operationLink)?.classList.contains('search-hidden')); tag.classList.toggle('search-hidden', !shown); if (query && shown) tag.querySelector('details').open = true; });
|
|
28
|
+
if (searchStatus) searchStatus.textContent = query ? `${visible} operation${visible === 1 ? '' : 's'} found` : '';
|
|
29
|
+
try { sessionStorage.setItem(searchStorageKey, query); } catch (_) { /* storage disabled */ }
|
|
30
|
+
};
|
|
31
|
+
search?.addEventListener('input', applySearch);
|
|
32
|
+
try { if (search) search.value = sessionStorage.getItem(searchStorageKey) || ''; } catch (_) { /* storage disabled */ }
|
|
33
|
+
applySearch();
|
|
34
|
+
document.querySelector('.search-shortcut')?.addEventListener('click', () => search?.focus());
|
|
35
|
+
|
|
36
|
+
const serverSelect = document.getElementById('server-select');
|
|
37
|
+
const environmentWarning = document.querySelector('[data-environment-warning]');
|
|
38
|
+
let activeServer = serverSelect?.options[serverSelect.selectedIndex]?.value || '';
|
|
39
|
+
const replaceText = (scope, before, after) => {
|
|
40
|
+
if (!before || before === after) return;
|
|
41
|
+
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_TEXT);
|
|
42
|
+
const nodes = [];
|
|
43
|
+
while (walker.nextNode()) nodes.push(walker.currentNode);
|
|
44
|
+
nodes.forEach(node => { node.nodeValue = node.nodeValue.replaceAll(before.replace(/\/$/, ''), after.replace(/\/$/, '')); });
|
|
45
|
+
};
|
|
46
|
+
const selectServer = () => {
|
|
47
|
+
if (!serverSelect) return;
|
|
48
|
+
const option = serverSelect.options[serverSelect.selectedIndex];
|
|
49
|
+
const nextServer = option.value;
|
|
50
|
+
const isProduction = /^prod\b/i.test(option.dataset.label || option.textContent || '');
|
|
51
|
+
serverSelect.closest('.server-picker')?.classList.toggle('is-production', isProduction);
|
|
52
|
+
if (environmentWarning) environmentWarning.hidden = !isProduction;
|
|
53
|
+
document.querySelectorAll('[data-server-url]').forEach(node => { node.textContent = nextServer; });
|
|
54
|
+
document.querySelectorAll('[data-server-label]').forEach(node => { node.textContent = option.dataset.label || 'Server'; });
|
|
55
|
+
document.querySelectorAll('[data-code-sample]').forEach(code => replaceText(code, activeServer, nextServer));
|
|
56
|
+
activeServer = nextServer;
|
|
57
|
+
try { localStorage.setItem('nadoc-server', nextServer); } catch (_) { /* storage disabled */ }
|
|
58
|
+
};
|
|
59
|
+
if (serverSelect) {
|
|
60
|
+
try {
|
|
61
|
+
const storedServer = localStorage.getItem('nadoc-server');
|
|
62
|
+
if (storedServer && Array.from(serverSelect.options).some(option => option.value === storedServer)) serverSelect.value = storedServer;
|
|
63
|
+
} catch (_) { /* storage disabled */ }
|
|
64
|
+
serverSelect.addEventListener('change', selectServer);
|
|
65
|
+
selectServer();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
document.querySelectorAll('[data-tabs]').forEach(tabs => {
|
|
69
|
+
const buttons = Array.from(tabs.querySelector('[role=tablist]')?.querySelectorAll('[role=tab]') || []);
|
|
70
|
+
const activate = button => buttons.forEach(candidate => { const selected = candidate === button; candidate.setAttribute('aria-selected', String(selected)); candidate.tabIndex = selected ? 0 : -1; document.getElementById(candidate.getAttribute('aria-controls')).hidden = !selected; });
|
|
71
|
+
const isCodeTabs = Boolean(tabs.closest('.code-panel'));
|
|
72
|
+
if (isCodeTabs) {
|
|
73
|
+
try {
|
|
74
|
+
const preferred = localStorage.getItem('nadoc-language');
|
|
75
|
+
const preferredButton = buttons.find(button => button.textContent.trim() === preferred);
|
|
76
|
+
if (preferredButton) activate(preferredButton);
|
|
77
|
+
} catch (_) { /* storage disabled */ }
|
|
78
|
+
}
|
|
79
|
+
buttons.forEach((button, index) => { button.addEventListener('click', () => { activate(button); if (isCodeTabs) try { localStorage.setItem('nadoc-language', button.textContent.trim()); } catch (_) { /* storage disabled */ } }); button.addEventListener('keydown', event => { let target = null; if (event.key === 'ArrowRight') target = buttons[(index + 1) % buttons.length]; if (event.key === 'ArrowLeft') target = buttons[(index - 1 + buttons.length) % buttons.length]; if (event.key === 'Home') target = buttons[0]; if (event.key === 'End') target = buttons[buttons.length - 1]; if (target) { event.preventDefault(); activate(target); target.focus(); if (isCodeTabs) try { localStorage.setItem('nadoc-language', target.textContent.trim()); } catch (_) { /* storage disabled */ } } }); });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const setOperationExpanded = (operation, expanded) => {
|
|
83
|
+
const body = operation.querySelector('.operation-body');
|
|
84
|
+
const button = operation.querySelector('.operation-toggle');
|
|
85
|
+
if (!body || !button) return;
|
|
86
|
+
body.hidden = !expanded;
|
|
87
|
+
button.setAttribute('aria-expanded', String(expanded));
|
|
88
|
+
button.querySelector('.sr-only').textContent = `${expanded ? 'Hide' : 'Show'} details for ${operation.querySelector('h3')?.textContent || 'operation'}`;
|
|
89
|
+
};
|
|
90
|
+
operations.forEach(operation => {
|
|
91
|
+
setOperationExpanded(operation, false);
|
|
92
|
+
operation.querySelector('.operation-toggle')?.addEventListener('click', () => setOperationExpanded(operation, operation.querySelector('.operation-body')?.hidden));
|
|
93
|
+
});
|
|
94
|
+
const revealHashOperation = () => {
|
|
95
|
+
if (!location.hash) return;
|
|
96
|
+
const operation = document.getElementById(location.hash.slice(1));
|
|
97
|
+
if (!operation?.classList.contains('operation-card')) return;
|
|
98
|
+
setOperationExpanded(operation, true);
|
|
99
|
+
requestAnimationFrame(() => requestAnimationFrame(() => operation.scrollIntoView({ behavior: 'instant', block: 'start' })));
|
|
100
|
+
};
|
|
101
|
+
document.querySelectorAll('[data-operation-link] a,.anchor-link').forEach(link => link.addEventListener('click', () => {
|
|
102
|
+
const operation = document.querySelector(link.getAttribute('href'));
|
|
103
|
+
if (operation) setOperationExpanded(operation, true);
|
|
104
|
+
}));
|
|
105
|
+
addEventListener('hashchange', revealHashOperation);
|
|
106
|
+
setTimeout(revealHashOperation, 0);
|
|
107
|
+
|
|
108
|
+
const live = document.querySelector('.copy-status');
|
|
109
|
+
document.addEventListener('click', async event => { const button = event.target.closest('[data-copy]'); if (!button) return; const source = button.parentElement.querySelector('code')?.textContent || ''; try { await navigator.clipboard.writeText(source); button.classList.add('copied'); button.setAttribute('aria-label', 'Copied'); button.title = 'Copied'; if (live) live.textContent = 'Code copied to clipboard'; setTimeout(() => { button.classList.remove('copied'); button.setAttribute('aria-label', 'Copy code'); button.title = 'Copy code'; }, 1400); } catch (_) { if (live) live.textContent = 'Unable to copy code'; } });
|
|
110
|
+
|
|
111
|
+
const menuButton = document.querySelector('.menu-toggle');
|
|
112
|
+
const sidebar = document.querySelector('.docs-sidebar');
|
|
113
|
+
const toggleMenu = (open, restoreFocus = false) => {
|
|
114
|
+
root.classList.toggle('menu-open', open);
|
|
115
|
+
menuButton?.setAttribute('aria-expanded', String(open));
|
|
116
|
+
if (!open && restoreFocus) menuButton?.focus();
|
|
117
|
+
};
|
|
118
|
+
menuButton?.addEventListener('click', () => toggleMenu(!root.classList.contains('menu-open')));
|
|
119
|
+
document.querySelector('.docs-sidebar')?.addEventListener('click', event => { if (event.target.closest('a') && matchMedia('(max-width: 760px)').matches) toggleMenu(false); });
|
|
120
|
+
document.addEventListener('click', event => { if (root.classList.contains('menu-open') && !sidebar?.contains(event.target) && !menuButton?.contains(event.target)) toggleMenu(false); });
|
|
121
|
+
document.addEventListener('keydown', event => { if (event.key === '/' && !/input|textarea|select/i.test(event.target.tagName)) { event.preventDefault(); search?.focus(); } if (event.key === 'Escape' && root.classList.contains('menu-open')) toggleMenu(false, true); });
|
|
122
|
+
|
|
123
|
+
const navLinks = new Map(Array.from(document.querySelectorAll('[data-operation-link]')).map(item => [item.dataset.operationLink, item.querySelector('a')]));
|
|
124
|
+
const observer = new IntersectionObserver(entries => { const visible = entries.filter(entry => entry.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0]; if (!visible) return; navLinks.forEach(link => link?.classList.remove('active')); navLinks.get(visible.target.id)?.classList.add('active'); }, { rootMargin: '-80px 0px -70% 0px' });
|
|
125
|
+
operations.forEach(operation => observer.observe(operation));
|
|
126
|
+
})();
|