@kerfjs/ui 5.0.0-beta.54 → 5.0.0-beta.55
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 +3 -2
- package/ai/component-catalog-v2.json +58 -1
- package/ai/component-catalog.json +105 -8
- package/ai/public-api-signatures-v1.md +265 -28
- package/ai/skill.md +6 -4
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/popup-menu.js +3 -0
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +10 -4
- package/dist/catalog.js +243 -300
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
- package/dist/chunk-24PHKUR3.js.map +1 -0
- package/dist/chunk-4BIMLITI.js +92 -0
- package/dist/chunk-4BIMLITI.js.map +1 -0
- package/dist/{chunk-ZK5EGVFP.js → chunk-5OLVUEND.js} +12 -2
- package/dist/chunk-5OLVUEND.js.map +1 -0
- package/dist/{chunk-CMUIXJZM.js → chunk-BSKEH3UC.js} +2 -2
- package/dist/{chunk-CMUIXJZM.js.map → chunk-BSKEH3UC.js.map} +1 -1
- package/dist/chunk-EAX2GSS4.js +384 -0
- package/dist/chunk-EAX2GSS4.js.map +1 -0
- package/dist/chunk-KH6VUGHU.js +399 -0
- package/dist/chunk-KH6VUGHU.js.map +1 -0
- package/dist/{chunk-BJJKFVWW.js → chunk-LZXQVUGN.js} +2 -2
- package/dist/chunk-LZXQVUGN.js.map +1 -0
- package/dist/chunk-N7FHFNT6.js +55 -0
- package/dist/chunk-N7FHFNT6.js.map +1 -0
- package/dist/{chunk-KPNTVB7A.js → chunk-R754MHXX.js} +3 -3
- package/dist/{chunk-KPNTVB7A.js.map → chunk-R754MHXX.js.map} +1 -1
- package/dist/{chunk-HJKRCKDR.js → chunk-RNRUVPJ3.js} +4 -2
- package/dist/chunk-RNRUVPJ3.js.map +1 -0
- package/dist/collapsible-panel.d.ts +40 -13
- package/dist/collapsible-panel.js +41 -10
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -16
- package/dist/list-header.js +1 -1
- package/dist/list-inset-text.d.ts +7 -1
- package/dist/list-inset-text.js +2 -1
- package/dist/panel-toolbar-BFQxFITu.d.ts +52 -0
- package/dist/popup-menu-register.d.ts +9 -0
- package/dist/popup-menu-register.js +30 -0
- package/dist/popup-menu-register.js.map +1 -0
- package/dist/popup-menu.d.ts +71 -0
- package/dist/popup-menu.js +3 -0
- package/dist/popup-menu.js.map +1 -0
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog/components/catalog-example.css +0 -16
- package/dist/styles/catalog/components/catalog-stage.css +8 -13
- package/dist/styles/catalog/components/catalog.css +8 -18
- package/dist/styles/catalog.css +0 -5
- package/dist/styles/popup-menu.css +12 -0
- package/dist/styles/state-banner.css +13 -4
- package/dist/styles/styles.css +1 -0
- package/dist/styles/tab-bar.css +31 -3
- package/dist/styles/toolbar-control-group.css +13 -0
- package/dist/styles/toolbar.css +43 -2
- package/dist/styles/workbench.css +31 -0
- package/dist/text.js +1 -1
- package/dist/token-search-field.d.ts +10 -1
- package/dist/token-search-field.js +1 -1
- package/dist/{types-CEsieBZi.d.ts → types-D6vzj-VT.d.ts} +15 -0
- package/dist/wire-catalog.d.ts +13 -1
- package/dist/wire-catalog.js +18 -3
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-sidebar.js +6 -3
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/wire-workbench.js +1 -350
- package/dist/wire-workbench.js.map +1 -1
- package/dist/workbench.d.ts +107 -6
- package/dist/workbench.js +11 -208
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +12 -1
- package/docs/catalog.md +27 -9
- package/docs/collapsible-panel.md +55 -0
- package/docs/component-contract.md +2 -2
- package/docs/component-selection.md +25 -17
- package/docs/design/templates/state-banner/danger-dark.svg +1 -1
- package/docs/design/templates/state-banner/danger.svg +1 -1
- package/docs/design/templates/state-banner/info-dark.svg +1 -1
- package/docs/design/templates/state-banner/info.svg +1 -1
- package/docs/design/templates/state-banner/success-dark.svg +1 -1
- package/docs/design/templates/state-banner/success.svg +1 -1
- package/docs/design/templates/state-banner/warning-dark.svg +1 -1
- package/docs/design/templates/state-banner/warning.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -1
- package/docs/design/templates/state-banner.svg +1 -1
- package/docs/layout.md +5 -0
- package/docs/recipes.md +44 -37
- package/docs/surface-scaffold.md +1 -1
- package/docs/ux-demo.md +6 -2
- package/docs/workbench.md +92 -7
- package/llms.txt +6 -5
- package/package.json +13 -2
- package/ux-demo/recipes/app-shell.tsx +141 -223
- package/ux-demo/recipes/collapsible-sidebar.tsx +44 -75
- package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
- package/ux-demo/recipes/mount-recipe.ts +0 -5
- package/ux-demo/recipes/types.ts +0 -1
- package/dist/chunk-7IUSV4XG.js.map +0 -1
- package/dist/chunk-BJJKFVWW.js.map +0 -1
- package/dist/chunk-HJKRCKDR.js.map +0 -1
- package/dist/chunk-ZK5EGVFP.js.map +0 -1
- package/dist/styles/catalog/components/catalog-detail.css +0 -35
- package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
- package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
- package/dist/styles/catalog/components/catalog-section-list.css +0 -22
- package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
|
@@ -1,32 +1,22 @@
|
|
|
1
1
|
import '@kerfjs/ui/layout.css';
|
|
2
|
+
import '@kerfjs/ui/workbench.css';
|
|
2
3
|
|
|
3
|
-
import { deviceClass } from '@kerfjs/ui/device-class';
|
|
4
|
-
import { Grid } from '@kerfjs/ui/grid';
|
|
5
4
|
import { List } from '@kerfjs/ui/list';
|
|
6
|
-
import { ListHeader } from '@kerfjs/ui/list-header';
|
|
7
5
|
import { ListItem } from '@kerfjs/ui/list-item';
|
|
8
6
|
import { LucideIcon } from '@kerfjs/ui/lucide-icon';
|
|
9
|
-
import { Pane, type PaneSeparatorSide } from '@kerfjs/ui/pane';
|
|
10
|
-
import { ResizableRegion } from '@kerfjs/ui/resizable-region';
|
|
11
|
-
import { Row } from '@kerfjs/ui/row';
|
|
12
7
|
import { Toolbar } from '@kerfjs/ui/toolbar';
|
|
13
8
|
import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
|
|
14
9
|
import { ToolbarText } from '@kerfjs/ui/toolbar-text';
|
|
15
10
|
import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
|
|
16
|
-
import {
|
|
11
|
+
import { wireWorkbench } from '@kerfjs/ui/wire-workbench';
|
|
12
|
+
import { Workbench } from '@kerfjs/ui/workbench';
|
|
13
|
+
import { delegate, signal } from 'kerfjs';
|
|
17
14
|
import { Bell, Folder, Inbox, Settings } from 'lucide';
|
|
18
15
|
|
|
19
16
|
import type { RecipeFactory, RecipePresentation } from './types.js';
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// Safe areas: the app bar claims the top edge and both sides, so it clears the
|
|
25
|
-
// status area. Each pane below compensates only for the screen edges it
|
|
26
|
-
// actually reaches: the bottom, plus its outer side in the three-pane layout or
|
|
27
|
-
// both sides when it is the only pane shown.
|
|
28
|
-
const appBarEdges: ScreenEdges = ['block-start', 'inline-start', 'inline-end'];
|
|
29
|
-
const soleEdges: ScreenEdges = ['block-end', 'inline-start', 'inline-end'];
|
|
18
|
+
const NAVIGATION_ACTION = 'recipe-shell-toggle-navigation';
|
|
19
|
+
const INSPECTOR_ACTION = 'recipe-shell-toggle-inspector';
|
|
30
20
|
|
|
31
21
|
const tasks = [
|
|
32
22
|
['Release accessibility audit', 'Interface systems · due this week'],
|
|
@@ -44,46 +34,19 @@ export const presentation: RecipePresentation = {
|
|
|
44
34
|
overflow: 'hidden',
|
|
45
35
|
shadow: true,
|
|
46
36
|
},
|
|
47
|
-
note: 'The recipe
|
|
37
|
+
note: 'The recipe is a Workbench under an app bar: resizable navigation and inspector rails beside the task list, each rail toggled by its standard control, which moves into the work-area toolbar while the rail is hidden. On a small screen the rails overlay the task list one at a time. The app owns routing, data, rail visibility, sizes, and persistence.',
|
|
48
38
|
};
|
|
49
39
|
|
|
50
40
|
export const createRecipe: RecipeFactory = (announce) => {
|
|
51
41
|
const selected = signal('inbox');
|
|
52
42
|
const navigationSize = signal(224);
|
|
53
43
|
const inspectorSize = signal(240);
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
// at a time and let the toolbar switch between them.
|
|
57
|
-
const device = deviceClass();
|
|
58
|
-
|
|
59
|
-
const paneButton = (
|
|
60
|
-
pane: ShellPane,
|
|
61
|
-
label: string,
|
|
62
|
-
icon: typeof Folder,
|
|
63
|
-
iconName: string,
|
|
64
|
-
) => (
|
|
65
|
-
<button
|
|
66
|
-
type="button"
|
|
67
|
-
aria-label={label}
|
|
68
|
-
aria-controls={`recipe-shell-${pane}`}
|
|
69
|
-
aria-pressed={String(responsivePane.value === pane)}
|
|
70
|
-
data-action="recipe-action"
|
|
71
|
-
data-recipe-command={`show-${pane}`}
|
|
72
|
-
>
|
|
73
|
-
<LucideIcon icon={icon} name={iconName} />
|
|
74
|
-
</button>
|
|
75
|
-
);
|
|
44
|
+
const navigationCollapsed = signal(false);
|
|
45
|
+
const inspectorCollapsed = signal(false);
|
|
76
46
|
|
|
77
|
-
const navigation = (
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
safeAreaEdges={edges}
|
|
81
|
-
id="recipe-shell-navigation"
|
|
82
|
-
contentElement="nav"
|
|
83
|
-
contentLabel="Workspace"
|
|
84
|
-
>
|
|
85
|
-
<section>
|
|
86
|
-
<ListHeader label="Workspace" />
|
|
47
|
+
const navigation = () => (
|
|
48
|
+
<nav aria-label="Workspace">
|
|
49
|
+
<List gap="2xs">
|
|
87
50
|
<ListItem
|
|
88
51
|
action="recipe-action"
|
|
89
52
|
itemId="inbox"
|
|
@@ -99,204 +62,159 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
99
62
|
selected={selected.value === 'projects'}
|
|
100
63
|
multiline
|
|
101
64
|
/>
|
|
102
|
-
</
|
|
103
|
-
</
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
const content = (edges: ScreenEdges) => (
|
|
107
|
-
<Pane
|
|
108
|
-
element="main"
|
|
109
|
-
safeAreaEdges={edges}
|
|
110
|
-
id="recipe-shell-content"
|
|
111
|
-
header={
|
|
112
|
-
<Toolbar
|
|
113
|
-
label="Current workspace view"
|
|
114
|
-
dividerSides=""
|
|
115
|
-
leading={
|
|
116
|
-
<ToolbarText
|
|
117
|
-
text={
|
|
118
|
-
selected.value === 'inbox' ? 'Inbox triage' : 'Active projects'
|
|
119
|
-
}
|
|
120
|
-
size="xlarge"
|
|
121
|
-
id="recipe-shell-main-title"
|
|
122
|
-
/>
|
|
123
|
-
}
|
|
124
|
-
trailing={
|
|
125
|
-
<ToolbarControlGroup appearance="borderless" content="text" single>
|
|
126
|
-
<button
|
|
127
|
-
type="button"
|
|
128
|
-
data-action="recipe-action"
|
|
129
|
-
data-recipe-command="new"
|
|
130
|
-
>
|
|
131
|
-
New task
|
|
132
|
-
</button>
|
|
133
|
-
</ToolbarControlGroup>
|
|
134
|
-
}
|
|
135
|
-
/>
|
|
136
|
-
}
|
|
137
|
-
>
|
|
138
|
-
<section aria-label="Tasks">
|
|
139
|
-
{tasks.map(([title, detail]) => (
|
|
140
|
-
<ListItem
|
|
141
|
-
action="recipe-action"
|
|
142
|
-
label={title}
|
|
143
|
-
description={detail}
|
|
144
|
-
multiline
|
|
145
|
-
rootAttributes={{ 'data-recipe-command': 'open-task' }}
|
|
146
|
-
/>
|
|
147
|
-
))}
|
|
148
|
-
</section>
|
|
149
|
-
</Pane>
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const inspector = (edges: ScreenEdges) => (
|
|
153
|
-
<Pane
|
|
154
|
-
element="aside"
|
|
155
|
-
safeAreaEdges={edges}
|
|
156
|
-
id="recipe-shell-inspector"
|
|
157
|
-
header={
|
|
158
|
-
<Toolbar
|
|
159
|
-
label="Inspector"
|
|
160
|
-
dividerSides=""
|
|
161
|
-
leading={
|
|
162
|
-
<ToolbarText
|
|
163
|
-
text="Inspector"
|
|
164
|
-
size="xlarge"
|
|
165
|
-
id="recipe-shell-inspector-title"
|
|
166
|
-
/>
|
|
167
|
-
}
|
|
168
|
-
/>
|
|
169
|
-
}
|
|
170
|
-
>
|
|
171
|
-
<ValueTable label="Selected task">
|
|
172
|
-
<ValueTableRow label="Status" value="In review" />
|
|
173
|
-
<ValueTableRow label="Owner" value="Mara Chen" />
|
|
174
|
-
<ValueTableRow label="Priority" value="High" />
|
|
175
|
-
</ValueTable>
|
|
176
|
-
</Pane>
|
|
65
|
+
</List>
|
|
66
|
+
</nav>
|
|
177
67
|
);
|
|
178
68
|
|
|
179
|
-
const render = () =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
69
|
+
const render = () => (
|
|
70
|
+
<List fill rootAttributes={{ 'data-recipe': 'recipe-app-shell' }}>
|
|
71
|
+
<Toolbar
|
|
72
|
+
label="Atlas workspace"
|
|
73
|
+
safeAreaEdges={['block-start', 'inline-start', 'inline-end']}
|
|
74
|
+
dividerSides="b"
|
|
75
|
+
leading={<ToolbarText text="Atlas" />}
|
|
76
|
+
trailing={
|
|
77
|
+
<ToolbarControlGroup
|
|
78
|
+
appearance="borderless"
|
|
79
|
+
label="Workspace controls"
|
|
80
|
+
>
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
aria-label="Notifications"
|
|
84
|
+
data-action="recipe-action"
|
|
85
|
+
data-recipe-command="notify"
|
|
86
|
+
>
|
|
87
|
+
<LucideIcon icon={Bell} name="bell" />
|
|
88
|
+
</button>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
aria-label="Settings"
|
|
92
|
+
data-action="recipe-action"
|
|
93
|
+
data-recipe-command="settings"
|
|
94
|
+
>
|
|
95
|
+
<LucideIcon icon={Settings} name="settings" />
|
|
96
|
+
</button>
|
|
97
|
+
</ToolbarControlGroup>
|
|
98
|
+
}
|
|
99
|
+
/>
|
|
100
|
+
<List flex>
|
|
101
|
+
<Workbench
|
|
102
|
+
id="recipe-shell"
|
|
103
|
+
label="Atlas workspace panes"
|
|
104
|
+
leftRail={{
|
|
105
|
+
label: 'Navigation',
|
|
106
|
+
size: navigationSize.value,
|
|
107
|
+
resizable: { min: 180, max: 320 },
|
|
108
|
+
collapsed: navigationCollapsed.value,
|
|
109
|
+
toolbar: {
|
|
110
|
+
label: 'Navigation',
|
|
111
|
+
title: <ToolbarText text="Workspace" />,
|
|
112
|
+
toggle: { action: NAVIGATION_ACTION, name: 'navigation' },
|
|
113
|
+
},
|
|
114
|
+
content: navigation(),
|
|
115
|
+
}}
|
|
116
|
+
mainToolbar={{
|
|
117
|
+
label: 'Current workspace view',
|
|
118
|
+
title: (
|
|
119
|
+
<ToolbarText
|
|
120
|
+
text={
|
|
121
|
+
selected.value === 'inbox'
|
|
122
|
+
? 'Inbox triage'
|
|
123
|
+
: 'Active projects'
|
|
124
|
+
}
|
|
125
|
+
size="xlarge"
|
|
126
|
+
id="recipe-shell-main-title"
|
|
127
|
+
/>
|
|
128
|
+
),
|
|
129
|
+
responsive: 'wrap',
|
|
130
|
+
trailing: (
|
|
216
131
|
<ToolbarControlGroup
|
|
217
132
|
appearance="borderless"
|
|
218
|
-
|
|
133
|
+
content="text"
|
|
134
|
+
single
|
|
219
135
|
>
|
|
220
136
|
<button
|
|
221
137
|
type="button"
|
|
222
|
-
aria-label="Notifications"
|
|
223
138
|
data-action="recipe-action"
|
|
224
|
-
data-recipe-command="
|
|
139
|
+
data-recipe-command="new"
|
|
225
140
|
>
|
|
226
|
-
|
|
227
|
-
</button>
|
|
228
|
-
<button
|
|
229
|
-
type="button"
|
|
230
|
-
aria-label="Settings"
|
|
231
|
-
data-action="recipe-action"
|
|
232
|
-
data-recipe-command="settings"
|
|
233
|
-
>
|
|
234
|
-
<LucideIcon icon={Settings} name="settings" />
|
|
141
|
+
New task
|
|
235
142
|
</button>
|
|
236
143
|
</ToolbarControlGroup>
|
|
237
|
-
|
|
144
|
+
),
|
|
145
|
+
}}
|
|
146
|
+
main={
|
|
147
|
+
<section aria-label="Tasks">
|
|
148
|
+
{tasks.map(([title, detail]) => (
|
|
149
|
+
<ListItem
|
|
150
|
+
action="recipe-action"
|
|
151
|
+
label={title}
|
|
152
|
+
description={detail}
|
|
153
|
+
multiline
|
|
154
|
+
rootAttributes={{ 'data-recipe-command': 'open-task' }}
|
|
155
|
+
/>
|
|
156
|
+
))}
|
|
157
|
+
</section>
|
|
238
158
|
}
|
|
159
|
+
rightRail={{
|
|
160
|
+
label: 'Inspector',
|
|
161
|
+
size: inspectorSize.value,
|
|
162
|
+
resizable: { min: 200, max: 360 },
|
|
163
|
+
collapsed: inspectorCollapsed.value,
|
|
164
|
+
toolbar: {
|
|
165
|
+
label: 'Inspector',
|
|
166
|
+
title: <ToolbarText text="Inspector" />,
|
|
167
|
+
toggle: { action: INSPECTOR_ACTION, name: 'inspector' },
|
|
168
|
+
},
|
|
169
|
+
content: (
|
|
170
|
+
<ValueTable label="Selected task">
|
|
171
|
+
<ValueTableRow label="Status" value="In review" />
|
|
172
|
+
<ValueTableRow label="Owner" value="Mara Chen" />
|
|
173
|
+
<ValueTableRow label="Priority" value="High" />
|
|
174
|
+
</ValueTable>
|
|
175
|
+
),
|
|
176
|
+
}}
|
|
239
177
|
/>
|
|
240
|
-
{onePane ? (
|
|
241
|
-
<Grid columns={1} gap="none" flex>
|
|
242
|
-
{responsivePane.value === 'navigation'
|
|
243
|
-
? navigation(soleEdges)
|
|
244
|
-
: responsivePane.value === 'inspector'
|
|
245
|
-
? inspector(soleEdges)
|
|
246
|
-
: content(soleEdges)}
|
|
247
|
-
</Grid>
|
|
248
|
-
) : (
|
|
249
|
-
<Row gap="none" flex>
|
|
250
|
-
<ResizableRegion
|
|
251
|
-
id="recipe-navigation"
|
|
252
|
-
label="Navigation"
|
|
253
|
-
size={navigationSize.value}
|
|
254
|
-
min={180}
|
|
255
|
-
max={320}
|
|
256
|
-
>
|
|
257
|
-
{navigation(['block-end', 'inline-start'])}
|
|
258
|
-
</ResizableRegion>
|
|
259
|
-
<Grid columns={1} gap="none" flex>
|
|
260
|
-
{content(['block-end'])}
|
|
261
|
-
</Grid>
|
|
262
|
-
<ResizableRegion
|
|
263
|
-
id="recipe-inspector"
|
|
264
|
-
label="Inspector"
|
|
265
|
-
size={inspectorSize.value}
|
|
266
|
-
min={200}
|
|
267
|
-
max={360}
|
|
268
|
-
edge="start"
|
|
269
|
-
>
|
|
270
|
-
{inspector(['block-end', 'inline-end'])}
|
|
271
|
-
</ResizableRegion>
|
|
272
|
-
</Row>
|
|
273
|
-
)}
|
|
274
178
|
</List>
|
|
275
|
-
|
|
276
|
-
|
|
179
|
+
</List>
|
|
180
|
+
);
|
|
181
|
+
|
|
277
182
|
return {
|
|
278
183
|
render,
|
|
279
184
|
action(command, element) {
|
|
280
|
-
const pane = command.match(
|
|
281
|
-
/^show-(navigation|content|inspector)$/,
|
|
282
|
-
)?.[1] as ShellPane | undefined;
|
|
283
|
-
if (pane) responsivePane.value = pane;
|
|
284
185
|
const id = element.dataset.itemId;
|
|
285
186
|
if (id) selected.value = id;
|
|
286
187
|
announce(
|
|
287
188
|
id
|
|
288
189
|
? `Opened ${id}`
|
|
289
|
-
:
|
|
290
|
-
?
|
|
291
|
-
: command
|
|
292
|
-
? 'New task requested'
|
|
293
|
-
: `${command} requested`,
|
|
190
|
+
: command === 'new'
|
|
191
|
+
? 'New task requested'
|
|
192
|
+
: `${command} requested`,
|
|
294
193
|
);
|
|
295
194
|
},
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
195
|
+
wire(root) {
|
|
196
|
+
const toggle = (action: string, collapsed: typeof navigationCollapsed) =>
|
|
197
|
+
delegate(root, 'click', `[data-action="${action}"]`, () => {
|
|
198
|
+
collapsed.value = !collapsed.value;
|
|
199
|
+
});
|
|
200
|
+
const stops = [
|
|
201
|
+
toggle(NAVIGATION_ACTION, navigationCollapsed),
|
|
202
|
+
toggle(INSPECTOR_ACTION, inspectorCollapsed),
|
|
203
|
+
wireWorkbench(root, {
|
|
204
|
+
id: 'recipe-shell',
|
|
205
|
+
panels: {
|
|
206
|
+
leftRail: { size: navigationSize, collapsed: navigationCollapsed },
|
|
207
|
+
rightRail: { size: inspectorSize, collapsed: inspectorCollapsed },
|
|
208
|
+
},
|
|
209
|
+
onResize: ({ panel, size }) =>
|
|
210
|
+
announce(
|
|
211
|
+
`${panel === 'leftRail' ? 'Navigation' : 'Inspector'} resized to ${size}px`,
|
|
212
|
+
),
|
|
213
|
+
}),
|
|
214
|
+
];
|
|
215
|
+
return () => {
|
|
216
|
+
for (const stop of stops) stop();
|
|
217
|
+
};
|
|
300
218
|
},
|
|
301
219
|
};
|
|
302
220
|
};
|
|
@@ -4,7 +4,8 @@ import '@kerfjs/ui/floating-toolbar.css';
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
CollapsiblePanel,
|
|
7
|
-
|
|
7
|
+
CollapsiblePanelRelocated,
|
|
8
|
+
type CollapsiblePanelToolbar,
|
|
8
9
|
} from '@kerfjs/ui/collapsible-panel';
|
|
9
10
|
import { deviceClass } from '@kerfjs/ui/device-class';
|
|
10
11
|
import { FloatingToolbar } from '@kerfjs/ui/floating-toolbar';
|
|
@@ -17,7 +18,6 @@ import { Pane } from '@kerfjs/ui/pane';
|
|
|
17
18
|
import { Row } from '@kerfjs/ui/row';
|
|
18
19
|
import { Text } from '@kerfjs/ui/text';
|
|
19
20
|
import { Toolbar } from '@kerfjs/ui/toolbar';
|
|
20
|
-
import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
|
|
21
21
|
import { ToolbarText } from '@kerfjs/ui/toolbar-text';
|
|
22
22
|
import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
|
|
23
23
|
import { type SidebarStorage, wireSidebar } from '@kerfjs/ui/wire-sidebar';
|
|
@@ -73,24 +73,20 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
73
73
|
const drawerCollapsed = signal(true);
|
|
74
74
|
const storage = memoryStorage();
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
panelId="sidebar-console"
|
|
91
|
-
label={drawerCollapsed.value ? 'Show activity' : 'Hide activity'}
|
|
92
|
-
/>
|
|
93
|
-
);
|
|
76
|
+
// Each panel composes its own toolbar with the standard toggle last. While a
|
|
77
|
+
// panel is collapsed, CollapsiblePanelRelocated carries that toggle: the
|
|
78
|
+
// rail's leads the main toolbar, the drawer's floats in its container's
|
|
79
|
+
// bottom-end corner. wireSidebar hands focus between the two positions.
|
|
80
|
+
const railToolbar: CollapsiblePanelToolbar = {
|
|
81
|
+
label: 'Workspace navigation',
|
|
82
|
+
title: <ToolbarText text="Atlas" />,
|
|
83
|
+
toggle: { action: RAIL_ACTION, name: 'navigation' },
|
|
84
|
+
};
|
|
85
|
+
const drawerToolbar: CollapsiblePanelToolbar = {
|
|
86
|
+
label: 'Activity',
|
|
87
|
+
title: <ToolbarText text="Activity" size="small" />,
|
|
88
|
+
toggle: { action: DRAWER_ACTION, name: 'activity' },
|
|
89
|
+
};
|
|
94
90
|
|
|
95
91
|
const rail = () => (
|
|
96
92
|
<CollapsiblePanel
|
|
@@ -99,23 +95,9 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
99
95
|
size={232}
|
|
100
96
|
collapsed={railCollapsed.value}
|
|
101
97
|
label="Workspace navigation"
|
|
98
|
+
toolbar={railToolbar}
|
|
102
99
|
>
|
|
103
|
-
<
|
|
104
|
-
contentElement="nav"
|
|
105
|
-
contentLabel="Workspace"
|
|
106
|
-
header={
|
|
107
|
-
<Toolbar
|
|
108
|
-
label="Workspace navigation"
|
|
109
|
-
dividerSides=""
|
|
110
|
-
leading={<ToolbarText text="Atlas" />}
|
|
111
|
-
trailing={
|
|
112
|
-
<ToolbarControlGroup appearance="borderless" single>
|
|
113
|
-
{railToggle()}
|
|
114
|
-
</ToolbarControlGroup>
|
|
115
|
-
}
|
|
116
|
-
/>
|
|
117
|
-
}
|
|
118
|
-
>
|
|
100
|
+
<nav aria-label="Workspace">
|
|
119
101
|
<section>
|
|
120
102
|
<ListHeader label="Workspace" />
|
|
121
103
|
<ListItem
|
|
@@ -141,15 +123,10 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
141
123
|
selected={selected.value === 'shared'}
|
|
142
124
|
/>
|
|
143
125
|
</section>
|
|
144
|
-
</
|
|
126
|
+
</nav>
|
|
145
127
|
</CollapsiblePanel>
|
|
146
128
|
);
|
|
147
129
|
|
|
148
|
-
// Each panel's own header holds its collapse toggle; its expand toggle shows
|
|
149
|
-
// only while it is collapsed, so exactly one control owns each action. The
|
|
150
|
-
// rail's sits in the main header; the drawer's is the drawer's own
|
|
151
|
-
// `restoreControl`, which the panel floats in its container's bottom-end
|
|
152
|
-
// corner. wireSidebar hands focus between them.
|
|
153
130
|
const main = () => (
|
|
154
131
|
<Pane
|
|
155
132
|
element="main"
|
|
@@ -159,11 +136,12 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
159
136
|
dividerSides=""
|
|
160
137
|
leading={
|
|
161
138
|
<>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
139
|
+
<CollapsiblePanelRelocated
|
|
140
|
+
panelId="sidebar-rail"
|
|
141
|
+
side="left"
|
|
142
|
+
collapsed={railCollapsed.value}
|
|
143
|
+
toolbar={railToolbar}
|
|
144
|
+
/>
|
|
167
145
|
<ToolbarText
|
|
168
146
|
text={labels[selected.value] ?? 'Inbox'}
|
|
169
147
|
size="xlarge"
|
|
@@ -195,39 +173,30 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
195
173
|
size={168}
|
|
196
174
|
collapsed={drawerCollapsed.value}
|
|
197
175
|
label="Activity"
|
|
176
|
+
toolbar={drawerToolbar}
|
|
198
177
|
restoreControl={
|
|
199
178
|
<FloatingToolbar label="Activity drawer">
|
|
200
|
-
<
|
|
179
|
+
<CollapsiblePanelRelocated
|
|
180
|
+
panelId="sidebar-console"
|
|
181
|
+
side="bottom"
|
|
182
|
+
collapsed={drawerCollapsed.value}
|
|
183
|
+
toolbar={drawerToolbar}
|
|
184
|
+
/>
|
|
201
185
|
</FloatingToolbar>
|
|
202
186
|
}
|
|
203
187
|
>
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
>
|
|
218
|
-
<ValueTable label="Recent activity">
|
|
219
|
-
<ValueTableRow
|
|
220
|
-
label="Deploy finished"
|
|
221
|
-
value="2m ago"
|
|
222
|
-
icon={<LucideIcon icon={Bell} name="bell" />}
|
|
223
|
-
/>
|
|
224
|
-
<ValueTableRow
|
|
225
|
-
label="Review requested"
|
|
226
|
-
value="9m ago"
|
|
227
|
-
icon={<LucideIcon icon={Bell} name="bell" />}
|
|
228
|
-
/>
|
|
229
|
-
</ValueTable>
|
|
230
|
-
</Pane>
|
|
188
|
+
<ValueTable label="Recent activity">
|
|
189
|
+
<ValueTableRow
|
|
190
|
+
label="Deploy finished"
|
|
191
|
+
value="2m ago"
|
|
192
|
+
icon={<LucideIcon icon={Bell} name="bell" />}
|
|
193
|
+
/>
|
|
194
|
+
<ValueTableRow
|
|
195
|
+
label="Review requested"
|
|
196
|
+
value="9m ago"
|
|
197
|
+
icon={<LucideIcon icon={Bell} name="bell" />}
|
|
198
|
+
/>
|
|
199
|
+
</ValueTable>
|
|
231
200
|
</CollapsiblePanel>
|
|
232
201
|
);
|
|
233
202
|
|