@celestia-island/hikari 0.55.168 → 0.55.170
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/package.json
CHANGED
|
@@ -255,15 +255,31 @@ describe("HkAdminHeader", () => {
|
|
|
255
255
|
const centre = c.querySelector(".s-admin-header-center");
|
|
256
256
|
expect(centre, "the centre wrapper must render when the slot is provided").not.toBeNull();
|
|
257
257
|
expect(centre?.querySelector(".centre-stub")?.textContent).toBe("filter group");
|
|
258
|
-
// Wing order: identity (left) → centre → actions (right).
|
|
258
|
+
// Wing order: identity (left) → centre → actions (right). The wings
|
|
259
|
+
// carry their chrome class PLUS the shared balanced-grid wing class,
|
|
260
|
+
// so match per-class instead of whole-className equality.
|
|
259
261
|
const header = c.querySelector("header")!;
|
|
260
262
|
const kids = [...header.children].map((el) => el.className);
|
|
261
|
-
|
|
262
|
-
expect(
|
|
263
|
+
const wingIdx = (cls: string) => kids.findIndex((c) => c.split(/\s+/).includes(cls));
|
|
264
|
+
expect(wingIdx("s-admin-header-user")).toBeLessThan(wingIdx("s-admin-header-center"));
|
|
265
|
+
expect(wingIdx("s-admin-header-center")).toBeLessThan(wingIdx("s-admin-header-actions"));
|
|
266
|
+
// The header hangs the shared balanced-grid contract — the same
|
|
267
|
+
// geometry the chat frontend's header uses (user report 2026-10-15:
|
|
268
|
+
// the console strip sat left of centre on phones).
|
|
269
|
+
expect(header.className).toContain("s-balanced-header");
|
|
270
|
+
expect(kids.find((c) => c.includes("s-admin-header-user"))).toContain("s-header-wing-start");
|
|
271
|
+
expect(kids.find((c) => c.includes("s-admin-header-center"))).toContain("s-header-wing-center");
|
|
272
|
+
expect(kids.find((c) => c.includes("s-admin-header-actions"))).toContain("s-header-wing-end");
|
|
263
273
|
});
|
|
264
274
|
|
|
265
275
|
it("renders no centre wrapper without the slot (DOM unchanged for hosts that skip it)", () => {
|
|
266
276
|
const c = mount(headerNode({ title: "Providers" }));
|
|
267
277
|
expect(c.querySelector(".s-admin-header-center")).toBeNull();
|
|
278
|
+
// Centre-less hosts are the MAJORITY of admin pages: the actions wing
|
|
279
|
+
// must still carry its explicit grid-column class, or auto-placement
|
|
280
|
+
// drops it into the empty middle track and it drifts to the viewport
|
|
281
|
+
// centre (R2, 2026-10-15 — the class IS the column).
|
|
282
|
+
const actions = c.querySelector(".s-admin-header-actions");
|
|
283
|
+
expect(actions?.className).toContain("s-header-wing-end");
|
|
268
284
|
});
|
|
269
285
|
});
|
|
@@ -162,24 +162,36 @@ export const HkAdminHeader = defineComponent({
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
// The header hangs the shared three-zone geometry (grid: two equal
|
|
166
|
+
// side tracks around a shrinkable centre) — the same contract the
|
|
167
|
+
// chat frontend top bar uses, so a page header-centre group sits on
|
|
168
|
+
// the true viewport middle on BOTH faces at every width. (Comment
|
|
169
|
+
// lives OUTSIDE the class expression: the self-sufficiency audit
|
|
170
|
+
// reads that expression's literals, and prose apostrophes inside it
|
|
171
|
+
// parse as string boundaries.)
|
|
165
172
|
return () => (
|
|
166
173
|
<header
|
|
167
174
|
class={[
|
|
168
175
|
"s-glass-header",
|
|
176
|
+
"s-balanced-header",
|
|
169
177
|
props.compact ? "s-glass-header--compact" : "",
|
|
170
178
|
]}
|
|
171
179
|
>
|
|
172
|
-
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
<div ref={userTriggerRef} class="s-admin-header-user s-header-wing-start">
|
|
181
|
+
{/* The hamburger rides INSIDE the left wing: the balanced grid
|
|
182
|
+
* above owns the header's columns, and a fourth in-flow child
|
|
183
|
+
* would fall into the left wing's track and skew every column
|
|
184
|
+
* after it. Inside the wing it keeps its place (leftmost, ahead
|
|
185
|
+
* of the avatar) at the wing's own 16px rhythm. */}
|
|
186
|
+
{props.showHamburger && (
|
|
187
|
+
<HButton
|
|
188
|
+
variant="ghost"
|
|
189
|
+
size="sm"
|
|
190
|
+
onClick={() => emit("hamburger")}
|
|
191
|
+
>
|
|
192
|
+
<Menu size={20} class="s-admin-header-hamburger-icon" />
|
|
193
|
+
</HButton>
|
|
194
|
+
)}
|
|
183
195
|
<button
|
|
184
196
|
class="s-admin-header-avatar"
|
|
185
197
|
aria-label={props.avatarTriggerLabel ?? t("hikari::adminHeader.avatarTrigger", "Account menu")}
|
|
@@ -284,19 +296,19 @@ export const HkAdminHeader = defineComponent({
|
|
|
284
296
|
</HkMenu>
|
|
285
297
|
|
|
286
298
|
{/* Page-owned centre group (page filter tab strips, segmented
|
|
287
|
-
* option pickers) — the console face of the balanced
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
* the host provides it, so headers without a centre keep
|
|
292
|
-
* exact DOM they always had. */}
|
|
299
|
+
* option pickers) — the console face of the balanced header the
|
|
300
|
+
* chat frontend's top bar already uses: the shared grid pins
|
|
301
|
+
* this column to the true viewport middle and lets the strip
|
|
302
|
+
* slide inside its own box when space runs short. Rendered only
|
|
303
|
+
* when the host provides it, so headers without a centre keep
|
|
304
|
+
* the exact DOM they always had. */}
|
|
293
305
|
{slots.center && (
|
|
294
|
-
<div class="s-admin-header-center">
|
|
306
|
+
<div class="s-admin-header-center s-header-wing-center">
|
|
295
307
|
{slots.center()}
|
|
296
308
|
</div>
|
|
297
309
|
)}
|
|
298
310
|
|
|
299
|
-
<div class="s-admin-header-actions">
|
|
311
|
+
<div class="s-admin-header-actions s-header-wing-end">
|
|
300
312
|
{props.showEmergencyStop && (
|
|
301
313
|
<button
|
|
302
314
|
class={[
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineComponent, h, type Component, type PropType } from "vue";
|
|
2
2
|
|
|
3
3
|
import { HNavItem, HSidebar } from "@celestia-island/hikari";
|
|
4
|
-
import { ChartBarBig as BarChart3, Bell, Bot, Box, Cable, Cpu, FileText, FolderOpen, Gauge, Key, Layers, LayoutDashboard, Mic, Monitor, Send, Settings, Share2, Shield, Webhook, Zap } from "lucide-vue-next";
|
|
4
|
+
import { ChartBarBig as BarChart3, Bell, Bot, Box, Cable, Cloud, Cpu, FileText, FolderOpen, Gauge, Key, Layers, LayoutDashboard, Mic, Monitor, Send, Settings, Share2, Shield, Webhook, Zap } from "lucide-vue-next";
|
|
5
5
|
|
|
6
6
|
interface NavItem {
|
|
7
7
|
key: string;
|
|
@@ -93,20 +93,59 @@ describe("admin header chrome geometry (the two user-requested fixes)", () => {
|
|
|
93
93
|
const rule = ruleDeclarations(adminTokens, ".s-admin-header-user");
|
|
94
94
|
expect(rule, ".s-admin-header-user must be declared").not.toBeNull();
|
|
95
95
|
expect(rule).toContainEqual(["gap", "var(--space-16)"]);
|
|
96
|
-
// Balanced left wing (the centre group stays viewport-centred).
|
|
97
|
-
expect(rule).toContainEqual(["flex", "1 1 0"]);
|
|
98
96
|
});
|
|
99
97
|
|
|
100
|
-
it("
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
it("hangs the shared balanced-header grid contract (the ONE header layout)", () => {
|
|
99
|
+
// User report 2026-10-15: the console's header-centre tab strip sat
|
|
100
|
+
// LEFT of centre on phones (drawer mode hides the title, so the left
|
|
101
|
+
// wing is just the avatar while three icon buttons sit right) while
|
|
102
|
+
// the frontend's strip read centred — two per-band flex dialects had
|
|
103
|
+
// drifted from the same idea. Both faces now hang the ONE grid
|
|
104
|
+
// contract: two EQUAL 1fr side tracks (true centring regardless of
|
|
105
|
+
// wing content) with min-content floors (wings can never be squeezed
|
|
106
|
+
// out of existence) around a shrinkable centre column (the strip
|
|
107
|
+
// slides inside its own box, edge fades + swipe).
|
|
108
|
+
const balanced = ruleDeclarations(adminTokens, ".s-balanced-header");
|
|
109
|
+
expect(balanced, ".s-balanced-header must be declared").not.toBeNull();
|
|
110
|
+
expect(balanced).toContainEqual([
|
|
111
|
+
"grid-template-columns",
|
|
112
|
+
"minmax(min-content, 1fr) minmax(0, auto) minmax(min-content, 1fr)",
|
|
113
|
+
]);
|
|
114
|
+
const start = ruleDeclarations(adminTokens, ".s-header-wing-start");
|
|
115
|
+
expect(start, ".s-header-wing-start must be declared").not.toBeNull();
|
|
116
|
+
// Each wing names its column EXPLICITLY: with auto-placement a
|
|
117
|
+
// centre-less host (the vast majority of admin pages — most never
|
|
118
|
+
// register a centre group) renders only two in-flow children and the
|
|
119
|
+
// actions wing would fall into the MIDDLE track, drifting to the
|
|
120
|
+
// viewport centre instead of hugging the right edge (R2, 2026-10-15).
|
|
121
|
+
expect(start).toContainEqual(["grid-column", "1"]);
|
|
122
|
+
expect(start).toContainEqual(["justify-self", "start"]);
|
|
123
|
+
expect(start).toContainEqual(["overflow", "hidden"]);
|
|
124
|
+
const centre = ruleDeclarations(adminTokens, ".s-header-wing-center");
|
|
125
|
+
expect(centre, ".s-header-wing-center must be declared").not.toBeNull();
|
|
126
|
+
// Default stretch, NOT justify-self: center: a centered item sizes by
|
|
127
|
+
// fit-content, whose min-content floor (the full strip width) punches
|
|
128
|
+
// the item past a shrunken middle track — the strip would paint over
|
|
129
|
+
// the wings instead of scrolling inside its own box.
|
|
130
|
+
expect(centre).toContainEqual(["grid-column", "2"]);
|
|
131
|
+
expect(centre).toContainEqual(["min-width", "0"]);
|
|
132
|
+
expect(centre).not.toContainEqual(["justify-self", "center"]);
|
|
133
|
+
const end = ruleDeclarations(adminTokens, ".s-header-wing-end");
|
|
134
|
+
expect(end, ".s-header-wing-end must be declared").not.toBeNull();
|
|
135
|
+
expect(end).toContainEqual(["grid-column", "3"]);
|
|
136
|
+
expect(end).toContainEqual(["justify-self", "end"]);
|
|
137
|
+
expect(end).toContainEqual(["overflow", "hidden"]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("keeps the wings free of their own flex-geometry dialect (the grid owns it)", () => {
|
|
141
|
+
// The flex era's per-wing declarations must stay gone: any return of
|
|
142
|
+
// `flex` on a wing re-introduces a second geometry that drifts from
|
|
143
|
+
// the shared grid (the 2026-10-15 skew).
|
|
144
|
+
expect(ruleDeclarations(adminTokens, ".s-admin-header-user")).not.toContainEqual(["flex", "1 1 0"]);
|
|
145
|
+
expect(ruleDeclarations(adminTokens, ".s-admin-header-actions")).not.toContainEqual(["flex", "1 1 0"]);
|
|
146
|
+
expect(ruleDeclarations(adminTokens, ".s-admin-header-center")).not.toContainEqual(["flex", "0 1 auto"]);
|
|
105
147
|
// The old push would fight the centre wing for the middle.
|
|
106
|
-
expect(actions).not.toContainEqual(["margin-left", "auto"]);
|
|
107
|
-
const centre = ruleDeclarations(adminTokens, ".s-admin-header-center");
|
|
108
|
-
expect(centre, ".s-admin-header-center must be declared").not.toBeNull();
|
|
109
|
-
expect(centre).toContainEqual(["flex", "0 1 auto"]);
|
|
148
|
+
expect(ruleDeclarations(adminTokens, ".s-admin-header-actions")).not.toContainEqual(["margin-left", "auto"]);
|
|
110
149
|
});
|
|
111
150
|
|
|
112
151
|
it("keeps the 28px icon-button step at the theme toggle's own box", () => {
|
|
@@ -120,25 +159,20 @@ describe("admin header chrome geometry (the two user-requested fixes)", () => {
|
|
|
120
159
|
expect(iconButton).toMatch(/PropType<16 \| 24 \| 28 \| 32 \| 36 \| 40>/);
|
|
121
160
|
});
|
|
122
161
|
|
|
123
|
-
it("
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
// inside its own box instead of over the avatar.
|
|
162
|
+
it("keeps the phone band free of ad-hoc wing overrides (one geometry at every width)", () => {
|
|
163
|
+
// The 2026-10-12 band pinned the wings and handed the leftover to
|
|
164
|
+
// the centre; it fixed the avatar overlap but skewed the strip off
|
|
165
|
+
// the viewport middle (user report 2026-10-15). The shared grid's
|
|
166
|
+
// min-content floors + shrinkable centre column handle phones
|
|
167
|
+
// intrinsically, so no per-band flex override may come back.
|
|
130
168
|
const userRules = allRuleDeclarations(adminTokens, ".s-admin-header-user");
|
|
131
169
|
const centreRules = allRuleDeclarations(adminTokens, ".s-admin-header-center");
|
|
132
170
|
const actionsRules = allRuleDeclarations(adminTokens, ".s-admin-header-actions");
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
expect(phone(actionsRules)[0]).toContainEqual(["flex", "0 0 auto"]);
|
|
140
|
-
expect(phone(centreRules)[0]).toContainEqual(["flex", "1 1 auto"]);
|
|
141
|
-
expect(phone(centreRules)[0]).toContainEqual(["min-width", "0"]);
|
|
142
|
-
expect(phone(centreRules)[0]).toContainEqual(["overflow", "hidden"]);
|
|
171
|
+
for (const [name, rules] of [["user", userRules], ["centre", centreRules], ["actions", actionsRules]] as const) {
|
|
172
|
+
expect(rules.filter((r) => r.nested), `${name}: no band-nested rules may remain`).toHaveLength(0);
|
|
173
|
+
for (const r of rules) {
|
|
174
|
+
expect(r.decls.map((d) => d[0]), `${name}: no flex geometry may remain`).not.toContain("flex");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
143
177
|
});
|
|
144
178
|
});
|
|
@@ -413,6 +413,74 @@
|
|
|
413
413
|
padding: 0 var(--space-16);
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
+
/* ── Balanced header columns (the ONE three-zone header layout) ─────────
|
|
417
|
+
* The shared geometry behind every top bar that owns a header-centre
|
|
418
|
+
* group: the frontend chat header (chest ChatLayout's .s-header-bar-*)
|
|
419
|
+
* and the console header (HkAdminHeader's .s-admin-header-*) both hang
|
|
420
|
+
* these classes next to their own chrome classes, so the two faces can
|
|
421
|
+
* never drift apart again (user report 2026-10-15: the console's
|
|
422
|
+
* header-centre tab strip sat LEFT of centre on phones while the
|
|
423
|
+
* frontend's strip read centred — two per-band flex dialects had grown
|
|
424
|
+
* from the same idea).
|
|
425
|
+
*
|
|
426
|
+
* Grid, not flex: two EQUAL 1fr side tracks pin the middle column to the
|
|
427
|
+
* true viewport middle no matter how lopsided the wings' CONTENT is
|
|
428
|
+
* (avatar-only left vs three icon buttons right — exactly the console's
|
|
429
|
+
* phone case, where the drawer mode hides the title and the left wing is
|
|
430
|
+
* just the 28px trigger). Flex wings grow from flex-basis 0, so equal
|
|
431
|
+
* growth centred the group only while spare space lasted; each band then
|
|
432
|
+
* grew its own ad-hoc override and each override skewed in SOME band.
|
|
433
|
+
* `minmax(min-content, 1fr)` gives each wing a hard content floor, so an
|
|
434
|
+
* overflowing centre column (a wide tab strip) can never squeeze the
|
|
435
|
+
* avatar/action wings out of existence — the 2026-10-12 phone incident
|
|
436
|
+
* class — and the centre column is `minmax(0, auto)`, so IT soaks the
|
|
437
|
+
* squeeze instead: the strip narrows while STAYING centred, and its
|
|
438
|
+
* internal HkTabs scroller takes over (edge fades + swipe, the frontend
|
|
439
|
+
* over-wide-strip behavior) without ever covering a wing. */
|
|
440
|
+
.s-balanced-header {
|
|
441
|
+
display: grid;
|
|
442
|
+
grid-template-columns: minmax(min-content, 1fr) minmax(0, auto) minmax(min-content, 1fr);
|
|
443
|
+
align-items: center;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* Each wing names its column EXPLICITLY: the header's in-flow children are
|
|
447
|
+
* exactly these three zones (every other child teleports out), but a
|
|
448
|
+
* centre-less host renders only two of them — with auto-placement the
|
|
449
|
+
* actions wing would fall into the MIDDLE track and drift to the viewport
|
|
450
|
+
* centre (R2 finding, 2026-10-15), because the trailing 1fr track would
|
|
451
|
+
* sit empty. Naming the columns makes the contract positional by class,
|
|
452
|
+
* not by child order or count: a centre-less header lays out as
|
|
453
|
+
* [user | empty | actions] exactly like the old flex bar did. */
|
|
454
|
+
.s-header-wing-start {
|
|
455
|
+
grid-column: 1;
|
|
456
|
+
justify-self: start;
|
|
457
|
+
min-width: 0;
|
|
458
|
+
/* A wing whose content floors exceed its track must not PAINT past the
|
|
459
|
+
* wing box underneath the centre group (popup surfaces teleport to
|
|
460
|
+
* body, so clipping here never cuts a menu). */
|
|
461
|
+
overflow: hidden;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.s-header-wing-center {
|
|
465
|
+
/* Default stretch, deliberately: the strip must inherit the COLUMN's
|
|
466
|
+
* shrunken width when the middle track soaks a squeeze, so the HTabs
|
|
467
|
+
* scroller inside it takes over (edge fades + swipe). justify-self:
|
|
468
|
+
* center here would size the item by fit-content, whose min-content
|
|
469
|
+
* floor (= the full strip width) punches the item past the shrunken
|
|
470
|
+
* track and the strip paints over the wings instead of scrolling.
|
|
471
|
+
* Centring itself is the tracks' job (equal 1fr sides), not the
|
|
472
|
+
* item's. */
|
|
473
|
+
grid-column: 2;
|
|
474
|
+
min-width: 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.s-header-wing-end {
|
|
478
|
+
grid-column: 3;
|
|
479
|
+
justify-self: end;
|
|
480
|
+
min-width: 0;
|
|
481
|
+
overflow: hidden;
|
|
482
|
+
}
|
|
483
|
+
|
|
416
484
|
/* ── Admin header chrome (HkAdminHeader) ────────────────────────────────
|
|
417
485
|
* The header's own layout. Every declaration below replaces a utility
|
|
418
486
|
* class the markup used to depend on (`w-7 h-7`, `rounded-full`,
|
|
@@ -420,7 +488,10 @@
|
|
|
420
488
|
* atomic layer rendered the header without them, and a host with one
|
|
421
489
|
* (chest/UnoCSS) owned values the design system could not fix. Values are
|
|
422
490
|
* the verified computed ones (audit 2026-09-15 against chest's generated
|
|
423
|
-
* CSS), so no host's rendering changes.
|
|
491
|
+
* CSS), so no host's rendering changes.
|
|
492
|
+
* The three-zone GEOMETRY itself lives in the shared .s-balanced-header
|
|
493
|
+
* contract above — the classes below keep only their wing-INTERNAL
|
|
494
|
+
* layout (row direction, gaps, alignment) and appearance. */
|
|
424
495
|
|
|
425
496
|
.s-admin-header-user {
|
|
426
497
|
display: flex;
|
|
@@ -433,50 +504,15 @@
|
|
|
433
504
|
* The wing gap here carries the whole distance so the title text
|
|
434
505
|
* lands on the same rhythm as the panel's button content. */
|
|
435
506
|
gap: var(--space-16);
|
|
436
|
-
/* Balanced left wing (same grammar as ChatLayout's .s-header-bar-left):
|
|
437
|
-
* grows from the same flex basis as the actions wing so a centre
|
|
438
|
-
* group, when a page renders one, stays pinned to the true middle. */
|
|
439
|
-
flex: 1 1 0;
|
|
440
|
-
min-width: 0;
|
|
441
507
|
}
|
|
442
508
|
|
|
443
509
|
/* The page-owned centre group (filter tab strips): keeps its natural
|
|
444
|
-
* width and hands overflow to the HTabs scroller inside it.
|
|
510
|
+
* width and hands overflow to the HTabs scroller inside it. Column
|
|
511
|
+
* placement/shrinkage is the shared grid contract's job. */
|
|
445
512
|
.s-admin-header-center {
|
|
446
|
-
flex: 0 1 auto;
|
|
447
513
|
display: flex;
|
|
448
514
|
align-items: center;
|
|
449
515
|
justify-content: center;
|
|
450
|
-
min-width: 0;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
/* Phone band (≤767px) — mirrors ChatLayout's own ≤767px header band
|
|
455
|
-
* (the console face of the same balanced-wing header). On phones the
|
|
456
|
-
* desktop balanced wings (`flex: 1 1 0` + `min-width: 0`) let a wide
|
|
457
|
-
* centre tab strip squeeze BOTH side wings below their content floors:
|
|
458
|
-
* the avatar wing shrank under its 28px trigger and the strip painted
|
|
459
|
-
* straight over the avatar (user report 2026-10-12, L2 firewall tabs).
|
|
460
|
-
* The frontend's answer — pin both wings, hand the leftover to the
|
|
461
|
-
* centre and let its HTabs scroller own the overflow — is reproduced
|
|
462
|
-
* here in substance: the strip keeps every pixel the avatar and the action
|
|
463
|
-
* buttons don't need, and slides INSIDE its own box (edge fades + scroll
|
|
464
|
-
* limits intact) without ever covering the avatar.
|
|
465
|
-
* Desktop (>767px) keeps the balanced-wing centring untouched. */
|
|
466
|
-
@media (max-width: 767px) {
|
|
467
|
-
.s-admin-header-user {
|
|
468
|
-
flex: 0 0 auto;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
.s-admin-header-actions {
|
|
472
|
-
flex: 0 0 auto;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
.s-admin-header-center {
|
|
476
|
-
flex: 1 1 auto;
|
|
477
|
-
min-width: 0;
|
|
478
|
-
overflow: hidden;
|
|
479
|
-
}
|
|
480
516
|
}
|
|
481
517
|
|
|
482
518
|
.s-admin-header-avatar {
|
|
@@ -527,13 +563,10 @@
|
|
|
527
563
|
display: flex;
|
|
528
564
|
align-items: center;
|
|
529
565
|
gap: var(--space-6);
|
|
530
|
-
/*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
* automatic min-content floor keeps the icon buttons from being
|
|
535
|
-
* squeezed below their own width on narrow viewports. */
|
|
536
|
-
flex: 1 1 0;
|
|
566
|
+
/* The actions hug the right edge of their grid column (the old
|
|
567
|
+
* margin-left:auto push fought the centre wing for the middle; the
|
|
568
|
+
* flex-balanced `1 1 0` era before that skewed whenever the wings'
|
|
569
|
+
* contents disagreed — the shared grid contract ends both). */
|
|
537
570
|
justify-content: flex-end;
|
|
538
571
|
}
|
|
539
572
|
|