Top-row chrome: dropdowns layer above the cost number; slight (4px) corners
- Stacking: the actions row is now relative + z-20 — an open settings or coverage dropdown paints over the cost number below it (owner report: it layered ON TOP of the panel, still hoverable/clickable). The row is a stacking context inside the column, so its dropdowns cover the number and clicks land on the panel; the number resurfaces untouched when the panel closes (verified with elementFromPoint). - Rectangular look (owner, 2026-09-20): the four top-row controls drop rounded-xl (16px theme) to rounded-sm (4px) — gear, coverage, search container + input, import container + button; the cost number's hover highlight joins the family. Dropdown panels keep their softer cards.
This commit is contained in:
@@ -102,7 +102,7 @@ export function GraphCoverageControl({ refreshKey = 0 }: { refreshKey?: number }
|
|||||||
title="Extraction coverage — what the knowledge graph has covered"
|
title="Extraction coverage — what the knowledge graph has covered"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
onClick={() => setOpen((o) => !o)}
|
onClick={() => setOpen((o) => !o)}
|
||||||
className={`flex size-9 items-center justify-center rounded-xl border bg-card/85 shadow-lg backdrop-blur transition-colors hover:bg-accent ${
|
className={`flex size-9 items-center justify-center rounded-sm border bg-card/85 shadow-lg backdrop-blur transition-colors hover:bg-accent ${
|
||||||
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ function GraphCostControl({ costs }: { costs: GraphCostSummary }) {
|
|||||||
title="Graph pipeline costs — click for the breakdown"
|
title="Graph pipeline costs — click for the breakdown"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
onClick={() => setOpen((o) => !o)}
|
onClick={() => setOpen((o) => !o)}
|
||||||
className={`rounded-lg px-2 py-1 text-xs tabular-nums transition-colors hover:bg-accent ${
|
className={`rounded-sm px-2 py-1 text-xs tabular-nums transition-colors hover:bg-accent ${
|
||||||
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -361,7 +361,7 @@ function GraphSettingsControl({
|
|||||||
title="Rendering settings"
|
title="Rendering settings"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
onClick={() => setOpen((o) => !o)}
|
onClick={() => setOpen((o) => !o)}
|
||||||
className={`flex size-9 items-center justify-center rounded-xl border bg-card/85 shadow-lg backdrop-blur transition-colors hover:bg-accent ${
|
className={`flex size-9 items-center justify-center rounded-sm border bg-card/85 shadow-lg backdrop-blur transition-colors hover:bg-accent ${
|
||||||
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
open ? "text-foreground" : "text-muted-foreground hover:text-foreground"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -1155,14 +1155,19 @@ export function GraphView() {
|
|||||||
rejected the two-row fold); in narrow windows the search is
|
rejected the two-row fold); in narrow windows the search is
|
||||||
the flexible element and shrinks instead. */}
|
the flexible element and shrinks instead. */}
|
||||||
<div className="lh-no-drag absolute right-3 top-2 z-10 flex max-w-[calc(100%-5.5rem)] flex-col items-end gap-2">
|
<div className="lh-no-drag absolute right-3 top-2 z-10 flex max-w-[calc(100%-5.5rem)] flex-col items-end gap-2">
|
||||||
<div className="flex min-w-0 items-start gap-2">
|
{/* z-20 (2026-09-20): the row paints above the cost number below
|
||||||
|
it — without this, the later-in-DOM cost control layered over
|
||||||
|
the settings/coverage dropdowns (owner report), still hoverable
|
||||||
|
and clickable on top of them. The row is a stacking context, so
|
||||||
|
its open dropdowns cover the number; clicks land on the panel. */}
|
||||||
|
<div className="relative z-20 flex min-w-0 items-start gap-2">
|
||||||
{!isEmpty && (
|
{!isEmpty && (
|
||||||
<>
|
<>
|
||||||
{/* Search — its own container (icon + input + no-match note).
|
{/* Search — its own container (icon + input + no-match note).
|
||||||
The header band's flexible element: w-56 normally, shrinks
|
The header band's flexible element: w-56 normally, shrinks
|
||||||
(min-w-0) when the column's width cap binds in narrow
|
(min-w-0) when the column's width cap binds in narrow
|
||||||
windows — the row's other controls are shrink-0. */}
|
windows — the row's other controls are shrink-0. */}
|
||||||
<div className="w-56 min-w-0 shrink rounded-xl border bg-card/85 px-1 py-[3px] shadow-lg backdrop-blur">
|
<div className="w-56 min-w-0 shrink rounded-sm border bg-card/85 px-1 py-[3px] shadow-lg backdrop-blur">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchIcon className="absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
|
<SearchIcon className="absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
|
||||||
<input
|
<input
|
||||||
@@ -1171,7 +1176,7 @@ export function GraphView() {
|
|||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
placeholder="Search nodes…"
|
placeholder="Search nodes…"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="h-7 w-full rounded-lg border bg-background pl-8 text-xs outline-none placeholder:text-muted-foreground focus:border-ring"
|
className="h-7 w-full rounded-sm border bg-background pl-8 text-xs outline-none placeholder:text-muted-foreground focus:border-ring"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{snapshot !== null && visibleIds.size === 0 && query.trim() !== "" && (
|
{snapshot !== null && visibleIds.size === 0 && query.trim() !== "" && (
|
||||||
@@ -1191,7 +1196,7 @@ export function GraphView() {
|
|||||||
{!isEmpty && (
|
{!isEmpty && (
|
||||||
<>
|
<>
|
||||||
{/* Import notes — its own container (36px, header band). */}
|
{/* Import notes — its own container (36px, header band). */}
|
||||||
<div className="shrink-0 rounded-xl border bg-card/85 px-1 py-[3px] shadow-lg backdrop-blur">
|
<div className="shrink-0 rounded-sm border bg-card/85 px-1 py-[3px] shadow-lg backdrop-blur">
|
||||||
<input
|
<input
|
||||||
ref={fileInputRef}
|
ref={fileInputRef}
|
||||||
type="file"
|
type="file"
|
||||||
@@ -1207,7 +1212,7 @@ export function GraphView() {
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={importing}
|
disabled={importing}
|
||||||
onClick={() => fileInputRef.current?.click()}
|
onClick={() => fileInputRef.current?.click()}
|
||||||
className="flex h-7 items-center gap-1.5 rounded-lg px-2.5 text-xs text-muted-foreground transition-colors hover:bg-accent disabled:opacity-50"
|
className="flex h-7 items-center gap-1.5 rounded-sm px-2.5 text-xs text-muted-foreground transition-colors hover:bg-accent disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<UploadIcon className="size-3" />
|
<UploadIcon className="size-3" />
|
||||||
{importing ? "Importing…" : "Import notes…"}
|
{importing ? "Importing…" : "Import notes…"}
|
||||||
|
|||||||
Reference in New Issue
Block a user