diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..0c26029f6 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,43 @@ +name: Build documentation + +on: [push, pull_request] + +permissions: + contents: read + +# Cancel ongoing builds on new changes +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Run tasks + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + with: + python-version: "3.14" + + - name: Install uv + uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --frozen --group docs + + - name: Build documentation + run: uv run poe build-docs + + - name: Upload artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + path: doc/_build + include-hidden-files: true diff --git a/.gitignore b/.gitignore index 7e40b86ad..36026debd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ htmlcov/ .dir-locals.el .venv/ junit.xml +doc/_build/ diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css new file mode 100644 index 000000000..2253c4f22 --- /dev/null +++ b/doc/_static/css/custom.css @@ -0,0 +1,1117 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * Copyright (c) 2023-2025, The Linux Foundation. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Various tweaks to the Read the Docs theme to better conform with Zephyr's + * visual identity. Many colors are also overridden to use CSS variables. + */ + + :root { + /* Use system font stacks for better performance (no Web fonts required) */ + --system-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --header-font-family: Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif; + --monospace-font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', 'Droid Sans Mono', 'Source Code Pro', monospace; + } + +body, +h1, +h2, +h3, +h4, +h5, +h6, +input[type="text"], +input[type="button"], +input[type="reset"], +input[type="submit"], +textarea, +legend, +.btn, +.rst-content .toctree-wrapper p.caption, +.rst-versions { + font-family: var(--system-font-family); +} + +h1, +h2, +h3, +h4, +h5, +h6, +legend, +.rst-content .toctree-wrapper p.caption { + /* Use a lighter font for headers (Semi-Bold instead of Bold) */ + font-weight: 600; + font-family: var(--header-font-family); +} + +.rst-content div.figure p.caption { + /* Tweak caption styling to be closer to typical captions */ + text-align: center; + margin-top: 8px; + opacity: 0.75; +} + +.rst-content div.figure.figure-w480 { + max-width: 480px; +} + +p, +article ul, +article ol, +.wy-plain-list-disc, +.wy-plain-list-decimal, +.rst-content ol.arabic, +.rst-content .section ul, +.rst-content .toctree-wrapper ul, +.rst-content .section ol { + /* Increase the line height slightly to account for the different font */ + line-height: 25px; +} + +body, +.rst-content table.docutils thead { + color: var(--body-color); +} + +a { + color: var(--link-color); +} + +a:hover { + color: var(--link-color-hover); + text-decoration: underline; +} + +a:active { + /* Add visual feedback when clicking on a link */ + color: var(--link-color-active); +} + +a:visited { + color: var(--link-color-visited); +} + +a.btn:hover { + text-decoration: none; +} + +.sphinx-tabs .sphinx-menu a.item { + /* Original definition has `!important` */ + color: var(--link-color) !important; +} + +.rst-content .toc-backref { + color: var(--link-color); +} + +/* Style external links differently to make them easier to distinguish from internal links. */ +.reference.external { + background-position: center right; + background-repeat: no-repeat; + background-image: var(--external-reference-icon); + padding-right: 13px; +} + +hr, +#search-results .search li:first-child, +#search-results .search li { + border-color: var(--hr-color); +} + +/* JavaScript documentation directives */ +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { + background-color: var(--admonition-note-background-color); + border-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl dt { + background-color: transparent; + border-color: transparent; + color: var(--footer-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute dt { + font-weight: 600; + padding: 0 8px; + margin-bottom: 1px; + width: 100%; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method > dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute > dt { + font-family: var(--monospace-font-family); + font-variant-ligatures: none; + font-size: 90%; + font-weight: normal; + margin-bottom: 16px; + padding: 6px 8px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-prename.descclassname { + color: var(--highlight-type2-color); + font-weight: normal; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name.descname { + color: var(--highlight-function-color); + font-weight: 700; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-paren, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { + color: var(--highlight-operator-color) !important; + font-weight: normal; + padding: 0 2px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { + font-style: italic; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > em { + color: var(--code-literal-color); + font-style: normal; + padding: 0 4px; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .k { + font-style: normal; +} +html.writer-html5 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { + border-top-color: var(--highlight-background-emph-color); + background: var(--highlight-background-color); +} +html.writer-html5 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { + border-left-color: var(--highlight-background-emph-color); + background: var(--highlight-background-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > .optional ~ em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > .optional ~ em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > .optional ~ em { + color: var(--highlight-number-color); + font-style: italic; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em.property { + color: var(--highlight-keyword-color); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt a.headerlink { + color: var(--link-color) !important; +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt a.headerlink:visited { + color: var(--link-color-visited); +} +html.writer-html5 .rst-content dl.field-list > dd strong { + font-family: var(--monospace-font-family); + font-variant-ligatures: none; +} + +footer, +#search-results .context { + color: var(--footer-color); +} + +/* Icon tweaks */ +a.icon-home, +a.icon-home:visited { + color: var(--navbar-level-1-color); +} + +/* Main sections */ + +.wy-nav-content-wrap { + background-color: var(--content-wrap-background-color); +} + +.wy-nav-content { + background-color: var(--content-background-color); + min-height: 100vh; + min-height: 100dvh; + display: flex; +} + +.wy-body-for-nav { + background-color: var(--content-wrap-background-color); +} + +@media only screen and (min-width: 769px) { + .wy-nav-content { + max-width: 915px; + } +} + +/* Table display tweaks */ + +.rst-content table.docutils, +.wy-table-bordered-all td, +.rst-content table.docutils td, +.wy-table thead th, +.rst-content table.docutils thead th, +.rst-content table.field-list thead th { + border-color: var(--code-border-color); +} + +.rst-content table.docutils caption, .rst-content table.field-list caption, .wy-table caption { + color: var(--body-color); +} +.wy-table-odd td, +.wy-table-striped tr:nth-child(2n-1) td, +.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { + background-color: var(--table-row-odd-background-color); +} + +/* Override table no-wrap */ +/* The first column cells are not verbose, no need to wrap them */ +.wy-table-responsive table td:not(:nth-child(1)), +.wy-table-responsive table th:not(:nth-child(1)) { + white-space: normal; +} + +/* Allow to control wrapping behavior per table */ +.wy-table-responsive table.wrap-normal td, +.wy-table-responsive table.wrap-normal th { + white-space: normal; +} + +/* Make sure not to wrap keyboard shortcuts */ +.wy-table-responsive table td kbd { + white-space: nowrap; +} + +/* Force table content font-size in responsive tables to be 100% + * fixing larger font size for paragraphs in the kconfig tables */ + .wy-table-responsive td p { + font-size: 100%; +} + +/* Code display tweaks */ + +code, +.rst-content tt, +.rst-content code { + font-size: 14px; + background-color: var(--code-background-color); + border: 1px solid var(--code-border-color); +} + +.rst-content tt.literal, +.rst-content code.literal { + color: var(--code-literal-color); +} + +.rst-content div[class^="highlight"] { + border-color: none; + border: none; +} + +.rst-content pre.literal-block, +.rst-content div[class^="highlight"] pre, +.rst-content .linenodiv pre { + /* Increase the font size and line height in code blocks */ + font-size: 14px; + line-height: 1.5; +} + +.rst-content pre.literal-block { + border: none; + border-radius: 0.25rem; + background-color: var(--code-background-color); +} + +/* Code tab display tweaks */ + +.ui.tabular.menu .active.item, +.ui.segment, +.sphinx-tabs-panel { + background-color: var(--code-background-color) !important; +} + +.sphinx-tabs-tab { + color: var(--link-color) !important; +} + +.sphinx-tabs-tab[aria-selected="true"] { + background-color: var(--code-background-color) !important; + border-bottom: 1px solid var(--code-background-color) !important; +} + +/* Code literals */ +a.internal code.literal { + color: var(--link-color); +} + +a.internal:visited code.literal { + color: var(--link-color-visited); +} + +/* Syntax highlighting */ + +.tab div[class^='highlight']:last-child { + margin-bottom: 1em; +} + +.rst-content tt.literal, .rst-content code.literal, .highlight { + border-radius: 0.25rem; +} + +.highlight { + background-color: var(--highlight-background-color); +} + +/* Emphasized lines */ +.highlight .hll { + background-color: var(--highlight-background-emph-color); +} + +.highlight .gh /* Generic.Heading */, +.highlight .gu /* Generic.Subheading */, +.highlight .go /* Generic.Output */, +.highlight .gt /* Generic.Traceback */ { + color: var(--highlight-default-color); +} + +.highlight .c /* Comment */, +.highlight .c1 /* Comment.Single */, +.highlight .cm /* Comment.Multiline */, +.highlight .cs /* Comment.Special */ { + color: var(--highlight-comment-color); +} + +.highlight .bp /* Name.Builtin.Pseudo */, +.highlight .k /* Keyword */, +.highlight .kc /* Keyword.Constant */, +.highlight .kd /* Keyword.Declaration */, +.highlight .kn /* Keyword.Namespace */, +.highlight .kp /* Keyword.Pseudo */, +.highlight .kr /* Keyword.Reserved */, +.highlight .kt /* Keyword.Type */, +.highlight .ow /* Operator.Word */ { + color: var(--highlight-keyword-color); +} + +.highlight .ch /* Comment.Hashbang */, +.highlight .cp /* Comment.Preproc */ { + color: var(--highlight-keyword2-color); +} + +.highlight .m /* Literal.Number */, +.highlight .mf /* Literal.Number.Float */, +.highlight .mi /* Literal.Number.Integer */, +.highlight .il /* Literal.Number.Integer.Long */, +.highlight .mb /* Literal.Number.Bin */, +.highlight .mh /* Literal.Number.Hex */, +.highlight .mo /* Literal.Number.Oct */ { + color: var(--highlight-number-color); +} + +.highlight .na /* Name.Attribute */, +.highlight .nd /* Name.Decorator */, +.highlight .ni /* Name.Entity */, +.highlight .nl /* Name.Label */ { + color: var(--highlight-decorator-color); +} + +.highlight .nb /* Name.Builtin */, +.highlight .ne /* Name.Exception */ { + color: var(--highlight-type-color); +} + +.highlight .nc /* Name.Class */, +.highlight .nn /* Name.Namespace */, +.highlight .no /* Name.Constant */, +.highlight .nv /* Name.Variable */, +.highlight .vc /* Name.Variable.Class */, +.highlight .vg /* Name.Variable.Global */, +.highlight .vi /* Name.Variable.Instance */, +.highlight .vm /* Name.Variable.Magic */ { + color: var(--highlight-type2-color); +} + +.highlight .nf /* Name.Function */, +.highlight .fm /* Name.Function.Magic */, +.highlight .nt /* Name.Tag */ { + color: var(--highlight-function-color); +} + +.highlight .o /* Operator */, +.highlight .si /* Literal.String.Interpol */, +.highlight .sx /* Literal.String.Other */, +.highlight .sr /* Literal.String.Regex */, +.highlight .ss /* Literal.String.Symbol */ { + color: var(--highlight-operator-color); +} + +.highlight .cpf/* Comment.PreprocFile */, +.highlight .s /* Literal.String */, +.highlight .s1 /* Literal.String.Single */, +.highlight .s2 /* Literal.String.Double */, +.highlight .sc /* Literal.String.Char */, +.highlight .se /* Literal.String.Escape */, +.highlight .sa /* Literal.String.Affix */, +.highlight .sb /* Literal.String.Backtick */, +.highlight .dl /* Literal.String.Delimiter */, +.highlight .sd /* Literal.String.Doc */, +.highlight .sh /* Literal.String.Heredoc */ { + color: var(--highlight-string-color); +} + +/* Admonition tweaks */ + +.rst-content .admonition, +.rst-content .admonition.note, +.rst-content .admonition.seealso { + background-color: var(--admonition-note-background-color); + color: var(--admonition-note-color); + overflow: auto; +} + +.rst-content .admonition .admonition-title, +.rst-content .admonition.note .admonition-title, +.rst-content .admonition.seealso .admonition-title { + background-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-title-color); +} + +.rst-content .admonition.attention, +.rst-content .admonition.caution, +.rst-content .admonition.warning { + background-color: var(--admonition-attention-background-color); + color: var(--admonition-attention-color); + overflow: auto; +} + +.rst-content .admonition.attention .admonition-title, +.rst-content .admonition.caution .admonition-title, +.rst-content .admonition.warning .admonition-title { + background-color: var(--admonition-attention-title-background-color); + color: var(--admonition-attention-title-color); +} + +.rst-content .admonition.danger { + background-color: var(--admonition-danger-background-color); + color: var(--admonition-danger-color); + overflow: auto; +} + +.rst-content .admonition.danger .admonition-title { + background-color: var(--admonition-danger-title-background-color); + color: var(--admonition-danger-title-color); +} + +.rst-content .admonition.tip, +.rst-content .admonition.important { + background-color: var(--admonition-tip-background-color); + color: var(--admonition-tip-color); + overflow: auto; +} + +.rst-content .admonition.tip .admonition-title, +.rst-content .admonition.important .admonition-title { + background-color: var(--admonition-tip-title-background-color); + color: var(--admonition-tip-title-color); +} + +/* Admonition tweaks - sphinx_togglebutton */ + +.rst-content .admonition.toggle { + overflow: visible; +} + +.rst-content .admonition.toggle button { + display: inline-flex; + color: var(--admonition-note-title-color); +} + +.rst-content .admonition.toggle .tb-icon { + height: 1em; + width: 1em; +} + +/* Keyboard shortcuts tweaks */ +kbd, .kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > .kbd { + background-color: var(--kbd-background-color); + border: 1px solid var(--kbd-outline-color); + border-radius: 3px; + box-shadow: inset 0 -1px 0 var(--kbd-shadow-color); + color: var(--kbd-text-color); + display: inline-block; + font-size: 12px; + line-height: 11px; + padding: 4px 5px; + vertical-align: middle; +} + +/* guilabel and menuselection tweaks */ +.rst-content .guilabel, +.rst-content .menuselection { + color: var(--body-color); + background-color: var(--guiitems-background-color); + border-color: var(--guiitems-border-color); +} + +/* heading tweaks to make document hierarchy easier to grasp */ + +.rst-content section > h1 { + font-weight: 700; + margin-bottom: 2.5rem; + position: relative; + line-height: 1; + z-index: 1; +} + +.rst-content section > h1::before { + content: ''; + position: absolute; + z-index:-1; + left: 0; + right: 0; + height: 4px; + bottom: -1px; + background: linear-gradient(to right, var(--admonition-note-title-background-color), var(--admonition-note-title-background-color) 50%, var(--admonition-note-background-color) 80%, transparent); /* Example gradient */ + opacity:50%; +} + +.rst-content section > h2, +.rst-content section > h3, +.rst-content section > h4, +.rst-content section > h5 { + font-weight: 500; + padding-inline-start: 8px; + margin-inline-start: 0px; + border-inline-start: 8px solid; + padding-top: 0.2em; + padding-bottom: 0.2em; +} + +.rst-content section > h2 { + border-color: var(--admonition-note-title-background-color); +} + +.rst-content section > h3 { + border-color: var(--admonition-note-background-color); +} + +.rst-content section > h4 { + border-color: transparent; + font-weight: 400; +} + +.rst-content section > h5 { + border-color: transparent; + font-weight: 100; +} + +/* Buttons */ + +.btn-neutral { + background-color: var(--btn-neutral-background-color) !important; + color: var(--body-color) !important; +} + +.btn-neutral:hover { + background-color: var(--btn-neutral-hover-background-color) !important; +} + +.btn-neutral:visited { + color: var(--body-color) !important; +} + +/* Navigation bar logo and search */ + +.logo { + opacity: var(--logo-opacity); +} + +.wy-side-nav-search > a img.logo { + /* Fixed size to prevent reflows and support hiDPI displays */ + height: 105px; +} + +.wy-side-nav-search { + background-color: var(--navbar-background-color); +} + +.wy-side-nav-search.fixed { + position: fixed; +} + +@media only screen and (min-width: 769px) { + /* Simulate a drop shadow that only affects the bottom edge */ + /* This is used to indicate the search bar is fixed */ + .wy-side-nav-search.fixed-and-scrolled::after { + content: ''; + position: absolute; + left: 0; + bottom: -8px; + width: 300px; + height: 8px; + pointer-events: none; + background: linear-gradient(hsla(0, 0%, 0%, 0.2), transparent); + } +} + +.wy-side-nav-search > a:hover, +.wy-side-nav-search .wy-dropdown > a:hover { + background-color: var(--navbar-background-color-hover); +} + +.wy-side-nav-search > a:active, +.wy-side-nav-search .wy-dropdown > a:active { + background-color: var(--navbar-background-color-active); +} + +.wy-side-nav-search input[type=search] { + width: 100%; + border-radius: 50px; + padding: 6px 12px; + background-color: var(--input-background-color); + color: var(--body-color); + /* Avoid reflowing when toggling the focus state */ + border: 2px solid transparent; + box-shadow: none; + /* Make visual feedback instant */ + transition: none; + font-size: 14px; +} + +.wy-side-nav-search input[type="search"]:focus { + border: 2px solid var(--input-focus-border-color); +} + +.wy-side-nav-search input[type="search"]::placeholder { + color: var(--body-color); + opacity: 0.55; +} + +/* Navigation bar */ + +.wy-nav-side { + background-color: var(--navbar-background-color); +} + +.wy-menu-vertical header, +.wy-menu-vertical p.caption { + color: var(--navbar-heading-color); + + /* Improves the appearance of uppercase text */ + letter-spacing: 0.75px; +} + +/* Mobile navigation */ + +.wy-nav-top, +.wy-nav-top a { + background-color: var(--navbar-background-color); + color: var(--navbar-level-1-color); +} + +/* Version branch label below the logo */ +.wy-side-nav-search > div.version { + color: var(--navbar-level-3-color); + opacity: 0.9; +} + +/* First level of navigation items */ + +.wy-menu-vertical a { + color: var(--navbar-level-1-color); +} + +.wy-menu-vertical a:hover { + background-color: var(--navbar-background-color-hover); + color: var(--navbar-level-1-color); +} + +.wy-menu-vertical a:active { + background-color: var(--navbar-background-color-active); +} + +.wy-menu-vertical li.toctree-l1.current > a { + border: none; +} + +.wy-menu-vertical a button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a button.toctree-expand { + color: var(--navbar-level-3-color); + opacity: 0.9; + margin-right: 6px; +} + +.wy-menu-vertical a:hover button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand { + color: var(--navbar-level-2-color); + opacity: 1; +} + +.wy-menu-vertical a:active button.toctree-expand, +.wy-menu-vertical li.toctree-l2 a:active button.toctree-expand { + color: var(--navbar-level-1-color); + opacity: 1; +} + +/* Second (and higher) levels of navigation items */ + +.wy-menu-vertical li.current a { + /* Make long words always display on a single line, keep wrapping for multiple words */ + /* This fixes the class reference titles' display with very long class names */ + display: flex; +} + +.wy-menu-vertical li.current a, +.wy-menu-vertical li.toctree-l2.current > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { + background-color: var(--navbar-current-background-color); + color: var(--navbar-level-2-color); + border-color: var(--navbar-current-background-color); +} + +.wy-menu-vertical li.current a:hover, +.wy-menu-vertical li.toctree-l2.current > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, +.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:hover { + background-color: var(--navbar-current-background-color-hover); +} + +.wy-menu-vertical li.current a:active, +.wy-menu-vertical li.toctree-l2.current > a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, +.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:active { + background-color: var(--navbar-current-background-color-active); +} + +.wy-menu-vertical a { + /* This overrides 8px margin added in other multi-selector rules */ + margin-right: 0; +} + +/* Banner panel in sidebar */ +.wy-nav-side .ethical-rtd.fixed { + position: fixed; +} + +/* Version selector (only visible on Read the Docs) */ + +.rst-versions { + background-color: var(--navbar-current-background-color); +} + +.rst-versions a, +.rst-versions .rst-current-version, +.rst-versions .rst-current-version .fa, +.rst-versions .rst-other-versions dd a { + color: var(--navbar-level-1-color); +} + +.rst-versions .rst-other-versions small { + color: var(--navbar-level-3-color); +} + +.rst-versions .rst-other-versions dd a:hover { + text-decoration: underline; +} + +.rst-versions .rst-other-versions { + color: var(--navbar-heading-color); +} + +.rst-versions .rst-current-version { + background-color: var(--navbar-current-background-color); +} + +.rst-versions .rst-current-version:hover { + background-color: var(--navbar-current-background-color-hover); +} + +.rst-versions .rst-current-version:active { + background-color: var(--navbar-current-background-color-active); +} + +.rst-versions.shift-up { + overflow-y: auto; +} + +/* Hide the obnoxious automatic highlight in search results */ +.rst-content .highlighted { + background-color: transparent; + font-weight: inherit; + padding: 0; +} + +/* Allows the scrollbar to be shown in the sidebar */ +@media only screen and (min-width: 769px) { + .wy-side-scroll { + overflow: hidden; + } + + .wy-nav-side .wy-side-scroll .ethical-rtd { + width: calc(300px - 1.25em); + padding: 0 0 0 1em; + } +} +.wy-menu.wy-menu-vertical { + overflow-y: auto; + overflow-x: hidden; + max-height: calc(100% - 243px); +} +@media screen and (max-width: 768px) { + .wy-nav-side { + padding-bottom: 44px; + } + .wy-menu.wy-menu-vertical { + overflow-y: initial; + max-height: initial; + } + .wy-nav-content { + min-height: calc(100vh - 64px); + min-height: calc(100dvh - 64px); + } +} + +/* Scrollbar styling */ +.wy-menu.wy-menu-vertical { + scrollbar-color: var(--navbar-scrollbar-color) var(--navbar-scrollbar-background); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar { + width: .75rem; +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-track { + background-color: var(--navbar-scrollbar-background); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb { + background-color: var(--navbar-scrollbar-color); +} +/* Firefox does the dimming on hover automatically. We emulate it for Webkit-based browsers. */ +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:hover { + background-color: var(--navbar-scrollbar-hover-color); +} +.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:active { + background-color: var(--navbar-scrollbar-active-color); +} + +/* Misc tweaks */ + +.rst-columns { + column-width: 18em; +} + +.rst-content div.figure, .rst-content figure { + text-align: center; +} + +.wy-alert.wy-alert-danger { + background-color: var(--admonition-danger-background-color); +} + + +dark-mode-toggle::part(fieldset) { + padding-inline: 0.75rem; + padding-block: 0; +} + +dark-mode-toggle::part(darkLabel), +dark-mode-toggle::part(lightLabel), +dark-mode-toggle::part(toggleLabel){ + font-size: unset; +} + +div.graphviz > object { + filter: var(--graphviz-filter); +} + +/* Home page grid display */ +.grid { + list-style-type: none !important; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin: 1rem auto; + max-width: calc((160px + 2rem) * 4); +} + +.grid-item { + list-style-type: none !important; + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: 150px; + text-align: center; + margin: 1rem; +} + +.grid-item a { + display: block; + width: 150px; + height: 150px; + padding: 20px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-radius: 1rem; + background: linear-gradient(135deg, #0070c5 0%, #5c13a5 100%); + color: white; +} + +.grid-item h2 { + font-size: 1rem; +} + +.grid-item img { + margin-bottom: 1rem; + max-width: 75%; +} + +.grid-item a:hover { + text-decoration: none; +} + +.grid-item p { + font-size: 0.9rem; + margin-top: 0.5rem; + color: var(--body-color); + font-weight: 200; + margin-left: -0.9em; + margin-right: -0.9em; + line-height: 1.4rem; +} + +.grid-icon { + line-height: 1.5; + font-size: 3rem; + color: white; +} + +.lastupdated { + font-weight: 200; + font-size: 0.9rem; +} + +/* Make actual document take all vertical space available so that footer is always at the bottom */ + +.rst-content { + flex: 1; + display: flex; + flex-direction: column; + width: 100%; +} + +.document { + flex-grow: 1; +} + +/* Custom search box, including search engine selection */ + +.search-container { + position: relative; +} + +#search-se-settings-icon { + position: absolute; + color: var(--body-color); + right: 10px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + opacity: 0.8; +} + +#search-se-menu { + display: none; + position: absolute; + font-size: 11px; + background-color: var(--input-background-color); + color: var(--body-color); + right: 0px; + top: 36px; + border: solid 1px var(--body-color); + border-radius: 10px; + z-index: 1000; +} + +#search-se-menu ul { + list-style: none; + margin: 0; + padding: 2px; +} + +#search-se-menu ul li { + padding: 8px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1em; +} + +#search-se-menu [role="menuitemradio"]:focus { + background-color: var(--navbar-current-background-color-hover); + color: var(--navbar-level-1-color); + border-radius: 10px; +} + +#search-se-menu ul li .fa-check { + display: none; + } + + #search-se-menu ul li.selected .fa-check { + display: inline; + } + +.doxygroup::after { + content: 'Doxygen'; + display: inline-block; + background-color: var(--admonition-note-title-background-color); + color: var(--admonition-note-title-color); + padding: 2px 8px; + border-radius: 12px; + margin-left: 8px; + font-size: 0.875em; + font-weight: bold; +} + +.code-sample-list li { + margin-bottom: 0.25em; +} +.code-sample-name { + font-weight: bold; + padding-right: 0.5em; +} + +.code-sample-description { + font-weight: 300; +} + +.code-sample-description::before { + content: '\F0A9'; /* arrow-circle-right */ + font-family: 'FontAwesome'; + padding-right: 0.5em; +} + +li>a.code-sample-link.reference.internal { + font-weight: 100; +} + +li>a.code-sample-link.reference.internal.current { + text-decoration: underline; +} diff --git a/doc/_static/css/dark.css b/doc/_static/css/dark.css new file mode 100644 index 000000000..bb1c20c0b --- /dev/null +++ b/doc/_static/css/dark.css @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Dark theme colors + */ + +:root { + --body-color: rgba(255, 255, 255, 0.85); + --content-wrap-background-color: #202326; + --content-background-color: #2e3236; + /* Decrease the logo opacity when using the dark theme to be less distracting */ + --logo-opacity: 0.85; + --navbar-background-color: #25282b; + --navbar-background-color-hover: #333639; + --navbar-background-color-active: #111417; + --navbar-current-background-color: #333639; + --navbar-current-background-color-hover: #44474a; + --navbar-current-background-color-active: #222528; + --navbar-level-1-color: #ddd; + --navbar-level-2-color: #ccc; + --navbar-level-3-color: #bbb; + --navbar-heading-color: #af7fe4; + --navbar-scrollbar-color: #af7fe4; + --navbar-scrollbar-hover-color: #9454db; + --navbar-scrollbar-active-color: #7929d2; + --navbar-scrollbar-background: #1c1e21; + + --link-color: #8cf; + --link-color-hover: #9df; + --link-color-active: #6ad; + --link-color-visited: #cb99f6; + --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOGNmIj48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); + --classref-badge-text-color: hsl(0, 0%, 70%); + + --hr-color: #555; + --table-row-odd-background-color: #3b3e41; + --code-background-color: #434649; + --code-border-color: #505356; + --code-literal-color: #faa; + --input-background-color: #333537; + --input-focus-border-color: #5f8cff; + + --search-input-background-color: #43464a; /* derived from --input-background-color */ + --search-match-color: #52b4ff; /* derived from --link-color */ + --search-match-background-color: #414c56; /* derived from --link-color */ + --search-active-color: #202326; + --search-credits-background-color: #202123; /* derived from --navbar-background-color */ + --search-credits-color: #6b6b6b; /* derived from --footer-color */ + --search-credits-link-color: #628fb1; /* derived from --link-color */ + + /* Colors taken from the Godot script editor with the Adaptive theme */ + --highlight-background-color: #202531; + --highlight-background-emph-color: #2d3444; + --highlight-default-color: rgba(255, 255, 255, 0.85); + --highlight-comment-color: rgba(204, 206, 211, 0.5); + --highlight-keyword-color: #ff7085; + --highlight-keyword2-color: #42ffc2; + --highlight-number-color: #a1ffe0; + --highlight-decorator-color: #abc8ff; + --highlight-type-color: #8effda; + --highlight-type2-color: #c6ffed; + --highlight-function-color: #57b3ff; + --highlight-operator-color: #abc8ff; + --highlight-string-color: #ffeca1; + + --admonition-note-background-color: #303d4f; + --admonition-note-color: #bfeeff; + --admonition-note-title-background-color: #305070; + --admonition-note-title-color: #bfefff; + --admonition-attention-background-color: #444033; + --admonition-attention-color: #ffeeaf; + --admonition-attention-title-background-color: #665022; + --admonition-attention-title-color: #ffeeaf; + --admonition-danger-background-color: #433; + --admonition-danger-color: #fcc; + --admonition-danger-title-background-color: #633; + --admonition-danger-title-color: #fcc; + --admonition-tip-background-color: #28382d; + --admonition-tip-color: #dfd; + --admonition-tip-title-background-color: #336648; + --admonition-tip-title-color: #dfd; + + --kbd-background-color: #595b5d; + --kbd-outline-color: #3d4144; + --kbd-shadow-color: #1e2023; + --kbd-text-color: #e2f2ff; + + --guiitems-background-color: #303d4f; + --guiitems-border-color: #7fbbe3; + + --btn-neutral-background-color: #404040; + --btn-neutral-hover-background-color: #505050; + --footer-color: #aaa; + + --graphviz-filter: invert(0.9) brightness(1.2); +} diff --git a/doc/_static/css/gcs.css b/doc/_static/css/gcs.css new file mode 100644 index 000000000..165011088 --- /dev/null +++ b/doc/_static/css/gcs.css @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023, Benjamin Cabé . + * SPDX-License-Identifier: Apache-2.0 + * + * Custom stylesheet for Google Programmable Search Engine results. + */ + +.gs-webResult .gs-snippet, +.gs-fileFormatType, +.gs-spelling, +.gsc-refinementHeader, +.gsc-result-info, +.gsc-orderby-label { + color: var(--body-color) !important; +} + +.gsc-control-cse { + width: 100%; + padding: 0 !important; + font-family: inherit !important; + font-size: inherit !important; + background-color: inherit !important; + border: none !important; + font-size: inherit !important; +} + +.gsc-completion-container { + font-family: inherit !important; +} + +.gs-result .gs-title, .gs-result .gs-title * { + color: var(--link-color) !important; + background-color: var(--content-background-color) !important; +} + +.gs-result .gs-title:visited, .gs-result .gs-title:visited * { + color: var(--link-color-visited) !important; +} + +.gsc-results .gsc-cursor-box .gsc-cursor-page, +.gsc-results .gsc-cursor-box .gsc-cursor-current-page { + background-color: var(--content-background-color) !important; + color: var(--link-color) !important; +} + +.gs-result .gs-image, .gs-result .gs-promotion-image { + border: none !important; + padding-right: .5em; +} + +.gsc-table-result { + font-family: inherit !important; + padding-top: .5em !important; + font-size: inherit !important; +} + +.gsc-tabHeader.gsc-tabhActive, .gsc-refinementHeader.gsc-refinementhActive, +.gsc-tabHeader.gsc-tabhInactive, .gsc-refinementHeader.gsc-refinementhInactive { + background-color: inherit !important; +} + +.gs-no-results-result .gs-snippet, .gs-error-result .gs-snippet { + color: var(--admonition-attention-title-color) !important; + background-color: var(--admonition-attention-title-background-color) !important; +} + +.gsc-webResult .gsc-result { + background-color: inherit !important; + margin: 0; + padding: .5em 0; + border: none !important; + border-bottom: 1px solid var(--hr-color) !important; +} + +.gs-webResult div.gs-per-result-labels { + margin-top: 1.3em; + margin-bottom: 0.3em; + font-size:0.8em; +} + +.gs-webResult div.gs-per-result-labels span { + display: none; +} + +.gs-webResult div.gs-per-result-labels a.gs-label { + text-decoration: none !important; + cursor: pointer; + padding: 0.4em 0.6em; + margin-left: .5em; + color: var(--admonition-tip-title-color) !important; + background-color: var(--admonition-tip-title-background-color) !important; + border-radius: 50px; +} + +.gcsc-find-more-on-google { + color: var(--link-color) !important; +} + +.gcsc-find-more-on-google-magnifier { + fill: var(--link-color) !important; +} diff --git a/doc/_static/css/light.css b/doc/_static/css/light.css new file mode 100644 index 000000000..eb019863c --- /dev/null +++ b/doc/_static/css/light.css @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community + * Copyright (c) 2021, Teslabs Engineering S.L. + * SPDX-License-Identifier: CC-BY-3.0 + * + * Light theme colors + */ + +:root { + --body-color: #404040; + --content-wrap-background-color: #efefef; + --content-background-color: #fcfcfc; + --logo-opacity: 1.0; + --navbar-background-color: #333f67; + --navbar-background-color-hover: #29355c; + --navbar-background-color-active: #212d51; + --navbar-current-background-color: #212d51; + --navbar-current-background-color-hover: #182343; + --navbar-current-background-color-active: #131e3b; + --navbar-level-1-color: #c3e3ff; + --navbar-level-2-color: #b8d6f0; + --navbar-level-3-color: #a3c4e1; + --navbar-heading-color: #af7fe4; + --navbar-scrollbar-color: #af7fe4; + --navbar-scrollbar-hover-color: #9454db; + --navbar-scrollbar-active-color: #7929d2; + --navbar-scrollbar-background: #131e2b; + + --link-color: #237ab3; + --link-color-hover: #3091d1; + --link-color-active: #105078; + --link-color-visited: #9b59b6; + --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjk4MGI5Ij48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); + --classref-badge-text-color: hsl(0, 0%, 45%); + + --hr-color: #e1e4e5; + --table-row-odd-background-color: #f3f6f6; + --code-background-color: #fff; + --code-border-color: #e1e4e5; + --code-literal-color: #d04c60; + --input-background-color: #fcfcfc; + --input-focus-border-color: #5f8cff; + + --search-input-background-color: #e6eef3; /* derived from --input-background-color */ + --search-match-color: #2c6b96; /* derived from --link-color */ + --search-match-background-color: #e3f2fd; /* derived from --link-color */ + --search-active-color: #efefef; + --search-credits-background-color: #333f67; /* derived from --navbar-background-color */ + --search-credits-color: #b3b3b3; /* derived from --footer-color */ + --search-credits-link-color: #4392c5; /* derived from --link-color */ + + --highlight-background-color: #f0f2f4; + --highlight-background-emph-color: #dbe6c3; + --highlight-default-color: #404040; + --highlight-comment-color: #408090; + --highlight-keyword-color: #007020; + --highlight-keyword2-color: #902000; + --highlight-number-color: #208050; + --highlight-decorator-color: #4070a0; + --highlight-type-color: #007020; + --highlight-type2-color: #0e84b5; + --highlight-function-color: #06287e; + --highlight-operator-color: #666666; + --highlight-string-color: #4070a0; + + --admonition-note-background-color: #e7f2fa; + --admonition-note-color: #404040; + --admonition-note-title-background-color: #6ab0de; + --admonition-note-title-color: #fff; + --admonition-attention-background-color: #ffedcc; + --admonition-attention-color: #404040; + --admonition-attention-title-background-color: #f0b37e; + --admonition-attention-title-color: #fff; + --admonition-danger-background-color: #fcf3f2; + --admonition-danger-color: #404040; + --admonition-danger-title-background-color: #e9a499; + --admonition-danger-title-color: #fff; + --admonition-tip-background-color: #dbfaf4; + --admonition-tip-color: #404040; + --admonition-tip-title-background-color: #1abc9c; + --admonition-tip-title-color: #fff; + + --kbd-background-color: #fafbfc; + --kbd-outline-color: #d1d5da; + --kbd-shadow-color: #b0b7bf; + --kbd-text-color: #444d56; + + --guiitems-background-color: #e7f2fa; + --guiitems-border-color: #7fbbe3; + + --btn-neutral-background-color: #f3f6f6; + --btn-neutral-hover-background-color: #e5ebeb; + --footer-color: #747474; + + --graphviz-filter: none; +} diff --git a/doc/_static/images/logo.png b/doc/_static/images/logo.png new file mode 100644 index 000000000..861db7d9f Binary files /dev/null and b/doc/_static/images/logo.png differ diff --git a/doc/_static/images/west-mr-model.png b/doc/_static/images/west-mr-model.png new file mode 100644 index 000000000..ddbfdb62a Binary files /dev/null and b/doc/_static/images/west-mr-model.png differ diff --git a/doc/_static/js/custom.js b/doc/_static/js/custom.js new file mode 100644 index 000000000..049d327c8 --- /dev/null +++ b/doc/_static/js/custom.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2020-2023, The Godot community + * Copyright (c) 2023, Benjamin Cabé + * SPDX-License-Identifier: CC-BY-3.0 + */ + + +// Handle page scroll and adjust sidebar accordingly. + +// Each page has two scrolls: the main scroll, which is moving the content of the page; +// and the sidebar scroll, which is moving the navigation in the sidebar. +// We want the logo to gradually disappear as the main content is scrolled, giving +// more room to the navigation on the left. This means adjusting the height +// available to the navigation on the fly. +const registerOnScrollEvent = (function(){ + // Configuration. + + // The number of pixels the user must scroll by before the logo is completely hidden. + const scrollTopPixels = 137; + // The target margin to be applied to the navigation bar when the logo is hidden. + const menuTopMargin = 54; + // The max-height offset when the logo is completely visible. + const menuHeightOffset_default = 210; + // The max-height offset when the logo is completely hidden. + const menuHeightOffset_fixed = 63; + // The distance between the two max-height offset values above; used for intermediate values. + const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); + + // Media query handler. + return function(mediaQuery) { + // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). + // This handler is executed when the result of the query evaluation changes, which means that + // the page has moved between "desktop" and "mobile" states. + + // When entering the "desktop" state, we register scroll events and adjust elements on the page. + // When entering the "mobile" state, we clean up any registered events and restore elements on the page + // to their initial state. + + const $window = $(window); + const $sidebar = $('.wy-side-scroll'); + const $search = $sidebar.children('.wy-side-nav-search'); + const $menu = $sidebar.children('.wy-menu-vertical'); + + if (mediaQuery.matches) { + // Entering the "desktop" state. + + // The main scroll event handler. + // Executed as the page is scrolled and once immediately as the page enters this state. + const handleMainScroll = (currentScroll) => { + if (currentScroll >= scrollTopPixels) { + // After the page is scrolled below the threshold, we fix everything in place. + $search.css('margin-top', `-${scrollTopPixels}px`); + $menu.css('margin-top', `${menuTopMargin}px`); + $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); + } + else { + // Between the top of the page and the threshold we calculate intermediate values + // to guarantee a smooth transition. + $search.css('margin-top', `-${currentScroll}px`); + $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); + + if (currentScroll > 0) { + const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; + const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; + $menu.css('max-height', `calc(100% - ${offsetValue}px)`); + } else { + $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); + } + } + }; + + // The sidebar scroll event handler. + // Executed as the sidebar is scrolled as well as after the main scroll. This is needed + // because the main scroll can affect the scrollable area of the sidebar. + const handleSidebarScroll = () => { + const menuElement = $menu.get(0); + const menuScrollTop = $menu.scrollTop(); + const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); + + // As the navigation is scrolled we add a shadow to the top bar hanging over it. + if (menuScrollTop > 0) { + $search.addClass('fixed-and-scrolled'); + } else { + $search.removeClass('fixed-and-scrolled'); + } + }; + + $search.addClass('fixed'); + + $window.scroll(function() { + handleMainScroll(window.scrollY); + handleSidebarScroll(); + }); + + $menu.scroll(function() { + handleSidebarScroll(); + }); + + handleMainScroll(window.scrollY); + handleSidebarScroll(); + } else { + // Entering the "mobile" state. + + $window.unbind('scroll'); + $menu.unbind('scroll'); + + $search.removeClass('fixed'); + + $search.css('margin-top', `0px`); + $menu.css('margin-top', `0px`); + $menu.css('max-height', 'initial'); + } + }; + })(); + + $(document).ready(() => { + // Initialize handlers for page scrolling and our custom sidebar. + const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); + + registerOnScrollEvent(mediaQuery); + mediaQuery.addListener(registerOnScrollEvent); + }); diff --git a/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js b/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js new file mode 100644 index 000000000..4b708b543 --- /dev/null +++ b/doc/_static/js/dark-mode-toggle-stylesheets-loader.min.js @@ -0,0 +1,2 @@ +// @license © 2024 Google LLC. Licensed under the Apache License, Version 2.0. +(()=>{const e="dark-mode-toggle-stylesheets";const s="dark-mode-toggle";const t="light";const l="dark";let o=document.getElementById(e).textContent;let c=null;try{c=localStorage.getItem(s)}catch(e){}const a=/\(\s*prefers-color-scheme\s*:\s*light\s*\)/gi;const r=/\(\s*prefers-color-scheme\s*:\s*dark\s*\)/gi;switch(c){case t:o=o.replace(a,"$&, all").replace(r,"$& and not all");break;case l:o=o.replace(r,"$&, all").replace(a,"$& and not all");break}document.write(o)})(); \ No newline at end of file diff --git a/doc/_static/js/dark-mode-toggle.min.mjs b/doc/_static/js/dark-mode-toggle.min.mjs new file mode 100644 index 000000000..9c78635c4 --- /dev/null +++ b/doc/_static/js/dark-mode-toggle.min.mjs @@ -0,0 +1,2 @@ +// @license © 2019 Google LLC. Licensed under the Apache License, Version 2.0. +const e=document;let t={};try{t=localStorage}catch(e){}const i="prefers-color-scheme";const a="media";const s="light";const r="dark";const h="system";const o=`(${i}:${r})`;const l=`(${i}:${s})`;const n="link[rel=stylesheet]";const c="remember";const d="legend";const p="toggle";const b="switch";const g="three-way";const m="appearance";const u="permanent";const f="mode";const k="colorschemechange";const y="permanentcolorscheme";const v="all";const $="not all";const L="dark-mode-toggle";const T="https://googlechromelabs.github.io/dark-mode-toggle/demo/";const W=(e,t,i=t)=>{Object.defineProperty(e,i,{enumerable:true,get(){const e=this.getAttribute(t);return e===null?"":e},set(e){this.setAttribute(t,e)}})};const w=(e,t,i=t)=>{Object.defineProperty(e,i,{enumerable:true,get(){return this.hasAttribute(t)},set(e){if(e){this.setAttribute(t,"")}else{this.removeAttribute(t)}}})};const x=e.createElement("template");x.innerHTML=`
`;export class DarkModeToggle extends HTMLElement{static get observedAttributes(){return[f,m,u,d,s,r,c]}constructor(){super();W(this,f);W(this,m);W(this,d);W(this,s);W(this,r);W(this,h);W(this,c);w(this,u);this.t=null;this.i=null;e.addEventListener(k,(e=>{this.mode=e.detail.colorScheme;this.h();this.o();this.l()}));e.addEventListener(y,(e=>{this.permanent=e.detail.permanent;this.p.checked=this.permanent;this.l()}));this.m()}m(){const t=this.attachShadow({mode:"open"});t.append(x.content.cloneNode(true));this.t=e.querySelectorAll(`${n}[${a}*=${i}][${a}*="${r}"]`);this.i=e.querySelectorAll(`${n}[${a}*=${i}][${a}*="${s}"]`);this.u=t.querySelector("[part=lightRadio]");this.k=t.querySelector("[part=lightLabel]");this.v=t.querySelector("[part=darkRadio]");this.$=t.querySelector("[part=darkLabel]");this.L=t.querySelector("[part=toggleCheckbox]");this.T=t.querySelector("[part=toggleLabel]");this.W=t.querySelector("[part=lightThreeWayRadio]");this.R=t.querySelector("[part=lightThreeWayLabel]");this.C=t.querySelector("[part=systemThreeWayRadio]");this.M=t.querySelector("[part=systemThreeWayLabel]");this.S=t.querySelector("[part=darkThreeWayRadio]");this._=t.querySelector("[part=darkThreeWayLabel]");this.A=t.querySelector("legend");this.D=t.querySelector("aside");this.p=t.querySelector("[part=permanentCheckbox]");this.O=t.querySelector("[part=permanentLabel]")}connectedCallback(){const e=matchMedia(o).media!==$;if(e){matchMedia(o).addListener((({matches:e})=>{if(this.permanent){return}this.mode=e?r:s;this.j(k,{colorScheme:this.mode})}))}let i=false;try{i=t.getItem(L)}catch(e){}if(i&&[r,s].includes(i)){this.mode=i;this.p.checked=true;this.permanent=true}else if(e){this.mode=matchMedia(l).matches?s:r}if(!this.mode){this.mode=s}if(this.permanent&&!i){try{t.setItem(L,this.mode)}catch(e){}}if(!this.appearance){this.appearance=p}this.P();this.h();this.o();this.l();[this.u,this.v].forEach((e=>{e.addEventListener("change",(()=>{this.mode=this.u.checked?s:r;this.o();this.l();this.j(k,{colorScheme:this.mode})}))}));this.L.addEventListener("change",(()=>{this.mode=this.L.checked?r:s;this.h();this.l();this.j(k,{colorScheme:this.mode})}));this.W.addEventListener("change",(()=>{this.mode=s;this.permanent=true;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.S.addEventListener("change",(()=>{this.mode=r;this.permanent=true;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.C.addEventListener("change",(()=>{this.mode=this.H();this.permanent=false;this.o();this.h();this.l();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}));this.p.addEventListener("change",(()=>{this.permanent=this.p.checked;this.l();this.j(y,{permanent:this.permanent})}));this.q();this.j(k,{colorScheme:this.mode});this.j(y,{permanent:this.permanent})}attributeChangedCallback(e,i,a){if(e===f){const e=[s,h,r];if(!e.includes(a)){throw new RangeError(`Allowed values are: "${e.join(`", "`)}".`)}if(matchMedia("(hover:none)").matches&&this.remember){this.B()}if(this.permanent){try{t.setItem(L,this.mode)}catch(e){}}this.h();this.o();this.l();this.q()}else if(e===m){const e=[p,b,g];if(!e.includes(a)){throw new RangeError(`Allowed values are: "${e.join(`", "`)}".`)}this.P()}else if(e===u){if(this.permanent){if(this.mode){try{t.setItem(L,this.mode)}catch(e){}}}else{try{t.removeItem(L)}catch(e){}}this.p.checked=this.permanent}else if(e===d){this.A.textContent=a}else if(e===c){this.O.textContent=a}else if(e===s){this.k.textContent=a;if(this.mode===s){this.T.textContent=a}}else if(e===r){this.$.textContent=a;if(this.mode===r){this.T.textContent=a}}}H(){return matchMedia(l).matches?s:r}j(e,t){this.dispatchEvent(new CustomEvent(e,{bubbles:true,composed:true,detail:t}))}P(){this.u.hidden=this.k.hidden=this.v.hidden=this.$.hidden=this.L.hidden=this.T.hidden=this.W.hidden=this.R.hidden=this.C.hidden=this.M.hidden=this.S.hidden=this._.hidden=true;switch(this.appearance){case b:this.u.hidden=this.k.hidden=this.v.hidden=this.$.hidden=false;break;case g:this.W.hidden=this.R.hidden=this.C.hidden=this.M.hidden=this.S.hidden=this._.hidden=false;break;case p:default:this.L.hidden=this.T.hidden=false;break}}h(){if(this.mode===s){this.u.checked=true}else{this.v.checked=true}}o(){if(this.mode===s){this.T.style.setProperty(`--${L}-checkbox-icon`,`var(--${L}-light-icon,url("${T}moon.png"))`);this.T.textContent=this.light;if(!this.light){this.T.ariaLabel=r}this.L.checked=false}else{this.T.style.setProperty(`--${L}-checkbox-icon`,`var(--${L}-dark-icon,url("${T}sun.png"))`);this.T.textContent=this.dark;if(!this.dark){this.T.ariaLabel=s}this.L.checked=true}}l(){this.R.ariaLabel=s;this.M.ariaLabel=h;this.R.ariaLabel=r;this.R.textContent=this.light;this.M.textContent=this.system;this._.textContent=this.dark;if(this.permanent){if(this.mode===s){this.W.checked=true}else{this.S.checked=true}}else{this.C.checked=true}}q(){if(this.mode===s){this.i.forEach((e=>{e.media=v;e.disabled=false}));this.t.forEach((e=>{e.media=$;e.disabled=true}))}else{this.t.forEach((e=>{e.media=v;e.disabled=false}));this.i.forEach((e=>{e.media=$;e.disabled=true}))}}B(){this.D.style.visibility="visible";setTimeout((()=>{this.D.style.visibility="hidden"}),3e3)}}customElements.define(L,DarkModeToggle); \ No newline at end of file diff --git a/doc/_templates/breadcrumbs.html b/doc/_templates/breadcrumbs.html new file mode 100644 index 000000000..3852afcfa --- /dev/null +++ b/doc/_templates/breadcrumbs.html @@ -0,0 +1,34 @@ +{% extends "!breadcrumbs.html" %} +{% block breadcrumbs %} + + {# parameterize default name "Docs" in breadcrumb via docs_title in conf.py #} + {% if not docs_title %} + {% set docs_title = "Docs" %} + {% endif %} + +
  • {{ docs_title }} »
  • + {% for doc in parents %} +
  • {{ doc.title }} »
  • + {% endfor %} +
  • {{ title }}
  • + +{% endblock %} +{%- block breadcrumbs_aside %} +
  • + +
  • +
  • + {%- if display_gh_links %} + {% set gh_blob_url = pagename | gh_link_get_blob_url %} + {% if gh_blob_url %} + {{ _('Open on GitHub') }} + {% endif %} + {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} + {%- if sha1 %} + + {{ _('Report an issue with this page')}} + + {% endif %} + {% endif %} +
  • +{%- endblock %} diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html new file mode 100644 index 000000000..9dacea711 --- /dev/null +++ b/doc/_templates/footer.html @@ -0,0 +1,18 @@ +{% extends "!footer.html" %} +{% block contentinfo %} +

    + {%- if show_copyright %} + © Copyright {{ copyright }}. + {%- endif %} + + {%- if last_updated %} +

    + Last generated: {{ last_updated }}. + {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} + {%- if git_last_updated %} + Last source update: {{ git_last_updated }}. + {%- endif %} +
    + {%- endif -%} +

    +{% endblock %} diff --git a/doc/_templates/gsearch.html b/doc/_templates/gsearch.html new file mode 100644 index 000000000..195346635 --- /dev/null +++ b/doc/_templates/gsearch.html @@ -0,0 +1,17 @@ +{%- extends "!search.html" %} + +{%- block scripts %} + {{ super.super() }} + +{%- endblock %} + +{% block footer %} + {{ super.super() }} +{% endblock %} + +{% block body %} +

    {{ _('Search Results') }}

    + +
    +{% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 000000000..c46987e9c --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,40 @@ +{% extends "!layout.html" %} +{% block document %} + {% if is_release %} +
    + The latest development version + of this page may be more current than this released {{ version }} version. +
    + {% endif %} + {{ super() }} +{% endblock %} +{% block menu %} +
    + {{ super() }} + {% if reference_links %} +
    +

    Reference

    +
      + {% for title, url in reference_links.items() %} +
    • + {{ title }} +
    • + {% endfor %} +
    +
    + {% endif %} +
    +{% endblock %} +{% block extrahead %} + + {# Use dark mode loader script to prevent "flashing" of the page on load. + As we need a