@poodle64/ui 2026.9.3 → 2026.9.4
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.
|
@@ -23,6 +23,13 @@
|
|
|
23
23
|
* baked in here: `onSignOut` and `onAccountSettings` are callbacks. Theme
|
|
24
24
|
* follows AppShell's own `onToggleTheme` pattern — override it, or accept
|
|
25
25
|
* mode-watcher's `toggleMode` by default.
|
|
26
|
+
*
|
|
27
|
+
* `onManageMembers` exists for the caller a workspace switcher has nothing
|
|
28
|
+
* to show: `WorkspaceMenu` (the factory template) renders nothing in the
|
|
29
|
+
* bar for a single-member workspace, and this is where Members lands
|
|
30
|
+
* instead (operator ruling, 07/09/2026, master-project#291's org-of-one
|
|
31
|
+
* case). Wire it whenever the app has a members route, whether or not it
|
|
32
|
+
* also renders a switcher.
|
|
26
33
|
*/
|
|
27
34
|
import { toggleMode } from 'mode-watcher';
|
|
28
35
|
import * as DropdownMenu from '../dropdown-menu/index.js';
|
|
@@ -35,6 +42,7 @@
|
|
|
35
42
|
entitlements = [],
|
|
36
43
|
onSignOut,
|
|
37
44
|
onAccountSettings,
|
|
45
|
+
onManageMembers,
|
|
38
46
|
onSwitchTheme
|
|
39
47
|
}: {
|
|
40
48
|
user: { username: string; display_name: string | null; email: string | null };
|
|
@@ -47,6 +55,19 @@
|
|
|
47
55
|
onSignOut: () => void;
|
|
48
56
|
/** Optional until the app has an account-settings destination to send it to. */
|
|
49
57
|
onAccountSettings?: () => void;
|
|
58
|
+
/**
|
|
59
|
+
* Reach the workspace's members surface from here. Ignored while
|
|
60
|
+
* `workspace` is unset.
|
|
61
|
+
*
|
|
62
|
+
* A workspace holding exactly one member has nothing to switch, so the
|
|
63
|
+
* app's own workspace switcher renders nothing for it (operator ruling,
|
|
64
|
+
* 07/09/2026) — and Members was that switcher's one non-switching act,
|
|
65
|
+
* the route an org-of-one needs to make its first grant. This is where
|
|
66
|
+
* that act lives once the switcher is gone; a switcher still showing for
|
|
67
|
+
* several workspaces keeps its own Members entry too, so the two never
|
|
68
|
+
* disagree about where it is.
|
|
69
|
+
*/
|
|
70
|
+
onManageMembers?: () => void;
|
|
50
71
|
/** Override the theme action. Defaults to mode-watcher's toggleMode, matching AppShell. */
|
|
51
72
|
onSwitchTheme?: () => void;
|
|
52
73
|
} = $props();
|
|
@@ -63,7 +84,31 @@
|
|
|
63
84
|
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
64
85
|
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
65
86
|
}
|
|
66
|
-
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Initials for a bare HANDLE — no display name to fall back on.
|
|
90
|
+
*
|
|
91
|
+
* A handle has no word boundaries a name has: `initialsOf` slicing the
|
|
92
|
+
* first two characters of one unbroken token produces a pair that reads
|
|
93
|
+
* as real initials while meaning nothing (operator ruling, 07/09/2026).
|
|
94
|
+
* Where the handle itself encodes two parts — `firstname.lastname`,
|
|
95
|
+
* `firstname-lastname` — one letter from each reads the same as a real
|
|
96
|
+
* name's initials; where it does not, only the first letter is honest.
|
|
97
|
+
*/
|
|
98
|
+
function handleInitials(handle: string): string {
|
|
99
|
+
const parts = handle.trim().split(/[.-]+/).filter(Boolean);
|
|
100
|
+
if (parts.length === 0) return '';
|
|
101
|
+
if (parts.length === 1) return parts[0].slice(0, 1).toUpperCase();
|
|
102
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Never text in the bar (operator ruling, 07/09/2026): with no display
|
|
106
|
+
// name, the trigger below still renders only this avatar, initialled off
|
|
107
|
+
// the handle rather than off `shown`, which for this branch just IS the
|
|
108
|
+
// handle.
|
|
109
|
+
const initials = $derived(
|
|
110
|
+
user.display_name ? initialsOf(user.display_name) : handleInitials(user.username)
|
|
111
|
+
);
|
|
67
112
|
|
|
68
113
|
function switchTheme() {
|
|
69
114
|
if (onSwitchTheme) onSwitchTheme();
|
|
@@ -128,6 +173,9 @@
|
|
|
128
173
|
{/each}
|
|
129
174
|
</div>
|
|
130
175
|
{/if}
|
|
176
|
+
{#if onManageMembers}
|
|
177
|
+
<DropdownMenu.Item onSelect={onManageMembers}>Members</DropdownMenu.Item>
|
|
178
|
+
{/if}
|
|
131
179
|
{/if}
|
|
132
180
|
<DropdownMenu.Separator />
|
|
133
181
|
<DropdownMenu.Item onSelect={switchTheme}>Switch theme</DropdownMenu.Item>
|
|
@@ -13,6 +13,19 @@ type $$ComponentProps = {
|
|
|
13
13
|
onSignOut: () => void;
|
|
14
14
|
/** Optional until the app has an account-settings destination to send it to. */
|
|
15
15
|
onAccountSettings?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Reach the workspace's members surface from here. Ignored while
|
|
18
|
+
* `workspace` is unset.
|
|
19
|
+
*
|
|
20
|
+
* A workspace holding exactly one member has nothing to switch, so the
|
|
21
|
+
* app's own workspace switcher renders nothing for it (operator ruling,
|
|
22
|
+
* 07/09/2026) — and Members was that switcher's one non-switching act,
|
|
23
|
+
* the route an org-of-one needs to make its first grant. This is where
|
|
24
|
+
* that act lives once the switcher is gone; a switcher still showing for
|
|
25
|
+
* several workspaces keeps its own Members entry too, so the two never
|
|
26
|
+
* disagree about where it is.
|
|
27
|
+
*/
|
|
28
|
+
onManageMembers?: () => void;
|
|
16
29
|
/** Override the theme action. Defaults to mode-watcher's toggleMode, matching AppShell. */
|
|
17
30
|
onSwitchTheme?: () => void;
|
|
18
31
|
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/ui",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.4",
|
|
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",
|
|
7
|
-
"repository":
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/radar-hooves/design-system.git"
|
|
10
|
+
},
|
|
8
11
|
"publishConfig": {
|
|
9
12
|
"registry": "https://registry.npmjs.org",
|
|
10
13
|
"access": "public",
|
|
@@ -32,7 +35,7 @@
|
|
|
32
35
|
}
|
|
33
36
|
},
|
|
34
37
|
"bin": {
|
|
35
|
-
"ds-check-colour-surface": "
|
|
38
|
+
"ds-check-colour-surface": "bin/check-colour-surface.mjs"
|
|
36
39
|
},
|
|
37
40
|
"peerDependencies": {
|
|
38
41
|
"bits-ui": "^2.18.1",
|
|
@@ -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.4`. 56 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
|
|