From 9b5f054bb2024d271235c5dbad4d695a681f2606 Mon Sep 17 00:00:00 2001 From: Ronan Berder Date: Fri, 2 May 2025 22:43:40 +0800 Subject: [PATCH] Adding mobile support for sidebar --- .eleventy.js | 12 - docs/src/_includes/layouts/base.njk | 103 ++-- docs/src/assets/styles.css | 716 +++++++++++++++------------- src/css/basecoat.css | 227 ++++----- src/jinja/popover.html.jinja | 6 +- src/js/dialog.js | 2 +- src/js/sidebar.js | 8 +- src/nunjucks/popover.njk | 6 +- src/nunjucks/sidebar.njk | 105 ++-- 9 files changed, 631 insertions(+), 554 deletions(-) diff --git a/.eleventy.js b/.eleventy.js index cb91258..9fe986e 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -9,18 +9,6 @@ export default async function(eleventyConfig) { eleventyConfig.addPassthroughCopy({"docs/src/assets": "assets"}); eleventyConfig.addPassthroughCopy({ "src/js": "assets/js" }); eleventyConfig.addPlugin(eleventyLucideicons); - // eleventyConfig.addShortcode("fetchCode", async function(filePath) { - // return "HELLO"; - // const absolutePath = path.resolve(process.cwd(), filePath); - // return absolutePath; - // try { - // console.log(absolutePath); - // return fs.readFileSync(absolutePath, 'utf8'); - // } catch (error) { - // console.error(`[Eleventy FetchCode Error] Failed to read: ${absolutePath}`, error); - // return ``; - // } - // }); eleventyConfig.addShortcode("fetchCode", function(filePath) { const absolutePath = path.resolve(process.cwd(), filePath); try { diff --git a/docs/src/_includes/layouts/base.njk b/docs/src/_includes/layouts/base.njk index 0581636..970d258 100644 --- a/docs/src/_includes/layouts/base.njk +++ b/docs/src/_includes/layouts/base.njk @@ -83,11 +83,33 @@ {% from "sidebar.njk" import sidebar %} +{% from "popover.njk" import popover %} + {% set footer %} - - - Logout - +{% set trigger %} + +
+ Ronan Berder + @hunvreus +
+{% lucide "chevrons-up-down" %} +{% endset %} +{% call popover( + trigger=trigger, + trigger_attrs={"class": "btn-ghost p-2 h-12 w-full flex items-center justify-start"}, + content_attrs={"data-side": "right", "data-align": "end", "class": "w-80"} +) %} +
+
+

I hope you like Basecoat...

+

I made this (and other things) because I thought it'd be helpful to others. If you find it useful, please consider sponsoring me on GitHub or following me on X.

+
+ +
+{% endcall %} {% endset %} {% set header %} @@ -97,7 +119,7 @@
Basecoat - v0.1.0 + v{{ pkg.version }}
@@ -109,45 +131,54 @@
{% endset %} +{% set link_attrs = { + "hx-boost": "true", + "hx-select": "#content", + "hx-target": "#content", + "hx-swap": "outerHTML" +} %} + {% set icon_info %}{% lucide "info" %}{% endset %} {% set icon_square_terminal %}{% lucide "square-terminal" %}{% endset %} {% set icon_layout_dashboard %}{% lucide "layout-dashboard" %}{% endset %} +{% set icon_github %}{% lucide "github" %}{% endset %} {% set menu = [ { type: "group", label: "Getting started", items: [ - { type: "item", label: "Introduction", url: "/", icon: icon_info, current: true }, - { type: "item", label: "Installation", url: "/installation", icon: icon_square_terminal }, - { type: "item", label: "Kitchen sink", url: "/kitchen-sink", icon: icon_layout_dashboard } + { type: "item", label: "Introduction", url: "/", icon: icon_info, current: true, attrs: link_attrs }, + { type: "item", label: "Installation", url: "/installation", icon: icon_square_terminal, attrs: link_attrs }, + { type: "item", label: "Kitchen sink", url: "/kitchen-sink", icon: icon_layout_dashboard, attrs: link_attrs }, + { type: "item", label: "GitHub", url: "https://github.com/hunvreus/basecoat", icon: icon_github, attrs: link_attrs } ]}, { type: 'group', label: 'Components', items: [ - { type: "item", url: "/components/accordion", label: "Accordion" }, - { type: "item", url: "/components/alert", label: "Alert" }, - { type: "item", url: "/components/alert-dialog", label: "Alert Dialog" }, - { type: "item", url: "/components/avatar", label: "Avatar" }, - { type: "item", url: "/components/badge", label: "Badge" }, - { type: "item", url: "/components/breadcrumb", label: "Breadcrumb" }, - { type: "item", url: "/components/button", label: "Button" }, - { type: "item", url: "/components/card", label: "Card" }, - { type: "item", url: "/components/checkbox", label: "Checkbox" }, - { type: "item", url: "/components/combobox", label: "Combobox" }, - { type: "item", url: "/components/dialog", label: "Dialog" }, - { type: "item", url: "/components/dropdown-menu", label: "Dropdown Menu" }, - { type: "item", url: "/components/form", label: "Form" }, - { type: "item", url: "/components/input", label: "Input" }, - { type: "item", url: "/components/label", label: "Label" }, - { type: "item", url: "/components/pagination", label: "Pagination" }, - { type: "item", url: "/components/popover", label: "Popover" }, - { type: "item", url: "/components/radio-group", label: "Radio Group" }, - { type: "item", url: "/components/select", label: "Select" }, - { type: "item", url: "/components/skeleton", label: "Skeleton" }, - { type: "item", url: "/components/sidebar", label: "Sidebar" }, - { type: "item", url: "/components/slider", label: "Slider" }, - { type: "item", url: "/components/switch", label: "Switch" }, - { type: "item", url: "/components/table", label: "Table" }, - { type: "item", url: "/components/tabs", label: "Tabs" }, - { type: "item", url: "/components/textarea", label: "Textarea" }, - { type: "item", url: "/components/toast", label: "Toast" }, - { type: "item", url: "/components/tooltip", label: "Tooltip" } + { type: "item", url: "/components/accordion", label: "Accordion", attrs: link_attrs }, + { type: "item", url: "/components/alert", label: "Alert", attrs: link_attrs }, + { type: "item", url: "/components/alert-dialog", label: "Alert Dialog", attrs: link_attrs }, + { type: "item", url: "/components/avatar", label: "Avatar", attrs: link_attrs }, + { type: "item", url: "/components/badge", label: "Badge", attrs: link_attrs }, + { type: "item", url: "/components/breadcrumb", label: "Breadcrumb", attrs: link_attrs }, + { type: "item", url: "/components/button", label: "Button", attrs: link_attrs }, + { type: "item", url: "/components/card", label: "Card", attrs: link_attrs }, + { type: "item", url: "/components/checkbox", label: "Checkbox", attrs: link_attrs }, + { type: "item", url: "/components/combobox", label: "Combobox", attrs: link_attrs }, + { type: "item", url: "/components/dialog", label: "Dialog", attrs: link_attrs }, + { type: "item", url: "/components/dropdown-menu", label: "Dropdown Menu", attrs: link_attrs }, + { type: "item", url: "/components/form", label: "Form", attrs: link_attrs }, + { type: "item", url: "/components/input", label: "Input", attrs: link_attrs }, + { type: "item", url: "/components/label", label: "Label", attrs: link_attrs }, + { type: "item", url: "/components/pagination", label: "Pagination", attrs: link_attrs }, + { type: "item", url: "/components/popover", label: "Popover", attrs: link_attrs }, + { type: "item", url: "/components/radio-group", label: "Radio Group", attrs: link_attrs }, + { type: "item", url: "/components/select", label: "Select", attrs: link_attrs }, + { type: "item", url: "/components/skeleton", label: "Skeleton", attrs: link_attrs }, + { type: "item", url: "/components/sidebar", label: "Sidebar", attrs: link_attrs }, + { type: "item", url: "/components/slider", label: "Slider", attrs: link_attrs }, + { type: "item", url: "/components/switch", label: "Switch", attrs: link_attrs }, + { type: "item", url: "/components/table", label: "Table", attrs: link_attrs }, + { type: "item", url: "/components/tabs", label: "Tabs", attrs: link_attrs }, + { type: "item", url: "/components/textarea", label: "Textarea", attrs: link_attrs }, + { type: "item", url: "/components/toast", label: "Toast", attrs: link_attrs }, + { type: "item", url: "/components/tooltip", label: "Tooltip", attrs: link_attrs } ]} ] %} diff --git a/docs/src/assets/styles.css b/docs/src/assets/styles.css index 99fbeaa..1ddbe95 100644 --- a/docs/src/assets/styles.css +++ b/docs/src/assets/styles.css @@ -1551,11 +1551,12 @@ --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); + --sidebar-width: 16rem; + --sidebar-mobile-width: 18rem; --scrollbar-track: transparent; --scrollbar-thumb: rgba(0, 0, 0, 0.3); --scrollbar-width: 6px; --scrollbar-radius: 6px; - --sidebar-width: 16rem; --chevron-down-icon: url('data:image/svg+xml;utf8,'); --chevron-down-icon-50: url('data:image/svg+xml;utf8,'); --check-icon: url('data:image/svg+xml;utf8,'); @@ -1592,10 +1593,7 @@ --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.439 0 0); - --scrollbar-track: transparent; --scrollbar-thumb: rgba(255, 255, 255, 0.3); - --scrollbar-width: 6px; - --scrollbar-radius: 6px; --chevron-down-icon: url('data:image/svg+xml;utf8,'); --chevron-down-icon-50: url('data:image/svg+xml;utf8,'); --check-icon: url('data:image/svg+xml;utf8,'); @@ -3096,6 +3094,384 @@ background-repeat: no-repeat; } } +.sidebar { + &:not([aria-hidden]), &[aria-hidden=false] { + @media (width < 48rem) { + position: fixed; + } + @media (width < 48rem) { + inset: calc(var(--spacing) * 0); + } + @media (width < 48rem) { + z-index: 40; + } + @media (width < 48rem) { + background-color: color-mix(in srgb, #000 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-black) 50%, transparent); + } + } + } + nav { + position: fixed; + inset-block: calc(var(--spacing) * 0); + z-index: 50; + display: flex; + width: var(--sidebar-mobile-width); + flex-direction: column; + background-color: var(--color-sidebar); + color: var(--color-sidebar-foreground); + transition-property: transform, translate, scale, rotate; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 300ms; + transition-duration: 300ms; + --tw-ease: var(--ease-in-out); + transition-timing-function: var(--ease-in-out); + @media (width >= 48rem) { + width: var(--sidebar-width); + } + } + &:not([data-side]), &[data-side=left] { + nav { + left: calc(var(--spacing) * 0); + border-right-style: var(--tw-border-style); + border-right-width: 1px; + } + & + * { + position: relative; + transition-property: margin; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 300ms; + transition-duration: 300ms; + --tw-ease: var(--ease-in-out); + transition-timing-function: var(--ease-in-out); + @media (width >= 48rem) { + margin-left: var(--sidebar-width); + } + } + &[aria-hidden=true] { + nav { + --tw-translate-x: -100%; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + & + * { + @media (width >= 48rem) { + margin-left: calc(var(--spacing) * 0); + } + } + } + } + &[data-side=right] { + nav { + right: calc(var(--spacing) * 0); + border-left-style: var(--tw-border-style); + border-left-width: 1px; + } + & + * { + position: relative; + transition-property: margin; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 300ms; + transition-duration: 300ms; + --tw-ease: var(--ease-in-out); + transition-timing-function: var(--ease-in-out); + @media (width >= 48rem) { + margin-right: var(--sidebar-width); + } + } + &[aria-hidden=true] { + nav { + --tw-translate-x: 100%; + translate: var(--tw-translate-x) var(--tw-translate-y); + } + & + * { + @media (width >= 48rem) { + margin-right: calc(var(--spacing) * 0); + } + } + } + } + nav { + > header, > footer { + display: flex; + flex-direction: column; + gap: calc(var(--spacing) * 2); + padding: calc(var(--spacing) * 2); + } + [role=separator] { + margin-inline: calc(var(--spacing) * 2); + width: auto; + border-color: var(--color-sidebar-border); + } + > section { + display: flex; + min-height: calc(var(--spacing) * 0); + flex: 1; + flex-direction: column; + gap: calc(var(--spacing) * 2); + overflow-y: auto; + > [role=group] { + position: relative; + display: flex; + width: 100%; + min-width: calc(var(--spacing) * 0); + flex-direction: column; + padding: calc(var(--spacing) * 2); + } + h3 { + display: flex; + height: calc(var(--spacing) * 8); + flex-shrink: 0; + align-items: center; + border-radius: var(--radius-md); + padding-inline: calc(var(--spacing) * 2); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + color: var(--color-sidebar-foreground); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-sidebar-foreground) 70%, transparent); + } + --tw-ring-color: var(--color-sidebar-ring); + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + transition-property: margin,opacity; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-duration: 200ms; + transition-duration: 200ms; + --tw-ease: linear; + transition-timing-function: linear; + &:focus-visible { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + &>svg { + width: calc(var(--spacing) * 4); + height: calc(var(--spacing) * 4); + } + &>svg { + flex-shrink: 0; + } + } + ul { + display: flex; + width: 100%; + min-width: calc(var(--spacing) * 0); + flex-direction: column; + gap: calc(var(--spacing) * 1); + li { + position: relative; + > a, > details > summary { + display: flex; + width: 100%; + align-items: center; + gap: calc(var(--spacing) * 2); + overflow: hidden; + border-radius: var(--radius-md); + padding: calc(var(--spacing) * 2); + text-align: left; + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + --tw-ring-color: var(--color-sidebar-ring); + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + transition-property: width,height,padding; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + &:is(:where(.group\/menu-item):has(*[data-sidebar="menu-action"]) *) { + padding-right: calc(var(--spacing) * 8); + } + &:is(:where(.group)[data-collapsible="icon"] *) { + width: calc(var(--spacing) * 8) !important; + height: calc(var(--spacing) * 8) !important; + } + &:is(:where(.group)[data-collapsible="icon"] *) { + padding: calc(var(--spacing) * 2) !important; + } + &:hover { + @media (hover: hover) { + background-color: var(--color-sidebar-accent); + } + } + &:hover { + @media (hover: hover) { + color: var(--color-sidebar-accent-foreground); + } + } + &:focus-visible { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + &:active { + background-color: var(--color-sidebar-accent); + } + &:active { + color: var(--color-sidebar-accent-foreground); + } + &:disabled { + pointer-events: none; + } + &:disabled { + opacity: 50%; + } + &[aria-disabled="true"] { + pointer-events: none; + } + &[aria-disabled="true"] { + opacity: 50%; + } + &[data-active="true"] { + background-color: var(--color-sidebar-accent); + } + &[data-active="true"] { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } + &[data-active="true"] { + color: var(--color-sidebar-accent-foreground); + } + &[data-state="open"] { + &:hover { + @media (hover: hover) { + background-color: var(--color-sidebar-accent); + } + } + } + &[data-state="open"] { + &:hover { + @media (hover: hover) { + color: var(--color-sidebar-accent-foreground); + } + } + } + &>span:last-child { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + &>svg { + width: calc(var(--spacing) * 4); + height: calc(var(--spacing) * 4); + } + &>svg { + flex-shrink: 0; + } + &:not([data-variant]), &[data-variant=default] { + &:hover { + @media (hover: hover) { + background-color: var(--color-sidebar-accent); + } + } + &:hover { + @media (hover: hover) { + color: var(--color-sidebar-accent-foreground); + } + } + } + &[data-variant=outline] { + background-color: var(--color-background); + --tw-shadow: 0 0 0 1px var(--tw-shadow-color, hsl(var(--sidebar-border))); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + &:hover { + @media (hover: hover) { + background-color: var(--color-sidebar-accent); + } + } + &:hover { + @media (hover: hover) { + color: var(--color-sidebar-accent-foreground); + } + } + &:hover { + @media (hover: hover) { + --tw-shadow: 0 0 0 1px var(--tw-shadow-color, hsl(var(--sidebar-accent))); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + } + &:not([data-size]), &[data-size=default] { + height: calc(var(--spacing) * 8); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + &[data-size=sm] { + height: calc(var(--spacing) * 7); + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + &[data-size=lg] { + height: calc(var(--spacing) * 12); + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + &:is(:where(.group)[data-collapsible="icon"] *) { + padding: calc(var(--spacing) * 0) !important; + } + } + } + > details { + &:not([open]) { + > summary { + &::after { + rotate: calc(90deg * -1); + } + } + } + > summary { + &::after { + margin-left: auto; + display: block; + width: calc(var(--spacing) * 3.5); + height: calc(var(--spacing) * 3.5); + background-color: var(--color-primary); + transition-property: transform, translate, scale, rotate; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + --tw-ease: linear; + transition-timing-function: linear; + --tw-content: ''; + content: var(--tw-content); + mask-image: var(--chevron-down-icon); + mask-size: 1rem; + mask-position: center; + mask-repeat: no-repeat; + } + } + &::details-content { + padding-inline: calc(var(--spacing) * 3.5); + } + } + } + ul { + display: flex; + width: 100%; + min-width: calc(var(--spacing) * 0); + --tw-translate-x: 1px; + translate: var(--tw-translate-x) var(--tw-translate-y); + flex-direction: column; + gap: calc(var(--spacing) * 1); + border-left-style: var(--tw-border-style); + border-left-width: 1px; + border-color: var(--color-sidebar-border); + padding-inline: calc(var(--spacing) * 2.5); + padding-block: calc(var(--spacing) * 0.5); + } + } + } + } +} @layer components { .form input[type='checkbox'][role='switch'], .input[type='checkbox'][role='switch'] { display: inline-flex; @@ -3730,338 +4106,6 @@ } } } -.sidebar { - position: fixed; - inset-block: calc(var(--spacing) * 0); - z-index: 50; - display: flex; - width: var(--sidebar-width); - flex-direction: column; - background-color: var(--color-sidebar); - color: var(--color-sidebar-foreground); - transition-property: transform, translate, scale, rotate; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); - &:not([data-side]), &[data-side=left] { - left: calc(var(--spacing) * 0); - border-right-style: var(--tw-border-style); - border-right-width: 1px; - &[aria-hidden="true"] { - --tw-translate-x: -100%; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - & + * { - position: relative; - margin-left: var(--sidebar-width); - transition-property: margin; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); - } - &[aria-hidden=true] + * { - margin-left: calc(var(--spacing) * 0); - } - } - &[data-side=right] { - right: calc(var(--spacing) * 0); - border-left-style: var(--tw-border-style); - border-left-width: 1px; - &[aria-hidden="true"] { - --tw-translate-x: 100%; - translate: var(--tw-translate-x) var(--tw-translate-y); - } - & + * { - position: relative; - margin-right: var(--sidebar-width); - transition-property: margin; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); - } - &[aria-hidden=true] + * { - margin-right: calc(var(--spacing) * 0); - } - } - > header, > footer { - display: flex; - flex-direction: column; - gap: calc(var(--spacing) * 2); - padding: calc(var(--spacing) * 2); - } - [role=separator] { - margin-inline: calc(var(--spacing) * 2); - width: auto; - border-color: var(--color-sidebar-border); - } - > section { - display: flex; - min-height: calc(var(--spacing) * 0); - flex: 1; - flex-direction: column; - gap: calc(var(--spacing) * 2); - overflow-y: auto; - > [role=group] { - position: relative; - display: flex; - width: 100%; - min-width: calc(var(--spacing) * 0); - flex-direction: column; - padding: calc(var(--spacing) * 2); - } - h3 { - display: flex; - height: calc(var(--spacing) * 8); - flex-shrink: 0; - align-items: center; - border-radius: var(--radius-md); - padding-inline: calc(var(--spacing) * 2); - font-size: var(--text-xs); - line-height: var(--tw-leading, var(--text-xs--line-height)); - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - color: var(--color-sidebar-foreground); - @supports (color: color-mix(in lab, red, red)) { - color: color-mix(in oklab, var(--color-sidebar-foreground) 70%, transparent); - } - --tw-ring-color: var(--color-sidebar-ring); - --tw-outline-style: none; - outline-style: none; - @media (forced-colors: active) { - outline: 2px solid transparent; - outline-offset: 2px; - } - transition-property: margin,opacity; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - --tw-ease: linear; - transition-timing-function: linear; - &:focus-visible { - --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - &>svg { - width: calc(var(--spacing) * 4); - height: calc(var(--spacing) * 4); - } - &>svg { - flex-shrink: 0; - } - } - ul { - display: flex; - width: 100%; - min-width: calc(var(--spacing) * 0); - flex-direction: column; - gap: calc(var(--spacing) * 1); - li { - position: relative; - > a, > details > summary { - display: flex; - width: 100%; - align-items: center; - gap: calc(var(--spacing) * 2); - overflow: hidden; - border-radius: var(--radius-md); - padding: calc(var(--spacing) * 2); - text-align: left; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - --tw-ring-color: var(--color-sidebar-ring); - --tw-outline-style: none; - outline-style: none; - @media (forced-colors: active) { - outline: 2px solid transparent; - outline-offset: 2px; - } - transition-property: width,height,padding; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - &:is(:where(.group\/menu-item):has(*[data-sidebar="menu-action"]) *) { - padding-right: calc(var(--spacing) * 8); - } - &:is(:where(.group)[data-collapsible="icon"] *) { - width: calc(var(--spacing) * 8) !important; - height: calc(var(--spacing) * 8) !important; - } - &:is(:where(.group)[data-collapsible="icon"] *) { - padding: calc(var(--spacing) * 2) !important; - } - &:hover { - @media (hover: hover) { - background-color: var(--color-sidebar-accent); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-sidebar-accent-foreground); - } - } - &:focus-visible { - --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - &:active { - background-color: var(--color-sidebar-accent); - } - &:active { - color: var(--color-sidebar-accent-foreground); - } - &:disabled { - pointer-events: none; - } - &:disabled { - opacity: 50%; - } - &[aria-disabled="true"] { - pointer-events: none; - } - &[aria-disabled="true"] { - opacity: 50%; - } - &[data-active="true"] { - background-color: var(--color-sidebar-accent); - } - &[data-active="true"] { - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - } - &[data-active="true"] { - color: var(--color-sidebar-accent-foreground); - } - &[data-state="open"] { - &:hover { - @media (hover: hover) { - background-color: var(--color-sidebar-accent); - } - } - } - &[data-state="open"] { - &:hover { - @media (hover: hover) { - color: var(--color-sidebar-accent-foreground); - } - } - } - &>span:last-child { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - &>svg { - width: calc(var(--spacing) * 4); - height: calc(var(--spacing) * 4); - } - &>svg { - flex-shrink: 0; - } - &:not([data-variant]), &[data-variant=default] { - &:hover { - @media (hover: hover) { - background-color: var(--color-sidebar-accent); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-sidebar-accent-foreground); - } - } - } - &[data-variant=outline] { - background-color: var(--color-background); - --tw-shadow: 0 0 0 1px var(--tw-shadow-color, hsl(var(--sidebar-border))); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - &:hover { - @media (hover: hover) { - background-color: var(--color-sidebar-accent); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-sidebar-accent-foreground); - } - } - &:hover { - @media (hover: hover) { - --tw-shadow: 0 0 0 1px var(--tw-shadow-color, hsl(var(--sidebar-accent))); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } - } - } - &:not([data-size]), &[data-size=default] { - height: calc(var(--spacing) * 8); - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - } - &[data-size=sm] { - height: calc(var(--spacing) * 7); - font-size: var(--text-xs); - line-height: var(--tw-leading, var(--text-xs--line-height)); - } - &[data-size=lg] { - height: calc(var(--spacing) * 12); - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - &:is(:where(.group)[data-collapsible="icon"] *) { - padding: calc(var(--spacing) * 0) !important; - } - } - } - > details { - &:not([open]) { - > summary { - &::after { - rotate: calc(90deg * -1); - } - } - } - > summary { - &::after { - margin-left: auto; - display: block; - width: calc(var(--spacing) * 3.5); - height: calc(var(--spacing) * 3.5); - background-color: var(--color-primary); - transition-property: transform, translate, scale, rotate; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-ease: linear; - transition-timing-function: linear; - --tw-content: ''; - content: var(--tw-content); - mask-image: var(--chevron-down-icon); - mask-size: 1rem; - mask-position: center; - mask-repeat: no-repeat; - } - } - &::details-content { - padding-inline: calc(var(--spacing) * 3.5); - } - } - } - ul { - display: flex; - width: 100%; - min-width: calc(var(--spacing) * 0); - --tw-translate-x: 1px; - translate: var(--tw-translate-x) var(--tw-translate-y); - flex-direction: column; - gap: calc(var(--spacing) * 1); - border-left-style: var(--tw-border-style); - border-left-width: 1px; - border-color: var(--color-sidebar-border); - padding-inline: calc(var(--spacing) * 2.5); - padding-block: calc(var(--spacing) * 0.5); - } - } - } -} .content { > h2 { margin-top: calc(var(--spacing) * 16); diff --git a/src/css/basecoat.css b/src/css/basecoat.css index a7bd279..14c7c8b 100644 --- a/src/css/basecoat.css +++ b/src/css/basecoat.css @@ -33,11 +33,12 @@ --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); + --sidebar-width: 16rem; + --sidebar-mobile-width: 18rem; --scrollbar-track: transparent; --scrollbar-thumb: rgba(0, 0, 0, 0.3); --scrollbar-width: 6px; --scrollbar-radius: 6px; - --sidebar-width: 16rem; --chevron-down-icon: url('data:image/svg+xml;utf8,'); /* --muted-foreground */ --chevron-down-icon-50: url('data:image/svg+xml;utf8,'); /* --muted-foreground + 50% opacity */ --check-icon: url('data:image/svg+xml;utf8,'); /* --muted-foreground */ @@ -75,10 +76,7 @@ --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.439 0 0); - --scrollbar-track: transparent; --scrollbar-thumb: rgba(255, 255, 255, 0.3); - --scrollbar-width: 6px; - --scrollbar-radius: 6px; --chevron-down-icon: url('data:image/svg+xml;utf8,'); /* --muted-foreground */ --chevron-down-icon-50: url('data:image/svg+xml;utf8,'); /* --muted-foreground + 50% opacity */ --check-icon: url('data:image/svg+xml;utf8,');/* --muted-foreground */ @@ -121,8 +119,6 @@ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); - /* --font-sans: 'Inter var', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; - --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; */ } @layer base { @@ -746,6 +742,120 @@ } } +/* Sidebar */ +.sidebar { + &:not([aria-hidden]), + &[aria-hidden=false] { + @apply max-md:bg-black/50 max-md:fixed max-md:inset-0 max-md:z-40; + } + nav { + @apply bg-sidebar text-sidebar-foreground flex flex-col w-(--sidebar-mobile-width) md:w-(--sidebar-width) fixed inset-y-0 transition-transform ease-in-out duration-300 z-50; + } + &:not([data-side]), + &[data-side=left] { + nav { + @apply left-0 border-r; + } + & + * { + @apply relative md:ml-(--sidebar-width) transition-[margin] ease-in-out duration-300; + } + &[aria-hidden=true] { + nav { + @apply -translate-x-full; + } + & + * { + @apply md:ml-0; + } + } + } + &[data-side=right] { + nav { + @apply right-0 border-l; + } + & + * { + @apply relative md:mr-(--sidebar-width) transition-[margin] ease-in-out duration-300; + } + &[aria-hidden=true] { + nav { + @apply translate-x-full; + } + & + * { + @apply md:mr-0; + } + } + } + nav { + > header, + > footer { + @apply flex flex-col gap-2 p-2; + } + [role=separator] { + @apply border-sidebar-border mx-2 w-auto; + } + > section { + @apply flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto; + + > [role=group] { + @apply relative flex w-full min-w-0 flex-col p-2; + } + h3 { + @apply text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0; + } + ul { + @apply flex w-full min-w-0 flex-col gap-1; + + li { + @apply relative; + + > a, + > details > summary { + @apply flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0; + + &:not([data-variant]), + &[data-variant=default] { + @apply hover:bg-sidebar-accent hover:text-sidebar-accent-foreground; + } + &[data-variant=outline] { + @apply bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]; + } + &:not([data-size]), + &[data-size=default] { + @apply h-8 text-sm; + } + &[data-size=sm] { + @apply h-7 text-xs; + } + &[data-size=lg] { + @apply h-12 text-sm group-data-[collapsible=icon]:p-0!; + } + } + > details { + &:not([open]) { + > summary { + &::after { + @apply -rotate-90; + } + } + } + > summary { + &::after { + @apply content-[''] block size-3.5 bg-primary ml-auto transition-transform ease-linear; + @apply mask-[image:var(--chevron-down-icon)] mask-size-[1rem] mask-no-repeat mask-center; + } + } + &::details-content { + @apply px-3.5; + } + } + } + ul { + @apply border-sidebar-border flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5 w-full; + } + } + } + } +} + /* Switch */ @layer components { .form input[type='checkbox'][role='switch'], @@ -909,109 +1019,4 @@ } } } -} - -/* Sidebar */ -.sidebar { - @apply bg-sidebar text-sidebar-foreground flex flex-col w-(--sidebar-width) fixed inset-y-0 transition-transform ease-in-out z-50; - /* h-svh */ - - &:not([data-side]), - &[data-side=left] { - @apply left-0 border-r aria-[hidden=true]:-translate-x-full; - - & + * { - @apply relative ml-(--sidebar-width) transition-[margin] ease-in-out; - } - &[aria-hidden=true] + * { - @apply ml-0; - } - } - &[data-side=right] { - @apply right-0 border-l aria-[hidden=true]:translate-x-full; - - & + * { - @apply relative mr-(--sidebar-width) transition-[margin] ease-in-out; - } - &[aria-hidden=true] + * { - @apply mr-0; - } - } - - - > header, - > footer { - @apply flex flex-col gap-2 p-2; - } - [role=separator] { - @apply border-sidebar-border mx-2 w-auto; - } - > section { - @apply flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto; - - > [role=group] { - @apply relative flex w-full min-w-0 flex-col p-2; - } - - h3 { - @apply text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0; - } - - /* GROUP CONTENT: w-full text-sm */ - ul { - @apply flex w-full min-w-0 flex-col gap-1; - - li { - /* group/menu-item */ - @apply relative; - - > a, - > details > summary { - /* peer/menu-button */ - @apply flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0; - - &:not([data-variant]), - &[data-variant=default] { - @apply hover:bg-sidebar-accent hover:text-sidebar-accent-foreground; - } - &[data-variant=outline] { - @apply bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]; - } - &:not([data-size]), - &[data-size=default] { - @apply h-8 text-sm; - } - &[data-size=sm] { - @apply h-7 text-xs; - } - &[data-size=lg] { - @apply h-12 text-sm group-data-[collapsible=icon]:p-0!; - } - } - - > details { - &:not([open]) { - > summary { - &::after { - @apply -rotate-90; - } - } - } - > summary { - &::after { - @apply content-[''] block size-3.5 bg-primary ml-auto transition-transform ease-linear; - @apply mask-[image:var(--chevron-down-icon)] mask-size-[1rem] mask-no-repeat mask-center; - } - } - &::details-content { - @apply px-3.5; - } - } - } - - ul { - @apply border-sidebar-border flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5 w-full; - } - } - } } \ No newline at end of file diff --git a/src/jinja/popover.html.jinja b/src/jinja/popover.html.jinja index 2b2bda9..23448ef 100644 --- a/src/jinja/popover.html.jinja +++ b/src/jinja/popover.html.jinja @@ -10,9 +10,9 @@ {% macro popover( id=None, trigger=None, - main_attrs=None, - trigger_attrs=None, - content_attrs=None + main_attrs={}, + trigger_attrs={}, + content_attrs={} ) %}
- + {% if item.icon %}{{ item.icon | safe }}{% endif %} {{ item.label }} @@ -12,7 +18,12 @@ {% elif item.type == 'submenu' %}
  • {% endmacro %} \ No newline at end of file