@adia-ai/web-modules 0.3.2 → 0.3.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/chat/chat-shell/chat-shell.examples.html +85 -0
  3. package/chat/chat-shell/chat-shell.html +42 -0
  4. package/editor/editor-shell/editor-shell.examples.html +71 -0
  5. package/editor/editor-shell/editor-shell.html +42 -0
  6. package/package.json +2 -2
  7. package/shell/admin-command/admin-command.a2ui.json +102 -0
  8. package/shell/admin-command/admin-command.examples.html +83 -0
  9. package/shell/admin-command/admin-command.html +42 -0
  10. package/shell/admin-command/admin-command.js +161 -0
  11. package/shell/admin-command/admin-command.test.js +115 -0
  12. package/shell/admin-command/admin-command.yaml +102 -0
  13. package/shell/admin-content/admin-content.a2ui.json +73 -0
  14. package/shell/admin-content/admin-content.examples.html +33 -0
  15. package/shell/admin-content/admin-content.html +42 -0
  16. package/shell/admin-content/admin-content.yaml +63 -0
  17. package/shell/admin-page/admin-page.a2ui.json +74 -0
  18. package/shell/admin-page/admin-page.examples.html +37 -0
  19. package/shell/admin-page/admin-page.html +42 -0
  20. package/shell/admin-page/admin-page.yaml +61 -0
  21. package/shell/admin-page-body/admin-page-body.a2ui.json +62 -0
  22. package/shell/admin-page-body/admin-page-body.examples.html +34 -0
  23. package/shell/admin-page-body/admin-page-body.html +42 -0
  24. package/shell/admin-page-body/admin-page-body.yaml +49 -0
  25. package/shell/admin-page-header/admin-page-header.a2ui.json +62 -0
  26. package/shell/admin-page-header/admin-page-header.examples.html +34 -0
  27. package/shell/admin-page-header/admin-page-header.html +42 -0
  28. package/shell/admin-page-header/admin-page-header.yaml +47 -0
  29. package/shell/admin-scroll/admin-scroll.a2ui.json +62 -0
  30. package/shell/admin-scroll/admin-scroll.examples.html +31 -0
  31. package/shell/admin-scroll/admin-scroll.html +42 -0
  32. package/shell/admin-scroll/admin-scroll.yaml +51 -0
  33. package/shell/admin-shell/admin-shell.a2ui.json +0 -10
  34. package/shell/admin-shell/admin-shell.css +1 -0
  35. package/shell/admin-shell/admin-shell.examples.html +61 -5
  36. package/shell/admin-shell/admin-shell.js +165 -121
  37. package/shell/admin-shell/admin-shell.yaml +6 -6
  38. package/shell/admin-shell/css/admin-shell.bespoke.css +198 -0
  39. package/shell/admin-shell/css/admin-shell.tokens.css +10 -0
  40. package/shell/admin-sidebar/admin-sidebar.a2ui.json +138 -0
  41. package/shell/admin-sidebar/admin-sidebar.examples.html +76 -0
  42. package/shell/admin-sidebar/admin-sidebar.html +47 -0
  43. package/shell/admin-sidebar/admin-sidebar.js +227 -0
  44. package/shell/admin-sidebar/admin-sidebar.test.js +123 -0
  45. package/shell/admin-sidebar/admin-sidebar.yaml +140 -0
  46. package/shell/admin-statusbar/admin-statusbar.a2ui.json +81 -0
  47. package/shell/admin-statusbar/admin-statusbar.examples.html +29 -0
  48. package/shell/admin-statusbar/admin-statusbar.html +42 -0
  49. package/shell/admin-statusbar/admin-statusbar.yaml +68 -0
  50. package/shell/admin-topbar/admin-topbar.a2ui.json +83 -0
  51. package/shell/admin-topbar/admin-topbar.examples.html +31 -0
  52. package/shell/admin-topbar/admin-topbar.html +42 -0
  53. package/shell/admin-topbar/admin-topbar.yaml +75 -0
  54. package/shell/index.js +2 -0
