@poodle64/ui 2026.9.11 → 2026.9.13
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.
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
import Menu from '@lucide/svelte/icons/menu';
|
|
85
85
|
import X from '@lucide/svelte/icons/x';
|
|
86
86
|
import Search from '@lucide/svelte/icons/search';
|
|
87
|
+
import Settings from '@lucide/svelte/icons/settings';
|
|
87
88
|
import Sun from '@lucide/svelte/icons/sun';
|
|
88
89
|
import Moon from '@lucide/svelte/icons/moon';
|
|
89
90
|
import PanelLeftClose from '@lucide/svelte/icons/panel-left-close';
|
|
@@ -107,6 +108,10 @@
|
|
|
107
108
|
context,
|
|
108
109
|
actions,
|
|
109
110
|
identity,
|
|
111
|
+
settingsHref,
|
|
112
|
+
settingsLabel = 'Settings',
|
|
113
|
+
version,
|
|
114
|
+
versionHref,
|
|
110
115
|
onSearch,
|
|
111
116
|
searchLabel = 'Search…',
|
|
112
117
|
searchShortcut = '⌘K',
|
|
@@ -162,8 +167,25 @@
|
|
|
162
167
|
context?: Snippet;
|
|
163
168
|
/** Trailing top-bar slot, before the theme toggle: app-level action buttons. */
|
|
164
169
|
actions?: Snippet;
|
|
165
|
-
/** The signed-in user surface. Rendered once, at the end of the top bar.
|
|
170
|
+
/** The signed-in user surface. Rendered once, at the end of the top bar.
|
|
171
|
+
* It stays there at EVERY width rather than moving into the rail foot on
|
|
172
|
+
* desktop: the rail is an overlay drawer below `md`, so a rail-placed
|
|
173
|
+
* account is two taps away and who-am-I is hidden behind the menu; and
|
|
174
|
+
* the alternative, rendering it in both, is the duplication this file
|
|
175
|
+
* exists to avoid. */
|
|
166
176
|
identity?: Snippet;
|
|
177
|
+
/** Where the Settings row at the rail's foot links. Absent renders no row.
|
|
178
|
+
* Settings sits at the foot because configuring the app is not navigating
|
|
179
|
+
* it, and the split reads without a label. */
|
|
180
|
+
settingsHref?: string;
|
|
181
|
+
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;
|
|
167
189
|
/** Provide to render the search affordance. Usually opens a CommandPalette. */
|
|
168
190
|
onSearch?: () => void;
|
|
169
191
|
searchLabel?: string;
|
|
@@ -638,6 +660,41 @@
|
|
|
638
660
|
label={navLabel}
|
|
639
661
|
onNavigate={() => (mobileNavOpen = false)}
|
|
640
662
|
/>
|
|
663
|
+
|
|
664
|
+
<!--
|
|
665
|
+
The rail's foot. `mt-auto` pins it under the nav however short the
|
|
666
|
+
section list is, so it sits on the rail's bottom edge rather than
|
|
667
|
+
trailing the last section. Two things live here and nothing else:
|
|
668
|
+
where you configure the app, and which build you are looking at.
|
|
669
|
+
|
|
670
|
+
Settings is a nav row like any other and takes the same active and
|
|
671
|
+
hover treatment, because it IS a destination — it is last rather
|
|
672
|
+
than separate because configuring the app is not navigating it.
|
|
673
|
+
The version is not a row: no icon, no tile, no hover, one muted
|
|
674
|
+
line, so it reads as metadata and never competes for a click.
|
|
675
|
+
-->
|
|
676
|
+
{#if settingsHref || version}
|
|
677
|
+
<div class="ds-shell-rail-foot mt-auto" class:sr-only={railCollapsed && !mobileNavOpen}>
|
|
678
|
+
{#if settingsHref}
|
|
679
|
+
<a
|
|
680
|
+
href={settingsHref}
|
|
681
|
+
class="ds-nav-item"
|
|
682
|
+
aria-current={currentPath?.startsWith(settingsHref) ? 'page' : undefined}
|
|
683
|
+
onclick={() => (mobileNavOpen = false)}
|
|
684
|
+
>
|
|
685
|
+
<Settings class="ds-nav-icon size-[1.125rem] flex-none" aria-hidden="true" />
|
|
686
|
+
<span class="truncate">{settingsLabel}</span>
|
|
687
|
+
</a>
|
|
688
|
+
{/if}
|
|
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}
|
|
696
|
+
</div>
|
|
697
|
+
{/if}
|
|
641
698
|
{#if collapsible && !railCollapsed && !mobileNavOpen}
|
|
642
699
|
<!-- The rail's right edge: drag to resize, drag past the snap to
|
|
643
700
|
collapse, arrows to nudge, Home to reset, double-click to reset.
|
|
@@ -732,14 +789,14 @@
|
|
|
732
789
|
|
|
733
790
|
{#if onSearch && searchPlacement === 'leading'}
|
|
734
791
|
{@render searchButton(
|
|
735
|
-
'h-9 w-9 flex-none justify-center px-0 sm:h-auto sm:w-[clamp(200px,
|
|
792
|
+
'h-9 w-9 flex-none justify-center px-0 sm:h-auto sm:w-[clamp(200px,24vw,420px)] sm:flex-1 sm:justify-start sm:gap-2 sm:px-3 sm:py-1.5'
|
|
736
793
|
)}
|
|
737
794
|
{/if}
|
|
738
795
|
|
|
739
796
|
<div class="ml-auto flex flex-none items-center gap-2 sm:gap-3">
|
|
740
797
|
{#if onSearch && searchPlacement === 'trailing'}
|
|
741
798
|
{@render searchButton(
|
|
742
|
-
'h-9 w-9 flex-none justify-center px-0 sm:h-auto sm:w-[clamp(
|
|
799
|
+
'h-9 w-9 flex-none justify-center px-0 sm:h-auto sm:w-[clamp(180px,18vw,300px)] sm:justify-start sm:gap-2 sm:px-3 sm:py-1.5'
|
|
743
800
|
)}
|
|
744
801
|
{/if}
|
|
745
802
|
|
|
@@ -124,8 +124,25 @@ type $$ComponentProps = {
|
|
|
124
124
|
context?: Snippet;
|
|
125
125
|
/** Trailing top-bar slot, before the theme toggle: app-level action buttons. */
|
|
126
126
|
actions?: Snippet;
|
|
127
|
-
/** The signed-in user surface. Rendered once, at the end of the top bar.
|
|
127
|
+
/** The signed-in user surface. Rendered once, at the end of the top bar.
|
|
128
|
+
* It stays there at EVERY width rather than moving into the rail foot on
|
|
129
|
+
* desktop: the rail is an overlay drawer below `md`, so a rail-placed
|
|
130
|
+
* account is two taps away and who-am-I is hidden behind the menu; and
|
|
131
|
+
* the alternative, rendering it in both, is the duplication this file
|
|
132
|
+
* exists to avoid. */
|
|
128
133
|
identity?: Snippet;
|
|
134
|
+
/** Where the Settings row at the rail's foot links. Absent renders no row.
|
|
135
|
+
* Settings sits at the foot because configuring the app is not navigating
|
|
136
|
+
* it, and the split reads without a label. */
|
|
137
|
+
settingsHref?: string;
|
|
138
|
+
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;
|
|
129
146
|
/** Provide to render the search affordance. Usually opens a CommandPalette. */
|
|
130
147
|
onSearch?: () => void;
|
|
131
148
|
searchLabel?: string;
|
package/dist/styles.css
CHANGED
|
@@ -793,6 +793,43 @@
|
|
|
793
793
|
border-left: 1px solid color-mix(in oklch, var(--ds-nav-ink) 50%, transparent);
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
/* The rail's foot: where you configure the app, and which build you are on.
|
|
797
|
+
Separated from the scrolling section list by a rule in the chrome's OWN
|
|
798
|
+
ink rather than `--border`, for the reason the group guide takes the same
|
|
799
|
+
treatment — a page-surface token cannot follow chrome an app has branded. */
|
|
800
|
+
/* `padding-inline` matches `.ds-nav`'s own `px-3`, because the foot sits
|
|
801
|
+
OUTSIDE that wrapper: without it the Settings row's icon lands 0.75rem
|
|
802
|
+
left of every icon above it and the rail reads as two lists. */
|
|
803
|
+
.ds-shell-rail-foot {
|
|
804
|
+
display: flex;
|
|
805
|
+
flex-direction: column;
|
|
806
|
+
padding-block: 0.375rem 0.75rem;
|
|
807
|
+
padding-inline: 0.75rem;
|
|
808
|
+
border-top: 1px solid color-mix(in oklch, var(--ds-nav-ink) 22%, transparent);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/* Metadata, not a row. No icon, no tile, no hover: it answers "what am I
|
|
812
|
+
running" when someone reports a bug and otherwise stays out of the way.
|
|
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
|
+
|
|
796
833
|
/* `hidden` is an attribute the UA stylesheet honours at the weakest possible
|
|
797
834
|
specificity, so the `display: flex` above beats it and a closed group would
|
|
798
835
|
render wide open. This is not belt-and-braces; without it the attribute is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/ui",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.13",
|
|
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.13`. 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
|
|