@xleddyl/443-components-vue 0.8.5 → 0.9.0

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.
package/README.md CHANGED
@@ -100,10 +100,27 @@ Vite 8 minifies CSS with Lightning CSS. Set `build.cssTarget` to browsers that s
100
100
 
101
101
  ## Theming
102
102
 
103
- Tokens live on `.k-root`, never on `:root`. Override them on a root element: Root props, inline style or host CSS.
103
+ Tokens live on `.k-root`, never on `:root`. Override them on a root element: host CSS, Root props or inline style.
104
+
105
+ The brand of an app is a custom theme: a class on the outermost root, with the token overrides in host CSS. Keep the brand values in this one place, not in Root props.
106
+
107
+ ```vue
108
+ <KRoot class="theme-acme">...</KRoot>
109
+ ```
110
+
111
+ ```css
112
+ .k-root.theme-acme {
113
+ --k-accent: #ff4d00;
114
+ --k-accent-contrast: #ffffff;
115
+ --k-font-sans: 'Inter', sans-serif;
116
+ --k-radius-scale: 0.75;
117
+ }
118
+ ```
119
+
120
+ Use Root props for values that change at runtime (an accent that the user selects, a preview, a demo):
104
121
 
105
122
  ```vue
106
- <KRoot accent="#ff4d00" font-sans="'Inter', sans-serif" :radius-scale="0.75" theme="dark">
123
+ <KRoot :accent="userAccent" theme="dark">
107
124
  ```
108
125
 
109
126
  Input tokens, declared only on the outermost root so nested roots inherit them: `--k-accent`, `--k-accent-contrast`, `--k-font-sans`, `--k-font-mono`, `--k-font-size`, `--k-font-features`, `--k-line-height`, `--k-radius-scale`. Every other token (surfaces, text, lines, accent shades, status colors, radii, shadows, motion) is derived per root, so a nested root with its own `theme` or `accent` re-themes a region. The full list is in [CONVENTIONS.md](./CONVENTIONS.md#tokens).
@@ -169,14 +186,10 @@ import '@fontsource-variable/funnel-display'
169
186
  import '@fontsource-variable/geist-mono'
170
187
  ```
171
188
 
172
- Presets set the input tokens (accent, accent contrast and accent text, fonts, font features, radius scale) and the surface, line and text tokens. Root props, inline style and unlayered host CSS still win, so a custom brand is a few lines:
173
-
174
- ```vue
175
- <KRoot accent="#ff4d00" accent-contrast="#ffffff" :radius-scale="0.5" theme="dark">...</KRoot>
176
- ```
189
+ Presets set the input tokens (accent, accent contrast and accent text, fonts, font features, radius scale) and the surface, line and text tokens. Unlayered host CSS, Root props and inline style still win, so a custom theme on top of a preset is a few lines of host CSS (see [Theming](#theming)):
177
190
 
178
191
  ```css
179
- .k-root.brand-secret {
192
+ .k-root.theme-acme {
180
193
  --k-accent: #ff4d00;
181
194
  --k-radius-scale: 0.5;
182
195
  }
@@ -184,6 +197,8 @@ Presets set the input tokens (accent, accent contrast and accent text, fonts, fo
184
197
 
185
198
  Semantic color props are always called `tone` and accept `'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger'` (type `Tone`).
186
199
 
200
+ Buttons show `icon` before the label and `trailingIcon` after it. Put action icons (`plus`, `trash`, `pencil`) in `icon`. Put direction icons (`arrow-right`, `chevron-right`, `arrow-top-right-on-square`) in `trailingIcon`: `<KButton trailing-icon="arrow-right">Continue</KButton>`.
201
+
187
202
  ## Scoping
188
203
 
189
204
  - The reset only matches `.k-root` and its descendants, wrapped in `:where()` (zero specificity). Markup outside a root keeps browser defaults.
@@ -452,7 +467,7 @@ Ready defaults to start a dashboard project: an app frame, an auth frame and pag
452
467
  | `breadcrumbs` | | Rendered in the desktop topbar. `#topbar` replaces them, `#actions` adds buttons on the right. |
453
468
  | `search` | `false` | `true` adds a CommandPalette with every navigation item, an array adds your own command groups, an async function `(query, signal) => CommandGroup<T>[]` searches on your server (item `data` reaches `#search-item` typed) (matching navigation items come first unless `searchNavigation` is `false`). `#search` replaces it. |
454
469
  | `searchProps` | | Options for the built-in CommandPalette: `minQueryLength`, `debounce`, `placeholder`, `label`, `emptyText` (a string or `(query) => string`), `minQueryText`, `errorText`, `loadingText`, `resultsText`, `notice`, `recentKey`, footer labels. Slots `#search-item`, `#search-empty`, `#search-group-label` and `#search-after-results` reach the palette. |
455
- | `themeSwitch` | `'sidebar'` | `'sidebar'`, `'topbar'` or `false`. |
470
+ | `themeSwitch` | `false` | `'sidebar'`, `'topbar'` or `false`. The default keeps the theme choice only in the Appearance section of the settings modal. With `accountAction="menu"` there is no settings modal, so set `'sidebar'` or `'topbar'`. |
456
471
  | `collapsible`, `v-model:collapsed`, `storageKey` | `true`, `'k-sidebar-collapsed'` | Icon rail on desktop. Persisted in a cookie under Nuxt (rendered on the server, no flash) or `localStorage` elsewhere. `false` disables persistence. |
457
472
  | `shortcut` | `'mod+b'` | Toggles the rail on desktop and the drawer on mobile. `searchShortcut` defaults to `mod+k`. |
458
473
  | `v-model:open` | `false` | Mobile drawer (below 768px of shell width): scrim, focus moves into the drawer, the content is `inert`, Escape and the scrim close it and focus returns to the burger. |
@@ -589,7 +604,7 @@ export default defineAppConfig({
589
604
  ],
590
605
  signOutTo: '/logout',
591
606
  },
592
- dashboard: { variant: 'inset', search: true, themeSwitch: 'sidebar' },
607
+ dashboard: { variant: 'inset', search: true },
593
608
  auth: { variant: 'split', footer: 'Acme Inc.', asideTitle: 'Run the store.' },
594
609
  },
595
610
  })
