hyperhive/frontend/packages/agent/src/components/SidePanel.tsx
atlas 39b95c2ede treefmt: apply prettier
Pure `nix fmt` output from the commit before this one — no hand edits.
203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs.

Reproduce with `nix develop -c nix fmt` on the parent commit; the result
should be byte-identical to this tree.

None of the 13 `.prettierignore` entries appears here — verified by
intersecting the changed-file list against the ignore file, with a
control proving the intersection finds a match when one exists.
2026-09-02 15:25:07 +02:00

64 lines
2.1 KiB
TypeScript

// <SidePanel> — the slide-in drawer for the inbox/todos flyouts.
// Deliberately a new Preact component, not the shared
// `<hive-side-panel>` shadow-DOM custom element (@hive/shared/
// side-panel.js) — same rationale as StatusChips' Badge/Dropdown:
// mara's ask was real Preact components for this rewrite, not a port
// of the old widget family. Drops that element's drag-to-resize +
// localStorage width persistence for this first slice (fixed width via
// CSS, see SidePanel.css) — a real simplification, not an oversight;
// revisit if a fixed width proves cramped in practice.
//
// Content styling (`.agent-inbox`, `.inbox-*`, `.side-panel-empty`)
// already ships globally via `agent.css` and is reused verbatim by
// InboxPanel/TodosPanel — only the drawer chrome itself is new here.
import { useEffect } from "preact/hooks";
import type { ComponentChildren } from "preact";
import "./SidePanel.css";
export interface SidePanelProps {
open: boolean;
title: string;
onClose: () => void;
children?: ComponentChildren;
}
export function SidePanel({ open, title, onClose, children }: SidePanelProps) {
useEffect(() => {
if (!open) return;
function onKey(e: KeyboardEvent) {
if (e.key === "Escape") onClose();
}
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open, onClose]);
return (
<>
<div
class={`agent-side-panel-backdrop${open ? " open" : ""}`}
onClick={onClose}
aria-hidden="true"
/>
<aside
class={`agent-side-panel-drawer${open ? " open" : ""}`}
role="dialog"
aria-modal="true"
aria-hidden={!open}
aria-label={title}
>
<div class="agent-side-panel-head">
<span class="agent-side-panel-title">{title}</span>
<button
type="button"
class="agent-side-panel-close"
title="close (esc)"
onClick={onClose}
>
</button>
</div>
<div class="agent-side-panel-body">{children}</div>
</aside>
</>
);
}