Per mara's review: '2 and maybe 1, but 3 also sounds reasonable on first
glance' (against 3 options I posted). Doing 2 and 1, leaving open()/
openNamed() as-is (option 3, tentative only).
Both dashboard/common.js and agent/app.js now export/use the
<hive-side-panel> element instance directly (sidePanel) instead of a
thin Panel = { open, openNamed, refresh, close } object that existed
purely to keep the old call-site shape unchanged. All 6 real call sites
updated to call the element's own methods directly.
The .side-panel-body class each wrapper stamped onto its own instance,
purely so common.css/agent.css's pre-existing content-styling selectors
kept matching, is gone too -- those selectors now use the element's own
tag name as the root (hive-side-panel .md, hive-side-panel .agent-inbox),
which already uniquely identifies the light-DOM instance without a
compatibility class. Verified via headless Chromium/CDP that the
tag-name selectors resolve correctly with no class needed.
Drive-by: removed an unrelated dead Panel import in call.js.
111 lines
3.3 KiB
CSS
111 lines
3.3 KiB
CSS
/* hive-side-panel.css — scoped stylesheet for the generic <hive-side-panel>
|
|
shadow-DOM custom element (hive-side-panel.js). Loaded as raw text at
|
|
build time (esbuild's `text` loader) and appended as a <style> element
|
|
inside the shadow root — see @hive/shared/shadow-css.js's header comment
|
|
for why a plain <style> tag and not adoptedStyleSheets.
|
|
|
|
Every rule here styles shadow-owned chrome this element builds itself
|
|
(backdrop, drawer, resize handle, header, title, close button) — none of
|
|
it is slotted, so this file needs zero `::slotted()`. The one slotted
|
|
node (the caller's opaque content, passed to open()/openNamed()/
|
|
refresh()) is intentionally un-styled from in here: each package's own
|
|
content-type-specific rules (`hive-side-panel .md` in the dashboard,
|
|
`hive-side-panel .agent-inbox` in the agent UI) live in that package's
|
|
own global stylesheet and reach the slotted content via the element's
|
|
own tag name as the selector root — no compatibility class needed,
|
|
same architecture floor as `<hive-menu>`'s item-row styling, not a
|
|
scope choice.
|
|
|
|
`:host(.open)`/`:host(.resizing)` respond to the two state classes the
|
|
JS toggles on the host itself (`open`, and `resizing` during a drag) —
|
|
the shadow-scoped counterparts of the page-global `body.side-panel-
|
|
resizing` cursor-override class, which stays in each package's own
|
|
stylesheet since it has to reach light-DOM elements outside this
|
|
element entirely (see hive-side-panel.js's module header). */
|
|
|
|
:host {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 200;
|
|
pointer-events: none;
|
|
}
|
|
.side-panel-backdrop {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: color-mix(in srgb, var(--crust) 55%, transparent);
|
|
opacity: 0;
|
|
transition: opacity 200ms ease;
|
|
}
|
|
.side-panel-drawer {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: var(--side-panel-w, min(42em, 95vw));
|
|
background: var(--bg-elev);
|
|
border-left: 1px solid var(--purple-dim);
|
|
display: flex;
|
|
flex-direction: column;
|
|
transform: translateX(100%);
|
|
transition: transform 220ms ease;
|
|
overflow: hidden;
|
|
}
|
|
:host(.open) { pointer-events: auto; }
|
|
:host(.open) .side-panel-backdrop { opacity: 1; }
|
|
:host(.open) .side-panel-drawer { transform: translateX(0); }
|
|
.side-panel-resize {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 6px;
|
|
cursor: ew-resize;
|
|
opacity: 0;
|
|
transition: opacity 120ms;
|
|
background: var(--purple-dim);
|
|
}
|
|
.side-panel-resize:hover,
|
|
:host(.resizing) .side-panel-resize {
|
|
opacity: 1;
|
|
}
|
|
:host(.resizing) .side-panel-resize {
|
|
background: var(--purple);
|
|
}
|
|
.side-panel-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6em;
|
|
padding: 0.6em 1em;
|
|
border-bottom: 1px solid var(--border);
|
|
flex: none;
|
|
}
|
|
.side-panel-title {
|
|
flex: 1;
|
|
font-size: 0.88em;
|
|
color: var(--muted);
|
|
letter-spacing: 0.04em;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.side-panel-close {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: none;
|
|
border: 1px solid var(--border);
|
|
border-radius: 3px;
|
|
color: var(--muted);
|
|
font-size: 1em;
|
|
line-height: 1;
|
|
padding: 0.15em 0.4em;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s ease, color 0.15s ease;
|
|
}
|
|
.side-panel-close:hover { border-color: var(--red); color: var(--red); }
|
|
.side-panel-body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0.8em 1em;
|
|
font-size: 0.88em;
|
|
}
|