feat(web): Linear-inspired sidebar with floating panel layout

- Add canvas background color for the base layer
- Sidebar blends into canvas, no border separator
- Content area rendered as floating white panel with rounded corners
  and shadow, offset from edges to reveal canvas underneath
- Simplify sidebar nav to: Inbox, Agents, Issues, Knowledge Base
- Add workspace switcher header with MulticaIcon

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan Zhang 2026-03-21 14:06:04 +08:00
parent ea7f5371f7
commit 9bd1c14d9d
2 changed files with 35 additions and 20 deletions

View file

@ -6,16 +6,16 @@ import {
Inbox,
ListTodo,
Bot,
Columns3,
Settings,
BookOpen,
ChevronDown,
} from "lucide-react";
import { MulticaIcon } from "@multica/ui/components/multica-icon";
const navItems = [
{ href: "/inbox", label: "Inbox", icon: Inbox },
{ href: "/issues", label: "Issues", icon: ListTodo },
{ href: "/board", label: "Board", icon: Columns3 },
{ href: "/agents", label: "Agents", icon: Bot },
{ href: "/settings", label: "Settings", icon: Settings },
{ href: "/issues", label: "Issues", icon: ListTodo },
{ href: "/knowledge-base", label: "Knowledge Base", icon: BookOpen },
];
export default function DashboardLayout({
@ -26,26 +26,34 @@ export default function DashboardLayout({
const pathname = usePathname();
return (
<div className="flex h-screen">
{/* Sidebar */}
<aside className="flex w-56 flex-col border-r bg-card">
<div className="flex h-14 items-center gap-2 border-b px-4">
<span className="text-lg font-bold">Multica</span>
<div className="flex h-screen bg-canvas">
{/* Sidebar — sits on the canvas layer */}
<aside className="flex w-56 shrink-0 flex-col">
{/* Workspace Switcher */}
<div className="flex h-12 items-center gap-2 px-3">
<MulticaIcon className="size-4" noSpin />
<span className="flex-1 truncate text-sm font-semibold">
Multica
</span>
<ChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
</div>
<nav className="flex-1 space-y-1 p-2">
{/* Navigation */}
<nav className="flex-1 space-y-0.5 px-2">
{navItems.map((item) => {
const isActive = pathname.startsWith(item.href);
const isActive =
pathname === item.href || pathname.startsWith(item.href + "/");
return (
<Link
key={item.href}
href={item.href}
className={`flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors ${
className={`flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm transition-colors ${
isActive
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50"
? "bg-sidebar-accent text-sidebar-accent-foreground font-medium"
: "text-sidebar-foreground/60 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground"
}`}
>
<item.icon className="h-4 w-4" />
<item.icon className="h-4 w-4 shrink-0" />
{item.label}
</Link>
);
@ -53,8 +61,12 @@ export default function DashboardLayout({
</nav>
</aside>
{/* Main content */}
<main className="flex-1 overflow-auto">{children}</main>
{/* Main content — floating panel on top of the canvas */}
<div className="flex-1 pt-1.5 pr-1.5 pb-1.5">
<main className="h-full overflow-auto rounded-xl bg-background shadow-sm">
{children}
</main>
</div>
</div>
);
}

View file

@ -86,6 +86,7 @@
--font-sans: var(--font-sans);
--font-mono: var(--font-geist-mono);
--font-brand: var(--font-brand);
--color-canvas: var(--canvas);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@ -156,7 +157,8 @@
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--canvas: oklch(0.95 0.002 286);
--sidebar: oklch(0.95 0.002 286);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.205 0.006 285.885);
--sidebar-primary-foreground: oklch(0.985 0 0);
@ -204,7 +206,8 @@
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--canvas: oklch(0.2 0.005 286);
--sidebar: oklch(0.2 0.005 286);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.922 0.006 285.885);
--sidebar-primary-foreground: oklch(0.205 0.006 285.885);