kiso 0.5.3.pre → 0.6.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/tailwind/kiso/button.css +12 -3
- data/app/assets/tailwind/kiso/checkbox.css +13 -2
- data/app/assets/tailwind/kiso/color-mode.css +15 -3
- data/app/assets/tailwind/kiso/dashboard.css +97 -44
- data/app/assets/tailwind/kiso/dialog.css +39 -5
- data/app/assets/tailwind/kiso/engine.css +117 -34
- data/app/assets/tailwind/kiso/input-otp.css +24 -4
- data/app/assets/tailwind/kiso/palettes/blue.css +14 -5
- data/app/assets/tailwind/kiso/palettes/green.css +9 -5
- data/app/assets/tailwind/kiso/palettes/orange.css +9 -5
- data/app/assets/tailwind/kiso/palettes/violet.css +9 -5
- data/app/assets/tailwind/kiso/palettes/zinc.css +11 -7
- data/app/assets/tailwind/kiso/radio-group.css +11 -4
- data/app/assets/tailwind/kiso/slider.css +25 -6
- data/app/assets/tailwind/kiso/tooltip.css +37 -11
- data/app/helpers/kiso/app_component_helper.rb +83 -34
- data/app/helpers/kiso/component_helper.rb +227 -70
- data/app/helpers/kiso/icon_helper.rb +101 -39
- data/app/helpers/kiso/theme_helper.rb +50 -9
- data/app/helpers/kiso/ui_context_helper.rb +87 -35
- data/app/javascript/controllers/kiso/combobox_controller.js +10 -2
- data/app/javascript/controllers/kiso/command_controller.js +2 -0
- data/app/javascript/controllers/kiso/command_dialog_controller.js +4 -0
- data/app/javascript/controllers/kiso/dialog_controller.js +6 -1
- data/app/javascript/controllers/kiso/dialog_trigger_controller.js +1 -1
- data/app/javascript/controllers/kiso/dropdown_menu_controller.js +23 -5
- data/app/javascript/controllers/kiso/index.js +25 -0
- data/app/javascript/controllers/kiso/input_otp_controller.js +5 -3
- data/app/javascript/controllers/kiso/popover_controller.js +18 -4
- data/app/javascript/controllers/kiso/select_controller.js +10 -2
- data/app/javascript/controllers/kiso/sidebar_controller.js +26 -4
- data/app/javascript/controllers/kiso/slider_controller.js +3 -3
- data/app/javascript/controllers/kiso/theme_controller.js +2 -1
- data/app/javascript/controllers/kiso/toggle_controller.js +2 -0
- data/app/javascript/controllers/kiso/toggle_group_controller.js +3 -0
- data/app/javascript/controllers/kiso/tooltip_controller.js +3 -0
- data/app/javascript/kiso/utils/focusable.js +14 -0
- data/app/javascript/kiso/utils/highlight.js +15 -1
- data/app/views/kiso/components/_alert.html.erb +2 -0
- data/app/views/kiso/components/_alert_dialog.html.erb +5 -2
- data/app/views/kiso/components/_app.html.erb +2 -0
- data/app/views/kiso/components/_aspect_ratio.html.erb +1 -0
- data/app/views/kiso/components/_avatar.html.erb +4 -0
- data/app/views/kiso/components/_button.html.erb +3 -0
- data/app/views/kiso/components/_checkbox.html.erb +1 -0
- data/app/views/kiso/components/_color_mode_button.html.erb +2 -0
- data/app/views/kiso/components/_color_mode_select.html.erb +2 -0
- data/app/views/kiso/components/_combobox.html.erb +3 -0
- data/app/views/kiso/components/_command.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_group.html.erb +4 -0
- data/app/views/kiso/components/_dashboard_navbar.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_panel.html.erb +1 -0
- data/app/views/kiso/components/_dashboard_sidebar.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_toolbar.html.erb +2 -0
- data/app/views/kiso/components/_dialog.html.erb +3 -0
- data/app/views/kiso/components/_dropdown_menu.html.erb +2 -0
- data/app/views/kiso/components/_empty.html.erb +2 -0
- data/app/views/kiso/components/_field.html.erb +2 -0
- data/app/views/kiso/components/_field_group.html.erb +1 -0
- data/app/views/kiso/components/_field_set.html.erb +1 -0
- data/app/views/kiso/components/_input_group.html.erb +1 -0
- data/app/views/kiso/components/_input_otp.html.erb +3 -0
- data/app/views/kiso/components/_nav.html.erb +2 -0
- data/app/views/kiso/components/_page_card.html.erb +3 -0
- data/app/views/kiso/components/_page_header.html.erb +3 -0
- data/app/views/kiso/components/_page_section.html.erb +2 -0
- data/app/views/kiso/components/_pagination.html.erb +2 -0
- data/app/views/kiso/components/_popover.html.erb +3 -0
- data/app/views/kiso/components/_select.html.erb +3 -0
- data/app/views/kiso/components/_select_native.html.erb +2 -0
- data/app/views/kiso/components/_separator.html.erb +2 -0
- data/app/views/kiso/components/_skeleton.html.erb +1 -0
- data/app/views/kiso/components/_slider.html.erb +4 -0
- data/app/views/kiso/components/_spinner.html.erb +2 -0
- data/app/views/kiso/components/_stats_card.html.erb +2 -0
- data/app/views/kiso/components/_stats_grid.html.erb +1 -0
- data/app/views/kiso/components/_switch.html.erb +2 -0
- data/app/views/kiso/components/_table.html.erb +2 -0
- data/app/views/kiso/components/_textarea.html.erb +3 -0
- data/app/views/kiso/components/_toggle.html.erb +2 -0
- data/app/views/kiso/components/_toggle_group.html.erb +2 -0
- data/app/views/kiso/components/_tooltip.html.erb +3 -0
- data/app/views/kiso/components/alert_dialog/_action.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_cancel.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_description.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_title.html.erb +1 -0
- data/app/views/kiso/components/avatar/_image.html.erb +1 -0
- data/app/views/kiso/components/breadcrumb/_separator.html.erb +3 -0
- data/app/views/kiso/components/combobox/_chips.html.erb +3 -0
- data/app/views/kiso/components/command/_dialog.html.erb +2 -0
- data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +2 -0
- data/app/views/kiso/components/dialog/_close.html.erb +1 -0
- data/app/views/kiso/components/field/_error.html.erb +4 -0
- data/app/views/kiso/components/field/_label.html.erb +2 -0
- data/app/views/kiso/components/field/_separator.html.erb +3 -0
- data/app/views/kiso/components/input_otp/_separator.html.erb +2 -0
- data/app/views/kiso/components/input_otp/_slot.html.erb +2 -0
- data/app/views/kiso/components/nav/_section.html.erb +4 -0
- data/app/views/kiso/components/tooltip/_content.html.erb +2 -0
- data/lib/generators/kiso/install/USAGE +23 -0
- data/lib/generators/kiso/install/install_generator.rb +91 -0
- data/lib/generators/kiso/install/templates/design_system.md.tt +190 -0
- data/lib/generators/kiso/install/templates/initializer.rb.tt +40 -0
- data/lib/kiso/cli/make.rb +6 -3
- data/lib/kiso/cli.rb +10 -0
- data/lib/kiso/color_utils.rb +21 -2
- data/lib/kiso/engine.rb +9 -2
- data/lib/kiso/propshaft_tailwind_stub_filter.rb +9 -2
- data/lib/kiso/themes/avatar.rb +40 -6
- data/lib/kiso/themes/badge.rb +5 -1
- data/lib/kiso/themes/color_mode_button.rb +11 -0
- data/lib/kiso/themes/color_mode_select.rb +7 -0
- data/lib/kiso/themes/dashboard.rb +28 -0
- data/lib/kiso/themes/dropdown_menu.rb +2 -2
- data/lib/kiso/themes/input_otp.rb +6 -3
- data/lib/kiso/themes/nav.rb +17 -0
- data/lib/kiso/themes/pagination.rb +9 -4
- data/lib/kiso/themes/shared.rb +27 -7
- data/lib/kiso/version.rb +5 -2
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 71bd073faf4eaf81467972ad2e834769956d808d79790d0de417697766823fcf
|
|
4
|
+
data.tar.gz: c31b53740f75c262b588d7b56416ed91a58496e6aad704286662c4575af81dff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd986968f5371f77ac6ab53852d6a9227fdb645734fd1c8fa51e0c6737b1074bb6d1839a6779bd3f2ed4e30c69f126a504ad5330b607ba68e4deadd9a735b125
|
|
7
|
+
data.tar.gz: c1834a11353dd43503b96317612cdbf76287c614845e264b53efb23182cdfc472f92dacd81d673cd7d2834abd278e0af96c22d63e1d894951459776975a15080
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/* ── Button ──────────────────────────────────────────────────────────────────
|
|
2
|
+
Default display value for the Button component.
|
|
3
|
+
|
|
4
|
+
Why CSS instead of a Tailwind class?
|
|
5
|
+
The theme module applies `inline-flex` via Tailwind, but Tailwind utilities
|
|
6
|
+
live in @layer utilities — the highest-priority layer. That means when JS
|
|
7
|
+
removes a `hidden` class, the button's `inline-flex` (also in utilities)
|
|
8
|
+
has no cascade advantage to restore visibility. Placing the default display
|
|
9
|
+
in @layer components (lower priority) lets utility classes like `hidden`
|
|
10
|
+
override it naturally, while still restoring inline-flex when `hidden` is
|
|
11
|
+
removed.
|
|
12
|
+
|
|
4
13
|
Fixes: https://github.com/steveclarke/kiso/issues/200 */
|
|
5
14
|
|
|
6
15
|
@layer components {
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
/* Checkbox
|
|
2
|
-
|
|
1
|
+
/* ── Checkbox ────────────────────────────────────────────────────────────────
|
|
2
|
+
Checkmark indicator via CSS ::after pseudo-element.
|
|
3
|
+
|
|
4
|
+
Why CSS instead of ERB?
|
|
5
|
+
Native <input type="checkbox"> cannot contain child elements, so the
|
|
6
|
+
checkmark must be rendered as a pseudo-element. The indicator uses
|
|
7
|
+
mask-image with an inline SVG (Lucide Check icon) and currentColor for
|
|
8
|
+
the fill, which inherits the text color set by compound variants — this
|
|
9
|
+
keeps the checkmark color in sync with the checkbox's checked state
|
|
10
|
+
styling (e.g., text-primary-foreground on a bg-primary background).
|
|
11
|
+
|
|
12
|
+
The grid + place-content: center pattern ensures the ::after checkmark
|
|
13
|
+
is perfectly centered within the checkbox regardless of its size. */
|
|
3
14
|
|
|
4
15
|
[data-component="checkbox"] {
|
|
5
16
|
display: grid;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
/* ── Color Mode
|
|
2
|
-
Icon visibility for the
|
|
3
|
-
|
|
1
|
+
/* ── Color Mode Button ────────────────────────────────────────────────────────
|
|
2
|
+
Icon visibility toggling for the light/dark mode button (kui(:color_mode_button)).
|
|
3
|
+
|
|
4
|
+
Why CSS instead of ERB?
|
|
5
|
+
The icon swap must respond to the .dark class on <html>, which is set by a
|
|
6
|
+
blocking script before first paint. Using CSS ensures the correct icon
|
|
7
|
+
(sun or moon) is visible immediately — no Stimulus controller or JS needed
|
|
8
|
+
for the initial render. The kiso--theme controller handles toggling after
|
|
9
|
+
that.
|
|
10
|
+
|
|
11
|
+
Uses @layer components so utility classes on the icon elements can override
|
|
12
|
+
if needed.
|
|
13
|
+
|
|
14
|
+
Light mode: sun icon visible, moon icon hidden.
|
|
15
|
+
Dark mode: moon icon visible, sun icon hidden. */
|
|
4
16
|
|
|
5
17
|
@layer components {
|
|
6
18
|
[data-slot="color-mode-icon-dark"] { display: none; }
|
|
@@ -1,37 +1,51 @@
|
|
|
1
1
|
/* ── Kiso Dashboard Layout ────────────────────────────────────────────────────
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
CSS grid mechanics, tokens, and state-driven rules for the full-screen
|
|
3
|
+
sidebar + topbar dashboard shell (kui(:dashboard_group) and friends).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Why CSS instead of ERB?
|
|
6
|
+
The dashboard layout uses CSS Grid with animated column widths, fixed
|
|
7
|
+
positioning for mobile overlays, pseudo-state-driven visibility, and
|
|
8
|
+
custom Tailwind variants — none of which can be expressed as Tailwind
|
|
9
|
+
utility classes in ERB templates. The sidebar open/close animation,
|
|
10
|
+
grid template transitions, mobile overlay transform, and scrim backdrop
|
|
11
|
+
all require real CSS rules.
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Host apps can override any @theme token in their own @theme block:
|
|
14
|
+
@theme { --sidebar-width: 18rem; --topbar-height: 4rem; }
|
|
15
|
+
|
|
16
|
+
All selectors target [data-slot="..."] attributes (shadcn v4 convention)
|
|
17
|
+
rather than class names, making them resilient to theme customization.
|
|
18
|
+
──────────────────────────────────────────────────────────────────────────── */
|
|
19
|
+
|
|
20
|
+
/* ── Design Tokens ───────────────────────────────────────────────────────── */
|
|
10
21
|
|
|
11
22
|
@theme {
|
|
12
|
-
/* Sidebar geometry */
|
|
23
|
+
/* Sidebar geometry — fixed width when open (collapses to 0 when closed) */
|
|
13
24
|
--sidebar-width: 16rem;
|
|
14
25
|
|
|
15
|
-
/*
|
|
26
|
+
/* Topbar row height — sidebar header matches this to align horizontally */
|
|
16
27
|
--topbar-height: 3.5rem;
|
|
17
28
|
|
|
18
|
-
/* Sidebar surface tokens (light mode defaults)
|
|
29
|
+
/* Sidebar surface tokens (light mode defaults).
|
|
30
|
+
These are separate from the main semantic tokens because the sidebar
|
|
31
|
+
can have its own distinct color scheme (e.g., a dark sidebar in an
|
|
32
|
+
otherwise light app). */
|
|
19
33
|
--sidebar-background: var(--color-white);
|
|
20
34
|
--sidebar-foreground: var(--color-zinc-900);
|
|
21
35
|
--sidebar-border: var(--color-zinc-200);
|
|
22
36
|
--sidebar-accent: var(--color-zinc-100);
|
|
23
37
|
--sidebar-accent-foreground: var(--color-zinc-700);
|
|
24
38
|
|
|
25
|
-
/* Animation */
|
|
39
|
+
/* Animation timing for sidebar open/close transitions */
|
|
26
40
|
--sidebar-duration: 220ms;
|
|
27
41
|
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
|
28
42
|
|
|
29
|
-
/* Z-index stack */
|
|
43
|
+
/* Z-index stack — sidebar above topbar for mobile overlay */
|
|
30
44
|
--z-topbar: 30;
|
|
31
45
|
--z-sidebar: 40;
|
|
32
46
|
}
|
|
33
47
|
|
|
34
|
-
/* Dark mode sidebar
|
|
48
|
+
/* Dark mode overrides for sidebar-specific surface tokens */
|
|
35
49
|
.dark {
|
|
36
50
|
--sidebar-background: var(--color-zinc-950);
|
|
37
51
|
--sidebar-foreground: var(--color-zinc-100);
|
|
@@ -40,11 +54,13 @@
|
|
|
40
54
|
--sidebar-accent-foreground: var(--color-zinc-300);
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
/* ── Sidebar
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
kui-sidebar-open:lg:hidden — hide on desktop when sidebar expanded
|
|
47
|
-
kui-sidebar-closed:lg:hidden — hide on desktop when sidebar collapsed
|
|
57
|
+
/* ── Sidebar State Variants (Tailwind v4 @custom-variant) ────────────────────
|
|
58
|
+
Register custom Tailwind variants that activate based on sidebar open/close
|
|
59
|
+
state. These let ERB templates use conditional classes without JS:
|
|
60
|
+
kui-sidebar-open:lg:hidden — hide on desktop when sidebar is expanded
|
|
61
|
+
kui-sidebar-closed:lg:hidden — hide on desktop when sidebar is collapsed
|
|
62
|
+
The variant matches any descendant of an element with the data-sidebar-open
|
|
63
|
+
attribute (set by the kiso--sidebar Stimulus controller on dashboard_group). */
|
|
48
64
|
|
|
49
65
|
@custom-variant kui-sidebar-open {
|
|
50
66
|
[data-sidebar-open="true"] & {
|
|
@@ -58,53 +74,71 @@
|
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
|
|
61
|
-
/* ── Layout
|
|
77
|
+
/* ── Layout Mechanics ─────────────────────────────────────────────────────────
|
|
78
|
+
All layout rules live in @layer components so Tailwind utility classes
|
|
79
|
+
(in the higher-priority @layer utilities) can override them when needed.
|
|
80
|
+
|
|
81
|
+
Grid structure (default "sidebar" layout):
|
|
82
|
+
┌─────────────┬──────────────────────────┐
|
|
83
|
+
│ sidebar │ topbar (navbar) │ row 1: --topbar-height
|
|
84
|
+
│ (full ├──────────────────────────┤
|
|
85
|
+
│ height) │ panel (main content) │ row 2: 1fr
|
|
86
|
+
└─────────────┴──────────────────────────┘
|
|
87
|
+
col 1: sidebar col 2: 1fr
|
|
88
|
+
──────────────────────────────────────────────────────────────────────────── */
|
|
62
89
|
|
|
63
90
|
@layer components {
|
|
64
|
-
|
|
91
|
+
|
|
92
|
+
/* ── Sidebar width state ─────────────────────────────────────────────────
|
|
93
|
+
The kiso--sidebar Stimulus controller sets data-sidebar-open on the
|
|
94
|
+
dashboard_group element. These rules translate that attribute into a
|
|
95
|
+
CSS variable that drives the grid column width. */
|
|
65
96
|
[data-sidebar-open="true"] { --sidebar-current-width: var(--sidebar-width); }
|
|
66
97
|
[data-sidebar-open="false"] { --sidebar-current-width: 0rem; }
|
|
67
98
|
|
|
68
|
-
/*
|
|
99
|
+
/* Prevent a 1px ghost border when sidebar is fully collapsed */
|
|
69
100
|
[data-sidebar-open="false"] [data-slot="dashboard-sidebar"] {
|
|
70
101
|
border-right-width: 0;
|
|
71
102
|
}
|
|
72
103
|
|
|
73
|
-
/*
|
|
104
|
+
/* ── Grid container ──────────────────────────────────────────────────── */
|
|
105
|
+
|
|
106
|
+
/* 2-row, 2-column grid with animated sidebar column */
|
|
74
107
|
[data-slot="dashboard-group"] {
|
|
75
108
|
grid-template-rows: var(--topbar-height) 1fr;
|
|
76
109
|
grid-template-columns: var(--sidebar-current-width) 1fr;
|
|
77
110
|
transition: grid-template-columns var(--sidebar-duration) var(--ease-out-expo);
|
|
78
111
|
}
|
|
79
112
|
|
|
80
|
-
/* Topbar
|
|
113
|
+
/* Topbar occupies column 2 only (sidebar spans both rows in column 1) */
|
|
81
114
|
[data-slot="dashboard-navbar"] {
|
|
82
115
|
grid-column: 2;
|
|
83
116
|
}
|
|
84
117
|
|
|
85
|
-
/*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
118
|
+
/* Sidebar spans full height (row 1 through last row).
|
|
119
|
+
background-color and border-right-color reference sidebar-specific CSS
|
|
120
|
+
variables and are set here rather than via Tailwind arbitrary classes
|
|
121
|
+
because bg-(--css-var) classes in @theme are tree-shaken if not
|
|
122
|
+
referenced elsewhere. */
|
|
90
123
|
[data-slot="dashboard-sidebar"] {
|
|
91
124
|
grid-row: 1 / -1;
|
|
92
125
|
background-color: var(--sidebar-background);
|
|
93
126
|
border-right: 1px solid var(--sidebar-border);
|
|
94
127
|
}
|
|
95
128
|
|
|
96
|
-
/* Sidebar header
|
|
129
|
+
/* Sidebar header aligns with the topbar height */
|
|
97
130
|
[data-slot="dashboard-sidebar-header"] {
|
|
98
131
|
height: var(--topbar-height);
|
|
99
132
|
border-bottom: 1px solid var(--sidebar-border);
|
|
100
133
|
}
|
|
101
134
|
|
|
102
|
-
/* Sidebar footer: top border */
|
|
103
135
|
[data-slot="dashboard-sidebar-footer"] {
|
|
104
136
|
border-top: 1px solid var(--sidebar-border);
|
|
105
137
|
}
|
|
106
138
|
|
|
107
|
-
/* Inner nav:
|
|
139
|
+
/* Inner nav container: fixed at --sidebar-width so content doesn't reflow
|
|
140
|
+
during the grid column animation (the outer column shrinks, clipping
|
|
141
|
+
the overflow from this fixed-width inner element). */
|
|
108
142
|
[data-slot="dashboard-sidebar-inner"] {
|
|
109
143
|
width: var(--sidebar-width);
|
|
110
144
|
height: 100%;
|
|
@@ -114,13 +148,16 @@
|
|
|
114
148
|
color: var(--sidebar-foreground);
|
|
115
149
|
}
|
|
116
150
|
|
|
117
|
-
/*
|
|
151
|
+
/* Main content panel: row 2, column 2 */
|
|
118
152
|
[data-slot="dashboard-panel"] {
|
|
119
153
|
grid-column: 2;
|
|
120
154
|
grid-row: 2;
|
|
121
155
|
}
|
|
122
156
|
|
|
123
|
-
/* ── Navbar layout variant
|
|
157
|
+
/* ── "Navbar" layout variant ─────────────────────────────────────────────
|
|
158
|
+
Alternative layout where the navbar spans the full width (both columns)
|
|
159
|
+
and the sidebar sits below it instead of spanning full height. Activated
|
|
160
|
+
by data-layout="navbar" on the dashboard_group element. */
|
|
124
161
|
[data-layout="navbar"] [data-slot="dashboard-navbar"] {
|
|
125
162
|
grid-column: 1 / -1;
|
|
126
163
|
}
|
|
@@ -128,16 +165,20 @@
|
|
|
128
165
|
grid-row: auto;
|
|
129
166
|
}
|
|
130
167
|
|
|
131
|
-
/* Scrim: hidden on desktop */
|
|
168
|
+
/* Scrim overlay: hidden on desktop, shown on mobile when sidebar is open */
|
|
132
169
|
[data-slot="dashboard-scrim"] { display: none; }
|
|
133
170
|
|
|
134
|
-
/* ── Collapse button icon switching ──────────────────────────────────────
|
|
171
|
+
/* ── Collapse button icon switching ──────────────────────────────────────
|
|
172
|
+
The sidebar collapse button shows different icons depending on whether
|
|
173
|
+
the sidebar is open or closed (e.g., chevron-left vs chevron-right). */
|
|
135
174
|
[data-sidebar-open="true"] [data-slot="collapse-icon-open"] { display: inline; }
|
|
136
175
|
[data-sidebar-open="true"] [data-slot="collapse-icon-closed"] { display: none; }
|
|
137
176
|
[data-sidebar-open="false"] [data-slot="collapse-icon-open"] { display: none; }
|
|
138
177
|
[data-sidebar-open="false"] [data-slot="collapse-icon-closed"] { display: inline; }
|
|
139
178
|
|
|
140
|
-
/* ── Nav section (details
|
|
179
|
+
/* ── Nav section accordion (native <details>/<summary>) ─────────────────
|
|
180
|
+
Chevron rotates 180deg when the section is expanded. Uses CSS transition
|
|
181
|
+
rather than JS for smooth animation. */
|
|
141
182
|
[data-slot="nav-section-chevron"] {
|
|
142
183
|
transition: transform 200ms ease;
|
|
143
184
|
}
|
|
@@ -145,7 +186,9 @@
|
|
|
145
186
|
transform: rotate(180deg);
|
|
146
187
|
}
|
|
147
188
|
|
|
148
|
-
/* ── Nav item
|
|
189
|
+
/* ── Nav item hover/active states inside sidebar ────────────────────────
|
|
190
|
+
Nav items use the sidebar's own accent tokens (not the global accent
|
|
191
|
+
tokens) so the sidebar can have an independent color scheme. */
|
|
149
192
|
[data-slot="dashboard-sidebar-inner"] [data-slot="nav-item"]:hover {
|
|
150
193
|
background-color: var(--sidebar-accent);
|
|
151
194
|
color: var(--sidebar-accent-foreground);
|
|
@@ -155,34 +198,44 @@
|
|
|
155
198
|
color: var(--sidebar-accent-foreground);
|
|
156
199
|
}
|
|
157
200
|
|
|
158
|
-
/* ── Mobile: sidebar becomes a
|
|
201
|
+
/* ── Mobile (< md breakpoint): sidebar becomes a full-width overlay ────
|
|
202
|
+
On small screens, the sidebar column collapses to 0 in the grid and the
|
|
203
|
+
sidebar element switches to a fixed-position overlay that slides in from
|
|
204
|
+
the left. A semi-transparent scrim appears behind it. */
|
|
159
205
|
@media (max-width: 767px) {
|
|
160
|
-
/*
|
|
206
|
+
/* Remove the sidebar column from the grid on mobile.
|
|
207
|
+
--sidebar-mobile-width caps the sidebar so the scrim remains
|
|
208
|
+
visible and tappable for dismiss (#208). */
|
|
161
209
|
[data-slot="dashboard-group"] {
|
|
210
|
+
--sidebar-mobile-width: min(var(--sidebar-width), 85dvw);
|
|
162
211
|
grid-template-columns: 0 1fr;
|
|
163
212
|
}
|
|
164
213
|
|
|
165
|
-
/* Sidebar
|
|
214
|
+
/* Sidebar becomes a fixed overlay that slides in from the left */
|
|
166
215
|
[data-slot="dashboard-sidebar"] {
|
|
167
216
|
position: fixed;
|
|
168
217
|
inset-block: 0;
|
|
169
218
|
inset-inline-start: 0;
|
|
170
219
|
z-index: var(--z-sidebar);
|
|
171
|
-
width:
|
|
172
|
-
transform: translateX(-
|
|
220
|
+
width: var(--sidebar-mobile-width);
|
|
221
|
+
transform: translateX(-100%);
|
|
173
222
|
transition: transform var(--sidebar-duration) var(--ease-out-expo);
|
|
174
223
|
}
|
|
175
224
|
|
|
225
|
+
/* Slide sidebar into view when open */
|
|
176
226
|
[data-sidebar-open="true"] [data-slot="dashboard-sidebar"] {
|
|
177
227
|
transform: translateX(0);
|
|
178
228
|
}
|
|
179
229
|
|
|
180
|
-
/* Inner nav
|
|
230
|
+
/* Inner nav matches mobile sidebar width */
|
|
181
231
|
[data-slot="dashboard-sidebar-inner"] {
|
|
182
|
-
width:
|
|
232
|
+
width: var(--sidebar-mobile-width);
|
|
183
233
|
}
|
|
184
234
|
|
|
185
|
-
/*
|
|
235
|
+
/* Semi-transparent scrim behind the open sidebar overlay.
|
|
236
|
+
z-index is one below the sidebar so it sits behind the sidebar
|
|
237
|
+
but above the main content. Clicking the scrim closes the sidebar
|
|
238
|
+
(handled by the kiso--sidebar Stimulus controller). */
|
|
186
239
|
[data-sidebar-open="true"] [data-slot="dashboard-scrim"] {
|
|
187
240
|
display: block;
|
|
188
241
|
position: fixed;
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
/* Dialog
|
|
1
|
+
/* ── Dialog & Alert Dialog ────────────────────────────────────────────────────
|
|
2
|
+
Entry/exit animations, scroll lock, and reduced-motion support for both
|
|
3
|
+
Dialog and Alert Dialog components.
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Why CSS instead of ERB?
|
|
6
|
+
Both components use the native <dialog> element with showModal(). Animations
|
|
7
|
+
on open/close, the ::backdrop fade, and scroll locking on the <html> element
|
|
8
|
+
require CSS — they cannot be expressed as Tailwind utility classes.
|
|
9
|
+
|
|
10
|
+
Animation lifecycle (managed by the kiso--dialog Stimulus controller):
|
|
11
|
+
1. Open: controller calls dialog.showModal() → browser sets [open] →
|
|
12
|
+
CSS triggers fade-in + scale-up on both backdrop and content.
|
|
13
|
+
2. Close: controller sets data-state="closing" → CSS triggers fade-out +
|
|
14
|
+
scale-down with `forwards` fill → animationend fires → controller
|
|
15
|
+
calls dialog.close() and removes data-state.
|
|
16
|
+
|
|
17
|
+
Selectors use :is() to target both dialog and alert-dialog with shared
|
|
18
|
+
rules, avoiding duplication.
|
|
19
|
+
──────────────────────────────────────────────────────────────────────────── */
|
|
20
|
+
|
|
21
|
+
/* ── Entry animations ──────────────────────────────────────────────────────
|
|
22
|
+
Triggered by the native [open] attribute when showModal() is called.
|
|
23
|
+
Backdrop fades in; content fades in and scales up from 95%. */
|
|
4
24
|
:is(dialog[data-slot="dialog"], dialog[data-slot="alert-dialog"])[open] {
|
|
5
25
|
animation: kiso-dialog-backdrop-in 200ms ease-out;
|
|
6
26
|
}
|
|
@@ -8,7 +28,10 @@
|
|
|
8
28
|
animation: kiso-dialog-content-in 200ms ease-out;
|
|
9
29
|
}
|
|
10
30
|
|
|
11
|
-
/* Exit
|
|
31
|
+
/* ── Exit animations ──────────────────────────────────────────────────────
|
|
32
|
+
Triggered by data-state="closing" which the Stimulus controller sets
|
|
33
|
+
before calling .close(). Uses `forwards` fill mode to hold the final
|
|
34
|
+
frame (opacity: 0) until the controller removes the dialog from view. */
|
|
12
35
|
:is(dialog[data-slot="dialog"], dialog[data-slot="alert-dialog"])[data-state="closing"] {
|
|
13
36
|
animation: kiso-dialog-backdrop-out 200ms ease-in forwards;
|
|
14
37
|
}
|
|
@@ -16,12 +39,18 @@
|
|
|
16
39
|
animation: kiso-dialog-content-out 200ms ease-in forwards;
|
|
17
40
|
}
|
|
18
41
|
|
|
42
|
+
/* ── Keyframes ─────────────────────────────────────────────────────────── */
|
|
43
|
+
|
|
44
|
+
/* Backdrop: simple opacity fade */
|
|
19
45
|
@keyframes kiso-dialog-backdrop-in {
|
|
20
46
|
from { opacity: 0; }
|
|
21
47
|
}
|
|
22
48
|
@keyframes kiso-dialog-backdrop-out {
|
|
23
49
|
to { opacity: 0; }
|
|
24
50
|
}
|
|
51
|
+
|
|
52
|
+
/* Content: opacity fade combined with a subtle scale transform (95% → 100%
|
|
53
|
+
on entry, 100% → 95% on exit) for a "zoom in" feel. */
|
|
25
54
|
@keyframes kiso-dialog-content-in {
|
|
26
55
|
from { opacity: 0; transform: scale(0.95); }
|
|
27
56
|
}
|
|
@@ -29,13 +58,18 @@
|
|
|
29
58
|
to { opacity: 0; transform: scale(0.95); }
|
|
30
59
|
}
|
|
31
60
|
|
|
32
|
-
/* Scroll lock
|
|
61
|
+
/* ── Scroll lock ──────────────────────────────────────────────────────────
|
|
62
|
+
Prevent background scrolling when a modal dialog is open. The :modal
|
|
63
|
+
pseudo-class ensures this only applies to dialogs opened with showModal()
|
|
64
|
+
(not dialog.show()). scrollbar-gutter: stable prevents layout shift when
|
|
65
|
+
the scrollbar disappears. */
|
|
33
66
|
html:has(:is(dialog[data-slot="dialog"], dialog[data-slot="alert-dialog"])[open]:modal) {
|
|
34
67
|
overflow: hidden;
|
|
35
68
|
scrollbar-gutter: stable;
|
|
36
69
|
}
|
|
37
70
|
|
|
38
|
-
/*
|
|
71
|
+
/* ── Reduced motion ───────────────────────────────────────────────────────
|
|
72
|
+
Disable all dialog animations for users who prefer reduced motion. */
|
|
39
73
|
@media (prefers-reduced-motion: reduce) {
|
|
40
74
|
:is(dialog[data-slot="dialog"], dialog[data-slot="alert-dialog"])[open],
|
|
41
75
|
:is(dialog[data-slot="dialog"], dialog[data-slot="alert-dialog"])[open] > :is([data-slot="dialog-content"], [data-slot="alert-dialog-content"]),
|