summaryrefslogtreecommitdiffstats
path: root/docs/theme
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-03 07:47:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-03 07:47:36 +0000
commit1f6a9795ed529247bb3370c5efeb009a81d30c8b (patch)
treeb0bb57ba2ba39cb69b7426cbc73632d1d0186c79 /docs/theme
parentAdding debian version 0.45+dfsg-1. (diff)
downloadjinjax-1f6a9795ed529247bb3370c5efeb009a81d30c8b.tar.xz
jinjax-1f6a9795ed529247bb3370c5efeb009a81d30c8b.zip
Merging upstream version 0.46.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--docs/theme/Autodoc.jinja127
-rw-r--r--docs/theme/Callout.jinja45
-rw-r--r--docs/theme/ExampleTabs.jinja27
-rw-r--r--docs/theme/Footer.jinja10
-rw-r--r--docs/theme/Header.jinja17
-rw-r--r--docs/theme/Layout.jinja25
-rw-r--r--docs/theme/MetaTags.jinja22
-rw-r--r--docs/theme/NavBar.jinja3
-rw-r--r--docs/theme/NavGlobal.jinja3
-rw-r--r--docs/theme/NavLocal.jinja5
-rw-r--r--docs/theme/NavMobile.jinja18
-rw-r--r--docs/theme/NavTop.jinja17
-rw-r--r--docs/theme/Page.jinja19
-rw-r--r--docs/theme/PageSingle.jinja10
-rw-r--r--docs/theme/PrevNext.jinja26
-rw-r--r--docs/theme/SocialCard.jinja61
-rw-r--r--docs/theme/Source.jinja24
-rw-r--r--docs/theme/Source.js123
-rw-r--r--docs/theme/Test.jinja6
-rw-r--r--docs/theme/ThemeSwitch.jinja36
-rw-r--r--docs/theme/ThemeSwitch.js41
-rw-r--r--docs/theme/Toc.jinja45
-rw-r--r--docs/theme/TocPage.jinja21
-rw-r--r--docs/theme/TocPage.js97
24 files changed, 828 insertions, 0 deletions
diff --git a/docs/theme/Autodoc.jinja b/docs/theme/Autodoc.jinja
new file mode 100644
index 0000000..e1a967c
--- /dev/null
+++ b/docs/theme/Autodoc.jinja
@@ -0,0 +1,127 @@
+{#def
+ obj: dict | None = None,
+ name: str = "",
+ level: int = 2,
+ members: bool = True,
+#}
+
+{% set obj = obj or autodoc(name) %}
+
+<h{{ level }}>
+ <code class="doc-symbol doc-symbol-{{ obj.symbol }}">{{ obj.symbol }}</code>
+ <span class="doc-oname doc-oname-{{ obj.symbol }}">{{ name or obj.name }}</span>
+ {% if obj.label -%}
+ <small class="doc-olabel doc-olabel-{{ obj.label }}">
+ <code>{{ obj.label }}</code>
+ </small>
+ {%- endif %}
+</h{{ level }}>
+
+{%- if obj.short_description -%}
+<div class="doc-short-description">
+ {{ obj.short_description | markdown | utils.widont }}
+</div>
+{% endif -%}
+
+{%- if obj.signature -%}
+<div class="doc-signature">
+{% filter markdown -%}
+```python
+{{ obj.signature }}
+```
+{%- endfilter %}
+</div>
+{%- endif %}
+
+{% if obj.bases -%}
+<div class="doc-bases">
+ <p>Bases:
+ {%- for base in obj.bases %} <code>{{ base }}</code>{% if not loop.last %}, {% endif %}
+ {%- endfor %}
+ </p>
+</div>
+{%- endif %}
+
+{% if obj.params -%}
+<table class="doc-arguments">
+ <thead><tr><th>Argument</th><th>Description</th></tr>
+ </thead>
+ <tbody>
+{%- for param in obj.params %}
+ <tr>
+ <td><code>{{ param.name }}</code></td>
+ <td>{{ param.description | markdown | utils.widont }}</td>
+ </tr>
+{%- endfor %}
+ </tbody>
+</table>
+{%- endif %}
+
+{%- if obj.description -%}
+<div class="doc-long-description">
+ {{ obj.description | markdown | utils.widont }}
+</div>
+{% endif -%}
+
+{% if obj.examples -%}
+<div class="doc-examples">
+<p><strong>Example:</strong></p>
+
+{% for ex in obj.examples -%}
+<div>
+{% if ex.description %}{{ ex.description | markdown | utils.widont }}{% endif %}
+{% if ex.snippet %}{{ ex.snippet }}{% endif %}
+<div>
+{% endfor -%}
+</div>
+{%- endif %}
+
+{% if obj.returns -%}
+<li class="doc-returns">
+ <p><strong>Returns:</strong></p>
+
+ {% if ex.returns -%}
+ <p>{{ obj.returns }}</p>
+ {%- endif %}
+ {% if ex.many_returns -%}
+ <ul>
+ {% for return in ex.many_returns %}
+ <li>{{ return }}</li>
+ {%- endfor %}
+ </ul>
+ {%- endif %}
+</div>
+{%- endif %}
+
+{% if obj.raises -%}
+ <div class="doc-raises"></div>
+ <p><strong>Raises:</strong></p>
+
+ <ul>
+ {% for raises in obj.raises -%}
+ <li>{{ raises.description | markdown | utils.widont }}<ul>
+ {% endfor -%}
+ </ul>
+ </li>
+{%- endif %}
+
+{% if members -%}
+ {% if obj.attrs or obj.properties-%}
+ <div class="doc-attrs">
+ {% for attr in obj.attrs -%}
+ <Autodoc obj={{ attr }} level={{ level + 1 }} />
+ {% endfor %}
+ {% for attr in obj.properties %}
+ <Autodoc obj={{ attr }} level={{ level + 1 }} />
+ {%- endfor %}
+ </div>
+ {%- endif %}
+
+ {% if obj.methods -%}
+ <div class="doc-methods">
+ {% for method in obj.methods %}
+ <Autodoc obj={{ method }} level={{ level + 1 }} />
+ {%- endfor %}
+ </div>
+ {%- endif %}
+{%- endif %} \ No newline at end of file
diff --git a/docs/theme/Callout.jinja b/docs/theme/Callout.jinja
new file mode 100644
index 0000000..4279b3a
--- /dev/null
+++ b/docs/theme/Callout.jinja
@@ -0,0 +1,45 @@
+{#def title="", type="info", icon="", open=True #}
+
+{% set icons = {
+ "note": "sticky_note",
+ "info": "info",
+ "tip": "check_circle",
+ "alert": "release_alert",
+ "warning": "warning",
+ "danger": "release_alert",
+ "error": "release_alert",
+ "internal": "rocket_launch",
+ "todo": "checklist",
+} %}
+
+{% if icon != False %}
+ {% set icon = icon or icons.get(type) %}
+{% endif %}
+
+{% do attrs.set(class="type-" + type or "none") %}
+
+{% if title -%}
+
+<details {{ attrs.render(open=open, class="cd-callout", data_component="Callout") }}>
+ <summary>
+ {% if icon -%}
+ <i class="icon">{{ icon }}</i>
+ {% endif -%}
+ {{ title }}
+ <icon class="icon arrow">keyboard_arrow_down</icon>
+ </summary>
+ <div class="content">{{content}}</div>
+</details>
+
+{%- else -%}
+
+<aside {{ attrs.render(class="cd-callout", data_component="Callout") }}>
+ {% if icon -%}
+ <div class="icon-wrapper">
+ <i class="icon">{{ icon }}</i>
+ </div>
+ {%- endif %}
+ <div class="content">{{content}}</div>
+</aside>
+
+{%- endif %}
diff --git a/docs/theme/ExampleTabs.jinja b/docs/theme/ExampleTabs.jinja
new file mode 100644
index 0000000..0853ec5
--- /dev/null
+++ b/docs/theme/ExampleTabs.jinja
@@ -0,0 +1,27 @@
+{#def prefix, panels={} #}
+
+<div {{ attrs.render(
+ class="cd-example-tabs not-prose",
+ data_component="ExampleTabs",
+) }}>
+ <TabGroup class="example-tabgroup">
+ <TabList class="example-tablist" data-md-skip>
+ {%- for text in panels.keys() %}
+ <Tab
+ class="example-tab"
+ target={{ "ex-%s-%s" % (prefix, loop.index) }}
+ selected={{ loop.index == 1 }}
+ >{{ text }}</Tab>
+ {%- endfor %}
+ </TabList>
+ {%- for name in panels.values() %}
+ <TabPanel
+ class="example-tabpanel"
+ id={{ "ex-%s-%s" % (prefix, loop.index) }}
+ hidden={{ loop.index != 1 }}
+ >
+ {{ catalog.irender(name) }}
+ </TabPanel>
+ {%- endfor %}
+ </TabGroup>
+</div>
diff --git a/docs/theme/Footer.jinja b/docs/theme/Footer.jinja
new file mode 100644
index 0000000..a9e9c5a
--- /dev/null
+++ b/docs/theme/Footer.jinja
@@ -0,0 +1,10 @@
+<footer {{ attrs.render(class="cd-footer", data_component="Footer") }}>
+ <div class="wrapper">
+ <Copyright />
+ <div class="built-with">
+ This site was
+ <a title="Coming soon!">built using Claydocs</a>
+ </div>
+ <ThemeSwitch class="themeswitch" />
+ </div>
+</footer>
diff --git a/docs/theme/Header.jinja b/docs/theme/Header.jinja
new file mode 100644
index 0000000..1b719cf
--- /dev/null
+++ b/docs/theme/Header.jinja
@@ -0,0 +1,17 @@
+{#def title="", section="" #}
+
+{% set section = section or page.section if section != false else None %}
+{% set title = title or page.title %}
+
+<header {{ attrs.render(
+ class="cd-header",
+ data_component="Header",
+) }}>
+ <div>
+ {% if section -%}
+ <div>{{ section }}</div>
+ {%- endif %}
+ <h1>{{ title | utils.widont }}</h1>
+ </div>
+ <p class="description">{{ content | utils.widont }}</p>
+</header>
diff --git a/docs/theme/Layout.jinja b/docs/theme/Layout.jinja
new file mode 100644
index 0000000..e76046f
--- /dev/null
+++ b/docs/theme/Layout.jinja
@@ -0,0 +1,25 @@
+{#def title="", description="" #}
+
+<!DOCTYPE html>
+<html lang="{{ page.lang }}" class="light">
+<head>
+<meta charset="utf-8">
+<MetaTags page={{ page }} />
+<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
+<link rel="apple-touch-icon" sizes="120x120" href="/static/img/apple-touch-icon.png">
+<link rel="stylesheet" href="/static/theme.css?v={{ utils.timestamp }}">
+<link rel="stylesheet" href="/static/prose.css?v={{ utils.timestamp }}">
+<link rel="stylesheet" href="/static/docs.css?v={{ utils.timestamp }}">
+{{ catalog.render_assets() }}
+{% if page.prev_page and page.prev_page.url -%}
+ <link href="{{ page.prev_page.url }}" rel="prev">
+{% endif -%}
+{% if page.next_page and page.next_page.url -%}
+ <link href="{{ page.next_page.url }}" rel="next">
+{% endif -%}
+<meta property="generator" content="claydocs" />
+</head>
+<body {{ attrs.render() }}>
+{{ content }}
+</body>
+</html>
diff --git a/docs/theme/MetaTags.jinja b/docs/theme/MetaTags.jinja
new file mode 100644
index 0000000..2639afb
--- /dev/null
+++ b/docs/theme/MetaTags.jinja
@@ -0,0 +1,22 @@
+{#def page #}
+
+{% set DEFAULT_TITLE = "JinjaX Documentation" %}
+{% set title = (page.title + " | " + DEFAULT_TITLE) if page.title else DEFAULT_TITLE %}
+{% set description = page.description %}
+
+<title>{{ title }}</title>
+<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
+<meta property="og:type" content="website">
+<meta property="og:url" content="{{ nav.domain }}{{ page.url }}">
+<meta property="og:title" content="{{ title }}">
+<meta property="twitter:title" content="{{ title }}">
+{% if description -%}
+<meta property="og:description" content="{{ description }}">
+<meta property="twitter:description" content="{{ description }}">
+{%- endif %}
+<meta property="og:image" content="{{ nav.domain }}{{ page.url }}/og-card.png">
+<meta property="og:image:type" content="image/png">
+<meta property="og:image:width" content="1200">
+<meta property="og:image:height" content="630">
+<meta property="twitter:card" content="summary_large_image">
+<meta property="twitter:image" content="{{ nav.domain }}{{ page.url }}/og-card.png">
diff --git a/docs/theme/NavBar.jinja b/docs/theme/NavBar.jinja
new file mode 100644
index 0000000..50f8ca2
--- /dev/null
+++ b/docs/theme/NavBar.jinja
@@ -0,0 +1,3 @@
+<nav {{ attrs.render(class="cd-navbar", data_component="NavBar") }}>
+{{ content }}
+</nav> \ No newline at end of file
diff --git a/docs/theme/NavGlobal.jinja b/docs/theme/NavGlobal.jinja
new file mode 100644
index 0000000..1171db0
--- /dev/null
+++ b/docs/theme/NavGlobal.jinja
@@ -0,0 +1,3 @@
+<div {{ attrs.render(class="cd-nav-global scrollbar-thin", data_component="NavGlobal") }}>
+ <Toc toc={{ nav.toc }} page={{ page}} />
+</div>
diff --git a/docs/theme/NavLocal.jinja b/docs/theme/NavLocal.jinja
new file mode 100644
index 0000000..2af7606
--- /dev/null
+++ b/docs/theme/NavLocal.jinja
@@ -0,0 +1,5 @@
+<div {{ attrs.render(class="cd-nav-local", data_component="NavLocal") }}>
+ <div class="wrapper scrollbar-thin">
+ <TocPage :page_toc="page.toc" />
+ </div>
+</div>
diff --git a/docs/theme/NavMobile.jinja b/docs/theme/NavMobile.jinja
new file mode 100644
index 0000000..4126fb0
--- /dev/null
+++ b/docs/theme/NavMobile.jinja
@@ -0,0 +1,18 @@
+{% do attrs.set(id="navMobile", class="cd-nav-mobile", data_component="NavMobile") %}
+
+<Popover _attrs={{ attrs }}>
+ <header>
+ <Logo base_url={{ page.base_url }} class="logo" />
+ <nav class="cd-navbar nav-links">
+ <ThemeSwitch class="themeswitch" text={{ false }} />
+ </nav>
+ <PopButton
+ target="navMobile"
+ action="close"
+ title="Close menu"
+ class="cd-toggle-sidebar cd-text-button"
+ >Close</PopButton>
+ </header>
+
+ <Toc class="toc" toc={{ nav.toc }} page={{ page }} />
+</Popover>
diff --git a/docs/theme/NavTop.jinja b/docs/theme/NavTop.jinja
new file mode 100644
index 0000000..8518391
--- /dev/null
+++ b/docs/theme/NavTop.jinja
@@ -0,0 +1,17 @@
+<section class="cd-nav-top", data_component="NavTop">
+ <div class="wrapper">
+ <Logo class="logo" base_url={{ page.base_url }} />
+ <nav class="cd-navbar nav-links">
+ <NavLinks />
+ <ThemeSwitch class="themeswitch" text={{ false }} />
+ </nav>
+ <nav class="nav-extra">
+ <NavExtra />
+ </nav>
+ <PopButton
+ target="navMobile"
+ title="Show menu"
+ class="cd-toggle-sidebar cd-text-button"
+ >Menu</PopButton>
+ </div>
+</section>
diff --git a/docs/theme/Page.jinja b/docs/theme/Page.jinja
new file mode 100644
index 0000000..8fec014
--- /dev/null
+++ b/docs/theme/Page.jinja
@@ -0,0 +1,19 @@
+<Layout
+ title={{ page.title }}
+ description={{ page.description }}
+ class={{ meta.get('class', 'cd-page') }}
+>
+ <NavTop></NavTop>
+ <div class="page-wrapper">
+ <NavGlobal></NavGlobal>
+ <main id="main" class="page prose">{{ content }}</main>
+ <NavLocal></NavLocal>
+ </div>
+ <PrevNext
+ curr={{ page }}
+ prev={{ page.prev_page }}
+ next={{ page.next_page }}
+ />
+ <NavMobile></NavMobile>
+ <Footer></Footer>
+</Layout>
diff --git a/docs/theme/PageSingle.jinja b/docs/theme/PageSingle.jinja
new file mode 100644
index 0000000..d89fd49
--- /dev/null
+++ b/docs/theme/PageSingle.jinja
@@ -0,0 +1,10 @@
+<Layout
+ title={{ page.title }}
+ description={{ page.description }}
+ class={{ meta.get('class', 'cd-page-single') }}
+>
+ <NavTop />
+ <main>{{ content }}</main>
+ <NavMobile />
+ <Footer />
+</Layout>
diff --git a/docs/theme/PrevNext.jinja b/docs/theme/PrevNext.jinja
new file mode 100644
index 0000000..9c6a572
--- /dev/null
+++ b/docs/theme/PrevNext.jinja
@@ -0,0 +1,26 @@
+{#def curr, prev, next #}
+
+<nav {{ attrs.render(class="cd-prevnext", data_component="PrevNext") }}>
+ {% if prev.url -%}
+ <a href="{{ prev.url }}" class="prev">
+ <i>&larr;</i>
+ <div>
+ <div class="section">
+ {{ prev.section or "Previous" if prev.section != curr.section else "Previous" }}
+ </div>
+ <div class="title">{{ prev.title }}</div>
+ </div>
+ </a>
+ {%- endif %}
+ {% if next.url -%}
+ <a href="{{ next.url }}" class="next">
+ <div>
+ <div class="section">
+ {{ next.section or "Next" if next.section != curr.section else "Next" }}
+ </div>
+ <div class="title">{{ next.title }}</div>
+ </div>
+ <i>&rarr;</i>
+ </a>
+ {%- endif %}
+</nav>
diff --git a/docs/theme/SocialCard.jinja b/docs/theme/SocialCard.jinja
new file mode 100644
index 0000000..2fe00be
--- /dev/null
+++ b/docs/theme/SocialCard.jinja
@@ -0,0 +1,61 @@
+{#def page #}
+<Layout
+ title={{ page.title }}
+ description={{page.description }}
+>
+ <style>
+ body {
+ background-color: black;
+ }
+ .sc1 {
+ width: 1200px;
+ height: 630px;
+ margin: 0;
+ font-family: SF Pro Display, system-ui, sans-serif;
+ color: white;
+ background-image: linear-gradient(to bottom, #404faa, #0068b2);
+ }
+ .sc1__wrapper {
+ position: absolute;
+ inset: 60px 90px 90px 60px;
+ }
+ .sc1__wrapper > * {
+ position: absolute;
+ left: 0;
+ max-width: 1060px;
+ }
+ .sc1__logo {
+ top: 0;
+ height: 50px;
+ }
+ .sc1__section {
+ top: 150px;
+ line-height: 1;
+ font-weight: bold;
+ text-transform: uppercase;
+ font-size: 22px;
+ width: 600px;
+ }
+ .sc1__title {
+ top: 180px;
+ line-height: 1;
+ font-weight: bold;
+ font-size: 68px;
+ }
+ .sc1__description {
+ bottom: 0;
+ line-height: 1.4;
+ font-weight: normal;
+ font-size: 22px;
+ }
+ </style>
+
+ <article class="sc1">
+ <div class="sc1__wrapper">
+ <img class="sc1__logo" src="/static/img/jinjax-logo-w.png" />
+ <h2 class="sc1__section">{{ page.section }}</h2>
+ <h1 class="sc1__title">{{ page.title | utils.widont }}</h1>
+ <div class="sc1__description">{{ page.description | utils.widont }}</div>
+ </div>
+ </article>
+</Layout>
diff --git a/docs/theme/Source.jinja b/docs/theme/Source.jinja
new file mode 100644
index 0000000..c742f56
--- /dev/null
+++ b/docs/theme/Source.jinja
@@ -0,0 +1,24 @@
+{# def url: str, label: str = "" #}
+{% do attrs.set(href=url, target="_blank") %}
+{% set icon = url.replace("http://", "").replace("https://", "").split(".")[0] %}
+
+<a {{ attrs.render(class="cd-source", data_component="Source") }}>
+ <div class="cd-source__icon">
+ {% if icon == "github" -%}
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
+ {% elif icon == "gitlab" -%}
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
+ {%- else -%}
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M439.55 236.05L244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
+ {%- endif %}
+ </div>
+ <div class="cd-source__repo">
+ <span class="cd-source__label">{{ label or url.split("/", 3)[-1] }}</span>
+ <ul class="cd-source__facts">
+ <li data-fact="version" hidden></li>
+ <li data-fact="stars" hidden></li>
+ <li data-fact="forks" hidden></li>
+ <li data-fact="numrepos" hidden></li>
+ </ul>
+ </div>
+</a> \ No newline at end of file
diff --git a/docs/theme/Source.js b/docs/theme/Source.js
new file mode 100644
index 0000000..e627460
--- /dev/null
+++ b/docs/theme/Source.js
@@ -0,0 +1,123 @@
+const ATTR_FACT = "data-fact";
+const CLASS_FACTS = "cd-source__facts";
+const CLASS_FACTS_VISIBLE = `${CLASS_FACTS}--visible`;
+
+document.addEventListener("DOMContentLoaded", function () {
+ document.querySelectorAll('[data-component="Source"]').forEach(showFacts);
+});
+
+function showFacts(node) {
+ function renderFacts(facts) {
+ Array.from(node.querySelectorAll(`[${ATTR_FACT}]`))
+ .forEach(function(node) {
+ const name = node.getAttribute(ATTR_FACT);
+ if (facts[name]) {
+ node.removeAttribute("hidden");
+ node.innerText = facts[name];
+ }
+ });
+
+ node.querySelector(`.${CLASS_FACTS}`).classList.add(CLASS_FACTS_VISIBLE);
+ }
+
+ getSourceFacts(node.href, renderFacts);
+}
+
+function getSourceFacts(url, callback) {
+ const key = `Source:${url}`;
+ let facts = sessionStorage.getItem(key);
+ if (facts) {
+ callback(JSON.parse(facts));
+ return;
+ }
+
+ fetchSourceFacts(url)
+ .then((facts) => {
+ if (facts && Object.keys(facts).length) {
+ sessionStorage.setItem(key, JSON.stringify(facts));
+ callback(facts);
+ }
+ });
+}
+
+function fetchJSON(url) {
+ return fetch(url)
+ .then(response => response.json())
+ .catch((error) => {
+ console.log(error);
+ });
+}
+
+function fetchSourceFacts(url) {
+ /* Try to match GitHub repository */
+ let match = url.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);
+ if (match) {
+ const [, user, repo] = match;
+ return fetchSourceFactsFromGitHub(user, repo);
+ }
+
+ /* Try to match GitLab repository */
+ match = url.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);
+ if (match) {
+ const [, base, slug] = match;
+ return fetchSourceFactsFromGitLab(base, slug);
+ }
+
+ /* Fallback */
+ return null;
+}
+
+function fetchSourceFactsFromGitLab(base, project) {
+ const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`
+
+ fetchJSON(url)
+ .then(function({ star_count, forks_count }) {
+ return {
+ stars: star_count,
+ forks: forks_count,
+ };
+ });
+}
+
+function fetchSourceFactsFromGitHub (user, repo) {
+ if (typeof repo === "undefined") {
+ return fetchSourceFactsFromGitHubOrg(user);
+ } else {
+ return fetchSourceFactsFromGitHubRepo(user, repo);
+ }
+}
+
+function fetchSourceFactsFromGitHubOrg(user) {
+ const url = `https://api.github.com/users/${user}`
+
+ fetchJSON(url)
+ .then(function(data) {
+ return {
+ numrepos: data.public_repos,
+ };
+ });
+}
+
+function fetchSourceFactsFromGitHubRepo(user, repo) {
+ const url = `https://api.github.com/repos/${user}/${repo}`
+
+ const release = fetchJSON(`${url}/releases/latest`)
+ .then((data) => {
+ return {
+ version: data.tag_name,
+ };
+ });
+
+ const info = fetchJSON(url)
+ .then((data) => {
+ return {
+ stars: data.stargazers_count,
+ forks: data.forks_count,
+ };
+ });
+
+ return Promise.all([release, info])
+ .then(([release, info]) => {
+ return { ...release, ...info };
+ });
+}
diff --git a/docs/theme/Test.jinja b/docs/theme/Test.jinja
new file mode 100644
index 0000000..00176ce
--- /dev/null
+++ b/docs/theme/Test.jinja
@@ -0,0 +1,6 @@
+<!DOCTYPE html><html>
+<head><MetaTags page={{ page }} /></head><body class="prose">
+
+{{ content }}
+
+</body></html> \ No newline at end of file
diff --git a/docs/theme/ThemeSwitch.jinja b/docs/theme/ThemeSwitch.jinja
new file mode 100644
index 0000000..3543b73
--- /dev/null
+++ b/docs/theme/ThemeSwitch.jinja
@@ -0,0 +1,36 @@
+{#def text=true #}
+
+<button {{ attrs.render(
+ class="cd-theme-switch",
+ data_component="ThemeSwitch",
+ title="Toggle light & dark mode",
+ aria_label="auto",
+ aria_live="polite",
+) }}>
+ <svg
+ class="sun-and-moon"
+ aria-hidden="true"
+ stroke-linecap="round"
+ viewBox="0 0 24 24"
+ >
+ <circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)"></circle>
+ <g class="sun-beams">
+ <line x1="12" y1="1" x2="12" y2="3" />
+ <line x1="12" y1="21" x2="12" y2="23" />
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
+ <line x1="1" y1="12" x2="3" y2="12" />
+ <line x1="21" y1="12" x2="23" y2="12" />
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
+ </g>
+ <mask class="moon" id="moon-mask">
+ <rect x="0" y="0" width="100%" height="100%" fill="white" />
+ <circle cx="24" cy="10" r="6"></circle>
+ </mask>
+ </svg>
+ {% if text -%}
+ <span class="light-text">Light</span>
+ <span class="dark-text">Dark</span>
+ {%- endif %}
+</button>
diff --git a/docs/theme/ThemeSwitch.js b/docs/theme/ThemeSwitch.js
new file mode 100644
index 0000000..c8b2847
--- /dev/null
+++ b/docs/theme/ThemeSwitch.js
@@ -0,0 +1,41 @@
+import { on } from "./jxui.js";
+
+const SEL_TARGET = ".cd-theme-switch";
+const STORAGE_KEY = "theme";
+
+const DARK = "dark";
+const LIGHT = "light";
+const theme = {value: getColorPreference()};
+
+reflectPreference();
+on("click", SEL_TARGET, onClick);
+// sync with system changes
+window
+ .matchMedia("(prefers-color-scheme: dark)")
+ .addEventListener("change", ({matches:isDark}) => {
+ theme.value = isDark ? DARK : LIGHT
+ setPreference()
+ });
+
+function onClick (event, target) {
+ if (target.matches("[disabled]")) return;
+ theme.value = theme.value === LIGHT ? DARK : LIGHT;
+ setPreference();
+}
+function setPreference () {
+ localStorage.setItem(STORAGE_KEY, theme.value);
+ reflectPreference();
+}
+function reflectPreference () {
+ const value = getColorPreference ();
+ if (value === DARK) {
+ document.documentElement.classList.add(DARK);
+ document.documentElement.classList.remove(LIGHT);
+ } else {
+ document.documentElement.classList.add(LIGHT);
+ document.documentElement.classList.remove(DARK);
+ }
+}
+function getColorPreference () {
+ return localStorage.getItem(STORAGE_KEY);
+} \ No newline at end of file
diff --git a/docs/theme/Toc.jinja b/docs/theme/Toc.jinja
new file mode 100644
index 0000000..2670b62
--- /dev/null
+++ b/docs/theme/Toc.jinja
@@ -0,0 +1,45 @@
+{# def toc, page #}
+
+{% macro render_page(url, title) %}
+{% if url != "/" -%}
+<div class="page {{ 'active' if page.url == url else '' }}">
+ <a href="{{ url }}#">{{ title }}</a>
+</div>
+{%- endif %}
+{% endmacro %}
+
+
+{% macro render_collapsable(title, children) %}
+<details open>
+ {% if title %}<summary>{{ title }}</summary>{% endif %}
+ {{ render_children(children) }}
+</details>
+{% endmacro %}
+
+
+{% macro render_section(title, children) %}
+<section open>
+ {% if title %}<h2>{{ title }}</h2>{% endif %}
+ {{ render_children(children) }}
+</section>
+{% endmacro %}
+
+
+{% macro render_children(children, collapsable=True) %}
+ {%- for url, title, sub_children in children %}
+ {% if sub_children -%}
+ {% if collapsable -%}
+ {{ render_collapsable(title, sub_children) }}
+ {%- else -%}
+ {{ render_section(title, sub_children) }}
+ {%- endif %}
+ {%- else -%}
+ {{ render_page(url, title) }}
+ {%- endif %}
+ {%- endfor %}
+{% endmacro %}
+
+
+<div {{ attrs.render(class="cd-toc", data_component="Toc") }}>
+ {{ render_children(toc, collapsable=False) }}
+</div> \ No newline at end of file
diff --git a/docs/theme/TocPage.jinja b/docs/theme/TocPage.jinja
new file mode 100644
index 0000000..754b624
--- /dev/null
+++ b/docs/theme/TocPage.jinja
@@ -0,0 +1,21 @@
+{#def page_toc, max_depth=3 #}
+
+{% macro render_sub_items(pages) %}
+{%- for section in pages %}
+ <li class="indent-{{ section.level }}">
+ <a href="#{{ section.id }}"><span>{{ section.name }}</span></a>
+ </li>
+ {% if section.level <= max_depth -%}
+ {{ render_sub_items(section.children) }}
+ {%- endif %}
+{%- endfor %}
+{% endmacro %}
+
+<ul {{ attrs.render(class="cd-toc-page", data_component="TocPage") }}>
+{%- for section in page_toc %}
+ <li class="indent-{{ section.level }}">
+ <a href="#{{ section.id }}"><span>{{ section.name }}</span></a>
+ </li>
+ {{ render_sub_items(section.children) }}
+{%- endfor %}
+</ul>
diff --git a/docs/theme/TocPage.js b/docs/theme/TocPage.js
new file mode 100644
index 0000000..77bad1e
--- /dev/null
+++ b/docs/theme/TocPage.js
@@ -0,0 +1,97 @@
+import { on } from "./jxui.js";
+
+const ACTIVE = "active";
+const SEL_BACKTOTOP = ".cd-back-to-top"
+const SEL_PAGETOC = ".cd-toc-page"
+const SEL_TARGET = `${SEL_PAGETOC} a`;
+const SEL_ACTIVE = `${SEL_TARGET}.${ACTIVE}`;
+const SEL_PAGE = "#main.page";
+const SEL_SECTIONS = `${SEL_PAGE} section[id]`;
+const DESKTOP_THRESHOLD = 1024;
+
+on("click", SEL_TARGET, handleClick);
+on("click", SEL_BACKTOTOP, backToTop);
+
+function handleClick(event, target) {
+ removeHighlight();
+ setTimeout(function () { updateHighlight(target) }, 10);
+}
+
+function updateHighlight (elem) {
+ if (window.innerWidth > DESKTOP_THRESHOLD && !elem?.classList.contains(ACTIVE)) {
+ removeHighlight();
+ if (!elem) return;
+ elem.classList.add(ACTIVE);
+ }
+}
+
+function removeHighlight () {
+ document.querySelectorAll(SEL_ACTIVE).forEach(function (node) {
+ node.classList.remove(ACTIVE);
+ });
+}
+
+function resetNavPosition () {
+ var pagetoc = document.querySelector(SEL_TOC);
+ pagetoc?.scroll({ top: 0 });
+}
+
+export function backToTop () {
+ window.scrollTo({ top: 0, behavior: "smooth" });
+ resetNavPosition();
+}
+
+export function scrollSpy() {
+ const sections = Array.from(document.querySelectorAll(SEL_SECTIONS));
+
+ function matchingNavLink(elem) {
+ if (!elem) return;
+ var index = sections.indexOf(elem);
+
+ var match;
+ while (index >= 0 && !match) {
+ var sectionId = sections[index].getAttribute("id");
+ if (sectionId) {
+ match = document.querySelector(`${SEL_PAGETOC} [href="#${sectionId}"]`);
+ }
+ index--;
+ }
+ return match;
+ }
+
+ function belowBottomHalf(i) {
+ return i.boundingClientRect.bottom > (i.rootBounds.bottom + i.rootBounds.top) / 2;
+ }
+
+ function prevElem(elem) {
+ var index = sections.indexOf(elem);
+ if (index <= 0) {
+ return null;
+ }
+ return sections[index - 1];
+ }
+
+ const PAGE_LOAD_BUFFER = 1000;
+
+ function navHighlight(entries) {
+ entries.forEach(function (entry) {
+ if (entry.isIntersecting) {
+ updateHighlight(matchingNavLink(entry.target));
+ } else if (entry.time >= PAGE_LOAD_BUFFER && belowBottomHalf(entry)) {
+ updateHighlight(matchingNavLink(prevElem(entry.target)));
+ }
+ });
+ }
+
+ const observer = new IntersectionObserver(navHighlight, {
+ threshold: 0,
+ rootMargin: "0% 0px -95% 0px"
+ });
+
+ sections.forEach(function (elem) {
+ observer.observe(elem);
+ })
+ observer.observe(document.querySelector(SEL_PAGE));
+}
+
+document.addEventListener("DOMContentLoaded", scrollSpy);