@adia-ai/web-components 0.0.28 → 0.0.29

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.
Files changed (69) hide show
  1. package/README.md +4 -8
  2. package/a2ui/index.js +1 -1
  3. package/components/canvas/canvas.js +1 -1
  4. package/components/feed/feed.css +9 -0
  5. package/components/feed/feed.js +118 -9
  6. package/components/toast/toast.js +48 -178
  7. package/index.css +3 -2
  8. package/index.js +15 -7
  9. package/package.json +1 -5
  10. package/patterns/a2ui-root/a2ui-root.a2ui.json +0 -125
  11. package/patterns/a2ui-root/a2ui-root.js +0 -191
  12. package/patterns/a2ui-root/a2ui-root.yaml +0 -87
  13. package/patterns/adia-chat/adia-chat.a2ui.json +0 -149
  14. package/patterns/adia-chat/adia-chat.css +0 -10
  15. package/patterns/adia-chat/adia-chat.js +0 -297
  16. package/patterns/adia-chat/adia-chat.yaml +0 -118
  17. package/patterns/adia-chat/css/adia-chat.empty.css +0 -12
  18. package/patterns/adia-chat/css/adia-chat.layout.css +0 -60
  19. package/patterns/adia-chat/css/adia-chat.markdown.css +0 -74
  20. package/patterns/adia-chat/css/adia-chat.messages.css +0 -87
  21. package/patterns/adia-chat/css/adia-chat.streaming.css +0 -30
  22. package/patterns/adia-chat/css/adia-chat.tokens.css +0 -95
  23. package/patterns/adia-editor/adia-editor.a2ui.json +0 -73
  24. package/patterns/adia-editor/adia-editor.css +0 -6
  25. package/patterns/adia-editor/adia-editor.js +0 -56
  26. package/patterns/adia-editor/adia-editor.yaml +0 -59
  27. package/patterns/adia-editor/css/adia-editor.layout.css +0 -171
  28. package/patterns/adia-editor/css/adia-editor.tokens.css +0 -28
  29. package/patterns/app-nav/app-nav.a2ui.json +0 -89
  30. package/patterns/app-nav/app-nav.css +0 -92
  31. package/patterns/app-nav/app-nav.js +0 -112
  32. package/patterns/app-nav/app-nav.yaml +0 -54
  33. package/patterns/app-nav-group/app-nav-group.a2ui.json +0 -82
  34. package/patterns/app-nav-group/app-nav-group.css +0 -264
  35. package/patterns/app-nav-group/app-nav-group.js +0 -116
  36. package/patterns/app-nav-group/app-nav-group.yaml +0 -59
  37. package/patterns/app-nav-item/app-nav-item.a2ui.json +0 -83
  38. package/patterns/app-nav-item/app-nav-item.css +0 -162
  39. package/patterns/app-nav-item/app-nav-item.js +0 -42
  40. package/patterns/app-nav-item/app-nav-item.yaml +0 -62
  41. package/patterns/app-shell/app-shell.a2ui.json +0 -129
  42. package/patterns/app-shell/app-shell.css +0 -14
  43. package/patterns/app-shell/app-shell.js +0 -251
  44. package/patterns/app-shell/app-shell.yaml +0 -89
  45. package/patterns/app-shell/css/app-shell.collapsed.css +0 -86
  46. package/patterns/app-shell/css/app-shell.helpers.css +0 -42
  47. package/patterns/app-shell/css/app-shell.main.css +0 -172
  48. package/patterns/app-shell/css/app-shell.shell.css +0 -44
  49. package/patterns/app-shell/css/app-shell.sidebar.css +0 -161
  50. package/patterns/app-shell/css/app-shell.templates.css +0 -214
  51. package/patterns/app-shell/css/app-shell.tokens.css +0 -119
  52. package/patterns/gen-ui/gen-ui.a2ui.json +0 -72
  53. package/patterns/gen-ui/gen-ui.css +0 -83
  54. package/patterns/gen-ui/gen-ui.js +0 -136
  55. package/patterns/gen-ui/gen-ui.yaml +0 -43
  56. package/patterns/index.js +0 -11
  57. package/patterns/section-nav/section-nav.a2ui.json +0 -91
  58. package/patterns/section-nav/section-nav.css +0 -60
  59. package/patterns/section-nav/section-nav.js +0 -42
  60. package/patterns/section-nav/section-nav.yaml +0 -58
  61. package/patterns/section-nav-group/section-nav-group.a2ui.json +0 -95
  62. package/patterns/section-nav-group/section-nav-group.css +0 -74
  63. package/patterns/section-nav-group/section-nav-group.js +0 -84
  64. package/patterns/section-nav-group/section-nav-group.yaml +0 -66
  65. package/patterns/section-nav-item/section-nav-item.a2ui.json +0 -97
  66. package/patterns/section-nav-item/section-nav-item.css +0 -106
  67. package/patterns/section-nav-item/section-nav-item.js +0 -66
  68. package/patterns/section-nav-item/section-nav-item.yaml +0 -70
  69. package/styles/layouts/admin.css +0 -7
