@adia-ai/web-modules 0.6.10 → 0.6.12
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/CHANGELOG.md +20 -1
- package/package.json +1 -1
- package/shell/admin-shell/css/admin-shell.bespoke.css +38 -6
- package/shell/admin-shell/css/admin-shell.collapsed.css +1 -1
- package/shell/admin-shell/css/admin-shell.main.css +46 -181
- package/shell/admin-shell/css/admin-shell.shell.css +19 -24
- package/shell/admin-shell/css/admin-shell.templates.css +52 -114
- package/shell/admin-shell/css/admin-shell.tokens.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-modules
|
|
2
2
|
|
|
3
|
+
## [0.6.12] — 2026-05-20
|
|
4
|
+
|
|
5
|
+
### Cleanup (no in-tree or audited external consumer impact)
|
|
6
|
+
- **Legacy shell-shape CSS bridges retired.** Per ADR-0032 (continuation of ADR-0023 + ADR-0024), the `:is(legacy, bespoke)` selector lists in `admin-shell.main.css`, `admin-shell.templates.css`, `admin-shell.collapsed.css`, and `admin-shell.shell.css` have been stripped to bespoke-only. Standalone `[data-content-root]` / `[data-content-header]` / `[data-content-body]` / `[data-content-footer]` rules in `admin-shell.templates.css` are gone. ADR-0024 retired the legacy JS-level reads in v0.4.0; the CSS bridges remained as a soft-deprecation through v0.6.x, and the v0.6.12 dogfooding sweep eliminated the last in-tree consumers. External-consumer audit at the v0.6.12 cut found zero usage of the legacy shape under `<admin-shell>` across the 4 known external projects (`claims-ui-v3`, `claims-ui-v2`, `claims-ui`, `color-app`) — patch-cut safe. Anyone outside that audit emitting `<main><header-ui>…<article data-content-root><div data-content-header>…</div></article></section-ui></main>` under `<admin-shell>` will need to migrate to the canonical 10-tag bespoke composition: `<admin-shell><admin-sidebar slot="leading">…</admin-sidebar><admin-content><admin-topbar>…</admin-topbar><admin-scroll><admin-page><admin-page-header><header>…</header></admin-page-header><admin-page-body><section>…</section></admin-page-body></admin-page></admin-scroll><admin-statusbar>…</admin-statusbar></admin-content></admin-shell>`. A future `adia-ui-kit` skill cut will ship an AST codemod for static-HTML migration.
|
|
7
|
+
|
|
8
|
+
### Substrate completion
|
|
9
|
+
- `admin-shell.bespoke.css` — completed missing slot-vocab properties on `:is(admin-topbar, admin-statusbar) > [slot="action"]` (added `display:flex`, `gap`, `align-items`, `flex-shrink` to handle multi-child action clusters). Added `scrollbar-width: none` to `<admin-scroll>`. Added `min-height: 0; width: 100%; box-sizing: border-box` to `<admin-page-body>`. Without these completions, stripping the legacy main.css rules would have lost cluster layout in multi-child topbar/statusbar slots.
|
|
10
|
+
|
|
11
|
+
### Verification
|
|
12
|
+
- `verify:no-legacy-shell-shapes` regression guard exits 0 (added + wired into omnibus `check` in v0.6.12).
|
|
13
|
+
- Playground + site geometry pixel-identical pre/post strip across all 232 doc-template routes.
|
|
14
|
+
- `smoke:consumers` 6/6, `smoke:engines` green, `smoke:register-engine` 11/11, `verify:traits` 56/56 clean, `eval:diff --engine zettel` cov=49% / avg=90 (baseline-identical).
|
|
15
|
+
- 4 external consumer projects (`claims-ui-v3`, `claims-ui-v2`, `claims-ui`, `color-app`) audited — zero legacy-shape usage, no migration debt below the lockstep.
|
|
16
|
+
|
|
17
|
+
## [0.6.11] — 2026-05-20
|
|
18
|
+
|
|
19
|
+
### Maintenance
|
|
20
|
+
- **Lockstep version bump only.** No source changes in this package; bumped to maintain the 9-package version coherence enforced by `scripts/release/check-lockstep.mjs`. Substantive v0.6.11 work shipped in `@adia-ai/web-components` (`<canvas-ui>` `.d.ts` hand-author covering 9 imperative runtime methods, claims-ui-v2 inbound FB-02 finding 2 closure) and `adia-ui-kit` skill v2.8.0 bundled feedback close (FB-01, FB-02 findings 1+3, FB-03; graduated `/with-css` opt-in docs + `ADIA_TICKETS_DIR` central-inbound workflow).
|
|
21
|
+
|
|
3
22
|
## [0.6.10] — 2026-05-21
|
|
4
23
|
|
|
5
24
|
### Added
|
|
@@ -607,7 +626,7 @@ This is a **minor cut on top of v0.2.5 with one BREAKING install change**: `@adi
|
|
|
607
626
|
### Changed
|
|
608
627
|
|
|
609
628
|
- **`<chat-shell>` chat-input now imports `streamChat` from `@adia-ai/llm`** instead of `@adia-ai/a2ui-compose/llm`. No behavior change at the chat-shell API surface (same `provider`/`model`/`messages` props, same chunk-stream events). Internal — but consumer-visible because `peerDependencies` changed.
|
|
610
|
-
- **Proxy mode now works correctly.** When `<chat-shell>` is configured with `proxy-url="/api/chat"` (or any proxy URL), the request body now includes `provider` so the proxy routes to the right upstream. Previously, OpenAI/Gemini requests through proxy mode silently routed to Anthropic and 404'd. The `Authorization: Bearer
|
|
629
|
+
- **Proxy mode now works correctly.** When `<chat-shell>` is configured with `proxy-url="/api/chat"` (or any proxy URL), the request body now includes `provider` so the proxy routes to the right upstream. Previously, OpenAI/Gemini requests through proxy mode silently routed to Anthropic and 404'd. The `Authorization: Bearer *** header that appeared in proxy-mode requests (when `apiKey` was absent) is also gone.
|
|
611
630
|
- `peerDependencies["@adia-ai/llm"]`: NEW, `^0.3.0`.
|
|
612
631
|
- `peerDependencies["@adia-ai/web-components"]`: `^0.2.0` → `^0.3.0`.
|
|
613
632
|
- `peerDependencies["@adia-ai/a2ui-utils"]` removed; replaced by `peerDependencies["@adia-ai/a2ui-runtime"]: ^0.3.0` (rename + bump).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-modules",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.12",
|
|
4
4
|
"description": "AdiaUI composite custom elements \u2014 shell, chat, editor, runtime clusters built from @adia-ai/web-components primitives. Subpath exports per cluster.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════
|
|
2
2
|
admin-shell — Bespoke shell-tier children (canonical since v0.4.0)
|
|
3
3
|
|
|
4
|
-
Per ADR-0023 + ADR-0024 (
|
|
5
|
-
|
|
4
|
+
Per ADR-0023 + ADR-0024 (host-element legacy reads stripped v0.4.0)
|
|
5
|
+
+ ADR-0032 (CSS bridges stripped v0.6.12), this file carries the
|
|
6
|
+
canonical styling for the bespoke shell-tier children:
|
|
6
7
|
admin-content, admin-topbar, admin-statusbar, admin-scroll,
|
|
7
8
|
admin-page, admin-page-header, admin-page-body, admin-sidebar.
|
|
8
9
|
|
|
9
10
|
The legacy raw-HTML shape (<main>, <header>, <footer>, <aside-ui slot>,
|
|
10
|
-
<aside data-sidebar>, <dialog data-command
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
<aside data-sidebar>, <dialog data-command>, [data-content-root],
|
|
12
|
+
[data-content-header], [data-content-body], [data-content-footer])
|
|
13
|
+
was the v0.3.x authoring contract. JS-level reads were retired in
|
|
14
|
+
v0.4.0; CSS bridges in main.css, templates.css, collapsed.css and
|
|
15
|
+
site/site.css were retired in v0.6.12 (see ADR-0032). All :is() lifts
|
|
16
|
+
in layered files now target ONLY the bespoke tags. See git history
|
|
17
|
+
prior to v0.6.12 for the legacy paths.
|
|
14
18
|
═══════════════════════════════════════════════════════════════ */
|
|
15
19
|
|
|
16
20
|
/* ── admin-content ≡ <main> ── */
|
|
@@ -58,6 +62,7 @@ admin-content > admin-scroll {
|
|
|
58
62
|
min-height: 0;
|
|
59
63
|
overflow-y: auto;
|
|
60
64
|
overscroll-behavior: contain;
|
|
65
|
+
scrollbar-width: none;
|
|
61
66
|
background: var(--page-content-bg);
|
|
62
67
|
border-inline: var(--page-content-border);
|
|
63
68
|
box-shadow: var(--page-content-shadow);
|
|
@@ -90,6 +95,9 @@ admin-page > admin-page-header {
|
|
|
90
95
|
/* ── admin-page-body ≡ <[data-content-body]> centered body ── */
|
|
91
96
|
admin-page > admin-page-body {
|
|
92
97
|
flex: 1;
|
|
98
|
+
min-height: 0;
|
|
99
|
+
width: 100%;
|
|
100
|
+
box-sizing: border-box;
|
|
93
101
|
display: flex;
|
|
94
102
|
flex-direction: column;
|
|
95
103
|
}
|
|
@@ -192,3 +200,27 @@ admin-sidebar[collapsed] {
|
|
|
192
200
|
color: var(--page-header-fg-muted);
|
|
193
201
|
font-size: var(--a-ui-sm);
|
|
194
202
|
}
|
|
203
|
+
|
|
204
|
+
/* Multi-child action clusters: turn the slot into a flex row so nested
|
|
205
|
+
buttons gap correctly. Legacy <main> > <header> > [slot="action"]
|
|
206
|
+
got this from main.css; the equivalent for the bespoke topbar/
|
|
207
|
+
statusbar lives here. */
|
|
208
|
+
:is(admin-topbar, admin-statusbar) > [slot="action"],
|
|
209
|
+
:is(admin-topbar, admin-statusbar) > [slot="action-leading"] {
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
gap: var(--page-actions-gap);
|
|
213
|
+
flex-shrink: 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Second + Nth [slot="action"] children: reset the auto-push from
|
|
217
|
+
:first-of-type so siblings sit flush against the first cluster. */
|
|
218
|
+
:is(admin-topbar, admin-statusbar) > [slot="action"] ~ [slot="action"] {
|
|
219
|
+
margin-inline-start: 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Slot icon: flex inner alignment (legacy parity). */
|
|
223
|
+
:is(admin-topbar, admin-statusbar) > [slot="icon"] {
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
}
|
|
@@ -1,143 +1,67 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════
|
|
2
|
-
App Shell — Main column
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
App Shell — Main column layout helpers
|
|
3
|
+
|
|
4
|
+
Post-ADR-0032 (v0.6.12): the legacy <main> / <header-ui> / <section-ui>
|
|
5
|
+
/ <footer-ui> selector lifts that lived here have been retired. The
|
|
6
|
+
canonical bespoke <admin-content> / <admin-topbar> / <admin-scroll> /
|
|
7
|
+
<admin-statusbar> geometry + slot vocabulary live in
|
|
8
|
+
admin-shell.bespoke.css.
|
|
9
|
+
|
|
10
|
+
What stays in this file:
|
|
11
|
+
• Edge-breathing-room :has() probes — they're cross-cutting (they
|
|
12
|
+
inspect both admin-shell-level chrome AND admin-content-level
|
|
13
|
+
chrome), so they don't belong in bespoke.css's pure-tag-keyed
|
|
14
|
+
rule blocks.
|
|
15
|
+
• <admin-scroll> WebKit scrollbar suppression sibling rule.
|
|
16
|
+
• Subnav rail grid layout — descendant-of-admin-scroll behavior
|
|
17
|
+
that's authored alongside the breathing-room logic.
|
|
11
18
|
═══════════════════════════════════════════════════════════════ */
|
|
12
19
|
|
|
13
|
-
/* ── Main column ── */
|
|
14
|
-
admin-shell > main {
|
|
15
|
-
display: flex;
|
|
16
|
-
flex-direction: column;
|
|
17
|
-
flex: 1;
|
|
18
|
-
min-width: 0;
|
|
19
|
-
min-height: 0;
|
|
20
|
-
border-inline: var(--page-main-border);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
20
|
/* ── Edge breathing room when adjacent chrome is absent ──
|
|
24
21
|
When the shell has no visible chrome on a given edge of the content
|
|
25
|
-
surface,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Block-edge probes accept either an app-level chrome bar
|
|
35
|
-
(`admin-shell > :is(header, header-ui)` / `> :is(footer, footer-ui)`)
|
|
36
|
-
OR a main-level chrome bar (`> main > :is(header, header-ui)` etc.).
|
|
37
|
-
Either qualifies as "chrome present" and suppresses the
|
|
38
|
-
corresponding margin. */
|
|
39
|
-
admin-shell:not(:has(> :is(asideadmin-sidebar[slot="trailing"], admin-sidebar[slot="trailing"]):not([hidden]))) > main > :is(section, section-ui) {
|
|
22
|
+
surface, `<admin-scroll>` owns a small inset against that edge so
|
|
23
|
+
the rounded/elevated surface doesn't sit flush with the viewport.
|
|
24
|
+
The `:has(... :not([hidden]))` probe catches both "element missing
|
|
25
|
+
from the DOM" AND "element present but [hidden]" — toggling [hidden]
|
|
26
|
+
flips the inset live with no JS coordination. Scope is the scroll
|
|
27
|
+
container, not admin-content, so the topbar / statusbar inside
|
|
28
|
+
admin-content keep spanning full-width even when the scroll surface
|
|
29
|
+
gets its inset. */
|
|
30
|
+
admin-shell:not(:has(> :is(asideadmin-sidebar[slot="trailing"], admin-sidebar[slot="trailing"]):not([hidden]))) > admin-content > admin-scroll {
|
|
40
31
|
margin-inline-end: var(--a-space-2);
|
|
41
32
|
}
|
|
42
|
-
admin-shell:not(:has(> :is(header, header-ui):not([hidden]), >
|
|
33
|
+
admin-shell:not(:has(> :is(header, header-ui, admin-topbar):not([hidden]), > admin-content > admin-topbar:not([hidden]))) > admin-content > admin-scroll {
|
|
43
34
|
margin-block-start: var(--a-space-2);
|
|
44
35
|
}
|
|
45
|
-
admin-shell:not(:has(> :is(footer, footer-ui):not([hidden]), >
|
|
36
|
+
admin-shell:not(:has(> :is(footer, footer-ui, admin-statusbar):not([hidden]), > admin-content > admin-statusbar:not([hidden]))) > admin-content > admin-scroll {
|
|
46
37
|
margin-block-end: var(--a-space-2);
|
|
47
38
|
}
|
|
48
39
|
|
|
49
|
-
/* ──
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
[slot="action"] trailing cluster; first pushes to end
|
|
58
|
-
The legacy data-sidebar-toggle / breadcrumb-ui / <span data-spacer>
|
|
59
|
-
/ <div data-actions> hooks (see app-shell.helpers.css) remain
|
|
60
|
-
fully supported — slots are additive, not a replacement. Use slots
|
|
61
|
-
for simpler chrome surfaces; keep breadcrumb + data-actions for
|
|
62
|
-
docs-style shells where those conventions carry semantic weight. */
|
|
63
|
-
admin-shell > main > :is(header, header-ui) {
|
|
64
|
-
display: flex;
|
|
65
|
-
align-items: center;
|
|
66
|
-
gap: var(--page-header-gap);
|
|
67
|
-
min-height: var(--page-header-height);
|
|
68
|
-
padding: 0 var(--page-header-px);
|
|
69
|
-
border-bottom: var(--page-border);
|
|
70
|
-
font-size: var(--page-header-font);
|
|
71
|
-
flex-shrink: 0;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
admin-shell > main > :is(header, header-ui) > [slot="icon"] {
|
|
75
|
-
display: flex;
|
|
76
|
-
align-items: center;
|
|
77
|
-
flex-shrink: 0;
|
|
78
|
-
color: var(--page-header-fg-muted);
|
|
79
|
-
}
|
|
80
|
-
admin-shell > main > :is(header, header-ui) > [slot="heading"] {
|
|
81
|
-
font-weight: var(--a-weight-medium);
|
|
82
|
-
color: var(--a-fg);
|
|
83
|
-
}
|
|
84
|
-
admin-shell > main > :is(header, header-ui) > [slot="description"] {
|
|
85
|
-
color: var(--page-header-fg-muted);
|
|
86
|
-
font-size: var(--a-ui-sm);
|
|
87
|
-
}
|
|
88
|
-
admin-shell > main > :is(header, header-ui) > [slot="action"] {
|
|
89
|
-
display: flex;
|
|
90
|
-
align-items: center;
|
|
91
|
-
gap: var(--page-actions-gap);
|
|
92
|
-
flex-shrink: 0;
|
|
93
|
-
margin-inline-start: auto;
|
|
94
|
-
}
|
|
95
|
-
admin-shell > main > :is(header, header-ui) > [slot="action"] ~ [slot="action"] {
|
|
96
|
-
margin-inline-start: 0;
|
|
97
|
-
}
|
|
98
|
-
/* Dual-cluster: leading group on inline-start, trailing cluster on inline-end. */
|
|
99
|
-
admin-shell > main > :is(header, header-ui) > [slot="action-leading"] {
|
|
100
|
-
display: flex;
|
|
101
|
-
align-items: center;
|
|
102
|
-
gap: var(--page-actions-gap);
|
|
103
|
-
flex-shrink: 0;
|
|
104
|
-
margin-inline-end: auto;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* ── Main > section (scroll container) ──
|
|
108
|
-
Wraps [data-content-root]. Scrolls vertically, hides scrollbar.
|
|
109
|
-
Soft elevation via --page-content-shadow (defaults to --a-shadow-md)
|
|
110
|
-
so the content surface lifts off the chrome canvas regardless of
|
|
111
|
-
mode — pairs with --page-content-radius under "rounded" and stays
|
|
112
|
-
visible under "borderless". */
|
|
113
|
-
admin-shell > main > :is(section, section-ui) {
|
|
114
|
-
flex: 1;
|
|
115
|
-
min-height: 0;
|
|
116
|
-
overflow-y: auto;
|
|
117
|
-
overscroll-behavior: contain;
|
|
118
|
-
scrollbar-width: none;
|
|
119
|
-
background: var(--page-content-bg);
|
|
120
|
-
box-shadow: var(--page-content-shadow);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
admin-shell > main > :is(section, section-ui)::-webkit-scrollbar { display: none; }
|
|
40
|
+
/* ── Scroll container ──
|
|
41
|
+
Canonical styling for `<admin-scroll>` (flex, scrollbar suppression,
|
|
42
|
+
background, content shadow) lives in admin-shell.bespoke.css.
|
|
43
|
+
--page-content-shadow defaults to --a-shadow-md so the content
|
|
44
|
+
surface lifts off the chrome canvas regardless of mode — pairs with
|
|
45
|
+
--page-content-radius under "rounded" and stays visible under
|
|
46
|
+
"borderless". */
|
|
47
|
+
admin-shell > admin-content > admin-scroll::-webkit-scrollbar { display: none; }
|
|
124
48
|
|
|
125
49
|
/* ── Subnav rail layout ──
|
|
126
|
-
When
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
admin-shell >
|
|
50
|
+
When admin-scroll contains an `[data-subnav]` aside (the left-rail
|
|
51
|
+
nav pattern — `<aside data-subnav>` followed by the `<admin-page>`
|
|
52
|
+
article), grid-layout the scroll container so the rail sits on the
|
|
53
|
+
inline-start side and the content fills the rest. Mirrors the
|
|
54
|
+
docs-site convention (site.css `:has(#subnav-rail)`) so consumer
|
|
55
|
+
apps using admin-shell + the subnav-rail authoring shape get the
|
|
56
|
+
canonical layout for free. */
|
|
57
|
+
admin-shell > admin-content > admin-scroll:has(> [data-subnav]:not([hidden])) {
|
|
134
58
|
display: grid;
|
|
135
59
|
grid-template-columns: var(--subnav-width, 14rem) 1fr;
|
|
136
60
|
grid-template-rows: minmax(0, 1fr);
|
|
137
61
|
gap: 0;
|
|
138
62
|
}
|
|
139
63
|
|
|
140
|
-
admin-shell >
|
|
64
|
+
admin-shell > admin-content > admin-scroll > [data-subnav] {
|
|
141
65
|
min-height: 0;
|
|
142
66
|
overflow-y: auto;
|
|
143
67
|
overscroll-behavior: contain;
|
|
@@ -148,70 +72,11 @@ admin-shell > main > :is(section, section-ui) > [data-subnav] {
|
|
|
148
72
|
|
|
149
73
|
/* Mobile: collapse to single column; subnav stacks above content. */
|
|
150
74
|
@container (max-width: 40rem) {
|
|
151
|
-
admin-shell >
|
|
75
|
+
admin-shell > admin-content > admin-scroll:has(> [data-subnav]:not([hidden])) {
|
|
152
76
|
grid-template-columns: 1fr;
|
|
153
77
|
}
|
|
154
|
-
admin-shell >
|
|
78
|
+
admin-shell > admin-content > admin-scroll > [data-subnav] {
|
|
155
79
|
border-inline-end: none;
|
|
156
80
|
border-block-end: 1px solid var(--a-border-subtle);
|
|
157
81
|
}
|
|
158
82
|
}
|
|
159
|
-
|
|
160
|
-
/* ── Main > footer (status bar) ──
|
|
161
|
-
Legacy pattern: last-child auto-pushed to trailing edge via
|
|
162
|
-
margin-inline-start: auto (works when authors use a simple
|
|
163
|
-
<span>…</span><span>version</span> shape).
|
|
164
|
-
Slot pattern: same icon / heading / description / action vocabulary
|
|
165
|
-
as > main > header (see comment block above). */
|
|
166
|
-
admin-shell > main > :is(footer, footer-ui) {
|
|
167
|
-
flex-shrink: 0;
|
|
168
|
-
display: flex;
|
|
169
|
-
align-items: center;
|
|
170
|
-
margin-top: auto;
|
|
171
|
-
gap: var(--page-header-gap);
|
|
172
|
-
min-height: var(--page-header-height);
|
|
173
|
-
padding: 0 var(--page-header-px);
|
|
174
|
-
border-top: var(--page-border);
|
|
175
|
-
font-size: var(--page-header-font);
|
|
176
|
-
color: var(--page-header-fg-muted);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/* Legacy: bare <span>…</span><span>version</span> shapes. Only kicks
|
|
180
|
-
in when NO slot="action" is present, so it doesn't fight the slot
|
|
181
|
-
rule below. */
|
|
182
|
-
admin-shell > main > :is(footer, footer-ui):not(:has(> [slot="action"])) > :last-child {
|
|
183
|
-
margin-inline-start: auto;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="icon"] {
|
|
187
|
-
display: flex;
|
|
188
|
-
align-items: center;
|
|
189
|
-
flex-shrink: 0;
|
|
190
|
-
color: var(--page-header-fg-muted);
|
|
191
|
-
}
|
|
192
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="heading"] {
|
|
193
|
-
font-weight: var(--a-weight-medium);
|
|
194
|
-
color: var(--a-fg);
|
|
195
|
-
}
|
|
196
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="description"] {
|
|
197
|
-
color: var(--page-header-fg-muted);
|
|
198
|
-
font-size: var(--a-ui-sm);
|
|
199
|
-
}
|
|
200
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="action"] {
|
|
201
|
-
display: flex;
|
|
202
|
-
align-items: center;
|
|
203
|
-
gap: var(--page-actions-gap);
|
|
204
|
-
flex-shrink: 0;
|
|
205
|
-
margin-inline-start: auto;
|
|
206
|
-
}
|
|
207
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="action"] ~ [slot="action"] {
|
|
208
|
-
margin-inline-start: 0;
|
|
209
|
-
}
|
|
210
|
-
/* Dual-cluster: leading group on inline-start, trailing cluster on inline-end. */
|
|
211
|
-
admin-shell > main > :is(footer, footer-ui) > [slot="action-leading"] {
|
|
212
|
-
display: flex;
|
|
213
|
-
align-items: center;
|
|
214
|
-
gap: var(--page-actions-gap);
|
|
215
|
-
flex-shrink: 0;
|
|
216
|
-
margin-inline-end: auto;
|
|
217
|
-
}
|
|
@@ -1,32 +1,27 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════
|
|
2
2
|
App Shell — Root layout + modes
|
|
3
3
|
|
|
4
|
-
Structure (
|
|
5
|
-
admin-shell
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
Structure (canonical bespoke shape, post-ADR-0032 v0.6.12):
|
|
5
|
+
admin-shell — root shell (flex row, fixed viewport)
|
|
6
|
+
admin-sidebar[slot="leading"] — nav sidebar (resizable, collapsible)
|
|
7
|
+
admin-content — center column (topbar + scroll + statusbar)
|
|
8
|
+
admin-topbar — topbar
|
|
9
|
+
admin-scroll — scroll container
|
|
10
|
+
admin-page — page wrapper (sticky bands + centered body)
|
|
11
|
+
admin-page-header > header — sticky page title + tabs
|
|
12
|
+
admin-page-body > section — centered reading column
|
|
13
|
+
admin-statusbar — status bar
|
|
14
|
+
admin-sidebar[slot="trailing"] — inspector sidebar
|
|
15
|
+
admin-command — command palette
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
Modes (space-separated on mode attribute):
|
|
18
|
+
"rounded" — border-radius on scroll section
|
|
19
|
+
"borderless" — removes chrome borders (content borders persist)
|
|
20
|
+
═══════════════════════════════════════════════════════════════ */
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
═══════════════════════════════════════════════════════════════ */
|
|
25
|
-
|
|
26
|
-
/* ── Page modes ── */
|
|
27
|
-
admin-shell[mode~="rounded"] > main > :is(section, section-ui) {
|
|
28
|
-
border-radius: var(--page-content-radius);
|
|
29
|
-
}
|
|
22
|
+
/* ── Page modes ──
|
|
23
|
+
Rounded-mode border-radius for the scroll container lives in
|
|
24
|
+
admin-shell.bespoke.css (`admin-shell[mode~="rounded"] > admin-content > admin-scroll`). */
|
|
30
25
|
|
|
31
26
|
admin-shell[mode~="borderless"] {
|
|
32
27
|
--page-main-border: none;
|
|
@@ -1,106 +1,65 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════
|
|
2
2
|
admin-shell — Page templates (headers, body layouts, form sections)
|
|
3
3
|
|
|
4
|
-
Structure:
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
<header>...</header>
|
|
8
|
-
|
|
9
|
-
<section>...</section>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
Structure (post-ADR-0032, v0.6.12):
|
|
5
|
+
<admin-page>
|
|
6
|
+
<admin-page-header> — sticky top band, border-bottom
|
|
7
|
+
<header>...</header> — centered column (padding + max-width)
|
|
8
|
+
<admin-page-body> — scrollable flex column (size only)
|
|
9
|
+
<section>...</section> — centered column (padding + max-width + gap)
|
|
10
|
+
|
|
11
|
+
The bespoke wrapper owns full-width concerns (sticky position, border,
|
|
12
|
+
background, scroll sizing) — see admin-shell.bespoke.css for those
|
|
13
|
+
rules. The inner semantic element (<header>/<section>) owns the
|
|
14
|
+
centered reading column (max-width, gutter, rhythm) — that's what
|
|
15
|
+
this file covers. Full-bleed content (iframes, split panes) can skip
|
|
16
|
+
<section> and sit directly in <admin-page-body> to opt out of the
|
|
17
|
+
column.
|
|
18
|
+
|
|
19
|
+
Note: pre-v0.6.12 legacy attribute hooks (data-content-root,
|
|
20
|
+
data-content-header, data-content-body, data-content-footer) were
|
|
21
|
+
retired in ADR-0032. See git history prior to v0.6.12 for the legacy
|
|
22
|
+
selector lists.
|
|
19
23
|
═══════════════════════════════════════════════════════════════ */
|
|
20
24
|
|
|
21
|
-
/* ── Content root ──
|
|
22
|
-
`<article data-content-root>` provides an inline-size query container
|
|
23
|
-
named `page-content` so descendants can adapt to the *available content
|
|
24
|
-
width* (sidebars expanded vs collapsed) instead of the viewport.
|
|
25
|
-
|
|
26
|
-
Breakpoint scale (mirrored in `:where(admin-shell) { --page-content-bp-* }`):
|
|
27
|
-
sm 480px — phone / very narrow rail
|
|
28
|
-
md 720px — tablet / 2-col → 1-col flip for [data-section]
|
|
29
|
-
lg 1024px — wide content (no current rule; reserved)
|
|
30
|
-
Container queries can't read custom properties as thresholds, so the
|
|
31
|
-
numbers below are duplicated — keep them in lockstep with the tokens. */
|
|
32
|
-
[data-content-root] {
|
|
33
|
-
position: relative;
|
|
34
|
-
isolation: isolate;
|
|
35
|
-
min-block-size: 100%;
|
|
36
|
-
container-type: inline-size;
|
|
37
|
-
container-name: page-content;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/* Fill-mode: when the body contains only an iframe (or explicit opt-in),
|
|
41
|
-
make the root a flex column that stretches to the scroll section's
|
|
42
|
-
visible height, so [data-content-body] flex: 1 resolves against a real
|
|
43
|
-
size and the iframe's block-size: 100% can fill. Prose pages (natural
|
|
44
|
-
root height + section scroll) are unaffected. */
|
|
45
|
-
[data-content-root]:has(> [data-content-body] > iframe:only-child),
|
|
46
|
-
[data-content-root][data-fill] {
|
|
47
|
-
display: flex;
|
|
48
|
-
flex-direction: column;
|
|
49
|
-
block-size: 100%;
|
|
50
|
-
min-block-size: 0;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
25
|
/* ── Scaffold content columns ─────────────────────────────────────
|
|
54
26
|
Max-width + centering + horizontal inset are properties of the
|
|
55
|
-
NAMED inner semantic elements, not the
|
|
27
|
+
NAMED inner semantic elements, not the bespoke wrappers.
|
|
56
28
|
|
|
57
29
|
Who owns what:
|
|
58
|
-
•
|
|
59
|
-
—
|
|
60
|
-
•
|
|
61
|
-
—
|
|
62
|
-
• Inner <header> / <section>
|
|
63
|
-
—
|
|
30
|
+
• <admin-page-header>
|
|
31
|
+
— sticky position, border, background (see bespoke.css).
|
|
32
|
+
• <admin-page-body>
|
|
33
|
+
— flex sizing + scroll; no padding, no max-width (see bespoke.css).
|
|
34
|
+
• Inner <header> / <section>
|
|
35
|
+
— max-width, margin-inline: auto, padding (centered column).
|
|
64
36
|
• Cards / modals / drawers
|
|
65
37
|
— own margin/padding via their own CSS; never inherit this.
|
|
66
38
|
─────────────────────────────────────────────────────────────── */
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
[data-content-footer] > :is(footer, footer-ui) {
|
|
39
|
+
admin-page-header > :is(header, header-ui),
|
|
40
|
+
admin-page-body > :is(section, section-ui) {
|
|
70
41
|
max-width: var(--page-content-max-width);
|
|
71
42
|
margin-inline: auto;
|
|
72
43
|
width: 100%;
|
|
73
44
|
box-sizing: border-box;
|
|
74
45
|
}
|
|
75
46
|
|
|
76
|
-
|
|
77
|
-
[data-content-footer] > :is(footer, footer-ui) {
|
|
47
|
+
admin-page-header > :is(header, header-ui) {
|
|
78
48
|
padding-inline: var(--page-content-inset);
|
|
79
49
|
}
|
|
80
50
|
|
|
81
|
-
/* Full-width escape hatch — stretch the centered column to 100%.
|
|
82
|
-
[data-content-full]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
[data-content-header] > :is(header, header-ui)[data-content-full],
|
|
89
|
-
[data-content-body] > :is(section, section-ui)[data-content-full],
|
|
90
|
-
[data-content-footer] > :is(footer, footer-ui)[data-content-full] {
|
|
51
|
+
/* Full-width escape hatch — stretch the centered column to 100%.
|
|
52
|
+
[data-content-full] can land on the bespoke wrapper or its inner
|
|
53
|
+
semantic element. */
|
|
54
|
+
admin-page-header[data-content-full] > :is(header, header-ui),
|
|
55
|
+
admin-page-body[data-content-full] > :is(section, section-ui),
|
|
56
|
+
admin-page-header > :is(header, header-ui)[data-content-full],
|
|
57
|
+
admin-page-body > :is(section, section-ui)[data-content-full] {
|
|
91
58
|
max-width: 100%;
|
|
92
59
|
}
|
|
93
60
|
|
|
94
|
-
/* ── Content header
|
|
95
|
-
|
|
96
|
-
position: sticky;
|
|
97
|
-
top: 0;
|
|
98
|
-
z-index: 1;
|
|
99
|
-
border-bottom: var(--page-content-border);
|
|
100
|
-
background: var(--page-content-bg);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
[data-content-header] > :is(header, header-ui) {
|
|
61
|
+
/* ── Content header inner layout ── */
|
|
62
|
+
admin-page-header > :is(header, header-ui) {
|
|
104
63
|
display: flex;
|
|
105
64
|
flex-direction: column;
|
|
106
65
|
gap: var(--page-header-gap);
|
|
@@ -108,24 +67,24 @@
|
|
|
108
67
|
}
|
|
109
68
|
|
|
110
69
|
/* When tabs are present, remove bottom padding so tabs sit flush against border */
|
|
111
|
-
|
|
70
|
+
admin-page-header > :is(header, header-ui):has(tabs-ui) {
|
|
112
71
|
padding-bottom: 0;
|
|
113
72
|
}
|
|
114
73
|
|
|
115
74
|
/* Variant: non-sticky, no border, transparent bg */
|
|
116
|
-
|
|
75
|
+
admin-page-header:has(> :is(header, header-ui)[data-flush]) {
|
|
117
76
|
position: static;
|
|
118
77
|
border-bottom: none;
|
|
119
78
|
background: none;
|
|
120
79
|
}
|
|
121
80
|
|
|
122
81
|
/* Variant: compact padding (for dense headers) */
|
|
123
|
-
|
|
82
|
+
admin-page-header > :is(header, header-ui)[data-compact] {
|
|
124
83
|
padding-block: var(--page-header-px);
|
|
125
84
|
}
|
|
126
85
|
|
|
127
86
|
/* Title row: h1 left, actions right */
|
|
128
|
-
|
|
87
|
+
admin-page-header > :is(header, header-ui) > div:first-child {
|
|
129
88
|
display: flex;
|
|
130
89
|
align-items: center;
|
|
131
90
|
justify-content: space-between;
|
|
@@ -133,27 +92,20 @@
|
|
|
133
92
|
}
|
|
134
93
|
|
|
135
94
|
/* h1 + description — typography handled by [variant] attribute */
|
|
136
|
-
|
|
137
|
-
|
|
95
|
+
admin-page-header h1 { margin: 0; }
|
|
96
|
+
admin-page-header > :is(header, header-ui) > p { margin: 0; }
|
|
138
97
|
|
|
139
|
-
/* ── Content body ──
|
|
98
|
+
/* ── Content body — flex column inner layout ──
|
|
140
99
|
Wrapper: flex column that fills the scroll section. No padding,
|
|
141
100
|
no max-width — those live on the inner <section>. Non-section
|
|
142
|
-
children (iframes, split panes) go full-bleed.
|
|
143
|
-
|
|
144
|
-
flex: 1;
|
|
145
|
-
min-height: 0;
|
|
146
|
-
width: 100%;
|
|
147
|
-
box-sizing: border-box;
|
|
148
|
-
display: flex;
|
|
149
|
-
flex-direction: column;
|
|
150
|
-
}
|
|
101
|
+
children (iframes, split panes) go full-bleed.
|
|
102
|
+
(Wrapper geometry — flex, min-height, width — lives in bespoke.css.) */
|
|
151
103
|
|
|
152
104
|
/* Inner <section> (or <section-ui>) — the centered reading column.
|
|
153
105
|
Owns gutter and section-to-section rhythm. Stacks with flex gap
|
|
154
106
|
so direct children (<card-ui>, <grid-ui>, nested <section>, …)
|
|
155
107
|
have zero wrapper margin. */
|
|
156
|
-
|
|
108
|
+
admin-page-body > :is(section, section-ui) {
|
|
157
109
|
padding: var(--page-content-inset);
|
|
158
110
|
display: flex;
|
|
159
111
|
flex-direction: column;
|
|
@@ -162,7 +114,7 @@
|
|
|
162
114
|
|
|
163
115
|
/* iframe-as-page-content: fill the body.
|
|
164
116
|
display: block kills the 4-5px inline-descender gap. */
|
|
165
|
-
|
|
117
|
+
admin-page-body > iframe {
|
|
166
118
|
display: block;
|
|
167
119
|
inline-size: 100%;
|
|
168
120
|
block-size: 100%;
|
|
@@ -170,19 +122,6 @@
|
|
|
170
122
|
flex: 1;
|
|
171
123
|
}
|
|
172
124
|
|
|
173
|
-
/* ── Content footer — sticky bottom, border-top ── */
|
|
174
|
-
[data-content-footer] {
|
|
175
|
-
position: sticky;
|
|
176
|
-
bottom: 0;
|
|
177
|
-
z-index: 1;
|
|
178
|
-
border-top: var(--page-content-border);
|
|
179
|
-
background: var(--page-content-bg);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
[data-content-footer] > footer {
|
|
183
|
-
padding: var(--page-content-inset);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
125
|
/* ── Tab content ──
|
|
187
126
|
Marker for the active tab's form sections. Gutter/padding is
|
|
188
127
|
owned by the <article> wrapper. */
|
|
@@ -239,12 +178,11 @@
|
|
|
239
178
|
|
|
240
179
|
/* Tighten the content gutter when the article is genuinely narrow. */
|
|
241
180
|
@container page-content (max-width: 480px) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
[data-content-footer] > :is(footer, footer-ui) {
|
|
181
|
+
admin-page-header > :is(header, header-ui),
|
|
182
|
+
admin-page-body > :is(section, section-ui) {
|
|
245
183
|
padding-inline: var(--a-space-4);
|
|
246
184
|
}
|
|
247
|
-
|
|
185
|
+
admin-page-body > :is(section, section-ui) {
|
|
248
186
|
padding-block: var(--a-space-4);
|
|
249
187
|
}
|
|
250
188
|
}
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
--page-content-border: 1px solid var(--a-border-subtle); /* content dividers (persists in "borderless") */
|
|
45
45
|
--page-content-shadow: var(--a-shadow-sm); /* soft lift on the content surface */
|
|
46
46
|
|
|
47
|
-
/* Content breakpoint scale —
|
|
47
|
+
/* Content breakpoint scale — `<admin-page>` is a `page-content`
|
|
48
48
|
container query provider (admin-shell.templates.css). These tokens
|
|
49
49
|
are the documented thresholds; @container queries can't read custom
|
|
50
50
|
properties for thresholds, so the numbers are duplicated in CSS. */
|