mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-12 13:18:22 +00:00
Fix sidebar nested item styling
This commit is contained in:
@@ -36,6 +36,27 @@
|
||||
"type": "group",
|
||||
"label": "Components",
|
||||
"items": [
|
||||
{
|
||||
"type": "submenu",
|
||||
"label": "Parent item",
|
||||
"icon": "folder",
|
||||
"items": [
|
||||
{
|
||||
"type": "item",
|
||||
"label": "Item 1",
|
||||
"icon": "file",
|
||||
"url": "#",
|
||||
"external": true
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"label": "Item 2",
|
||||
"icon": "file",
|
||||
"url": "#",
|
||||
"external": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"components/accordion",
|
||||
"components/alert",
|
||||
"components/alert-dialog",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{# Dark mode #}
|
||||
<script>
|
||||
@@ -12,17 +12,6 @@
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
const apply = dark => {
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
try { localStorage.setItem('themeMode', dark ? 'dark' : 'light'); } catch (_) {}
|
||||
};
|
||||
|
||||
document.addEventListener('basecoat:theme', (event) => {
|
||||
const mode = event.detail?.mode;
|
||||
apply(mode === 'dark' ? true
|
||||
: mode === 'light' ? false
|
||||
: !document.documentElement.classList.contains('dark'));
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{# Theme variant #}
|
||||
@@ -36,17 +25,6 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{# Style variant #}
|
||||
<script>
|
||||
(function() {
|
||||
try {
|
||||
const storedStyle = localStorage.getItem('styleVariant') || 'nova';
|
||||
document.documentElement.dataset.styleVariant = storedStyle;
|
||||
} catch (event) {
|
||||
console.error('Could not apply style variant from localStorage', event);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{# Meta #}
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
@@ -58,34 +36,43 @@
|
||||
<meta name="description" content="{{ meta_description }}"/>
|
||||
<meta name="title" content="{{ meta_title }}">
|
||||
{% if site.keywords %}<meta name="keywords" content="{{ site.keywords | join(',') }}" />{% endif %}
|
||||
{% if siteUrl %}<link rel="canonical" href="{{ siteUrl }}{{ page.url }}">{% endif %}
|
||||
{# Favicon #}
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/svg+xml" href="{{ siteUrl }}/assets/favicon.svg">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ siteUrl }}/assets/apple-touch-icon.png">
|
||||
{# Open Graph / Facebook #}
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ site.url }}{{ page.url }}">
|
||||
<meta property="og:url" content="{{ siteUrl }}{{ page.url }}">
|
||||
<meta property="og:title" content="{{ meta_title }}">
|
||||
<meta property="og:description" content="{{ meta_description }}">
|
||||
<meta property="og:image" content="{{ site.url }}/assets/social-screenshot.png">
|
||||
<meta property="og:image" content="{{ siteUrl }}/assets/social.png">
|
||||
<meta property="og:site_name" content="{{ site.title }}">
|
||||
<meta property="og:locale" content="en_US">
|
||||
<meta property="og:author" content="{{ site.author.name }}">
|
||||
{# X/Twitter #}
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:url" content="{{ site.url }}{{ page.url }}">
|
||||
<meta name="twitter:title" content="{{ title if title else site.title }}">
|
||||
<meta name="twitter:url" content="{{ siteUrl }}{{ page.url }}">
|
||||
<meta name="twitter:title" content="{{ meta_title }}">
|
||||
<meta name="twitter:description" content="{{ meta_description }}">
|
||||
<meta name="twitter:image" content="{{ site.url }}/assets/social-screenshot.png">
|
||||
<meta name="twitter:image" content="{{ siteUrl }}/assets/social.png">
|
||||
<meta name="twitter:creator" content="{{ site.author.x }}">
|
||||
{# CSS #}
|
||||
<link rel="stylesheet" id="style-variant-stylesheet" href="/assets/styles-nova.css">
|
||||
<script>
|
||||
(() => {
|
||||
const styleLink = document.getElementById('style-variant-stylesheet');
|
||||
const styleVariant = document.documentElement.dataset.styleVariant || 'nova';
|
||||
styleLink.href = `/assets/styles-${styleVariant}.css`;
|
||||
const styles = new Set(['vega', 'nova', 'maia', 'lyra', 'mira', 'luma', 'sera', 'rhea']);
|
||||
let styleVariant = 'nova';
|
||||
try {
|
||||
const storedStyle = localStorage.getItem('styleVariant');
|
||||
if (styles.has(storedStyle)) styleVariant = storedStyle;
|
||||
} catch (event) {
|
||||
console.error('Could not apply style variant from localStorage', event);
|
||||
}
|
||||
|
||||
document.documentElement.dataset.styleVariant = styleVariant;
|
||||
document.write(`<link rel="stylesheet" id="style-variant-stylesheet" href="/assets/styles-${styleVariant}.css">`);
|
||||
})();
|
||||
</script>
|
||||
<noscript><link rel="stylesheet" id="style-variant-stylesheet" href="/assets/styles-nova.css"></noscript>
|
||||
{# JS #}
|
||||
<script src="/assets/js/basecoat.js?v={{ pkg.version }}" defer></script>
|
||||
<script src="/assets/js/command.js?v={{ pkg.version }}" defer></script>
|
||||
|
||||
@@ -4,69 +4,74 @@ layout: layouts/layout.njk
|
||||
{% set docsMenu = docs.menu if docs and docs.menu else menu %}
|
||||
{% set navigation = docsMenu | getNavigation(collections) %}
|
||||
|
||||
<main class="mx-auto relative flex w-full max-w-screen-lg gap-10">
|
||||
<div class="mx-auto w-full flex-1 max-w-screen-md">
|
||||
<header class="space-y-2">
|
||||
<div class="flex items-start gap-x-2">
|
||||
<h1 class="text-2xl font-semibold tracking-tight sm:text-3xl xl:text-4xl mr-auto">{{ title }}</h1>
|
||||
<div class="flex items-center gap-x-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-sm-secondary h-7 px-2.5 text-[13px] max-sm:size-7"
|
||||
data-md-url="{{ page.url | markdownUrl }}"
|
||||
onclick="copyPageMarkdown(this)"
|
||||
>
|
||||
{% lucide "copy" %}
|
||||
<span class="hidden sm:block">Copy page</span>
|
||||
</button>
|
||||
<div role="group" class="button-group">
|
||||
{% if navigation.prev %}
|
||||
<a href="{{ navigation.prev.url }}" class="btn-sm-icon-secondary hidden sm:flex size-7">
|
||||
<span class="sr-only">{{ navigation.prev.label }}</span>
|
||||
{% lucide "arrow-left" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if navigation.prev and navigation.next %}
|
||||
<hr role="separator">
|
||||
{% endif %}
|
||||
{% if navigation.next %}
|
||||
<a href="{{ navigation.next.url }}" class="btn-sm-icon-secondary hidden sm:flex size-7">
|
||||
<span class="sr-only">{{ navigation.next.label }}</span>
|
||||
{% lucide "arrow-right" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="mx-auto flex w-full max-w-screen-lg gap-10">
|
||||
<article class="min-w-0 flex-1 wrap-break-word">
|
||||
<div class="mx-auto w-full max-w-screen-md">
|
||||
<header class="space-y-2">
|
||||
<div class="flex items-start gap-x-2">
|
||||
<h1 class="text-2xl font-semibold tracking-tight sm:text-3xl xl:text-4xl mr-auto">{{ title }}</h1>
|
||||
<div class="flex items-center gap-x-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-sm-secondary h-7 px-2.5 text-[13px] max-sm:size-7"
|
||||
data-md-url="{{ page.url | markdownUrl }}"
|
||||
onclick="copyPageMarkdown(this)"
|
||||
>
|
||||
{% lucide "copy" %}
|
||||
<span class="hidden sm:block">Copy page</span>
|
||||
</button>
|
||||
<div role="group" class="button-group">
|
||||
{% if navigation.prev %}
|
||||
<a href="{{ navigation.prev.url }}" class="btn-sm-icon-secondary hidden sm:flex size-7">
|
||||
<span class="sr-only">{{ navigation.prev.label }}</span>
|
||||
{% lucide "arrow-left" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if navigation.prev and navigation.next %}
|
||||
<hr role="separator">
|
||||
{% endif %}
|
||||
{% if navigation.next %}
|
||||
<a href="{{ navigation.next.url }}" class="btn-sm-icon-secondary hidden sm:flex size-7">
|
||||
<span class="sr-only">{{ navigation.next.label }}</span>
|
||||
{% lucide "arrow-right" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted-foreground text-[1.05rem] sm:text-base">{{ description }}</p>
|
||||
</header>
|
||||
<div class="pb-12 mt-8 content">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
<p class="text-muted-foreground text-[1.05rem] sm:text-base">{{ description }}</p>
|
||||
</header>
|
||||
<article class="pb-12 mt-8 content">
|
||||
{{ content | safe }}
|
||||
</article>
|
||||
{% if navigation.prev or navigation.next %}
|
||||
<footer class="flex items-center gap-2 border-t pt-6 mt-12">
|
||||
{% if navigation.prev %}
|
||||
<a href="{{ navigation.prev.url }}" class="btn-sm-secondary mr-auto">
|
||||
{% lucide "arrow-left" %}
|
||||
{{ navigation.prev.label }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if navigation.next %}
|
||||
<a href="{{ navigation.next.url }}" class="btn-sm-secondary ml-auto">
|
||||
{{ navigation.next.label }}
|
||||
{% lucide "arrow-right" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if toc %}
|
||||
<div class="hidden text-sm xl:block w-full max-w-[300px]">
|
||||
{% from "macros/toc.njk" import toc_nav %}
|
||||
{{ toc_nav(toc) }}
|
||||
{% if navigation.prev or navigation.next %}
|
||||
<footer class="flex items-center gap-2 border-t pt-6 mt-12">
|
||||
{% if navigation.prev %}
|
||||
<a href="{{ navigation.prev.url }}" class="btn-sm-secondary mr-auto">
|
||||
{% lucide "arrow-left" %}
|
||||
{{ navigation.prev.label }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if navigation.next %}
|
||||
<a href="{{ navigation.next.url }}" class="btn-sm-secondary ml-auto">
|
||||
{{ navigation.next.label }}
|
||||
{% lucide "arrow-right" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</main>
|
||||
</article>
|
||||
<aside class="hidden xl:block w-56 shrink-0">
|
||||
<div class="sticky top-20 text-sm [&_a]:text-muted-foreground [&_a]:hover:text-primary space-y-2 [&_ol]:space-y-2 [&_ol_ol]:pl-3 [&_ol_ol]:mt-2">
|
||||
<h2 class="font-medium flex items-center gap-1">
|
||||
{% lucide "table-of-contents", { class: "size-4" } %}
|
||||
On this page
|
||||
</h2>
|
||||
{{ content | toc | safe }}
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function copyPageMarkdown(button) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<div class="flex h-14 w-full items-center gap-2 px-4">
|
||||
<button
|
||||
type="button"
|
||||
onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))"
|
||||
onclick="document.getElementById('sidebar')?.toggle()"
|
||||
aria-label="Toggle sidebar"
|
||||
data-tooltip="Toggle sidebar"
|
||||
data-side="bottom"
|
||||
@@ -83,8 +83,11 @@
|
||||
const styleLink = document.getElementById('style-variant-stylesheet');
|
||||
const applyStyle = (styleName) => {
|
||||
const nextStyle = styleName || 'nova';
|
||||
const nextHref = `/assets/styles-${nextStyle}.css`;
|
||||
document.documentElement.dataset.styleVariant = nextStyle;
|
||||
if (styleLink) styleLink.href = `/assets/styles-${nextStyle}.css`;
|
||||
if (styleLink && styleLink.getAttribute('href') !== nextHref) {
|
||||
styleLink.href = nextHref;
|
||||
}
|
||||
};
|
||||
|
||||
const storedStyle = localStorage.getItem('styleVariant') || 'nova';
|
||||
@@ -104,7 +107,7 @@
|
||||
aria-label="Toggle dark mode"
|
||||
data-tooltip="Toggle dark mode"
|
||||
data-side="bottom"
|
||||
onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))"
|
||||
onclick="window.basecoat?.theme.toggle()"
|
||||
class="btn-icon-outline size-8"
|
||||
>
|
||||
<span class="hidden dark:block">{% lucide "sun" %}</span>
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||
<span class="truncate font-medium">{{ site.title }}</span>
|
||||
<span class="truncate text-xs">v{{ pkg.version }}</span>
|
||||
<span class="truncate font-semibold">{{ site.title }}</span>
|
||||
<span class="truncate text-xs text-muted-foreground">v{{ pkg.version }}</span>
|
||||
</div>
|
||||
</a>
|
||||
{% endset %}
|
||||
|
||||
+9088
-1
File diff suppressed because one or more lines are too long
+9029
-1
File diff suppressed because one or more lines are too long
+9025
-1
File diff suppressed because one or more lines are too long
+9083
-1
File diff suppressed because one or more lines are too long
+9084
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+9037
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -147,6 +147,10 @@ toc:
|
||||
<dd>Removes a selected value.</dd>
|
||||
<dt><code>toggle(value)</code> <span class="badge-secondary">Multiple only</span></dt>
|
||||
<dd>Toggles a selected value.</dd>
|
||||
<dt><code>refresh()</code></dt>
|
||||
<dd>Rescans options after changing children inside the existing <code>role="listbox"</code> element.</dd>
|
||||
<dt><code>window.basecoat.refresh(combobox)</code></dt>
|
||||
<dd>Calls the component refresh method through the global dispatcher.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ toc:
|
||||
id: usage-html-js-2
|
||||
- label: HTML structure
|
||||
id: usage-html-js-3
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-4
|
||||
- label: Jinja and Nunjucks
|
||||
id: usage-macro
|
||||
@@ -183,12 +183,16 @@ toc:
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
<dt><code>basecoat:initialized</code></dt>
|
||||
<dd>Once the component is initialized, it dispatches a custom non-bubbling <code>basecoat:initialized</code> event on itself.</dd>
|
||||
<dt><code>command.refresh()</code></dt>
|
||||
<dd>Rescans command items after changing children inside the existing <code>role="menu"</code> list.</dd>
|
||||
<dt><code>window.basecoat.refresh(command)</code></dt>
|
||||
<dd>Calls the component refresh method through the global dispatcher.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ toc:
|
||||
id: usage-html-js-2
|
||||
- label: HTML structure
|
||||
id: usage-html-js-3
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-4
|
||||
- label: Jinja and Nunjucks
|
||||
id: usage-macro
|
||||
@@ -151,7 +151,7 @@ toc:
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
@@ -159,6 +159,16 @@ toc:
|
||||
<dd>Once the component is initialized, it dispatches a custom non-bubbling <code>basecoat:initialized</code> event on itself.</dd>
|
||||
<dt><code>basecoat:popover</code></dt>
|
||||
<dd>When the menu opens, the component dispatches a custom event on <code>document</code>. Other popover-based components listen for this to close any open popovers.</dd>
|
||||
<dt><code>dropdown.open()</code></dt>
|
||||
<dd>Opens the menu.</dd>
|
||||
<dt><code>dropdown.close()</code></dt>
|
||||
<dd>Closes the menu.</dd>
|
||||
<dt><code>dropdown.toggle()</code></dt>
|
||||
<dd>Toggles the menu.</dd>
|
||||
<dt><code>dropdown.refresh()</code></dt>
|
||||
<dd>Rescans menu items after changing children inside the existing <code>role="menu"</code> element.</dd>
|
||||
<dt><code>window.basecoat.refresh(dropdown)</code></dt>
|
||||
<dd>Calls the component refresh method through the global dispatcher.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -123,6 +123,6 @@ toc:
|
||||
<section class="prose">
|
||||
<ul>
|
||||
<li>Use <strong>Native Select</strong> for native browser behavior, better performance, form integration, and mobile-optimized pickers.</li>
|
||||
<li>Use <strong>Select</strong> for a custom popover, richer option content, multi-select behavior, or custom JavaScript events.</li>
|
||||
<li>Use <strong>Select</strong> for a custom popover, richer option content, multi-select behavior, or custom JavaScript APIs.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -283,6 +283,10 @@ toc:
|
||||
<dd>
|
||||
<p><strong>Deprecated:</strong> Alias for <code>select(value)</code>. Kept for backward compatibility.</p>
|
||||
</dd>
|
||||
<dt><code>refresh()</code></dt>
|
||||
<dd>Rescans options after changing children inside the existing <code>role="listbox"</code> element.</dd>
|
||||
<dt><code>window.basecoat.refresh(selectComponent)</code></dt>
|
||||
<dd>Calls the component refresh method through the global dispatcher.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ toc:
|
||||
id: usage-html-js-3
|
||||
- label: Basecoat differences
|
||||
id: usage-html-js-4
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-5
|
||||
- label: Jinja and Nunjucks
|
||||
id: usage-macro
|
||||
@@ -82,7 +82,7 @@ toc:
|
||||
menu=menu
|
||||
) }}
|
||||
<main>
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))">Toggle sidebar</button>
|
||||
<button type="button" onclick="document.getElementById('sidebar')?.toggle()">Toggle sidebar</button>
|
||||
<h1>Content</h1>
|
||||
</main>
|
||||
{% endset %}
|
||||
@@ -95,7 +95,7 @@ toc:
|
||||
<dt><code class="highlight language-html"><aside class="sidebar" aria-hidden="false"></code></dt>
|
||||
<dd>Wraps the sidebar component. Supported attributes:
|
||||
<ul>
|
||||
<li><code>id</code>: target a specific sidebar from the <code>basecoat:sidebar</code> event.</li>
|
||||
<li><code>id</code>: target a specific sidebar from JavaScript methods.</li>
|
||||
<li><code>aria-hidden</code>: current open state. <code>false</code> means visible, <code>true</code> means hidden.</li>
|
||||
<li><code>data-side</code>: physical side of the viewport. Use <code>left</code> or <code>right</code>. Defaults to <code>left</code>.</li>
|
||||
<li><code>data-initial-open</code>: set to <code>false</code> to start closed on desktop.</li>
|
||||
@@ -123,8 +123,8 @@ toc:
|
||||
<dd>Bottom area for account controls, settings, or secondary actions.</dd>
|
||||
<dt><code class="highlight language-html"><main></code></dt>
|
||||
<dd>The sibling content wrapper. Basecoat applies the desktop margin to the sibling that follows the sidebar.</dd>
|
||||
<dt><code class="highlight language-html"><button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))"></code></dt>
|
||||
<dd>Dispatches the event used to toggle, open, or close the sidebar.</dd>
|
||||
<dt><code class="highlight language-html"><button type="button" onclick="document.getElementById('sidebar')?.toggle()"></code></dt>
|
||||
<dd>Calls the sidebar method used to toggle, open, or close the sidebar.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
@@ -146,26 +146,29 @@ toc:
|
||||
<p>RTL content is supported through logical spacing and borders. The <code>data-side</code> value remains physical: <code>left</code> means the left side of the viewport and <code>right</code> means the right side.</p>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-5"><a href="#usage-html-js-5">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-5"><a href="#usage-html-js-5">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
<dt><code>basecoat:initialized</code></dt>
|
||||
<dd>Once the component is fully initialized, it dispatches a custom (non-bubbling) <code>basecoat:initialized</code> event on itself.</dd>
|
||||
<dt><code>basecoat:sidebar</code></dt>
|
||||
<dd>
|
||||
<p>Sidebars listen for this event on <code>document</code> to open, close or toggle themselves. By default, the event will toggle the sidebar, but can be used to open or close if you add an <code>action</code> to the detail. Additionally, if you have multiple sidebars on the page, you can target a specific sidebar by adding its <code>id</code> to the detail:</p>
|
||||
{% set code_trigger %}<!-- Toggles the sidebar -->
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'));">Toggle sidebar</button>
|
||||
<!-- Opens the `#main-navigation` sidebar -->
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: 'main-navigation', action: 'open' } }));">Open sidebar</button>
|
||||
<!-- Closes the sidebar -->
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { action: 'close' } }));">Close sidebar</button>{% endset %}
|
||||
{{ code_block(code_trigger | prettyHtml, "html") }}
|
||||
</dd>
|
||||
<dt><code>sidebar.open()</code></dt>
|
||||
<dd>Opens the specific sidebar element.</dd>
|
||||
<dt><code>sidebar.close()</code></dt>
|
||||
<dd>Closes the specific sidebar element.</dd>
|
||||
<dt><code>sidebar.toggle()</code></dt>
|
||||
<dd>Toggles the specific sidebar element.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
{% set code_trigger %}<!-- Toggles the sidebar -->
|
||||
<button type="button" onclick="document.getElementById('sidebar')?.toggle()">Toggle sidebar</button>
|
||||
<!-- Opens the `#main-navigation` sidebar -->
|
||||
<button type="button" onclick="document.getElementById('main-navigation')?.open()">Open sidebar</button>
|
||||
<!-- Closes the sidebar -->
|
||||
<button type="button" onclick="document.getElementById('sidebar')?.close()">Close sidebar</button>{% endset %}
|
||||
{{ code_block(code_trigger | prettyHtml, "html") }}
|
||||
|
||||
<h3 id="usage-macro"><a href="#usage-macro">Jinja and Nunjucks</a></h3>
|
||||
|
||||
<div class="prose">
|
||||
|
||||
@@ -16,7 +16,7 @@ toc:
|
||||
id: usage-html-js-2
|
||||
- label: HTML structure
|
||||
id: usage-html-js-3
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-4
|
||||
- label: Jinja and Nunjucks
|
||||
id: usage-macro
|
||||
@@ -159,12 +159,18 @@ toc:
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-4"><a href="#usage-html-js-4">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
<dt><code>basecoat:initialized</code></dt>
|
||||
<dd>Once the component is initialized, it dispatches a custom non-bubbling <code>basecoat:initialized</code> event on itself.</dd>
|
||||
<dt><code>tabs.select(tab)</code></dt>
|
||||
<dd>Selects a tab button in the tablist.</dd>
|
||||
<dt><code>tabs.refresh()</code></dt>
|
||||
<dd>Rescans tabs and panels after changing children inside the existing tablist/panel structure.</dd>
|
||||
<dt><code>window.basecoat.refresh(tabs)</code></dt>
|
||||
<dd>Calls the component refresh method through the global dispatcher.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
templateEngineOverride: njk
|
||||
layout: layouts/page.njk
|
||||
title: Theme Switcher
|
||||
description: A component that allows the user to switch between light and dark mode.
|
||||
description: A simple button pattern for switching between light and dark mode.
|
||||
toc:
|
||||
- label: Usage
|
||||
id: usage
|
||||
@@ -10,48 +10,47 @@ toc:
|
||||
- label: HTML + JavaScript
|
||||
id: usage-html-js
|
||||
children:
|
||||
- label: "Step 1: Include the JavaScript script"
|
||||
- label: "Step 1: Avoid the initial flash"
|
||||
id: usage-html-js-1
|
||||
- label: "Step 2: Add your switcher"
|
||||
id: usage-html-js-2
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-3
|
||||
---
|
||||
|
||||
<div class="alert mb-6">
|
||||
{% lucide "circle-alert" %}
|
||||
<h2>There is no dedicated theme switcher component in Basecoat.</h2>
|
||||
<section><p>Instead, we offer a short JavaScript <code><script></code> block you can insert in the <code><head></code> of your page.</p></section>
|
||||
<section><p>Theme switching is handled by <code>window.basecoat.theme</code> and a small inline script that applies the stored mode before styles render.</p></section>
|
||||
</div>
|
||||
|
||||
|
||||
{% from "macros/code_preview.njk" import code_preview %}
|
||||
{% from "macros/code_block.njk" import code_block %}
|
||||
|
||||
{% set code %}<button
|
||||
{% set code_switcher %}<button
|
||||
type="button"
|
||||
aria-label="Toggle dark mode"
|
||||
data-tooltip="Toggle dark mode"
|
||||
data-side="bottom"
|
||||
onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))"
|
||||
onclick="window.basecoat.theme.toggle()"
|
||||
class="btn-icon-outline size-8"
|
||||
>
|
||||
<span class="hidden dark:block">{% lucide "sun" %}</span>
|
||||
<span class="block dark:hidden">{% lucide "moon" %}</span>
|
||||
</button>{% endset %}
|
||||
{{ code_preview("button", code) }}
|
||||
{{ code_preview("button", code_switcher) }}
|
||||
|
||||
<h2 id="usage"><a href="#usage">Usage</a></h2>
|
||||
|
||||
<h3 id="usage-html-js"><a href="#usage-html-js">HTML + JavaScript</a></h3>
|
||||
|
||||
<h4 id="usage-html-js-1"><a href="#usage-html-js-1">Step 1: Include the JavaScript script</a></h4>
|
||||
<h4 id="usage-html-js-1"><a href="#usage-html-js-1">Step 1: Avoid the initial flash</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<p>Insert the following JavaScript block right at the beginning of the <code><head></code> your page. We do this instead of using a separate file to ensure the theme is defined before the page loads, avoiding a flash of unstyled or mist-styled content.</p>
|
||||
<p>Add this inline script before loading your styles. It applies the stored mode before the page renders.</p>
|
||||
</section>
|
||||
|
||||
{% set code %}<script>
|
||||
{% set code_head %}<script>
|
||||
(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem('themeMode');
|
||||
@@ -60,53 +59,31 @@ toc:
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
const apply = dark => {
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
try { localStorage.setItem('themeMode', dark ? 'dark' : 'light'); } catch (_) {}
|
||||
};
|
||||
|
||||
document.addEventListener('basecoat:theme', (event) => {
|
||||
const mode = event.detail?.mode;
|
||||
apply(mode === 'dark' ? true
|
||||
: mode === 'light' ? false
|
||||
: !document.documentElement.classList.contains('dark'));
|
||||
});
|
||||
})();
|
||||
</script>{% endset %}
|
||||
{{ code_block(code) }}
|
||||
{{ code_block(code_head | prettyHtml, "html") }}
|
||||
|
||||
<section class="prose">
|
||||
<p>Load <code>basecoat.js</code> or the bundled JavaScript before calling <code>window.basecoat.theme</code>.</p>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-2"><a href="#usage-html-js-2">Step 2: Add your switcher</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<p>To change the theme, you need to dispatch a <code>basecoat:theme</code> event:</p>
|
||||
</section>
|
||||
{{ code_block(code_switcher | prettyHtml, "html") }}
|
||||
|
||||
{% set code %}<button
|
||||
type="button"
|
||||
aria-label="Toggle dark mode"
|
||||
data-tooltip="Toggle dark mode"
|
||||
data-side="bottom"
|
||||
onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))"
|
||||
class="btn-icon-outline size-8"
|
||||
>
|
||||
<span class="hidden dark:block">{% lucide "sun" %}</span>
|
||||
<span class="block dark:hidden">{% lucide "moon" %}</span>
|
||||
</button>{% endset %}
|
||||
{{ code_block(code) }}
|
||||
|
||||
<h4 id="usage-html-js-3"><a href="#usage-html-js-3">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-3"><a href="#usage-html-js-3">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
<dt><code>basecoat:theme</code></dt>
|
||||
<dd>
|
||||
<p>By default, the event will toggle the theme, but you can also add a <code>mode</code> to the detail to set the theme explicitly:</p>
|
||||
{% set code_trigger %}<!-- Toggles the theme -->
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'));">Toggle theme</button>
|
||||
<!-- Sets the theme to dark -->
|
||||
<button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:theme', { detail: { mode: 'dark' } }));">Set dark theme</button>{% endset %}
|
||||
{{ code_block(code_trigger | prettyHtml, "html") }}
|
||||
</dd>
|
||||
<dt><code>window.basecoat.theme.get()</code></dt>
|
||||
<dd>Returns <code>"dark"</code> or <code>"light"</code>.</dd>
|
||||
<dt><code>window.basecoat.theme.set(mode)</code></dt>
|
||||
<dd>Sets the mode to <code>"dark"</code> or <code>"light"</code> and stores it in <code>localStorage.themeMode</code>.</dd>
|
||||
<dt><code>window.basecoat.theme.toggle()</code></dt>
|
||||
<dd>Toggles between dark and light mode.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
{% set code_methods %}<button type="button" onclick="window.basecoat.theme.toggle()">Toggle theme</button>
|
||||
<button type="button" onclick="window.basecoat.theme.set('dark')">Set dark theme</button>{% endset %}
|
||||
{{ code_block(code_methods | prettyHtml, "html") }}
|
||||
|
||||
@@ -18,7 +18,7 @@ toc:
|
||||
id: usage-html-js-3
|
||||
- label: HTML structure
|
||||
id: usage-html-js-4
|
||||
- label: JavaScript events
|
||||
- label: JavaScript API
|
||||
id: usage-html-js-5
|
||||
- label: Toast config object
|
||||
id: usage-html-js-6
|
||||
@@ -44,18 +44,14 @@ toc:
|
||||
|
||||
{% set code_client_side %}<button
|
||||
class="btn-outline"
|
||||
onclick="document.dispatchEvent(new CustomEvent('basecoat:toast', {
|
||||
detail: {
|
||||
config: {
|
||||
category: 'success',
|
||||
title: 'Success',
|
||||
description: 'A success toast called from the front-end.',
|
||||
cancel: {
|
||||
label: 'Dismiss'
|
||||
}
|
||||
}
|
||||
onclick="document.getElementById('toaster').toast({
|
||||
category: 'success',
|
||||
title: 'Success',
|
||||
description: 'A success toast called from the front-end.',
|
||||
cancel: {
|
||||
label: 'Dismiss'
|
||||
}
|
||||
}))"
|
||||
})"
|
||||
>
|
||||
Toast from front-end
|
||||
</button>{% endset %}
|
||||
@@ -106,7 +102,7 @@ toc:
|
||||
<h4 id="usage-html-js-3"><a href="#usage-html-js-3">Step 3: Add your toasts</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<p>If you decide to server-render your toasts, or load them using asynchronoulsy with something like HTMX, you can just add the toast's markup to the toaster:</p>
|
||||
<p>If you decide to server-render your toasts, or load them asynchronously with something like HTMX, you can just add the toast's markup to the toaster:</p>
|
||||
</section>
|
||||
|
||||
{% set code_toast_html %}<div id="toaster" class="toaster">
|
||||
@@ -123,14 +119,14 @@ toc:
|
||||
{{ code_block(code_toast_html | prettyHtml, "html") }}
|
||||
|
||||
<div class="flex flex-wrap gap-2 my-6">
|
||||
<a class="badge-outline" href="#usage-html-js-5">
|
||||
<a class="badge-outline" href="#usage-html-js-4">
|
||||
HTML structure
|
||||
{% lucide "arrow-right" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<section class="prose">
|
||||
<p>If you need to create a toast from the front-end, you can dispatch a custom <code>basecoat:toast</code> event as such:</p>
|
||||
<p>If you need to create a toast from the front-end, call the toaster element's <code>toast(config)</code> method:</p>
|
||||
</section>
|
||||
|
||||
{{ code_block(code_client_side | prettyHtml, "html") }}
|
||||
@@ -181,16 +177,18 @@ toc:
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<h4 id="usage-html-js-5"><a href="#usage-html-js-5">JavaScript events</a></h4>
|
||||
<h4 id="usage-html-js-5"><a href="#usage-html-js-5">JavaScript API</a></h4>
|
||||
|
||||
<section class="prose">
|
||||
<dl>
|
||||
<dt><code>basecoat:initialized</code></dt>
|
||||
<dd>Once the component is fully initialized, it dispatches a custom (non-bubbling) <code>basecoat:initialized</code> event on the <code>toaster</code> element.</dd>
|
||||
<dt><code>basecoat:toast</code></dt>
|
||||
<dd>
|
||||
<p>The <code>toaster</code> listens for <code>basecoat:toast</code> events on <code>document</code> to create toasts. The event's <code>detail</code> object must contain a <code>config</code> object (see <a href="#usage-html-js-6">JavaScript config object</a> below).</p>
|
||||
</dd>
|
||||
<dt><code>toaster.toast(config)</code></dt>
|
||||
<dd>Creates a toast from a config object and returns the inserted <code>.toast</code> element. See <a href="#usage-html-js-6">Toast config object</a>.</dd>
|
||||
<dt><code>toaster.closeAll()</code></dt>
|
||||
<dd>Closes every toast inside the toaster.</dd>
|
||||
<dt><code>toast.close()</code></dt>
|
||||
<dd>Closes one initialized toast element.</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
|
||||
+28
-15
@@ -33,20 +33,33 @@ description: A collection of all the components available in Basecoat.
|
||||
{ label: "Tooltip", id: "tooltip" }
|
||||
] %}
|
||||
|
||||
<div class="flex gap-x-10 justify-center">
|
||||
<div>
|
||||
<header class="space-y-2 mb-8">
|
||||
<h1 class="text-3xl font-semibold tracking-tight">{{ title }}</h1>
|
||||
<p class="text-muted-foreground">{{ description }}</p>
|
||||
</header>
|
||||
<div class="grid gap-4 flex-1">
|
||||
{% for component in components %}
|
||||
{% include "partials/kitchen-sink/" ~ component.id ~ ".njk" %}
|
||||
{% endfor %}
|
||||
<div class="mx-auto flex w-full max-w-screen-lg gap-10">
|
||||
<article class="min-w-0 flex-1 wrap-break-word">
|
||||
<div class="mx-auto w-full max-w-screen-md">
|
||||
<header class="space-y-2 mb-8">
|
||||
<h1 class="text-3xl font-semibold tracking-tight">{{ title }}</h1>
|
||||
<p class="text-muted-foreground">{{ description }}</p>
|
||||
</header>
|
||||
<div class="grid gap-4 flex-1">
|
||||
{% for component in components %}
|
||||
{% include "partials/kitchen-sink/" ~ component.id ~ ".njk" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden text-sm xl:block w-full max-w-[200px]">
|
||||
{% from "macros/toc.njk" import toc_nav %}
|
||||
{{ toc_nav(components) }}
|
||||
</div>
|
||||
</article>
|
||||
<aside class="hidden xl:block w-56 shrink-0">
|
||||
<div class="sticky top-20 text-sm [&_a]:text-muted-foreground [&_a]:hover:text-primary space-y-2 [&_ol]:space-y-2">
|
||||
<h2 class="font-medium flex items-center gap-1">
|
||||
{% lucide "table-of-contents", { class: "size-4" } %}
|
||||
On this page
|
||||
</h2>
|
||||
<nav class="toc">
|
||||
<ol>
|
||||
{% for component in components %}
|
||||
<li><a href="#{{ component.id }}">{{ component.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -2,6 +2,6 @@
|
||||
permalink: /robots.txt
|
||||
eleventyExcludeFromCollections: true
|
||||
---
|
||||
Sitemap: {{ site.url }}/sitemap.xml
|
||||
Sitemap: {{ siteUrl }}/sitemap.xml
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow:
|
||||
|
||||
@@ -5,11 +5,11 @@ eleventyExcludeFromCollections: true
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
{% for page in collections.all %}
|
||||
{% if not page.url.startsWith('/fragments/') %}
|
||||
{% if page.url and not page.url.startsWith('/fragments/') %}
|
||||
<url>
|
||||
<loc>{{ site.url }}{{ page.url | url }}</loc>
|
||||
<loc>{{ siteUrl }}{{ page.url | url }}</loc>
|
||||
<lastmod>{{ page.date.toISOString() }}</lastmod>
|
||||
</url>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</urlset>
|
||||
</urlset>
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
layout: layouts/layout.njk
|
||||
eleventyExcludeFromCollections: true
|
||||
---
|
||||
|
||||
{% from "dialog.njk" import dialog %}
|
||||
@@ -36,4 +37,4 @@ footer=footer
|
||||
]
|
||||
) }}
|
||||
</form>
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
|
||||
Reference in New Issue
Block a user