refactor: replace dashboard sidebar list with compact dropdown

- Single-line select dropdown instead of one list item per dashboard
- Scales to any number of teams without clutter
- "+ New dashboard" as last option in dropdown
- Preserves the create flow with inline name input

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-09 13:24:33 +02:00
parent 35b7f49518
commit c79cd183d4

View File

@@ -202,66 +202,70 @@ function SidebarNav() {
{dashboards.length > 0 && ( {dashboards.length > 0 && (
<div className="mt-4"> <div className="mt-4">
{!collapsed && ( {!collapsed && (
<div className="flex items-center justify-between px-2 py-1.5"> <button
<button type="button"
type="button" onClick={() => setExpanded((e) => ({ ...e, dashboards: !e.dashboards }))}
onClick={() => setExpanded((e) => ({ ...e, dashboards: !e.dashboards }))} className="flex w-full items-center gap-1 px-2 py-1.5 text-[11px] font-semibold text-sidebar-foreground/45 uppercase hover:text-sidebar-foreground/70"
className="flex items-center gap-1 text-[11px] font-semibold text-sidebar-foreground/45 uppercase hover:text-sidebar-foreground/70" >
<ChevronRightIcon
className={cn("h-3 w-3 transition-transform", expanded.dashboards && "rotate-90")}
/>
Dashboards
</button>
)}
{expanded.dashboards && dashboards.length > 0 && (
<div className="px-2">
<select
value={dashboards.find((d) => pathname.startsWith("/dashboards/") && pathname.endsWith(d.id))?.id ?? ""}
onChange={(e) => {
const id = e.target.value;
if (id === "_new") {
setAddingDashboard(true);
e.target.value = dashboards.find((d) => pathname.startsWith("/dashboards/") && pathname.endsWith(d.id))?.id ?? "";
return;
}
if (id) window.location.href = `/dashboards/${id}`;
}}
className="h-7 w-full rounded border border-sidebar-border bg-sidebar-accent px-1.5 text-[12px] text-sidebar-foreground outline-none"
> >
<ChevronRightIcon {dashboards.map((dash) => (
className={cn("h-3 w-3 transition-transform", expanded.dashboards && "rotate-90")} <option key={dash.id} value={dash.id}>{dash.name}</option>
/> ))}
Dashboards <option value="_new">+ New dashboard</option>
</button> </select>
{addingDashboard ? (
<div className="flex items-center gap-1">
<input
value={newDashboardName}
onChange={(e) => setNewDashboardName(e.target.value)}
placeholder="Name"
className="h-6 w-24 rounded border border-sidebar-border bg-sidebar-accent px-1.5 text-[11px] text-sidebar-foreground outline-none"
autoFocus
onKeyDown={async (e) => {
if (e.key === "Enter" && newDashboardName.trim()) {
const { data } = await createDashboard({ name: newDashboardName.trim(), is_default: false });
if (data) {
setDashboards((prev) => [...prev, data]);
setNewDashboardName("");
setAddingDashboard(false);
window.location.href = `/dashboards/${data.id}`;
}
} else if (e.key === "Escape") {
setNewDashboardName("");
setAddingDashboard(false);
}
}}
/>
</div>
) : (
<button
type="button"
onClick={() => setAddingDashboard(true)}
className="text-sidebar-foreground/35 hover:text-sidebar-foreground/70"
title="New dashboard"
>
<PlusIcon className="h-3 w-3" />
</button>
)}
</div> </div>
)} )}
{expanded.dashboards && dashboards.map((dash) => { {addingDashboard && (
const active = <div className="mt-1 px-2">
pathname.startsWith("/dashboards/") && pathname.endsWith(dash.id); <input
return ( value={newDashboardName}
<SidebarNavItem onChange={(e) => setNewDashboardName(e.target.value)}
key={dash.id} placeholder="Dashboard name"
href={`/dashboards/${dash.id}`} className="h-7 w-full rounded border border-sidebar-border bg-sidebar-accent px-1.5 text-[12px] text-sidebar-foreground outline-none"
icon={LayoutGridIcon} autoFocus
label={dash.name} onKeyDown={async (e) => {
active={active} if (e.key === "Enter" && newDashboardName.trim()) {
const { data } = await createDashboard({ name: newDashboardName.trim(), is_default: false });
if (data) {
setDashboards((prev) => [...prev, data]);
setNewDashboardName("");
setAddingDashboard(false);
window.location.href = `/dashboards/${data.id}`;
}
} else if (e.key === "Escape") {
setNewDashboardName("");
setAddingDashboard(false);
}
}}
onBlur={() => {
if (!newDashboardName.trim()) {
setNewDashboardName("");
setAddingDashboard(false);
}
}}
/> />
); </div>
})} )}
</div> </div>
)} )}