@@ -189,7 +189,7 @@ const props = defineProps({
189
189
  searchPlaceholder: { type: String, required: false },
190
190
  searchShortcut: { type: [String, Boolean], required: false, default: "mod+k" },
191
191
  searchNavigationLabel: { type: String, required: false },
192
- themeSwitch: { type: [String, Boolean], required: false, default: "sidebar" },
192
+ themeSwitch: { type: [String, Boolean], required: false, default: false },
193
193
  collapsible: { type: Boolean, required: false, default: true },
194
194
  storageKey: { type: [String, Boolean], required: false, default: "k-sidebar-collapsed" },
195
195
  shortcut: { type: [String, Boolean], required: false, default: "mod+b" },
@@ -203,6 +203,49 @@ html.k-root body {
203
203
  transform: rotate(180deg);
204
204
  }
205
205
 
206
+ @media (hover: hover) {
207
+ .k-shell.is-collapsed .k-sidebar-header:has(> .k-sidebar-brand:not(:empty)) {
208
+ position: relative;
209
+ }
210
+
211
+ .k-shell.is-collapsed
212
+ .k-sidebar-header:has(> .k-sidebar-brand:not(:empty))
213
+ > .k-sidebar-brand,
214
+ .k-shell.is-collapsed
215
+ .k-sidebar-header:has(> .k-sidebar-brand:not(:empty))
216
+ > .k-sidebar-collapse {
217
+ transition: opacity var(--k-duration) var(--k-ease);
218
+ }
219
+
220
+ .k-shell.is-collapsed
221
+ .k-sidebar-header:has(> .k-sidebar-brand:not(:empty))
222
+ > .k-sidebar-collapse {
223
+ position: absolute;
224
+ top: 50%;
225
+ left: 50%;
226
+ translate: -50% -50%;
227
+ opacity: 0;
228
+ }
229
+
230
+ .k-shell.is-collapsed
231
+ .k-sidebar-header:has(> .k-sidebar-brand:not(:empty)):is(
232
+ :hover,
233
+ :has(> .k-sidebar-collapse:focus-visible)
234
+ )
235
+ > .k-sidebar-brand {
236
+ opacity: 0;
237
+ }
238
+
239
+ .k-shell.is-collapsed
240
+ .k-sidebar-header:has(> .k-sidebar-brand:not(:empty)):is(
241
+ :hover,
242
+ :has(> .k-sidebar-collapse:focus-visible)
243
+ )
244
+ > .k-sidebar-collapse {
245
+ opacity: 1;
246
+ }
247
+ }
248
+
206
249
  .k-shell.is-collapsed .k-navlink {
207
250
  justify-content: center;
208
251
  padding-inline: 0;
@@ -13,7 +13,7 @@
13
13
  border: 1px solid var(--k-field-line);
14
14
  border-radius: var(--k-radius-md);
15
15
  box-shadow: var(--k-shadow-xs);
16
- cursor: text;
16
+ cursor: pointer;
17
17
  transition:
18
18
  border-color var(--k-duration) var(--k-ease),
19
19
  color var(--k-duration) var(--k-ease),
@@ -55,7 +55,30 @@
55
55
  @container k-shell (min-width: 768px) {
56
56
  .k-shell.is-collapsed .k-dashboard-search.k-command-trigger {
57
57
  justify-content: center;
58
+ min-width: 0;
59
+ height: 1.875rem;
58
60
  padding: 0;
61
+ color: var(--k-text-dimmed);
62
+ background: transparent;
63
+ border-color: transparent;
64
+ box-shadow: none;
65
+ transition:
66
+ background-color var(--k-duration) var(--k-ease),
67
+ color var(--k-duration) var(--k-ease),
68
+ scale var(--k-duration) var(--k-ease);
69
+ }
70
+
71
+ .k-shell.is-collapsed .k-dashboard-search.k-command-trigger:hover {
72
+ color: var(--k-text-muted);
73
+ background: var(--k-hover);
74
+ }
75
+
76
+ .k-shell.is-collapsed .k-dashboard-search.k-command-trigger:active {
77
+ scale: 0.985;
78
+ }
79
+
80
+ .k-shell.is-collapsed .k-dashboard-search.k-command-trigger:focus-visible {
81
+ box-shadow: var(--k-focus-ring);
59
82
  }
60
83
 
61
84
  .k-shell.is-collapsed .k-dashboard-search .k-command-trigger-text,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xleddyl/443-components-vue",
3
- "version": "0.8.5",
3
+ "version": "0.9.0",
4
4
  "description": "Compact, scoped dashboard components for Vue and Nuxt",
5
5
  "license": "MIT",
6
6
  "author": "Edoardo Alberti (https://github.com/xleddyl)",