@poodle64/ui 2026.9.14 → 2026.9.16
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/dist/components/ui/app-shell/app-shell.svelte +32 -33
- package/dist/components/ui/app-shell/app-shell.svelte.d.ts +6 -8
- package/dist/components/ui/app-shell/types.d.ts +2 -0
- package/dist/components/ui/app-shell/types.js +1 -1
- package/dist/styles.css +1 -19
- package/package.json +1 -1
- package/registry/component-map.json +1 -1
- package/registry/component-map.md +1 -1
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
import PanelLeftClose from '@lucide/svelte/icons/panel-left-close';
|
|
91
91
|
import PanelLeftOpen from '@lucide/svelte/icons/panel-left-open';
|
|
92
92
|
import AppNav from './app-nav.svelte';
|
|
93
|
-
import { activeNavLabel, toItems, type NavSource } from './types.js';
|
|
93
|
+
import { activeNavLabel, matchesPrefix, toItems, type NavSource } from './types.js';
|
|
94
94
|
import { provideShellControls, type ShellControlsSlot } from './controls.js';
|
|
95
95
|
import { cn } from '../../../utils.js';
|
|
96
96
|
|
|
@@ -110,8 +110,6 @@
|
|
|
110
110
|
identity,
|
|
111
111
|
settingsHref,
|
|
112
112
|
settingsLabel = 'Settings',
|
|
113
|
-
version,
|
|
114
|
-
versionHref,
|
|
115
113
|
onSearch,
|
|
116
114
|
searchLabel = 'Search…',
|
|
117
115
|
searchShortcut = '⌘K',
|
|
@@ -176,16 +174,14 @@
|
|
|
176
174
|
identity?: Snippet;
|
|
177
175
|
/** Where the Settings row at the rail's foot links. Absent renders no row.
|
|
178
176
|
* Settings sits at the foot because configuring the app is not navigating
|
|
179
|
-
* it, and the split reads without a label.
|
|
177
|
+
* it, and the split reads without a label.
|
|
178
|
+
*
|
|
179
|
+
* The app's version does NOT live beside it. A build string earns rail
|
|
180
|
+
* space only if it saves a trip, and it does not: Settings is on screen
|
|
181
|
+
* at every moment and its About section is one click from here, so the
|
|
182
|
+
* line was permanent furniture duplicating the thing directly above it. */
|
|
180
183
|
settingsHref?: string;
|
|
181
184
|
settingsLabel?: string;
|
|
182
|
-
/** The build this person is looking at, e.g. `2026.9.3 · b032a3a`. Rendered
|
|
183
|
-
* as one muted line under the Settings row: no icon, no hover, not a nav
|
|
184
|
-
* row. It earns its place by answering "what am I running" the moment
|
|
185
|
-
* someone reports a bug, and it links into Settings where the full
|
|
186
|
-
* About section lives. */
|
|
187
|
-
version?: string;
|
|
188
|
-
versionHref?: string;
|
|
189
185
|
/** Provide to render the search affordance. Usually opens a CommandPalette. */
|
|
190
186
|
onSearch?: () => void;
|
|
191
187
|
searchLabel?: string;
|
|
@@ -237,9 +233,19 @@
|
|
|
237
233
|
|
|
238
234
|
const hasNav = $derived(toItems(nav).length > 0);
|
|
239
235
|
|
|
236
|
+
// The foot's Settings row owns its subtree, matched exactly as a nav `href`
|
|
237
|
+
// is, so the row's own current state and the bar's label cannot disagree.
|
|
238
|
+
const atSettings = $derived(
|
|
239
|
+
!!settingsHref && !!currentPath && matchesPrefix(currentPath, settingsHref)
|
|
240
|
+
);
|
|
241
|
+
|
|
240
242
|
// Where the user is, in words: the rail is icons when collapsed and a closed
|
|
241
|
-
// drawer on a phone, so the bar names the section.
|
|
242
|
-
|
|
243
|
+
// drawer on a phone, so the bar names the section. Settings is a section like
|
|
244
|
+
// any other and is named the same way — by the foot row's own label, since
|
|
245
|
+
// the shell knows nothing of the pages inside it.
|
|
246
|
+
const location = $derived(
|
|
247
|
+
activeNavLabel(nav, currentPath) ?? (atSettings ? settingsLabel : undefined)
|
|
248
|
+
);
|
|
243
249
|
|
|
244
250
|
// The page's scope controls, registered by `<ShellControls>` from the route.
|
|
245
251
|
const controls: ShellControlsSlot = $state({ content: null });
|
|
@@ -673,26 +679,19 @@
|
|
|
673
679
|
The version is not a row: no icon, no tile, no hover, one muted
|
|
674
680
|
line, so it reads as metadata and never competes for a click.
|
|
675
681
|
-->
|
|
676
|
-
{#if settingsHref
|
|
677
|
-
<div class="ds-shell-rail-foot mt-auto"
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
</
|
|
688
|
-
|
|
689
|
-
{#if version}
|
|
690
|
-
{#if versionHref}
|
|
691
|
-
<a href={versionHref} class="ds-shell-version">{version}</a>
|
|
692
|
-
{:else}
|
|
693
|
-
<p class="ds-shell-version">{version}</p>
|
|
694
|
-
{/if}
|
|
695
|
-
{/if}
|
|
682
|
+
{#if settingsHref}
|
|
683
|
+
<div class="ds-shell-rail-foot mt-auto">
|
|
684
|
+
<a
|
|
685
|
+
href={settingsHref}
|
|
686
|
+
class="ds-nav-item"
|
|
687
|
+
aria-current={atSettings ? 'page' : undefined}
|
|
688
|
+
onclick={() => (mobileNavOpen = false)}
|
|
689
|
+
>
|
|
690
|
+
<Settings class="ds-nav-icon size-[1.125rem] flex-none" aria-hidden="true" />
|
|
691
|
+
<span class={railCollapsed && !mobileNavOpen ? 'sr-only' : 'truncate'}>
|
|
692
|
+
{settingsLabel}
|
|
693
|
+
</span>
|
|
694
|
+
</a>
|
|
696
695
|
</div>
|
|
697
696
|
{/if}
|
|
698
697
|
{#if collapsible && !railCollapsed && !mobileNavOpen}
|
|
@@ -133,16 +133,14 @@ type $$ComponentProps = {
|
|
|
133
133
|
identity?: Snippet;
|
|
134
134
|
/** Where the Settings row at the rail's foot links. Absent renders no row.
|
|
135
135
|
* Settings sits at the foot because configuring the app is not navigating
|
|
136
|
-
* it, and the split reads without a label.
|
|
136
|
+
* it, and the split reads without a label.
|
|
137
|
+
*
|
|
138
|
+
* The app's version does NOT live beside it. A build string earns rail
|
|
139
|
+
* space only if it saves a trip, and it does not: Settings is on screen
|
|
140
|
+
* at every moment and its About section is one click from here, so the
|
|
141
|
+
* line was permanent furniture duplicating the thing directly above it. */
|
|
137
142
|
settingsHref?: string;
|
|
138
143
|
settingsLabel?: string;
|
|
139
|
-
/** The build this person is looking at, e.g. `2026.9.3 · b032a3a`. Rendered
|
|
140
|
-
* as one muted line under the Settings row: no icon, no hover, not a nav
|
|
141
|
-
* row. It earns its place by answering "what am I running" the moment
|
|
142
|
-
* someone reports a bug, and it links into Settings where the full
|
|
143
|
-
* About section lives. */
|
|
144
|
-
version?: string;
|
|
145
|
-
versionHref?: string;
|
|
146
144
|
/** Provide to render the search affordance. Usually opens a CommandPalette. */
|
|
147
145
|
onSearch?: () => void;
|
|
148
146
|
searchLabel?: string;
|
|
@@ -129,6 +129,8 @@ export declare function navChildren(item: NavItem): readonly NavChildItem[];
|
|
|
129
129
|
* is looking for.
|
|
130
130
|
*/
|
|
131
131
|
export declare function toItems(nav: NavSource | undefined): NavItem[];
|
|
132
|
+
/** Prefix-match `path` against `prefix`, without running past a path segment. */
|
|
133
|
+
export declare function matchesPrefix(path: string, prefix: string): boolean;
|
|
132
134
|
/**
|
|
133
135
|
* Whether `item` is the current page.
|
|
134
136
|
*
|
|
@@ -74,7 +74,7 @@ export function toItems(nav) {
|
|
|
74
74
|
return items;
|
|
75
75
|
}
|
|
76
76
|
/** Prefix-match `path` against `prefix`, without running past a path segment. */
|
|
77
|
-
function matchesPrefix(path, prefix) {
|
|
77
|
+
export function matchesPrefix(path, prefix) {
|
|
78
78
|
return path === prefix || path.startsWith(prefix + '/');
|
|
79
79
|
}
|
|
80
80
|
/**
|
package/dist/styles.css
CHANGED
|
@@ -803,7 +803,7 @@
|
|
|
803
803
|
.ds-shell-rail-foot {
|
|
804
804
|
display: flex;
|
|
805
805
|
flex-direction: column;
|
|
806
|
-
padding-block: 0.375rem 0.
|
|
806
|
+
padding-block: 0.375rem 0.5rem;
|
|
807
807
|
padding-inline: 0.75rem;
|
|
808
808
|
border-top: 1px solid color-mix(in oklch, var(--ds-nav-ink) 22%, transparent);
|
|
809
809
|
}
|
|
@@ -811,24 +811,6 @@
|
|
|
811
811
|
/* Metadata, not a row. No icon, no tile, no hover: it answers "what am I
|
|
812
812
|
running" when someone reports a bug and otherwise stays out of the way.
|
|
813
813
|
`tabular-nums` so a version does not re-flow as the digits change. */
|
|
814
|
-
/* Below Settings, on the rail's bottom edge, so the rail OPENS with the app's
|
|
815
|
-
name and CLOSES with its build — identity at both ends, the action between
|
|
816
|
-
them. Above Settings would put metadata before the thing people click.
|
|
817
|
-
`padding-inline` matches `.ds-nav-item`'s own, so it starts on the same
|
|
818
|
-
vertical as the icons rather than the labels: it is a line of metadata,
|
|
819
|
-
not a row missing its icon. */
|
|
820
|
-
.ds-shell-version {
|
|
821
|
-
margin: 0;
|
|
822
|
-
padding: 0.25rem 0.625rem 0;
|
|
823
|
-
color: var(--ds-nav-ink-muted);
|
|
824
|
-
font-size: var(--ds-text-2xs);
|
|
825
|
-
font-variant-numeric: tabular-nums;
|
|
826
|
-
text-decoration: none;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
a.ds-shell-version:hover {
|
|
830
|
-
color: var(--ds-nav-ink);
|
|
831
|
-
}
|
|
832
814
|
|
|
833
815
|
/* `hidden` is an attribute the UA stylesheet honours at the weakest possible
|
|
834
816
|
specificity, so the `display: flex` above beats it and a closed group would
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/ui",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.16",
|
|
4
4
|
"description": "Household shared component layer: shadcn-svelte primitives (bits-ui) plus the composed page chrome every app builds its routes from, restyled by each app's @poodle64/design-tokens alias layer. One fix reaches every app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @poodle64/ui — situation → component map
|
|
2
2
|
|
|
3
3
|
<!-- GENERATED by scripts/generate-registry.mjs from scripts/situations.json + package source. DO NOT EDIT. -->
|
|
4
|
-
Generated from `@poodle64/ui@2026.9.
|
|
4
|
+
Generated from `@poodle64/ui@2026.9.16`. 57 components, 15 situations.
|
|
5
5
|
|
|
6
6
|
**Read this before writing a `<div>`.** Find the SITUATION you are in below, then compose the component named for it — do not hand-build it from raw `Card` or utility classes. Import is `import { Name } from '<import path>'`. Props marked `?` are optional. This map is the retrieval step the [`frontend-design` skill] makes mandatory; the [CHI 2026 study] measured composing-from-a-registry at 95% design-system compliance against 71% for writing the CSS from a prose style guide.
|
|
7
7
|
|