@@ -0,0 +1,198 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ admin-shell — Bespoke shell-tier children (Phase 2 of ADR-0023)
3
+
4
+ The admin-* CSS-only structural children are styled by SHARING the
5
+ same CSS rules as their legacy raw-HTML counterparts. This file
6
+ re-applies the existing selectors (main / section / header / footer)
7
+ to the new bespoke tags via display + structural mappings.
8
+
9
+ Rather than duplicate every rule in main.css / sidebar.css /
10
+ templates.css, we declare the bespoke tags as `display: contents` or
11
+ the relevant layout box, then let the existing selectors (which
12
+ already use :is() lifts for legacy + slot-vocabulary) match.
13
+
14
+ For Phase 2, the simplest map: each bespoke tag mimics its legacy
15
+ counterpart's display behavior. The host shell.css already handles
16
+ admin-shell flex layout; main.css handles main-as-column; sidebar.css
17
+ handles sidebar geometry.
18
+ ═══════════════════════════════════════════════════════════════ */
19
+
20
+ /* ── admin-content ≡ <main> ── */
21
+ admin-shell > admin-content {
22
+ display: flex;
23
+ flex-direction: column;
24
+ flex: 1;
25
+ min-width: 0;
26
+ min-height: 0;
27
+ border-inline: var(--page-main-border);
28
+ }
29
+
30
+ /* ── admin-topbar ≡ <header-ui> at shell tier ── */
31
+ admin-content > admin-topbar,
32
+ admin-shell > admin-topbar,
33
+ :is([data-sidebar], aside-ui[slot="leading"], aside-ui[slot="trailing"], admin-sidebar) > admin-topbar {
34
+ display: flex;
35
+ align-items: center;
36
+ gap: var(--page-header-gap);
37
+ padding: 0 var(--page-header-px);
38
+ height: var(--page-header-height);
39
+ font-size: var(--page-header-font);
40
+ border-bottom: var(--page-border);
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ /* ── admin-statusbar ≡ <footer-ui> at shell tier ── */
45
+ admin-content > admin-statusbar,
46
+ admin-shell > admin-statusbar,
47
+ :is([data-sidebar], aside-ui[slot="leading"], aside-ui[slot="trailing"], admin-sidebar) > admin-statusbar {
48
+ display: flex;
49
+ align-items: center;
50
+ gap: var(--page-header-gap);
51
+ padding: 0 var(--page-header-px);
52
+ height: var(--page-header-height);
53
+ font-size: var(--page-header-font);
54
+ color: var(--page-header-fg-muted);
55
+ border-top: var(--page-border);
56
+ flex-shrink: 0;
57
+ }
58
+
59
+ /* ── admin-scroll ≡ <section> child of <main> ── */
60
+ admin-content > admin-scroll {
61
+ flex: 1;
62
+ min-height: 0;
63
+ overflow-y: auto;
64
+ overscroll-behavior: contain;
65
+ background: var(--page-content-bg);
66
+ border-inline: var(--page-content-border);
67
+ box-shadow: var(--page-content-shadow);
68
+ }
69
+
70
+ admin-shell[mode~="rounded"] > admin-content > admin-scroll {
71
+ border-radius: var(--page-content-radius);
72
+ }
73
+
74
+ /* ── admin-page ≡ <article data-content-root> ── */
75
+ admin-scroll > admin-page,
76
+ admin-content > admin-page {
77
+ display: flex;
78
+ flex-direction: column;
79
+ min-height: 100%;
80
+ container-type: inline-size;
81
+ container-name: page-content;
82
+ }
83
+
84
+ /* ── admin-page-header ≡ <[data-content-header]> sticky band ── */
85
+ admin-page > admin-page-header {
86
+ position: sticky;
87
+ top: 0;
88
+ z-index: 1;
89
+ background: var(--page-content-bg);
90
+ border-bottom: var(--page-content-border);
91
+ flex-shrink: 0;
92
+ }
93
+
94
+ /* ── admin-page-body ≡ <[data-content-body]> centered body ── */
95
+ admin-page > admin-page-body {
96
+ flex: 1;
97
+ display: flex;
98
+ flex-direction: column;
99
+ }
100
+
101
+ /* ── admin-sidebar — bridge to existing sidebar.css selectors ──
102
+ Rather than expand every :is([data-sidebar], aside-ui[slot=…], …)
103
+ selector in sidebar.css with `, admin-sidebar[slot=…]`, we apply the
104
+ core sidebar geometry + container query rules here. The remaining
105
+ slot-routing rules in sidebar.css (header/footer chrome, section,
106
+ nav-ui colors) match by descendant selector rather than parent
107
+ tag, so they pick up admin-sidebar children automatically. */
108
+
109
+ :is(admin-sidebar[slot="leading"], admin-sidebar[slot="trailing"]) {
110
+ display: flex;
111
+ flex-direction: column;
112
+ flex-shrink: 0;
113
+ min-width: var(--page-sidebar-min-width);
114
+ max-width: var(--page-sidebar-max-width);
115
+ min-height: 0;
116
+ font-size: var(--page-sidebar-font);
117
+ position: relative;
118
+ container-type: inline-size;
119
+ container-name: sidebar;
120
+ transition: width var(--page-duration) var(--page-easing);
121
+ background: var(--page-bg);
122
+ }
123
+
124
+ admin-sidebar[slot="leading"] {
125
+ width: var(--page-sidebar-width-leading);
126
+ border-right: var(--page-border);
127
+ }
128
+
129
+ admin-sidebar[slot="trailing"] {
130
+ width: var(--page-sidebar-width-trailing);
131
+ border-left: var(--page-border);
132
+ }
133
+
134
+ /* Resize handle — same shape as legacy [data-sidebar] > [data-resize] */
135
+ :is(admin-sidebar[slot="leading"], admin-sidebar[slot="trailing"]) > [data-resize] {
136
+ position: absolute;
137
+ top: 0;
138
+ bottom: 0;
139
+ width: 6px;
140
+ cursor: col-resize;
141
+ z-index: 1;
142
+ user-select: none;
143
+ }
144
+
145
+ admin-sidebar[slot="leading"] > [data-resize] { right: -3px; }
146
+ admin-sidebar[slot="trailing"] > [data-resize] { left: -3px; }
147
+
148
+ :is(admin-sidebar[slot="leading"], admin-sidebar[slot="trailing"]) > [data-resize]:hover {
149
+ background: var(--page-sidebar-resize-accent);
150
+ opacity: 0.5;
151
+ }
152
+
153
+ admin-sidebar[resizing] {
154
+ transition: none;
155
+ }
156
+
157
+ admin-sidebar[resizing] > [data-resize] {
158
+ background: var(--page-sidebar-resize-accent);
159
+ opacity: 0.8;
160
+ }
161
+
162
+ /* When collapsed, suppress text labels in slot vocabulary children
163
+ inside the sidebar via the bespoke [collapsed] reflected attribute */
164
+ admin-sidebar[collapsed] {
165
+ /* Container query in collapsed.css already handles narrow-mode children;
166
+ this rule is a backup for browsers without container query support. */
167
+ }
168
+
169
+ /* ── Slot vocabulary inside topbar/statusbar ──
170
+ Uniform action-cluster routing — same shape used inside
171
+ header-ui, footer-ui, and now admin-topbar/admin-statusbar. */
172
+
173
+ :is(admin-topbar, admin-statusbar) {
174
+ /* Default: action cluster pushes itself + siblings to the end */
175
+ }
176
+
177
+ :is(admin-topbar, admin-statusbar) > [slot="action"]:first-of-type {
178
+ margin-inline-start: auto;
179
+ }
180
+
181
+ :is(admin-topbar, admin-statusbar) > [slot="action-leading"] {
182
+ margin-inline-end: var(--page-actions-gap);
183
+ }
184
+
185
+ :is(admin-topbar, admin-statusbar) > [slot="icon"] {
186
+ color: var(--page-header-fg-muted);
187
+ flex-shrink: 0;
188
+ }
189
+
190
+ :is(admin-topbar, admin-statusbar) > [slot="heading"] {
191
+ font-weight: var(--a-weight-medium, 500);
192
+ color: var(--a-fg);
193
+ }
194
+
195
+ :is(admin-topbar, admin-statusbar) > [slot="description"] {
196
+ color: var(--page-header-fg-muted);
197
+ font-size: var(--a-ui-sm);
198
+ }
@@ -89,6 +89,16 @@
89
89
  --page-font-family: var(--a-font-family);
90
90
  --page-body-size: var(--a-body-size);
91
91
 
92
+ /* ── Nav tokens — shell-context overrides ──
93
+ These are NOT the canonical nav tokens. The canonical tokens live in
94
+ each nav primitive's @scope :where():
95
+ packages/web-components/components/nav/nav.css
96
+ packages/web-components/components/nav-group/nav-group.css
97
+ packages/web-components/components/nav-item/nav-item.css
98
+ The overrides below adjust nav presentation specifically when nested
99
+ inside <admin-shell>. Outside the shell, nav primitives fall back to
100
+ their own :where() declarations. */
101
+
92
102
  /* Nav — root container tokens */
93
103
  --nav-duration: var(--a-duration);
94
104
  --nav-duration-fast: var(--a-duration-fast);
@@ -0,0 +1,138 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/AdminSidebar.json",
4
+ "title": "AdminSidebar",
5
+ "description": "Module-tier shell sidebar — owns resize, snap-to-collapsed, persistence,\nand the [collapsed] reflected attribute. Sits inside <admin-shell> as\nslot=\"leading\" or slot=\"trailing\". Authors compose chrome bars + content\ninside via slot vocabulary.\n\nThis is the bespoke web-component replacement for the legacy\n<aside data-sidebar> shape. <admin-shell> still recognizes the legacy\nshape via :is() selector for backwards compat. New code should prefer\n<admin-sidebar>.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "collapsed": {
17
+ "description": "Reflected — set when the sidebar's measured width is at or below\n96px. Consumers query this to style \"collapsed mode\" without\nduplicating threshold math.\n",
18
+ "type": "boolean",
19
+ "default": false
20
+ },
21
+ "collapsible": {
22
+ "description": "Opts in to programmatic collapse — toggle button wiring + the\n.toggle() / .collapse() / .expand() public methods.\n",
23
+ "type": "boolean",
24
+ "default": false
25
+ },
26
+ "component": {
27
+ "const": "AdminSidebar"
28
+ },
29
+ "min-width": {
30
+ "description": "Optional override for the snap-floor width. Defaults to reading\nCSS min-width via getComputedStyle.\n",
31
+ "type": "string",
32
+ "default": ""
33
+ },
34
+ "name": {
35
+ "description": "Identifier for localStorage namespacing. Defaults to slot value\n(\"leading\" or \"trailing\"). Override when running multiple sidebars\nwith the same slot.\n",
36
+ "type": "string",
37
+ "default": ""
38
+ },
39
+ "resizable": {
40
+ "description": "Opts in to drag-to-resize behavior. Author supplies a child\n[data-resize] element as the drag handle.\n",
41
+ "type": "boolean",
42
+ "default": false
43
+ },
44
+ "resizing": {
45
+ "description": "Reflected — set during an active pointer-drag on the resize handle.\nUseful for suppressing transitions while dragging.\n",
46
+ "type": "boolean",
47
+ "default": false
48
+ }
49
+ },
50
+ "required": [
51
+ "component"
52
+ ],
53
+ "unevaluatedProperties": false,
54
+ "x-adiaui": {
55
+ "anti_patterns": [],
56
+ "category": "layout",
57
+ "events": {
58
+ "sidebar-resize": {
59
+ "description": "Bubbles when an active pointer-drag releases.",
60
+ "detail": {
61
+ "name": "string",
62
+ "width": "number"
63
+ }
64
+ },
65
+ "sidebar-toggle": {
66
+ "description": "Bubbles when sidebar collapses or expands.",
67
+ "detail": {
68
+ "expanded": "boolean",
69
+ "name": "string"
70
+ }
71
+ }
72
+ },
73
+ "examples": [],
74
+ "keywords": [
75
+ "admin-sidebar",
76
+ "sidebar",
77
+ "aside",
78
+ "rail",
79
+ "panel",
80
+ "leading",
81
+ "trailing",
82
+ "inspector",
83
+ "nav"
84
+ ],
85
+ "name": "AdminSidebar",
86
+ "related": [
87
+ "AdminShell",
88
+ "AdminCommand",
89
+ "Aside",
90
+ "Nav",
91
+ "NavGroup",
92
+ "NavItem"
93
+ ],
94
+ "slots": {
95
+ "default": {
96
+ "description": "Default content — typically a <nav-ui> for navigation, or a list / tree for the trailing inspector pattern."
97
+ },
98
+ "footer": {
99
+ "description": "Bottom chrome bar (user select, status indicator, etc.)."
100
+ },
101
+ "header": {
102
+ "description": "Top chrome bar (workspace select, breadcrumb, etc.)."
103
+ }
104
+ },
105
+ "states": [
106
+ {
107
+ "description": "Default, expanded.",
108
+ "name": "idle"
109
+ },
110
+ {
111
+ "description": "Sidebar width is at or below the snap threshold; CSS container queries flip child layout to icon-only mode.",
112
+ "attribute": "collapsed",
113
+ "name": "collapsed"
114
+ },
115
+ {
116
+ "description": "Active pointer-drag in progress.",
117
+ "attribute": "resizing",
118
+ "name": "resizing"
119
+ }
120
+ ],
121
+ "synonyms": {
122
+ "collapsed": [
123
+ "minimized",
124
+ "narrow",
125
+ "icon-only"
126
+ ],
127
+ "sidebar": [
128
+ "aside",
129
+ "rail",
130
+ "panel"
131
+ ]
132
+ },
133
+ "tag": "admin-sidebar",
134
+ "tokens": {},
135
+ "traits": [],
136
+ "version": 1
137
+ }
138
+ }
@@ -0,0 +1,76 @@
1
+ <header>
2
+ <div>
3
+ <h1>Admin Sidebar</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">admin-sidebar</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>Module-tier shell sidebar — owns resize, snap-to-collapsed, persistence, and the <code>[collapsed]</code> reflected attribute. Sits inside <code>&lt;admin-shell&gt;</code> as <code>slot="leading"</code> or <code>slot="trailing"</code>. Authors compose chrome bars + content inside via slot vocabulary.</p>
9
+ </header>
10
+
11
+ <section data-section>
12
+ <h2 variant="section">Basic shape</h2>
13
+ <p data-note>Drop into <code>&lt;admin-shell&gt;</code> as a slotted child. Add <code>resizable</code> to wire the drag handle, <code>collapsible</code> to wire programmatic collapse.</p>
14
+ <code-ui language="html">&lt;admin-sidebar slot="leading" resizable collapsible&gt;
15
+ &lt;admin-topbar slot="header"&gt;…&lt;/admin-topbar&gt;
16
+ &lt;nav-ui&gt;…&lt;/nav-ui&gt;
17
+ &lt;admin-statusbar slot="footer"&gt;…&lt;/admin-statusbar&gt;
18
+ &lt;div data-resize&gt;&lt;/div&gt;
19
+ &lt;/admin-sidebar&gt;</code-ui>
20
+ </section>
21
+
22
+ <section data-section>
23
+ <h2 variant="section">State as attribute</h2>
24
+ <p>The sidebar reflects its state on the element itself — no <code>data-*</code> proxy attributes, no threshold math from the outside.</p>
25
+ <table>
26
+ <thead><tr><th>Attribute</th><th>When set</th><th>Use for</th></tr></thead>
27
+ <tbody>
28
+ <tr><td><code>collapsed</code></td><td>Width is at or below 96px (snap floor)</td><td>CSS <code>:has(admin-sidebar[collapsed])</code> selectors; JS <code>.hasAttribute('collapsed')</code></td></tr>
29
+ <tr><td><code>resizing</code></td><td>Active pointer-drag</td><td>Suppress transitions during drag</td></tr>
30
+ </tbody>
31
+ </table>
32
+ <p data-note>The reflection is round-tripped — set <code>collapsed</code> programmatically and the sidebar will width-snap; release the attribute and it expands to the previously-saved width.</p>
33
+ </section>
34
+
35
+ <section data-section>
36
+ <h2 variant="section">Public methods</h2>
37
+ <table>
38
+ <thead><tr><th>Method</th><th>Effect</th></tr></thead>
39
+ <tbody>
40
+ <tr><td><code>.toggle()</code></td><td>Flip collapsed state. Returns the new <code>collapsed</code> value.</td></tr>
41
+ <tr><td><code>.collapse()</code></td><td>Force collapsed (idempotent if already collapsed).</td></tr>
42
+ <tr><td><code>.expand()</code></td><td>Restore the previous expanded width.</td></tr>
43
+ </tbody>
44
+ </table>
45
+ </section>
46
+
47
+ <section data-section>
48
+ <h2 variant="section">Events</h2>
49
+ <table>
50
+ <thead><tr><th>Event</th><th>Detail</th></tr></thead>
51
+ <tbody>
52
+ <tr><td><code>sidebar-toggle</code></td><td><code>{ name, expanded }</code> — bubbles when collapsed/expanded</td></tr>
53
+ <tr><td><code>sidebar-resize</code></td><td><code>{ name, width }</code> — bubbles after a pointer-drag releases</td></tr>
54
+ </tbody>
55
+ </table>
56
+ </section>
57
+
58
+ <section data-section>
59
+ <h2 variant="section">Properties</h2>
60
+ <table>
61
+ <thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
62
+ <tbody>
63
+ <tr><td><code>resizable</code></td><td>boolean</td><td><code>false</code></td><td>Opts in to drag-to-resize. Author supplies a child <code>[data-resize]</code> element.</td></tr>
64
+ <tr><td><code>collapsible</code></td><td>boolean</td><td><code>false</code></td><td>Opts in to <code>.toggle()</code>/<code>.collapse()</code>/<code>.expand()</code>.</td></tr>
65
+ <tr><td><code>name</code></td><td>string</td><td>(slot value)</td><td>localStorage namespace override.</td></tr>
66
+ <tr><td><code>min-width</code></td><td>string</td><td>(CSS min-width)</td><td>Override for the snap-floor width.</td></tr>
67
+ <tr><td><code>collapsed</code></td><td>boolean</td><td>—</td><td>Reflected — set when width ≤ 96px.</td></tr>
68
+ <tr><td><code>resizing</code></td><td>boolean</td><td>—</td><td>Reflected — set during active drag.</td></tr>
69
+ </tbody>
70
+ </table>
71
+ </section>
72
+
73
+ <section data-section>
74
+ <h2 variant="section">Persistence</h2>
75
+ <p>Width is saved to <code>localStorage</code> on every drag release + every toggle, under the key <code>adia-sidebar-{name}</code> (where <code>name</code> defaults to the slot value). On reconnect, the saved width is restored — the &ldquo;previous expanded width&rdquo; tracker preserves the user's preferred expanded size across collapse cycles.</p>
76
+ </section>
@@ -0,0 +1,47 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="auto">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Admin Sidebar — AdiaUI</title>
7
+
8
+ <!-- Token base -->
9
+ <link rel="stylesheet" href="../../../web-components/styles/resets.css">
10
+ <link rel="stylesheet" href="../../../web-components/styles/tokens.css">
11
+
12
+ <!-- Component CSS — admin-sidebar inherits from admin-shell tokens
13
+ when nested inside one; standalone styling below for the demo. -->
14
+ <link rel="stylesheet" href="../admin-shell/admin-shell.css">
15
+ <link rel="stylesheet" href="../../../web-components/components/code/code.css">
16
+ <link rel="stylesheet" href="../../../web-components/components/tag/tag.css">
17
+
18
+ <!-- Component JS -->
19
+ <script type="module" src="./admin-sidebar.js"></script>
20
+ <script type="module" src="../../../web-components/components/code/code.js"></script>
21
+ <script type="module" src="../../../web-components/components/tag/tag.js"></script>
22
+
23
+ <style>
24
+ :where(html, body) { margin: 0; min-height: 100vh; background: var(--a-bg); color: var(--a-fg); font-family: var(--a-font); }
25
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
26
+ </style>
27
+ </head>
28
+ <body>
29
+
30
+ <main id="demo-root">
31
+ <p>Loading examples…</p>
32
+ </main>
33
+
34
+ <script type="module">
35
+ const root = document.getElementById('demo-root');
36
+ try {
37
+ const res = await fetch('./admin-sidebar.examples.html');
38
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
39
+ root.innerHTML = await res.text();
40
+ } catch (err) {
41
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load admin-sidebar.examples.html — ${err.message}</p>`;
42
+ console.error('[admin-sidebar.html]', err);
43
+ }
44
+ </script>
45
+
46
+ </body>
47
+ </html>