@@ -1,251 +0,0 @@
1
- /**
2
- * <app-shell-ui mode="rounded borderless">
3
- * <aside data-sidebar="leading">...</aside>
4
- * <main>...</main>
5
- * <aside data-sidebar="trailing">...</aside>
6
- * <dialog data-command>...</dialog>
7
- * </app-shell-ui>
8
- *
9
- * Behavior-only app shell. Stamps no HTML — the page author writes the
10
- * structure using semantic elements + data attributes. The component
11
- * auto-wires four JS behaviors that CSS can't handle:
12
- *
13
- * 1. Sidebar resize (drag handle with snap thresholds)
14
- * 2. Sidebar toggle (collapse/restore width)
15
- * 3. Command palette (Cmd+K keyboard shortcut)
16
- * 4. ResizeObserver (select placement in narrow sidebars)
17
- *
18
- * CSS handles everything else: layout, collapse, container queries,
19
- * sticky headers, scroll containment, mode composition.
20
- */
21
-
22
- import { AdiaElement } from '../../core/element.js';
23
-
24
- const SNAP_THRESHOLD = 96;
25
- const SNAP_MIN_USABLE = 160;
26
-
27
- class AdiaAppShell extends AdiaElement {
28
- static properties = {
29
- mode: { type: String, default: '', reflect: true },
30
- };
31
-
32
- static template = () => null;
33
-
34
- #sidebarWidths = new Map();
35
- #resizeCleanups = [];
36
- #sidebarRO = null;
37
- #cmdKeyHandler = null;
38
-
39
- connected() {
40
- this.#setupToggles();
41
- this.#setupResizeHandles();
42
- this.#setupCommandPalette();
43
- this.#setupResizeObserver();
44
- }
45
-
46
- disconnected() {
47
- // Clean up resize handles
48
- for (const cleanup of this.#resizeCleanups) cleanup();
49
- this.#resizeCleanups = [];
50
-
51
- // Clean up ResizeObserver
52
- this.#sidebarRO?.disconnect();
53
- this.#sidebarRO = null;
54
-
55
- // Clean up Cmd+K
56
- if (this.#cmdKeyHandler) {
57
- document.removeEventListener('keydown', this.#cmdKeyHandler);
58
- this.#cmdKeyHandler = null;
59
- }
60
- }
61
-
62
- // ── Sidebar persistence ────────────────────────────────────
63
-
64
- #persistSidebar(sidebarName, width) {
65
- try { localStorage.setItem(`adia-sidebar-${sidebarName}`, width); } catch {}
66
- }
67
-
68
- #restoreSidebars() {
69
- for (const sidebar of this.querySelectorAll('[data-sidebar]')) {
70
- const name = sidebar.getAttribute('data-sidebar');
71
- try {
72
- const saved = localStorage.getItem(`adia-sidebar-${name}`);
73
- if (saved) {
74
- sidebar.style.width = saved;
75
- // Only store as the "previous expanded width" if it's actually expanded.
76
- // If collapsed, keep the default expanded width so toggle can restore it.
77
- const w = parseFloat(saved);
78
- if (isNaN(w) || w > SNAP_THRESHOLD) {
79
- this.#sidebarWidths.set(name, saved);
80
- }
81
- }
82
- } catch {}
83
- }
84
- }
85
-
86
- // ── 1. Sidebar toggle ──────────────────────────────────────
87
-
88
- #setupToggles() {
89
- this.#restoreSidebars();
90
-
91
- for (const btn of this.querySelectorAll('[data-sidebar-toggle]')) {
92
- const sidebarName = btn.getAttribute('data-sidebar-toggle');
93
- btn.addEventListener('click', () => {
94
- const sidebar = this.querySelector(`[data-sidebar="${sidebarName}"]`);
95
- if (!sidebar) return;
96
-
97
- const isCollapsed = sidebar.getBoundingClientRect().width <= SNAP_THRESHOLD;
98
-
99
- if (isCollapsed) {
100
- // Expand: restore previous width
101
- const prev = this.#sidebarWidths.get(sidebarName);
102
- sidebar.style.width = prev || '';
103
- this.#persistSidebar(sidebarName, prev || '');
104
- } else {
105
- // Collapse: save current width, set to min
106
- this.#sidebarWidths.set(sidebarName, sidebar.style.width || getComputedStyle(sidebar).width);
107
- const minW = getComputedStyle(sidebar).minWidth;
108
- sidebar.style.width = minW;
109
- this.#persistSidebar(sidebarName, minW);
110
- }
111
-
112
- this.dispatchEvent(new CustomEvent('sidebar-toggle', {
113
- bubbles: true,
114
- detail: { sidebar: sidebarName, expanded: !isCollapsed },
115
- }));
116
- });
117
- }
118
- }
119
-
120
- // ── 2. Sidebar resize handles ──────────────────────────────
121
-
122
- #setupResizeHandles() {
123
- for (const handle of this.querySelectorAll('[data-sidebar] > [data-resize]')) {
124
- const sidebar = handle.parentElement;
125
- const sidebarName = sidebar.getAttribute('data-sidebar');
126
- const isLeading = sidebarName === 'leading';
127
-
128
- const onPointerDown = (e) => {
129
- e.preventDefault();
130
- handle.setPointerCapture(e.pointerId);
131
- const startX = e.clientX;
132
- const startW = sidebar.getBoundingClientRect().width;
133
- sidebar.setAttribute('data-resizing', '');
134
- document.documentElement.style.cursor = 'col-resize';
135
-
136
- const onMove = (e) => {
137
- const dx = e.clientX - startX;
138
- const max = parseInt(getComputedStyle(sidebar).getPropertyValue('max-width')) || 480;
139
- const w = Math.max(48, Math.min(max, startW + (isLeading ? dx : -dx)));
140
- sidebar.style.width = `${w}px`;
141
- };
142
-
143
- const onUp = () => {
144
- sidebar.removeAttribute('data-resizing');
145
- document.documentElement.style.cursor = '';
146
- handle.removeEventListener('pointermove', onMove);
147
- handle.removeEventListener('pointerup', onUp);
148
-
149
- // Snap logic
150
- const w = sidebar.getBoundingClientRect().width;
151
- if (w <= SNAP_THRESHOLD) {
152
- sidebar.style.width = getComputedStyle(sidebar).minWidth;
153
- } else if (w < SNAP_MIN_USABLE) {
154
- sidebar.style.width = `${SNAP_MIN_USABLE}px`;
155
- }
156
-
157
- this.#persistSidebar(sidebarName, sidebar.style.width);
158
- this.dispatchEvent(new CustomEvent('sidebar-resize', {
159
- bubbles: true,
160
- detail: { sidebar: sidebarName, width: sidebar.getBoundingClientRect().width },
161
- }));
162
- };
163
-
164
- handle.addEventListener('pointermove', onMove);
165
- handle.addEventListener('pointerup', onUp);
166
- };
167
-
168
- handle.addEventListener('pointerdown', onPointerDown);
169
- this.#resizeCleanups.push(() => handle.removeEventListener('pointerdown', onPointerDown));
170
- }
171
- }
172
-
173
- // ── 3. Command palette ─────────────────────────────────────
174
-
175
- #setupCommandPalette() {
176
- const dialog = this.querySelector('dialog[data-command]');
177
- if (!dialog) return;
178
-
179
- const cmdEl = dialog.querySelector('command-ui');
180
- const nav = this.querySelector('app-nav-ui');
181
-
182
- const openCmd = () => {
183
- dialog.showModal();
184
- if (cmdEl) { cmdEl.open = true; cmdEl.value = ''; cmdEl.focus(); }
185
- };
186
-
187
- const closeCmd = () => {
188
- dialog.close();
189
- if (cmdEl) cmdEl.open = false;
190
- };
191
-
192
- // Trigger elements
193
- for (const trigger of this.querySelectorAll('[data-command-trigger]')) {
194
- trigger.addEventListener('click', (e) => {
195
- e.stopPropagation();
196
- openCmd();
197
- });
198
- }
199
-
200
- // Backdrop click closes
201
- dialog.addEventListener('click', (e) => {
202
- if (e.target === dialog) closeCmd();
203
- });
204
-
205
- // Command-n events
206
- if (cmdEl) {
207
- cmdEl.addEventListener('dismiss', closeCmd);
208
- cmdEl.addEventListener('select', (e) => {
209
- closeCmd();
210
- if (nav) {
211
- const item = nav.querySelector(`app-nav-item-ui[value="${e.detail.value}"]`);
212
- if (item) nav.select(item);
213
- }
214
- this.dispatchEvent(new CustomEvent('command-select', {
215
- bubbles: true,
216
- detail: e.detail,
217
- }));
218
- });
219
- }
220
-
221
- // Cmd+K / Ctrl+K
222
- this.#cmdKeyHandler = (e) => {
223
- if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
224
- e.preventDefault();
225
- dialog.open ? closeCmd() : openCmd();
226
- }
227
- };
228
- document.addEventListener('keydown', this.#cmdKeyHandler);
229
- }
230
-
231
- // ── 4. ResizeObserver for select placement ─────────────────
232
-
233
- #setupResizeObserver() {
234
- this.#sidebarRO = new ResizeObserver((entries) => {
235
- for (const entry of entries) {
236
- const sidebar = entry.target;
237
- const narrow = entry.contentBoxSize[0].inlineSize <= SNAP_THRESHOLD;
238
- for (const sel of sidebar.querySelectorAll('select-ui')) {
239
- sel.setAttribute('placement', narrow ? 'right' : 'bottom-start');
240
- }
241
- }
242
- });
243
-
244
- for (const sb of this.querySelectorAll('[data-sidebar]')) {
245
- this.#sidebarRO.observe(sb);
246
- }
247
- }
248
- }
249
-
250
- customElements.define('app-shell-ui', AdiaAppShell);
251
- export { AdiaAppShell };
@@ -1,89 +0,0 @@
1
- $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
- name: AdiaAppShell
3
- tag: app-shell-ui
4
- component: AppShell
5
- category: layout
6
- version: 1
7
- description: |
8
- Behavior-only application shell. Wires sidebar toggles, resize handles,
9
- a Cmd+K command palette, and a ResizeObserver that drives responsive
10
- sidebar collapse. Author supplies the DOM (aside[data-sidebar], main,
11
- dialog[data-command]); app-shell-ui binds the interactions.
12
-
13
- props:
14
- mode:
15
- type: string
16
- default: ""
17
- enum: ["", rounded, borderless]
18
- reflect: true
19
- description: Layout variant — default is bordered surface; rounded softens edges; borderless removes the outer chrome.
20
-
21
- events:
22
- sidebar-toggle:
23
- description: Fired when a sidebar is collapsed or expanded.
24
- detail:
25
- sidebar: string
26
- expanded: boolean
27
- sidebar-resize:
28
- description: Fired as a sidebar is dragged; debounced on the trailing edge.
29
- detail:
30
- sidebar: string
31
- width: number
32
- command-select:
33
- description: Forwarded from the command palette when an option is chosen.
34
- detail:
35
- value: string
36
-
37
- slots:
38
- default:
39
- description: >-
40
- Author-supplied page DOM. Expected structure — aside[data-sidebar] for
41
- navigation, main for content, optional dialog[data-command] for Cmd+K.
42
- icon:
43
- description: >-
44
- Leading glyph inside any chrome bar — > main > header / footer and
45
- [data-sidebar] > header / footer. Muted color, flex-align.
46
- heading:
47
- description: >-
48
- Primary label inside any chrome bar. Medium-weight + strong fg.
49
- description:
50
- description: >-
51
- Secondary metadata inside any chrome bar. Muted + --a-ui-sm size.
52
- action:
53
- description: >-
54
- Trailing control cluster inside any chrome bar. The first
55
- [slot="action"] child pushes itself (and siblings) to the end;
56
- subsequent siblings flow with gap. Coexists with legacy
57
- <span data-spacer> / <div data-actions> hooks for one release —
58
- new code should prefer slots.
59
- action-leading:
60
- description: >-
61
- Leading (inline-start) control cluster inside any chrome bar.
62
- Pairs with [slot="action"] for dual-cluster chrome (e.g. back
63
- button + breadcrumb on the left, primary actions on the right).
64
- Replaces the legacy <span data-spacer> hack.
65
-
66
- states:
67
- - name: idle
68
- description: Default, interactive shell.
69
- - name: collapsed-leading
70
- attribute: data-sidebar-leading-collapsed
71
- description: Leading sidebar is collapsed; content expands.
72
- - name: collapsed-trailing
73
- attribute: data-sidebar-trailing-collapsed
74
- description: Trailing sidebar (inspector) is collapsed.
75
-
76
- traits: []
77
-
78
- a2ui:
79
- rules:
80
- - >-
81
- app-shell-ui is a behavior wrapper; its children are native HTML landmarks
82
- (aside, main, header). Don't wrap them in col-ui/row-ui — app-shell.css
83
- handles grid layout based on [data-sidebar] attributes.
84
-
85
- keywords: [app-shell, shell, layout, admin, dashboard, sidebar, nav]
86
- synonyms:
87
- admin: [dashboard, shell, app-shell]
88
- dashboard: [admin, shell, app-shell]
89
- related: [AppNav, AppNavGroup, AppNavItem, Command]
@@ -1,86 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- App Shell — Sidebar collapsed state
3
-
4
- @container sidebar (max-width: 96px)
5
-
6
- All collapse behavior is CSS-driven via container queries.
7
- JS only handles:
8
- - Resize drag with snap (≤96px → 48px, 97-159px → 160px)
9
- - Toggle button (sets width to min/restore)
10
- - Select placement attribute (bottom-start → right)
11
- - Nav-group popover-vs-toggle (checks width at click time)
12
- ═══════════════════════════════════════════════════════════════ */
13
-
14
- @container sidebar (max-width: 96px) {
15
- /* Center header/footer content */
16
- header, footer {
17
- justify-content: center;
18
- padding: var(--page-sidebar-px);
19
- }
20
-
21
- /* Center section content */
22
- section {
23
- display: flex;
24
- flex-direction: column;
25
- align-items: center;
26
- }
27
-
28
- /* Select: hide text + caret, keep leading icon/avatar */
29
- select-ui [slot="display"],
30
- select-ui [slot="caret"] {
31
- display: none;
32
- }
33
-
34
- select-ui [slot="trigger"] {
35
- justify-content: center;
36
- padding: 0;
37
- min-height: var(--page-header-height);
38
- }
39
-
40
- /* Select leading: bump icon/avatar size for collapsed state */
41
- select-ui [slot="leading"] {
42
- --a-icon-size: var(--page-sidebar-collapsed-icon);
43
- font-size: var(--page-sidebar-collapsed-icon);
44
- }
45
-
46
- select-ui img[slot="leading"] {
47
- width: var(--page-sidebar-collapsed-avatar);
48
- height: var(--page-sidebar-collapsed-avatar);
49
- }
50
-
51
- /* Nav: hide all text/meta, show only icons */
52
- app-nav-ui [slot="text"],
53
- app-nav-ui [slot="badge"],
54
- app-nav-ui [slot="caret"],
55
- app-nav-ui [slot="trailing"],
56
- app-nav-ui [data-nav-label],
57
- app-nav-ui [data-nav-divider] {
58
- display: none !important;
59
- }
60
-
61
- /* Nav items/group headers: center icon, ensure square hit area */
62
- app-nav-group-ui [slot="header"] {
63
- justify-content: center;
64
- padding: 0;
65
- min-height: var(--nav-group-row-height);
66
- min-width: var(--nav-group-row-height);
67
- }
68
-
69
- app-nav-item-ui {
70
- justify-content: center;
71
- padding: 0;
72
- min-height: var(--nav-item-row-height);
73
- min-width: var(--nav-item-row-height);
74
- }
75
-
76
- /* Button: icon-only mode */
77
- button-ui {
78
- --button-px: 0;
79
- width: auto !important;
80
- justify-content: center;
81
- }
82
-
83
- button-ui [slot="trailing"] {
84
- display: none;
85
- }
86
- }
@@ -1,42 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- App Shell — Layout helpers
3
-
4
- Generic layout utilities used across admin pages.
5
- ═══════════════════════════════════════════════════════════════ */
6
-
7
- /* Flex spacer — pushes siblings to opposite ends */
8
- [data-spacer] { flex: 1; }
9
-
10
- /* Inline action group (buttons, icons) */
11
- [data-actions] {
12
- display: flex;
13
- align-items: center;
14
- gap: var(--page-actions-gap);
15
- }
16
-
17
- /* ── Form layout helpers ── */
18
-
19
- /* 2-column grid (default), 3-column with data-grid="3" */
20
- [data-grid] {
21
- display: grid;
22
- grid-template-columns: 1fr 1fr;
23
- gap: var(--page-grid-gap);
24
- }
25
-
26
- [data-grid="3"] {
27
- grid-template-columns: 1fr 1fr 1fr;
28
- }
29
-
30
- /* Vertical stack */
31
- [data-col] {
32
- display: flex;
33
- flex-direction: column;
34
- gap: var(--page-grid-gap);
35
- }
36
-
37
- /* Horizontal row */
38
- [data-row] {
39
- display: flex;
40
- align-items: center;
41
- gap: var(--page-grid-gap);
42
- }
@@ -1,172 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- App Shell — Main column (topbar + scroll + footer)
3
- ═══════════════════════════════════════════════════════════════ */
4
-
5
- /* ── Main column ── */
6
- app-shell-ui > main {
7
- display: flex;
8
- flex-direction: column;
9
- flex: 1;
10
- min-width: 0;
11
- min-height: 0;
12
- border-inline: var(--page-main-border);
13
- }
14
-
15
- /* ── Edge breathing room when adjacent chrome is absent ──
16
- When the shell has no visible chrome on a given edge of the content
17
- surface, `> main > section` owns a small inset against that edge so
18
- the rounded/elevated surface doesn't sit flush with the viewport.
19
- The `:has(... :not([hidden]))` probe catches both "element missing
20
- from the DOM" AND "element present but [hidden]" — toggling
21
- [hidden] flips the inset live with no JS coordination. Scope is the
22
- section, not main, so the topbar/statusbar inside main keep
23
- spanning full-width even when the section gets its inset.
24
-
25
- Block-edge probes accept either an app-level chrome bar
26
- (`app-shell-ui > header / > footer`) OR a main-level chrome bar
27
- (`> main > header / > main > footer`). Either qualifies as
28
- "chrome present" and suppresses the corresponding margin. */
29
- app-shell-ui:not(:has(> aside[data-sidebar="trailing"]:not([hidden]))) > main > section {
30
- margin-inline-end: var(--a-space-2);
31
- }
32
- app-shell-ui:not(:has(> header:not([hidden]), > main > header:not([hidden]))) > main > section {
33
- margin-block-start: var(--a-space-2);
34
- }
35
- app-shell-ui:not(:has(> footer:not([hidden]), > main > footer:not([hidden]))) > main > section {
36
- margin-block-end: var(--a-space-2);
37
- }
38
-
39
- /* ── Main > header (topbar) ──
40
- Contains: sidebar toggle, breadcrumb, spacer, action buttons.
41
-
42
- Slot contract (shared with > main > footer and [data-sidebar] >
43
- header/footer) — identical to card-ui / drawer-ui / adia-editor-ui:
44
- [slot="icon"] leading glyph
45
- [slot="heading"] primary label; strong weight + strong fg
46
- [slot="description"] secondary metadata; muted fg + --a-ui-sm
47
- [slot="action"] trailing cluster; first pushes to end
48
- The legacy data-sidebar-toggle / breadcrumb-ui / <span data-spacer>
49
- / <div data-actions> hooks (see app-shell.helpers.css) remain
50
- fully supported — slots are additive, not a replacement. Use slots
51
- for simpler chrome surfaces; keep breadcrumb + data-actions for
52
- docs-style shells where those conventions carry semantic weight. */
53
- app-shell-ui > main > header {
54
- display: flex;
55
- align-items: center;
56
- gap: var(--page-header-gap);
57
- min-height: var(--page-header-height);
58
- padding: 0 var(--page-header-px);
59
- border-bottom: var(--page-border);
60
- font-size: var(--page-header-font);
61
- flex-shrink: 0;
62
- }
63
-
64
- app-shell-ui > main > header > [slot="icon"] {
65
- display: flex;
66
- align-items: center;
67
- flex-shrink: 0;
68
- color: var(--page-header-fg-muted);
69
- }
70
- app-shell-ui > main > header > [slot="heading"] {
71
- font-weight: var(--a-weight-medium);
72
- color: var(--a-fg);
73
- }
74
- app-shell-ui > main > header > [slot="description"] {
75
- color: var(--page-header-fg-muted);
76
- font-size: var(--a-ui-sm);
77
- }
78
- app-shell-ui > main > header > [slot="action"] {
79
- display: flex;
80
- align-items: center;
81
- gap: var(--page-actions-gap);
82
- flex-shrink: 0;
83
- margin-inline-start: auto;
84
- }
85
- app-shell-ui > main > header > [slot="action"] ~ [slot="action"] {
86
- margin-inline-start: 0;
87
- }
88
- /* Dual-cluster: leading group on inline-start, trailing cluster on inline-end. */
89
- app-shell-ui > main > header > [slot="action-leading"] {
90
- display: flex;
91
- align-items: center;
92
- gap: var(--page-actions-gap);
93
- flex-shrink: 0;
94
- margin-inline-end: auto;
95
- }
96
-
97
- /* ── Main > section (scroll container) ──
98
- Wraps [data-content-root]. Scrolls vertically, hides scrollbar.
99
- Soft elevation via --page-content-shadow (defaults to --a-shadow-md)
100
- so the content surface lifts off the chrome canvas regardless of
101
- mode — pairs with --page-content-radius under "rounded" and stays
102
- visible under "borderless". */
103
- app-shell-ui > main > section {
104
- flex: 1;
105
- min-height: 0;
106
- overflow-y: auto;
107
- overscroll-behavior: contain;
108
- scrollbar-width: none;
109
- background: var(--page-content-bg);
110
- box-shadow: var(--page-content-shadow);
111
- }
112
-
113
- app-shell-ui > main > section::-webkit-scrollbar { display: none; }
114
-
115
- /* ── Main > footer (status bar) ──
116
- Legacy pattern: last-child auto-pushed to trailing edge via
117
- margin-inline-start: auto (works when authors use a simple
118
- <span>…</span><span>version</span> shape).
119
- Slot pattern: same icon / heading / description / action vocabulary
120
- as > main > header (see comment block above). */
121
- app-shell-ui > main > footer {
122
- flex-shrink: 0;
123
- display: flex;
124
- align-items: center;
125
- margin-top: auto;
126
- gap: var(--page-header-gap);
127
- min-height: var(--page-header-height);
128
- padding: 0 var(--page-header-px);
129
- border-top: var(--page-border);
130
- font-size: var(--page-header-font);
131
- color: var(--page-header-fg-muted);
132
- }
133
-
134
- /* Legacy: bare <span>…</span><span>version</span> shapes. Only kicks
135
- in when NO slot="action" is present, so it doesn't fight the slot
136
- rule below. */
137
- app-shell-ui > main > footer:not(:has(> [slot="action"])) > :last-child {
138
- margin-inline-start: auto;
139
- }
140
-
141
- app-shell-ui > main > footer > [slot="icon"] {
142
- display: flex;
143
- align-items: center;
144
- flex-shrink: 0;
145
- color: var(--page-header-fg-muted);
146
- }
147
- app-shell-ui > main > footer > [slot="heading"] {
148
- font-weight: var(--a-weight-medium);
149
- color: var(--a-fg);
150
- }
151
- app-shell-ui > main > footer > [slot="description"] {
152
- color: var(--page-header-fg-muted);
153
- font-size: var(--a-ui-sm);
154
- }
155
- app-shell-ui > main > footer > [slot="action"] {
156
- display: flex;
157
- align-items: center;
158
- gap: var(--page-actions-gap);
159
- flex-shrink: 0;
160
- margin-inline-start: auto;
161
- }
162
- app-shell-ui > main > footer > [slot="action"] ~ [slot="action"] {
163
- margin-inline-start: 0;
164
- }
165
- /* Dual-cluster: leading group on inline-start, trailing cluster on inline-end. */
166
- app-shell-ui > main > footer > [slot="action-leading"] {
167
- display: flex;
168
- align-items: center;
169
- gap: var(--page-actions-gap);
170
- flex-shrink: 0;
171
- margin-inline-end: auto;
172
- }
@@ -1,44 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- App Shell — Root layout + modes
3
-
4
- Structure:
5
- app-shell-ui — root shell (flex row, fixed viewport)
6
- aside[data-sidebar="leading"] — nav sidebar (resizable, collapsible)
7
- main — center column (topbar + scroll + footer)
8
- header — topbar
9
- section — scroll container
10
- article[data-content-root] — page wrapper (sticky bands + centered body)
11
- div[data-content-header] > header — sticky page title + tabs
12
- div[data-content-body] > section — centered reading column (tab/form content)
13
- footer — status bar
14
- aside[data-sidebar="trailing"] — inspector sidebar
15
- dialog[data-command] — command palette
16
-
17
- Modes (space-separated on mode attribute):
18
- "rounded" — border-radius on scroll section
19
- "borderless" — removes chrome borders (content borders persist)
20
- ═══════════════════════════════════════════════════════════════ */
21
-
22
- /* ── Page modes ── */
23
- app-shell-ui[mode~="rounded"] > main > section {
24
- border-radius: var(--page-content-radius);
25
- }
26
-
27
- app-shell-ui[mode~="borderless"] {
28
- --page-main-border: none;
29
- --page-border: none;
30
- /* Note: --page-content-border is NOT reset — content dividers persist */
31
- }
32
-
33
- /* ── Page shell ── */
34
- app-shell-ui {
35
- display: flex;
36
- height: 100dvh;
37
- overflow: hidden;
38
- background: var(--page-bg);
39
- position: fixed;
40
- inset: 0;
41
- overscroll-behavior: none;
42
- font-family: var(--page-font-family);
43
- font-size: var(--page-body-size);
44
- }