summaryrefslogtreecommitdiffstats
path: root/docs/components
diff options
context:
space:
mode:
Diffstat (limited to 'docs/components')
-rw-r--r--docs/components/Copyright.jinja4
-rw-r--r--docs/components/Home.jinja154
-rw-r--r--docs/components/Logo.jinja7
-rw-r--r--docs/components/NavExtra.jinja1
-rw-r--r--docs/components/NavLinks.jinja2
-rw-r--r--docs/components/SocialCardIndex.jinja66
-rw-r--r--docs/components/guide/slots/CompArchive.jinja10
-rw-r--r--docs/components/guide/slots/CompLayout.jinja14
-rw-r--r--docs/components/guide/slots/Modal.jinja7
-rw-r--r--docs/components/guide/slots/ModalBody.jinja7
-rw-r--r--docs/components/guide/slots/ModalFooter.jinja7
-rw-r--r--docs/components/guide/slots/ModalHeader.jinja10
-rw-r--r--docs/components/ui/Accordion/Accordion.css67
-rw-r--r--docs/components/ui/Accordion/DemoCSS.jinja51
-rw-r--r--docs/components/ui/Accordion/DemoHTML.jinja29
-rw-r--r--docs/components/ui/Accordion/DemoResult.jinja32
-rw-r--r--docs/components/ui/Dialog/DemoCode.jinja6
-rw-r--r--docs/components/ui/Dialog/DemoPreview.jinja0
-rw-r--r--docs/components/ui/LinkedList/DemoCSS.jinja83
-rw-r--r--docs/components/ui/LinkedList/DemoHTML.jinja35
-rw-r--r--docs/components/ui/LinkedList/DemoResult.jinja89
-rw-r--r--docs/components/ui/LinkedList/LinkedList.css96
-rw-r--r--docs/components/ui/Menu/DemoCSS.jinja131
-rw-r--r--docs/components/ui/Menu/DemoHTML.jinja89
-rw-r--r--docs/components/ui/Menu/DemoResult.jinja94
-rw-r--r--docs/components/ui/Menu/Menu.css127
-rw-r--r--docs/components/ui/Popover/DemoCSS.jinja96
-rw-r--r--docs/components/ui/Popover/DemoHTML.jinja23
-rw-r--r--docs/components/ui/Popover/DemoResult.jinja27
-rw-r--r--docs/components/ui/Popover/Popover.css101
-rw-r--r--docs/components/ui/Tabs/DemoCSS.jinja59
-rw-r--r--docs/components/ui/Tabs/DemoHTML.jinja23
-rw-r--r--docs/components/ui/Tabs/DemoResult.jinja28
-rw-r--r--docs/components/ui/Tabs/ManualHTML.jinja28
-rw-r--r--docs/components/ui/Tabs/ManualResult.jinja33
-rw-r--r--docs/components/ui/Tabs/SelectHTML.jinja35
-rw-r--r--docs/components/ui/Tabs/SelectResult.jinja40
-rw-r--r--docs/components/ui/Tabs/Tabs.css126
-rw-r--r--docs/components/ui/Tabs/VerticalHTML.jinja28
-rw-r--r--docs/components/ui/Tabs/VerticalResult.jinja33
40 files changed, 1898 insertions, 0 deletions
diff --git a/docs/components/Copyright.jinja b/docs/components/Copyright.jinja
new file mode 100644
index 0000000..473b66b
--- /dev/null
+++ b/docs/components/Copyright.jinja
@@ -0,0 +1,4 @@
+<div {{ attrs.render(class="copy") }}>
+ <p>Website &copy; <a href="https://jpscaletti.com">Juan-Pablo Scaletti</a>.</p>
+ <p>JinjaX and the documentation text licensed under the MIT license.</p>
+</div> \ No newline at end of file
diff --git a/docs/components/Home.jinja b/docs/components/Home.jinja
new file mode 100644
index 0000000..045150b
--- /dev/null
+++ b/docs/components/Home.jinja
@@ -0,0 +1,154 @@
+<div class="homepage">
+ <section class="hero">
+ <h1>JinjaX</h1>
+ <h2>
+ Super
+ <span class="g1">components powers</span>
+ for your
+ <span class="g2">Jinja templates</span>
+ </h2>
+ </section>
+
+ <section class="code">
+ <div class="stack">
+ <div class="panel">
+ <h2>Before: chaos!</h2>
+{% filter markdown %}{% raw %}
+```html+jinja
+{% extends "layout.html" %}
+{% block title %}My title{% endblock %}
+
+{% from "bunch_of_macros.html"
+ import card_macro, another_macro %}
+
+{% block content -%}
+ <div>
+ <h2>Hello {{ mistery or "World?" }}</h2>
+ <div>
+ {% call card_macro(div="So verbose") %}
+ {% for product in products %}
+ {{ another_macro(product) }}
+ {% endfor %}
+ {% endcall %}
+ </div>
+ </div>
+ {% with items=products %}
+ {% include "snippets/pagination.html" %}
+ {% endwith %}
+{%- endblock %}
+```
+{% endraw %}{% endfilter %}
+ </div>
+
+ <div class="panel">
+ <h2>After: ✨ clarity ✨</h2>
+{% filter markdown %}{% raw %}
+```html+jinja
+{#def products, msg="World!" #}
+
+<Layout title="My title">
+ <div>
+ <h2>Hello, {{ msg }}</h2>
+ <div>
+ <Card div="So clean">
+ {% for product in products %}
+ <Product product={{ product }} />
+ {% endfor %}
+ </Card>
+ </div>
+ </div>
+ <Paginator items={{ products }} />
+</Layout>
+```
+{% endraw %}{% endfilter %}
+ </div>
+ </div>
+ </section>
+
+ <section class="features">
+ <h2>
+ Better than <code>include</code> and&nbsp;<code>macros</code>
+ </h2>
+ <div class="cd-cards">
+ <article class="card">
+ <div class="header">
+ <h3>Encapsulated</h3>
+ <img src="/static/img/encapsulated.svg" width="32" height="32">
+ </div>
+ <div class="body prose prose-zinc">
+ <div>
+ Link to their own <code>css</code> and/or <code>js</code> files
+ and can be copy/pasted to other projects without&nbsp;modifications.
+ </div>
+ </div>
+ </article>
+
+ <article class="card">
+ <div class="header">
+ <h3>Simple</h3>
+ <img src="/static/img/simple.svg" width="32" height="32">
+ </div>
+ <div class="body prose prose-zinc">
+ <div>
+ Just regular Jinja files and no need to import&nbsp;them.
+ Easier to use and easier to&nbsp;read.
+ </div>
+ </div>
+ </article>
+
+ <article class="card">
+ <div class="header">
+ <h3>Modern</h3>
+ <img src="/static/img/modern.svg" width="32" height="32">
+ </div>
+ <div class="body prose prose-zinc">
+ <div>
+ Components works great with
+ <a href="https://htmx.org/" target="_blank">htmx</a>,
+ <a href="https://tailwindcss.com/" target="_blank">TailwindCSS</a>,
+ or&nbsp;<a href="https://hotwired.dev/" target="_blank">Hotwire</a>
+ </div>
+ </div>
+ </article>
+
+ <article class="card">
+ <div class="header">
+ <h3>Composable</h3>
+ <img src="/static/img/composable.svg" width="32" height="32">
+ </div>
+ <div class="body prose prose-zinc">
+ <div>
+ Can wrap content (HTML, other components, etc.) in a natural&nbsp;way.
+ </div>
+ </div>
+ </article>
+ </div>
+ </section>
+
+ <section class="spaghetti">
+ <div class="wrapper">
+ <h2>
+ Say goodbye to spaghetti&nbsp;templates
+ </h2>
+
+ <div class="text">
+ <img src="/static/img/spaghetti_code.png" alt="Spaguetti code">
+
+ <p>Your Python code should be easy to understand and&nbsp;test.</p>
+ <p><b>Template code, however, often fails even basic code standards</b>: long methods, deep conditional nesting,and mystery variables&nbsp;everywhere.
+ </p>
+ <p><b>But when it's built with components, you see</b> where everything is, understand what are the possible statesof every piece of UI, and know exactly what data need to&nbsp;have.
+ </p>
+ <p>You can replace <b>all</b> your templates with components, or start with one&nbsp;section.</p>
+ </div>
+ </div>
+ </section>
+
+ <section class="engage" data-md-skip>
+ <div class="wrapper">
+ <h3>Ready to get going? Engage!</h3>
+ <a href="./guide/">Get started <i>&rarr;</i></a>
+ <div class="hint">Millions of people clicked a button in the last week alone!</div>
+ </div>
+ </section>
+</div> \ No newline at end of file
diff --git a/docs/components/Logo.jinja b/docs/components/Logo.jinja
new file mode 100644
index 0000000..3dd9ecd
--- /dev/null
+++ b/docs/components/Logo.jinja
@@ -0,0 +1,7 @@
+{#def base_url="/" #}
+
+<a
+ {{ attrs.render(class="Logo", href=base_url, title="Back home") }}>
+ <img class="light" src="/static/img/jinjax-logo.svg" width="140" aria-hidden>
+ <img class="dark" src="/static/img/jinjax-logo-w.svg" width="140" aria-hidden>
+</a>
diff --git a/docs/components/NavExtra.jinja b/docs/components/NavExtra.jinja
new file mode 100644
index 0000000..e6bb984
--- /dev/null
+++ b/docs/components/NavExtra.jinja
@@ -0,0 +1 @@
+<Source title="Go to repo" url="https://github.com/jpsca/jinjax" /> \ No newline at end of file
diff --git a/docs/components/NavLinks.jinja b/docs/components/NavLinks.jinja
new file mode 100644
index 0000000..fd2e693
--- /dev/null
+++ b/docs/components/NavLinks.jinja
@@ -0,0 +1,2 @@
+<a href="/guide/">Documentation</a>
+<a href="/ui/">UI components</a>
diff --git a/docs/components/SocialCardIndex.jinja b/docs/components/SocialCardIndex.jinja
new file mode 100644
index 0000000..54da150
--- /dev/null
+++ b/docs/components/SocialCardIndex.jinja
@@ -0,0 +1,66 @@
+{#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: black;
+ background-color: white
+ }
+ .sc1 > * {
+ position: absolute;
+ left: 100px;
+ width: 900px;
+ text-align: center;
+ overflow: hidden;
+ }
+ .sc1__logo {
+ top: 100px;
+ }
+ .sc1__logo img {
+ display: inline-block;
+ height: 200px;
+ width: auto;
+ margin: 0 auto;
+ }
+ .sc1__description {
+ top: 350px;
+ font-weight: bold;
+ font-size: 60px;
+ line-height: 1.2;
+ letter-spacing: -0.05em;
+ text-align: center;
+ }
+ .sc1__description .g1 {
+ background-image: linear-gradient(to bottom right, #fbbf24, #fb923c);
+ background-clip: text;
+ color: transparent;
+ }
+
+ .sc1__description .g2 {
+ background-image: linear-gradient(to bottom right, #34d399, #3b82f6);
+ background-clip: text;
+ color: transparent;
+ }
+ </style>
+
+ <article class="sc1">
+ <div class="sc1__logo">
+ <img src="/static/img/jinjax-logo.png" />
+ </div>
+ <div class="sc1__description">
+ Super
+ <span class="g1">components powers</span>
+ for your
+ <span class="g2">Jinja templates</span>
+ </div>
+ </article>
+</Layout>
diff --git a/docs/components/guide/slots/CompArchive.jinja b/docs/components/guide/slots/CompArchive.jinja
new file mode 100644
index 0000000..dc242fe
--- /dev/null
+++ b/docs/components/guide/slots/CompArchive.jinja
@@ -0,0 +1,10 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+{#def posts #}
+<Layout title="Archive">
+ {% for post in posts %}
+ <Post post={post} />
+ {% endfor %}
+</Layout>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/guide/slots/CompLayout.jinja b/docs/components/guide/slots/CompLayout.jinja
new file mode 100644
index 0000000..86c482e
--- /dev/null
+++ b/docs/components/guide/slots/CompLayout.jinja
@@ -0,0 +1,14 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+{#def title #}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>{{ title }}</title>
+</head>
+<body>
+ {{ content }}
+</body>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/guide/slots/Modal.jinja b/docs/components/guide/slots/Modal.jinja
new file mode 100644
index 0000000..c2a9f66
--- /dev/null
+++ b/docs/components/guide/slots/Modal.jinja
@@ -0,0 +1,7 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<dialog class="modal">
+ {{ content }}
+</dialog>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/guide/slots/ModalBody.jinja b/docs/components/guide/slots/ModalBody.jinja
new file mode 100644
index 0000000..66794ce
--- /dev/null
+++ b/docs/components/guide/slots/ModalBody.jinja
@@ -0,0 +1,7 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<div class="modal-body">
+ {{ content }}
+</div>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/guide/slots/ModalFooter.jinja b/docs/components/guide/slots/ModalFooter.jinja
new file mode 100644
index 0000000..e4eac26
--- /dev/null
+++ b/docs/components/guide/slots/ModalFooter.jinja
@@ -0,0 +1,7 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<footer class="modal-footer">
+ {{ content }}
+</footer>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/guide/slots/ModalHeader.jinja b/docs/components/guide/slots/ModalHeader.jinja
new file mode 100644
index 0000000..6f5bc52
--- /dev/null
+++ b/docs/components/guide/slots/ModalHeader.jinja
@@ -0,0 +1,10 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<header class="modal-header>
+ <h2 class="modal-title">
+ {{ content }}
+ </h2>
+ <CloseButton />
+</header>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/ui/Accordion/Accordion.css b/docs/components/ui/Accordion/Accordion.css
new file mode 100644
index 0000000..e39911b
--- /dev/null
+++ b/docs/components/ui/Accordion/Accordion.css
@@ -0,0 +1,67 @@
+@scope (#accordion-demo) {
+ :scope {
+ position: relative;
+ display: block;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 4rem 0.5rem 0;
+ height: 360px;
+ margin: 0 auto;
+ }
+ @media (min-width: 38rem) {
+ :scope {
+ width: 36rem;
+ }
+ }
+
+ details {
+ margin: 0;
+ border-width: 1px;
+ border-color: rgb(212 212 212);
+ background-color: rgb(245 245 245);
+ padding: 0;
+ overflow: hidden;
+ height: 3.5rem;
+ transition: all 0.15s ease-in-out;
+ }
+ details[open] {
+ height: 10rem;
+ }
+ details:focus-within {
+ box-shadow: 0 1px 2px 0 #2563eb;
+ }
+ details:first-of-type {
+ margin-top: 0px;
+ border-top-left-radius: 0.375rem;
+ border-top-right-radius: 0.375rem;
+ }
+ details:last-of-type {
+ margin-bottom: 0px;
+ border-bottom-left-radius: 0.375rem;
+ border-bottom-right-radius: 0.375rem;
+ }
+
+ summary {
+ position: relative;
+ height: 3.5rem;
+ border-bottom-width: 1px;
+ border-color: transparent;
+ background-color: rgb(255, 255, 255);
+ padding: 1rem 1.25rem;
+ color: rgb(0, 0, 0);
+ cursor: default;
+ }
+ details[open] > summary {
+ border-color: rgb(229 229 229);
+ }
+
+ .panel {
+ color: rgb(82 82 82);
+ padding: 0 1.25rem;
+ padding: 0.75rem 1.25rem;
+ }
+ .panel code {
+ font-weight: bold;
+ }
+} \ No newline at end of file
diff --git a/docs/components/ui/Accordion/DemoCSS.jinja b/docs/components/ui/Accordion/DemoCSS.jinja
new file mode 100644
index 0000000..d256041
--- /dev/null
+++ b/docs/components/ui/Accordion/DemoCSS.jinja
@@ -0,0 +1,51 @@
+{% filter markdown %}{% raw %}
+```css
+@scope (#accordion-demo) {
+ details {
+ margin: 0;
+ border-width: 1px;
+ border-color: rgb(212 212 212);
+ background-color: rgb(245 245 245);
+ padding: 0;
+ overflow: hidden;
+ height: 3.5rem;
+ width: 36rem;
+ transition: all 0.15s ease-in-out;
+ }
+ details[open] {
+ height: 10rem;
+ }
+ details:focus-within {
+ box-shadow: 0 1px 2px 0 #2563eb;
+ }
+ details:first-of-type {
+ margin-top: 0px;
+ border-top-left-radius: 0.375rem;
+ border-top-right-radius: 0.375rem;
+ }
+ details:last-of-type {
+ margin-bottom: 0px;
+ border-bottom-left-radius: 0.375rem;
+ border-bottom-right-radius: 0.375rem;
+ }
+ summary {
+ position: relative;
+ height: 3.5rem;
+ border-bottom-width: 1px;
+ border-color: transparent;
+ background-color: rgb(255, 255, 255);
+ padding: 1rem 1.25rem;
+ color: rgb(0, 0, 0);
+ cursor: default;
+ }
+ details[open] > summary {
+ border-color: rgb(229 229 229);
+ }
+ .panel {
+ color: rgb(82 82 82);
+ padding: 0 1.25rem;
+ padding: 0.75rem 1.25rem;
+ }
+}
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/ui/Accordion/DemoHTML.jinja b/docs/components/ui/Accordion/DemoHTML.jinja
new file mode 100644
index 0000000..1e28d29
--- /dev/null
+++ b/docs/components/ui/Accordion/DemoHTML.jinja
@@ -0,0 +1,29 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<Accordion>
+ <details>
+ <summary>Is it accessible?</summary>
+ <div class="panel">
+ Yes, more than any custom accordion you'll find on the web, because it's made
+ with native elements.
+ </div>
+ </details>
+
+ <details>
+ <summary>Is it unstyled?</summary>
+ <div class="panel">
+ Yes. The Accordion doesn't need any styles, you are free to style your
+ <code>&lt;details&gt;</code> elements however you need.
+ </div>
+ </details>
+
+ <details>
+ <summary>Can it be animated?</summary>
+ <div class="panel">
+ The <code>&lt;details&gt;</code> elements can be animated (with some restrictions)
+ using CSS animations, or with JS.
+ </div>
+ </details>
+</Accordion>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Accordion/DemoResult.jinja b/docs/components/ui/Accordion/DemoResult.jinja
new file mode 100644
index 0000000..8666e2d
--- /dev/null
+++ b/docs/components/ui/Accordion/DemoResult.jinja
@@ -0,0 +1,32 @@
+{#css ui/Accordion/Accordion.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(252,211,77, 0.9), rgba(251,146,60, 0.9))"
+ data-md-skip
+></div>
+
+<Accordion id="accordion-demo" data-md-skip>
+ <details>
+ <summary>Is it accessible?</summary>
+ <div class="panel">
+ Yes, more than any custom accordion you'll find on the web, because it's made
+ with native elements.
+ </div>
+ </details>
+
+ <details>
+ <summary>Is it unstyled?</summary>
+ <div class="panel">
+ Yes. The Accordion doesn't need any styles, you are free to style your
+ <code>&lt;details&gt;</code> elements however you need.
+ </div>
+ </details>
+
+ <details>
+ <summary>Can it be animated?</summary>
+ <div class="panel">
+ The <code>&lt;details&gt;</code> elements can be animated (with some restrictions)
+ using CSS animations, or with JS.
+ </div>
+ </details>
+</Accordion> \ No newline at end of file
diff --git a/docs/components/ui/Dialog/DemoCode.jinja b/docs/components/ui/Dialog/DemoCode.jinja
new file mode 100644
index 0000000..36ecb76
--- /dev/null
+++ b/docs/components/ui/Dialog/DemoCode.jinja
@@ -0,0 +1,6 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+{# Style classes and some content removed for clarity #}
+
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Dialog/DemoPreview.jinja b/docs/components/ui/Dialog/DemoPreview.jinja
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/components/ui/Dialog/DemoPreview.jinja
diff --git a/docs/components/ui/LinkedList/DemoCSS.jinja b/docs/components/ui/LinkedList/DemoCSS.jinja
new file mode 100644
index 0000000..0927d4e
--- /dev/null
+++ b/docs/components/ui/LinkedList/DemoCSS.jinja
@@ -0,0 +1,83 @@
+{% filter markdown %}{% raw %}
+```css
+.ui-linkedlist {
+ padding: 0px;
+ background-color: rgb(255 255 255);
+ overscroll-behavior: contain;
+ overflow-y: scroll;
+ list-style-type: none;
+ height: 16rem;
+ margin: 0px;
+ border: 1px solid rgb(128 128 128);
+ border-radius: 0.25rem;
+ font-size: 0.85rem;
+}
+.ui-linkedlist li {
+ cursor: pointer;
+ display: flex;
+ padding: 0.25rem 1rem;
+ align-items: center;
+}
+.ui-linkedlist li[disabled] {
+ color: rgb(156 156 156);
+ cursor: default;
+}
+.ui-linkedlist li:hover {
+ background-color: rgb(243 244 246);
+}
+.ui-linkedlist input[type="checkbox"] {
+ margin-right: 0.5rem;
+}
+label {
+ display: inline-block;
+ font-weight: bold;
+ background-color: white;
+ padding: 0.25rem 2rem;
+ border: 1px solid rgb(128 128 128);
+ border-radius: 0.25rem 0.25rem 0 0;
+ font-size: 0.7rem;
+ margin-bottom: -1px;
+}
+
+button {
+ margin-top: 0.5rem;
+ display: inline-flex;
+ cursor: pointer;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ align-items: center;
+ justify-content: center;
+}
+button > :not([hidden]) ~ :not([hidden]) {
+ margin-left: 0.25rem;
+}
+button {
+ white-space: nowrap;
+ border-radius: 0.25rem;
+ border: 1px solid transparent;
+ background-color: rgb(229 231 235);
+ padding: 0.5rem 0.75rem;
+ text-align: center;
+ font-size: 0.75rem;
+ line-height: 1rem;
+}
+button:hover {
+ border-color: rgb(219 234 254);
+ background-color: rgb(243 244 246);
+}
+button:focus {
+ background-color: rgb(229 231 235);
+ outline-offset: 1px;
+ outline-color: #3b82f6;
+}
+@media (min-width: 640px) {
+ button {
+ padding: 0.25rem 0.5rem;
+ }
+}
+button.select-all {
+ float: right;
+}
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/ui/LinkedList/DemoHTML.jinja b/docs/components/ui/LinkedList/DemoHTML.jinja
new file mode 100644
index 0000000..375ddd7
--- /dev/null
+++ b/docs/components/ui/LinkedList/DemoHTML.jinja
@@ -0,0 +1,35 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<div>
+ <label>Known Mutants</label>
+ <LinkedList id="linkedlist-demo-list1" linked_to="linkedlist-demo-list2">
+ <li><input type="checkbox" name="users" value="1" />
+ Alexander Summers</li>
+ <!-- ... etc ... -->
+ <li><input type="checkbox" name="users" value="27" />
+ Warren Worthington III</li>
+ </LinkedList>
+
+ <button
+ type="button"
+ class="select-all"
+ onclick="document.getElementById('linkedlist-demo-list1').dispatchEvent(new CustomEvent('jxui:linked:sendall'));"
+ >
+ Select all &raquo;
+ </button>
+</div>
+<div>
+ <label>X-Men</label>
+ <LinkedList id="linkedlist-demo-list2" linked_to="linkedlist-demo-list1" active>
+ </LinkedList>
+
+ <button
+ type="button"
+ class="remove-all"
+ onclick="document.getElementById('linkedlist-demo-list2').dispatchEvent(new CustomEvent('jxui:linked:sendall'));"
+ >
+ &laquo; Remove all
+ </button>
+</div>
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/ui/LinkedList/DemoResult.jinja b/docs/components/ui/LinkedList/DemoResult.jinja
new file mode 100644
index 0000000..e3d9631
--- /dev/null
+++ b/docs/components/ui/LinkedList/DemoResult.jinja
@@ -0,0 +1,89 @@
+{#css ui/LinkedList/LinkedList.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(132,204,22,0.7), rgba(22,163,74,0.7))"
+ data-md-skip
+></div>
+
+<div id="linkedlist-demo" data-md-skip>
+ <div>
+ <label>Known Mutants</label>
+ <LinkedList id="linkedlist-demo-list1" linked_to="linkedlist-demo-list2">
+ <li><input type="checkbox" name="users" value="1" />
+ Alexander Summers</li>
+ <li><input type="checkbox" name="users" value="2" />
+ Alison Blaire</li>
+ <li><input type="checkbox" name="users" value="3" />
+ Anna Marie LeBeau</li>
+ <li><input type="checkbox" name="users" value="4" />
+ Charles Francis Xavier</li>
+ <li><input type="checkbox" name="users" value="5" />
+ Elizabeth Braddock</li>
+ <li><input type="checkbox" name="users" value="6" />
+ Emma Grace Frost</li>
+ <li disabled><input type="checkbox" name="users" value="7" disabled />
+ Erik Magnus Lehnsherr</li>
+ <li><input type="checkbox" name="users" value="8" />
+ Henry Philip McCoy</li>
+ <li><input type="checkbox" name="users" value="9" />
+ James Howlett</li>
+ <li><input type="checkbox" name="users" value="10" />
+ Jean Elaine Grey</li>
+ <li><input type="checkbox" name="users" value="11" />
+ John Proudstar</li>
+ <li><input type="checkbox" name="users" value="12" />
+ Jubilation Lee</li>
+ <li><input type="checkbox" name="users" value="13" />
+ Katherine Anne Pryde</li>
+ <li><input type="checkbox" name="users" value="14" />
+ Kurt Wagner</li>
+ <li><input type="checkbox" name="users" value="15" />
+ Lucas Bishop</li>
+ <li><input type="checkbox" name="users" value="16" />
+ Nathan Summers</li>
+ <li><input type="checkbox" name="users" value="17" />
+ Ororo Munroe</li>
+ <li><input type="checkbox" name="users" value="18" />
+ Piotr Nikolaievitch Rasputin</li>
+ <li><input type="checkbox" name="users" value="19
+ Rachel Anne Summers</li>
+ <li><input type="checkbox" name="users" value="20" />
+ Raven Darkhölme</li>
+ <li><input type="checkbox" name="users" value="21" />
+ Remy Etienne LeBeau</li>
+ <li><input type="checkbox" name="users" value="22" />
+ Robert Louis Drake</li>
+ <li><input type="checkbox" name="users" value="23" />
+ Roberto da Costa</li>
+ <li><input type="checkbox" name="users" value="24" />
+ Scott Summers</li>
+ <li><input type="checkbox" name="users" value="25" />
+ Sean Cassidy</li>
+ <li><input type="checkbox" name="users" value="26" />
+ Shiro Yoshida</li>
+ <li><input type="checkbox" name="users" value="27" />
+ Warren Worthington III</li>
+ </LinkedList>
+
+ <button
+ type="button"
+ class="select-all"
+ onclick="document.getElementById('linkedlist-demo-list1').dispatchEvent(new CustomEvent('jxui:linked:sendall'));"
+ >
+ Select all &raquo;
+ </button>
+ </div>
+ <div>
+ <label>X-Men</label>
+ <LinkedList id="linkedlist-demo-list2" linked_to="linkedlist-demo-list1" active>
+ </LinkedList>
+
+ <button
+ type="button"
+ class="remove-all"
+ onclick="document.getElementById('linkedlist-demo-list2').dispatchEvent(new CustomEvent('jxui:linked:sendall'));"
+ >
+ &laquo; Remove all
+ </button>
+ </div>
+</div> \ No newline at end of file
diff --git a/docs/components/ui/LinkedList/LinkedList.css b/docs/components/ui/LinkedList/LinkedList.css
new file mode 100644
index 0000000..fd69adc
--- /dev/null
+++ b/docs/components/ui/LinkedList/LinkedList.css
@@ -0,0 +1,96 @@
+@scope (#linkedlist-demo) {
+ :scope {
+ position: relative;
+ display: block;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.5rem;
+ height: 360px;
+ margin: 0 auto;
+ }
+ :scope > div {
+ width: 100%;
+ margin: 0 1rem;
+ }
+
+ .ui-linkedlist {
+ padding: 0px;
+ background-color: rgb(255 255 255);
+ overscroll-behavior: contain;
+ overflow-y: scroll;
+ list-style-type: none;
+ height: 16rem;
+ margin: 0px;
+ border: 1px solid rgb(128 128 128);
+ border-radius: 0.25rem;
+ font-size: 0.85rem;
+ }
+ .ui-linkedlist li {
+ cursor: pointer;
+ display: flex;
+ padding: 0.25rem 1rem;
+ align-items: center;
+ }
+ .ui-linkedlist li[disabled] {
+ color: rgb(156 156 156);
+ cursor: default;
+ }
+ .ui-linkedlist li:hover {
+ background-color: rgb(243 244 246);
+ }
+ .ui-linkedlist input[type="checkbox"] {
+ margin-right: 0.5rem;
+ }
+ label {
+ display: inline-block;
+ font-weight: bold;
+ background-color: white;
+ padding: 0.25rem 2rem;
+ border: 1px solid rgb(128 128 128);
+ border-radius: 0.25rem 0.25rem 0 0;
+ font-size: 0.7rem;
+ margin-bottom: -1px;
+ }
+
+ button {
+ margin-top: 0.5rem;
+ display: inline-flex;
+ cursor: pointer;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ align-items: center;
+ justify-content: center;
+ }
+ button > :not([hidden]) ~ :not([hidden]) {
+ margin-left: 0.25rem;
+ }
+ button {
+ white-space: nowrap;
+ border-radius: 0.25rem;
+ border: 1px solid transparent;
+ background-color: rgb(229 231 235);
+ padding: 0.5rem 0.75rem;
+ text-align: center;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ }
+ button:hover {
+ border-color: rgb(219 234 254);
+ background-color: rgb(243 244 246);
+ }
+ button:focus {
+ background-color: rgb(229 231 235);
+ outline-offset: 1px;
+ outline-color: #3b82f6;
+ }
+ @media (min-width: 640px) {
+ button {
+ padding: 0.25rem 0.5rem;
+ }
+ }
+ button.select-all {
+ float: right;
+ }
+} \ No newline at end of file
diff --git a/docs/components/ui/Menu/DemoCSS.jinja b/docs/components/ui/Menu/DemoCSS.jinja
new file mode 100644
index 0000000..d726800
--- /dev/null
+++ b/docs/components/ui/Menu/DemoCSS.jinja
@@ -0,0 +1,131 @@
+{% filter markdown %}{% raw %}
+```css
+@scope (#menu-demo) {
+ :scope {
+ position: relative;
+ display: block;
+ padding: 2rem 0.5rem 0;
+ height: 300px;
+ margin: 0 auto;
+ }
+
+ .ui-menubutton {
+ border-radius: 0.25rem;
+ border-width: 1px;
+ background-color: rgb(0 0 0 / 0.1);
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-weight: 600;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
+ width: fit-content;
+ margin: 0 auto;
+ }
+ .ui-menubutton:hover {
+ background-color: rgb(0 0 0 / 0.2);
+ }
+ .ui-menubutton .icon {
+ margin-left: 0.25rem;
+ }
+
+ .group:not([hidden]) ~ .group:not([hidden]) {
+ border-top: 1px solid #d1d5db;
+ }
+ .ui-menu {
+ margin-top: 4px;
+ padding: 8px 0;
+ border-radius: 8px;
+ width: 400px;
+ background-color: #ffffff;
+ box-shadow: 0 1px 3px 4px rgba(0, 0, 0, 0.2);
+ overflow: visible;
+ font-size: 0.9rem;
+ font-weight: 400;
+ transition: all 0.2s allow-discrete;
+ /* Final state of the exit animation */
+ opacity: 0;
+ transform: translateY(-1rem);
+ }
+ .ui-menu:popover-open {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ /* Needs to be after the previous .ui-menu:popover-open rule
+ to take effect, as the specificity is the same */
+ @starting-style {
+ .ui-menu:popover-open {
+ opacity: 0;
+ transform: translateY(-1rem);
+ }
+ }
+ .ui-menu:focus {
+ outline: none;
+ }
+ .ui-menu .ui-menu {
+ position: absolute;
+ margin: 0 0 0 -4px;
+ width: 300px;
+ z-index: 1;
+ transition: opacity 0.2s allow-discrete;
+ }
+ .ui-menu * {
+ user-select: none;
+ }
+
+ .ui-menuitem {
+ display: flex;
+ height: 40px;
+ padding-left: 24px;
+ padding-right: 24px;
+ align-items: center;
+ justify-items: flex-start;
+ line-height: 40px;
+ color: #000000;
+ background-color: #ffffff;
+ cursor: default;
+ user-select: none;
+ position: relative;
+ text-align: left;
+ }
+ .ui-menuitem.ui-selected {
+ background-color: #f2e7e4;
+ }
+ .ui-menuitem.ui-disabled {
+ color: #5f6368;
+ }
+ .ui-menuitem > .icon {
+ font-size: 1rem;
+ width: 24px;
+ text-align: left;
+ }
+ .ui-menuitem.ui-disabled > .icon {
+ color: #aca6a7;
+ }
+ .ui-menuitem > a {
+ flex-grow: 1;
+ }
+ .ui-menuitem > kbd {
+ visibility: hidden;
+ margin-left: auto;
+ font-size: 0.9rem;
+ font-family: inherit;
+ text-align: right;
+ color: #524f50;
+ }
+ .ui-menuitem:not(.ui-disabled):hover > kbd {
+ visibility: visible;
+ }
+ .ui-menuitem > .arrow {
+ margin-left: auto;
+ font-size: 0.7rem;
+ text-align: right;
+ }
+}
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Menu/DemoHTML.jinja b/docs/components/ui/Menu/DemoHTML.jinja
new file mode 100644
index 0000000..60c126a
--- /dev/null
+++ b/docs/components/ui/Menu/DemoHTML.jinja
@@ -0,0 +1,89 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<MenuButton id="menu-demo-btn" target="menu-demo-menu">
+ Menu <i class="icon">keyboard_arrow_down</i>
+</MenuButton>
+
+<Menu id="menu-demo-menu" anchor="menu-demo-btn" anchor-to="bottom end">
+ <div class="group">
+ <MenuItem>
+ <i class="icon">tab</i>
+ <a>New tab</a>
+ <kbd>Ctrl+T</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">new_window</i>
+ <a>New window</a>
+ <kbd>Ctrl+N</kbd>
+ </MenuItem>
+ <MenuItem disabled>
+ <i class="icon">fingerprint_off</i>
+ <a>Disabled item</a>
+ <kbd>Ctrl+Shift+N</kbd>
+ </MenuItem>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">download</i>
+ <a>Downloads</a>
+ <kbd>Ctrl+J</kbd>
+ </MenuItem>
+ <MenuItemSub id="bookmarks-item">
+ <i class="icon">bookmarks</i>
+ <a>Bookmarks and lists</a>
+ <span class="icon arrow">keyboard_arrow_right</span>
+
+ <Menu anchor="bookmarks-item" anchor_to="right start">
+ <div class="group">
+ <MenuItem>
+ <i class="icon">bookmark_add</i>
+ <a>Bookmark this tab...</a>
+ <kbd>Ctrl+D</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmarks</i>
+ <a>Bookmark all tabs...</a>
+ <kbd>Ctrl+Shift+D</kbd>
+ </MenuItem>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">toolbar</i>
+ <a>Hide bookmarks bar</a>
+ <kbd>Ctrl+Shift+B</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmarks</i>
+ <a>Show all bookmarks</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmark_manager</i>
+ <a>Bookmark manager</a>
+ <kbd>Ctrl+Shift+O</kbd>
+ </MenuItem>
+ </div>
+ </Menu>
+ </MenuItemSub>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">print</i>
+ <a>Print...</a>
+ <kbd>Ctrl+P</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">help</i>
+ <a>Help</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">settings</i>
+ <a>Settings</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">exit_to_app</i>
+ <a>Exit</a>
+ </MenuItem>
+ </div>
+</Menu>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Menu/DemoResult.jinja b/docs/components/ui/Menu/DemoResult.jinja
new file mode 100644
index 0000000..b62226c
--- /dev/null
+++ b/docs/components/ui/Menu/DemoResult.jinja
@@ -0,0 +1,94 @@
+{#css ui/Menu/Menu.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(244,114,182, 0.9), rgba(219,39,119, 0.9))"
+ data-md-skip
+></div>
+
+<div id="menu-demo" data-md-skip>
+ <MenuButton id="menu-demo-btn" target="menu-demo-menu">
+ Menu <i class="icon">keyboard_arrow_down</i>
+ </MenuButton>
+
+ <Menu id="menu-demo-menu" anchor="menu-demo-btn" anchor-to="bottom end">
+ <div class="group">
+ <MenuItem>
+ <i class="icon">tab</i>
+ <a>New tab</a>
+ <kbd>Ctrl+T</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">new_window</i>
+ <a>New window</a>
+ <kbd>Ctrl+N</kbd>
+ </MenuItem>
+ <MenuItem disabled>
+ <i class="icon">fingerprint_off</i>
+ <a>Disabled item</a>
+ <kbd>Ctrl+Shift+N</kbd>
+ </MenuItem>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">download</i>
+ <a>Downloads</a>
+ <kbd>Ctrl+J</kbd>
+ </MenuItem>
+ <MenuItemSub id="bookmarks-item">
+ <i class="icon">bookmarks</i>
+ <a>Bookmarks and lists</a>
+ <span class="icon arrow">keyboard_arrow_right</span>
+
+ <Menu anchor="bookmarks-item" anchor_to="right start">
+ <div class="group">
+ <MenuItem>
+ <i class="icon">bookmark_add</i>
+ <a>Bookmark this tab...</a>
+ <kbd>Ctrl+D</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmarks</i>
+ <a>Bookmark all tabs...</a>
+ <kbd>Ctrl+Shift+D</kbd>
+ </MenuItem>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">toolbar</i>
+ <a>Hide bookmarks bar</a>
+ <kbd>Ctrl+Shift+B</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmarks</i>
+ <a>Show all bookmarks</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">bookmark_manager</i>
+ <a>Bookmark manager</a>
+ <kbd>Ctrl+Shift+O</kbd>
+ </MenuItem>
+ </div>
+ </Menu>
+ </MenuItemSub>
+ </div>
+ <div class="group">
+ <MenuItem>
+ <i class="icon">print</i>
+ <a>Print...</a>
+ <kbd>Ctrl+P</kbd>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">help</i>
+ <a>Help</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">settings</i>
+ <a>Settings</a>
+ </MenuItem>
+ <MenuItem>
+ <i class="icon">exit_to_app</i>
+ <a>Exit</a>
+ </MenuItem>
+ </div>
+ </Menu>
+</div>
diff --git a/docs/components/ui/Menu/Menu.css b/docs/components/ui/Menu/Menu.css
new file mode 100644
index 0000000..a93313d
--- /dev/null
+++ b/docs/components/ui/Menu/Menu.css
@@ -0,0 +1,127 @@
+@scope (#menu-demo) {
+ :scope {
+ position: relative;
+ display: block;
+ padding: 2rem 0.5rem 0;
+ height: 200px;
+ margin: 0 auto;
+ }
+
+ .ui-menubutton {
+ border-radius: 0.25rem;
+ border-width: 1px;
+ background-color: rgb(0 0 0 / 0.1);
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-weight: 600;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
+ width: fit-content;
+ margin: 0 auto;
+ }
+ .ui-menubutton:hover {
+ background-color: rgb(0 0 0 / 0.2);
+ }
+ .ui-menubutton .icon {
+ margin-left: 0.25rem;
+ }
+
+ .group:not([hidden]) ~ .group:not([hidden]) {
+ border-top: 1px solid #d1d5db;
+ }
+ .ui-menu {
+ margin-top: 4px;
+ padding: 8px 0;
+ border-radius: 8px;
+ width: 400px;
+ background-color: #ffffff;
+ box-shadow: 0 1px 3px 4px rgba(0, 0, 0, 0.2);
+ overflow: visible;
+ font-size: 0.9rem;
+ font-weight: 400;
+ transition: all 0.2s allow-discrete;
+ /* Final state of the exit animation */
+ opacity: 0;
+ transform: translateY(-1rem);
+ }
+ .ui-menu:popover-open {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ /* Needs to be after the previous .ui-menu:popover-open rule
+ to take effect, as the specificity is the same */
+ @starting-style {
+ .ui-menu:popover-open {
+ opacity: 0;
+ transform: translateY(-1rem);
+ }
+ }
+ .ui-menu:focus {
+ outline: none;
+ }
+ .ui-menu .ui-menu {
+ position: absolute;
+ margin: 0 0 0 -4px;
+ width: 300px;
+ z-index: 1;
+ transition: opacity 0.2s allow-discrete;
+ }
+ .ui-menu * {
+ user-select: none;
+ }
+
+ .ui-menuitem {
+ display: flex;
+ height: 40px;
+ padding-left: 24px;
+ padding-right: 24px;
+ align-items: center;
+ justify-items: flex-start;
+ line-height: 40px;
+ color: #000000;
+ background-color: #ffffff;
+ cursor: default;
+ user-select: none;
+ position: relative;
+ text-align: left;
+ }
+ .ui-menuitem.ui-selected {
+ background-color: #f2e7e4;
+ }
+ .ui-menuitem.ui-disabled {
+ color: #5f6368;
+ }
+ .ui-menuitem > .icon {
+ font-size: 1rem;
+ width: 24px;
+ text-align: left;
+ }
+ .ui-menuitem.ui-disabled > .icon {
+ color: #aca6a7;
+ }
+ .ui-menuitem > a {
+ flex-grow: 1;
+ }
+ .ui-menuitem > kbd {
+ visibility: hidden;
+ margin-left: auto;
+ font-size: 0.9rem;
+ font-family: inherit;
+ text-align: right;
+ color: #524f50;
+ }
+ .ui-menuitem:not(.ui-disabled):hover > kbd {
+ visibility: visible;
+ }
+ .ui-menuitem > .arrow {
+ margin-left: auto;
+ font-size: 0.7rem;
+ text-align: right;
+ }
+} \ No newline at end of file
diff --git a/docs/components/ui/Popover/DemoCSS.jinja b/docs/components/ui/Popover/DemoCSS.jinja
new file mode 100644
index 0000000..83418c9
--- /dev/null
+++ b/docs/components/ui/Popover/DemoCSS.jinja
@@ -0,0 +1,96 @@
+{% filter markdown %}{% raw %}
+```css
+.ui-popbutton {
+ border-radius: 0.25rem;
+ border-width: 1px;
+ background-color: rgb(0 0 0 / 0.1);
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-weight: 600;
+ color: white;
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
+}
+.ui-popbutton:hover {
+ background-color: rgb(0 0 0 / 0.2);
+}
+
+[popover] {
+ background-color: Canvas;
+ border-radius: 0.25rem;
+ border: 1px solid #666;
+ color: CanvasText;
+ height: fit-content;
+ margin: 0.75rem auto 0;
+ padding: 1rem;
+ width: 15rem;
+ overflow: visible;
+ transition: all 0.2s allow-discrete;
+ /* Final state of the exit animation */
+ opacity: 0;
+ transform: translateY(-3rem);
+}
+[popover]:popover-open {
+ opacity: 1;
+ transform: translateY(0);
+}
+/* Needs to be after the previous [popover]:popover-open rule
+to take effect, as the specificity is the same */
+@starting-style {
+ [popover]:popover-open {
+ opacity: 0;
+ transform: translateY(-3rem);
+ }
+}
+
+/* Transition for the popover's backdrop */
+[popover]::backdrop {
+ transition: all 0.2s allow-discrete;
+ /* Final state of the exit animation */
+ background-color: rgb(0 0 0 / 0%);
+}
+[popover]:popover-open::backdrop {
+ background-color: rgb(0 0 0 / 15%);
+}
+/* The nesting selector (&) cannot represent pseudo-elements
+so this starting-style rule cannot be nested */
+@starting-style {
+ [popover]:popover-open::backdrop {
+ background-color: rgb(0 0 0 / 0%);
+ }
+}
+
+[popover] h1 {
+ font-weight: bold;
+ margin-bottom: 0.75rem;
+}
+[popover] label {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 0.75rem;
+ line-height: 1rem;
+}
+[popover] input {
+ margin-left: auto;
+ width: 66.666667%;
+ border-radius: 0.25rem;
+ border-width: 1px;
+ padding: 0.25rem;
+ font-size: 0.75rem;
+ line-height: 1rem;
+}
+[popover] svg.arrow {
+ position: absolute;
+ top: -4px;
+ left: 50%;
+ z-index: 10;
+ display: block;
+ transform: rotate(180deg);
+ border-color: rgb(255 255 255);
+ fill: white;
+}
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Popover/DemoHTML.jinja b/docs/components/ui/Popover/DemoHTML.jinja
new file mode 100644
index 0000000..b40ddfb
--- /dev/null
+++ b/docs/components/ui/Popover/DemoHTML.jinja
@@ -0,0 +1,23 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<PopButton id="pop-demo-btn" target="pop-demo-pop">Open popover</PopButton>
+
+<Popover id="pop-demo-pop" anchor="pop-demo-btn" anchor-to="bottom">
+ <h1>Edit Dimensions</h1>
+ <fieldset class="space-y-2">
+ <label>
+ <span>Width</span>
+ <input type="text" name="width" value="340px">
+ </label>
+ <label>
+ <span>Height</span>
+ <input type="text" name="height" value="25px">
+ </label>
+ </fieldset>
+
+ <svg class="arrow" width="10" height="5" viewBox="0 0 30 10" aria-hidden="true">
+ <polygon points="0,0 30,0 15,10"></polygon>
+ </svg>
+</Popover>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Popover/DemoResult.jinja b/docs/components/ui/Popover/DemoResult.jinja
new file mode 100644
index 0000000..a0b73e8
--- /dev/null
+++ b/docs/components/ui/Popover/DemoResult.jinja
@@ -0,0 +1,27 @@
+{#css ui/Popover/Popover.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(217,70,239, 0.9), rgba(147,51,234, 0.9))"
+ data-md-skip
+></div>
+
+<div id="pop-demo" data-md-skip>
+ <PopButton id="pop-demo-btn" target="pop-demo-pop">Open popover</PopButton>
+
+ <Popover id="pop-demo-pop" anchor="pop-demo-btn" anchor-to="bottom">
+ <h1 data-outline-skip=>Edit Dimensions</h1>
+ <fieldset class="space-y-2">
+ <label>
+ <span>Width</span>
+ <input type="text" name="width" value="340px">
+ </label>
+ <label>
+ <span>Height</span>
+ <input type="text" name="height" value="25px">
+ </label>
+ </fieldset>
+ <svg class="arrow" width="10" height="5" viewBox="0 0 30 10" aria-hidden="true">
+ <polygon points="0,0 30,0 15,10"></polygon>
+ </svg>
+ </Popover>
+</div>
diff --git a/docs/components/ui/Popover/Popover.css b/docs/components/ui/Popover/Popover.css
new file mode 100644
index 0000000..724547f
--- /dev/null
+++ b/docs/components/ui/Popover/Popover.css
@@ -0,0 +1,101 @@
+@scope (#pop-demo) {
+ :scope {
+ position: relative;
+ display: block;
+ padding: 2rem 0.5rem 0;
+ height: 300px;
+ margin: 0 auto;
+ text-align: center;
+ }
+
+ .ui-popbutton {
+ border-radius: 0.25rem;
+ border-width: 1px;
+ background-color: rgb(0 0 0 / 0.1);
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-weight: 600;
+ color: white;
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1),
+ 0 4px 6px -4px rgb(0 0 0 / 0.1);
+ }
+ .ui-popbutton:hover {
+ background-color: rgb(0 0 0 / 0.2);
+ }
+
+ [popover] {
+ background-color: Canvas;
+ border-radius: 0.25rem;
+ border: 1px solid #666;
+ color: CanvasText;
+ height: fit-content;
+ margin: 0.75rem auto 0;
+ padding: 1rem;
+ width: 15rem;
+ overflow: visible;
+ transition: all 0.2s allow-discrete;
+ /* Final state of the exit animation */
+ opacity: 0;
+ transform: translateY(-3rem);
+ }
+ [popover]:popover-open {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ /* Needs to be after the previous [popover]:popover-open rule
+ to take effect, as the specificity is the same */
+ @starting-style {
+ [popover]:popover-open {
+ opacity: 0;
+ transform: translateY(-3rem);
+ }
+ }
+
+ /* Transition for the popover's backdrop */
+ [popover]::backdrop {
+ /* Final state of the exit animation */
+ background-color: rgb(0 0 0 / 0%);
+ transition: all 0.2s allow-discrete;
+ }
+ [popover]:popover-open::backdrop {
+ background-color: rgb(0 0 0 / 15%);
+ }
+ @starting-style {
+ [popover]:popover-open::backdrop {
+ background-color: rgb(0 0 0 / 0%);
+ }
+ }
+
+ [popover] h1 {
+ font-weight: bold;
+ margin-bottom: 0.75rem;
+ }
+ [popover] label {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ }
+ [popover] input {
+ margin-left: auto;
+ width: 66.666667%;
+ border-radius: 0.25rem;
+ border-width: 1px;
+ padding: 0.25rem;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ }
+ [popover] svg.arrow {
+ position: absolute;
+ top: -4px;
+ left: 50%;
+ z-index: 10;
+ display: block;
+ transform: rotate(180deg);
+ border-color: rgb(255 255 255);
+ fill: white;
+ }
+} \ No newline at end of file
diff --git a/docs/components/ui/Tabs/DemoCSS.jinja b/docs/components/ui/Tabs/DemoCSS.jinja
new file mode 100644
index 0000000..07db8f0
--- /dev/null
+++ b/docs/components/ui/Tabs/DemoCSS.jinja
@@ -0,0 +1,59 @@
+{% filter markdown %}{% raw %}
+```css
+.ui-tablist {
+ display: flex;
+}
+.ui-tablist > :not([hidden]) ~ :not([hidden]) {
+ margin-left: 0.25rem ;
+}
+.ui-tablist {
+ border-radius: 1rem;
+ background-color: rgb(30 58 138 / 0.6);
+ padding: 0.5rem;
+ color: #111;
+}
+.ui-tablist > .ui-tab:not([hidden]) ~ .ui-tab:not([hidden]) {
+ margin-left: 0.5rem;
+}
+.ui-tab {
+ width: 100%;
+ border-radius: 0.5rem;
+ color: #222;
+ background-color: rgb(255 255 255 / 0.7);
+ padding: 0.75rem 0.25rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ line-height: 1.25rem;
+}
+.ui-tab:focus {
+ outline: 2px solid rgb(59 130 246 / 0.8);
+ outline-offset: 2px;
+}
+.ui-tab.ui-selected {
+ background-color: white;
+ color: black;
+}
+.ui-tab:hover:not(.ui-selected, .ui-disabled),
+.ui-tab:focus:not(.ui-selected, .ui-disabled) {
+ background-color: rgb(255 255 255 / 0.8);
+}
+.ui-tabpanel {
+ margin-top: 0.5rem;
+ border-radius: 0.75rem;
+ background-color: rgb(254 254 254);
+ border: 2px solid rgb(59 130 246 / 0.8);
+ padding: 0.1rem;
+ min-height: 8rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.ui-tabpanel:focus {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+.ui-tabpanel.ui-hidden {
+ display: none;
+}
+```
+{% endraw %}{% endfilter %} \ No newline at end of file
diff --git a/docs/components/ui/Tabs/DemoHTML.jinja b/docs/components/ui/Tabs/DemoHTML.jinja
new file mode 100644
index 0000000..e267335
--- /dev/null
+++ b/docs/components/ui/Tabs/DemoHTML.jinja
@@ -0,0 +1,23 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<TabGroup>
+ <TabList>
+ <Tab target="demo-recent" selected>Recent</Tab>
+ <Tab target="demo-popular">Popular</Tab>
+ <Tab target="demo-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id>
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="demo-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="demo-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+</TabGroup>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Tabs/DemoResult.jinja b/docs/components/ui/Tabs/DemoResult.jinja
new file mode 100644
index 0000000..3306eac
--- /dev/null
+++ b/docs/components/ui/Tabs/DemoResult.jinja
@@ -0,0 +1,28 @@
+{#css ui/Tabs/Tabs.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(56,189,248, 0.9), rgba(37,99,235, 0.9))"
+ data-md-skip
+></div>
+
+<div class="horizontal-tabs" data-md-skip>
+ <TabGroup>
+ <TabList>
+ <Tab target="demo-recent" selected>Recent</Tab>
+ <Tab target="demo-popular">Popular</Tab>
+ <Tab target="demo-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="demo-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="demo-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="demo-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+ </TabGroup>
+</div>
diff --git a/docs/components/ui/Tabs/ManualHTML.jinja b/docs/components/ui/Tabs/ManualHTML.jinja
new file mode 100644
index 0000000..1a39f35
--- /dev/null
+++ b/docs/components/ui/Tabs/ManualHTML.jinja
@@ -0,0 +1,28 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<TabGroup>
+ <TabList manual>
+ <Tab target="manual-recent" selected>Recent</Tab>
+ <Tab target="manual-popular">Popular</Tab>
+ <Tab target="manual-disabled" disabled>Disabled</Tab>
+ <Tab target="manual-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="manual-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="manual-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="manual-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="manual-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+</TabGroup>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Tabs/ManualResult.jinja b/docs/components/ui/Tabs/ManualResult.jinja
new file mode 100644
index 0000000..2a067bd
--- /dev/null
+++ b/docs/components/ui/Tabs/ManualResult.jinja
@@ -0,0 +1,33 @@
+{#css ui/Tabs/Tabs.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(56,189,248, 0.3), rgba(37,99,235, 0.3))"
+ data-md-skip
+></div>
+
+<div class="horizontal-tabs" data-md-skip>
+ <TabGroup>
+ <TabList manual>
+ <Tab target="manual-recent" selected>Recent</Tab>
+ <Tab target="manual-popular">Popular</Tab>
+ <Tab target="manual-disabled" disabled>Disabled</Tab>
+ <Tab target="manual-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="manual-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="manual-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="manual-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="manual-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+ </TabGroup>
+</div>
diff --git a/docs/components/ui/Tabs/SelectHTML.jinja b/docs/components/ui/Tabs/SelectHTML.jinja
new file mode 100644
index 0000000..7651bb8
--- /dev/null
+++ b/docs/components/ui/Tabs/SelectHTML.jinja
@@ -0,0 +1,35 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<TabGroup>
+ <TabSelect>
+ <TabOption target="select-recent">Recent</TabOption>
+ <TabOption target="select-popular">Popular</TabOption>
+ <TabOption target="select-disabled" disabled>Disabled</TabOption>
+ <TabOption target="select-trending">Trending</TabOption>
+ </TabSelect>
+
+ <TabList>
+ <Tab target="select-recent">Recent</Tab>
+ <Tab target="select-popular" selected>Popular</Tab>
+ <Tab target="select-disabled" disabled>Disabled</Tab>
+ <Tab target="select-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="select-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="select-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="select-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="select-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+</TabGroup>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Tabs/SelectResult.jinja b/docs/components/ui/Tabs/SelectResult.jinja
new file mode 100644
index 0000000..ffdf0ea
--- /dev/null
+++ b/docs/components/ui/Tabs/SelectResult.jinja
@@ -0,0 +1,40 @@
+{#css ui/Tabs/Tabs.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(56,189,248, 0.3), rgba(37,99,235, 0.3))"
+ data-md-skip
+></div>
+
+<div class="horizontal-tabs" data-md-skip>
+ <TabGroup>
+ <TabSelect>
+ <TabOption target="select-recent">Recent</TabOption>
+ <TabOption target="select-popular">Popular</TabOption>
+ <TabOption target="select-disabled" disabled>Disabled</TabOption>
+ <TabOption target="select-trending">Trending</TabOption>
+ </TabSelect>
+
+ <TabList>
+ <Tab target="select-recent">Recent</Tab>
+ <Tab target="select-popular" selected>Popular</Tab>
+ <Tab target="select-disabled" disabled>Disabled</Tab>
+ <Tab target="select-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="select-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="select-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="select-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="select-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+ </TabGroup>
+</div>
diff --git a/docs/components/ui/Tabs/Tabs.css b/docs/components/ui/Tabs/Tabs.css
new file mode 100644
index 0000000..ddbef0e
--- /dev/null
+++ b/docs/components/ui/Tabs/Tabs.css
@@ -0,0 +1,126 @@
+@scope(.horizontal-tabs,.vertical-tabs) {
+ :scope {
+ width: 100%;
+ max-width: 36rem;
+ margin: 10% auto;
+ padding: 0.5rem;
+ }
+
+ .ui-tablist {
+ display: flex;
+ border-radius: 1rem;
+ background-color: #6383dd;
+ padding: 0.5rem;
+ color: #111;
+ }
+ .ui-tablist > .ui-tab:not([hidden]) ~ .ui-tab:not([hidden]) {
+ margin-left: 0.5rem;
+ }
+ .ui-tab {
+ width: 100%;
+ border-radius: 0.5rem;
+ color: #222;
+ background-color: rgb(255 255 255 / 0.7);
+ padding: 0.75rem 0.25rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ line-height: 1.25rem;
+ }
+ .ui-tab:focus {
+ outline: 2px solid rgb(255 255 255 / 0.8);
+ outline-offset: 2px;
+ }
+ .ui-tab.ui-selected {
+ background-color: white;
+ color: black;
+ }
+ .ui-tab.ui-disabled {
+ background-color: rgb(255 255 255 / 0.5);
+ color: #666;
+ cursor: default;
+ }
+ .ui-tab:hover:not(.ui-selected, .ui-disabled),
+ .ui-tab:focus:not(.ui-selected, .ui-disabled) {
+ background-color: rgb(255 255 255 / 0.8);
+ }
+ .ui-tabpanel {
+ margin-top: 0.5rem;
+ border-radius: 1rem;
+ background-color: rgb(254 254 254);
+ border: 2px solid rgb(59 130 246 / 0.8);
+ padding: 0.1rem;
+ min-height: 8rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .ui-tabpanel:focus {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+ }
+ .ui-tabpanel.ui-hidden {
+ display: none;
+ }
+ .ui-tabpanel b {
+ font-weight: bold;
+ }
+
+ .ui-tabselect {
+ display: block;
+ width: 100%;
+ border-radius: 0.5rem;
+ border-width: 1px;
+ border-color: rgb(209 213 219);
+ background-color: rgb(249 250 251);
+ padding: 0.5rem;
+ font-size: 1rem;
+ line-height: 1.25rem;
+ color: rgb(17 24 39);
+ margin-bottom: 0.5rem;
+ }
+ .ui-tabselect:focus {
+ border-color: rgb(59 130 246);
+ }
+ .ui-tabselect:is(.dark *) {
+ border-color: rgb(75 85 99);
+ background-color: rgb(55 65 81);
+ color: rgb(255 255 255);
+ }
+ .ui-tabselect:is(.dark *)::-moz-placeholder {
+ color: rgb(156 163 175);
+ }
+ .ui-tabselect:is(.dark *):-ms-input-placeholder {
+ color: rgb(156 163 175);
+ }
+ .ui-tabselect:is(.dark *)::placeholder {
+ color: rgb(156 163 175);
+ }
+ .ui-tabselect:is(.dark *):focus {
+ border-color: rgb(59 130 246);
+ }
+}
+
+@scope(.vertical-tabs) {
+ .ui-tabgroup {
+ display: flex;
+ }
+ .ui-tablist {
+ flex-direction: column;
+ width: 10rem;
+ border-radius: 1rem 0 0 1rem;
+ padding-right: 0;
+ }
+ .ui-tablist > .ui-tab:not([hidden]) ~ .ui-tab:not([hidden]) {
+ margin: 0.5rem 0 0 0;
+ }
+ .ui-tab {
+ border-radius: 0.5rem 0 0 0.5rem;
+ padding: 1rem;
+ }
+ .ui-tabpanel {
+ margin: 0;
+ border-radius: 0 1rem 1rem 0;
+ padding: 2rem;
+ min-width: 24rem;
+ }
+} \ No newline at end of file
diff --git a/docs/components/ui/Tabs/VerticalHTML.jinja b/docs/components/ui/Tabs/VerticalHTML.jinja
new file mode 100644
index 0000000..1dd7123
--- /dev/null
+++ b/docs/components/ui/Tabs/VerticalHTML.jinja
@@ -0,0 +1,28 @@
+{% filter markdown %}{% raw %}
+```html+jinja
+<TabGroup>
+ <TabList vertical>
+ <Tab target="vertical-recent" selected>Recent</Tab>
+ <Tab target="vertical-popular">Popular</Tab>
+ <Tab target="vertical-disabled" disabled>Disabled</Tab>
+ <Tab target="vertical-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="vertical-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+</TabGroup>
+```
+{% endraw %}{% endfilter %}
diff --git a/docs/components/ui/Tabs/VerticalResult.jinja b/docs/components/ui/Tabs/VerticalResult.jinja
new file mode 100644
index 0000000..b83204a
--- /dev/null
+++ b/docs/components/ui/Tabs/VerticalResult.jinja
@@ -0,0 +1,33 @@
+{#css ui/Tabs/Tabs.css #}
+
+<div class="bg-cover"
+ style="background-image:linear-gradient(to right, rgba(56,189,248, 0.3), rgba(37,99,235, 0.3))"
+ data-md-skip
+></div>
+
+<div class="vertical-tabs" data-md-skip>
+ <TabGroup>
+ <TabList vertical>
+ <Tab target="vertical-recent" selected>Recent</Tab>
+ <Tab target="vertical-popular">Popular</Tab>
+ <Tab target="vertical-disabled" disabled>Disabled</Tab>
+ <Tab target="vertical-trending">Trending</Tab>
+ </TabList>
+
+ <TabPanel id="vertical-recent">
+ <p>This is the tab panel for <b>"Recent"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-popular" hidden>
+ <p>This is the tab panel for <b>"Popular"</b>.</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-disabled" hidden>
+ <p>This is the tab panel for "Disabled".</p>
+ </TabPanel>
+
+ <TabPanel id="vertical-trending" hidden>
+ <p>This is the tab panel for <b>"Trending"</b>.</p>
+ </TabPanel>
+ </TabGroup>
+</div>