M1 UI: shadcn + TeamUp design language
Initialize shadcn/ui (radix-nova, Tailwind v4) in client/ and rebuild the M1 interface on the design language: - Token layer recolored in index.css: light "calm command center" content surface, rationed indigo brand, the deep-indigo sidebar, the load-bearing seat-state triad (--color-seat-human slate / -open amber / -ai indigo) + teal "approved" / amber "held", Hanken Grotesk (variable) as the production font. - App shell: deep-indigo sidebar (Board / Cartable / Org-chart-soon nav + sign out) on a light content area; StatusDot uses the seat-state tokens. - LoginPage: Card-based sign-in / first-owner bootstrap, toast (sonner) errors. - BoardPage: shadcn Card columns (backlog→in progress→in review→done), Badge task types, Select to move, Avatar/Assign-to-me, and the cartable panel — wired to the M1 API. - Path alias @ -> src (tsconfig paths + vite); dropped baseUrl (deprecated in TS 6). Components added via the shadcn CLI: button, card, badge, input, label, select, separator, avatar, skeleton, sonner. Client `npm run build` is green (tsc + vite). Still pending a live click-through. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { Inbox, type LucideIcon, LayoutDashboard, LogOut, Network } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useAuth } from '@/store/auth'
|
||||
|
||||
export function AppShell({ children }: { children: ReactNode }) {
|
||||
const email = useAuth((s) => s.email)
|
||||
const logout = useAuth((s) => s.logout)
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen bg-background text-foreground">
|
||||
<aside className="flex w-60 shrink-0 flex-col bg-sidebar text-sidebar-foreground">
|
||||
<div className="flex items-center gap-3 px-5 py-4">
|
||||
<span className="grid size-8 place-items-center rounded-md bg-sidebar-primary font-bold text-sidebar-primary-foreground">
|
||||
T
|
||||
</span>
|
||||
<div className="leading-tight">
|
||||
<div className="font-semibold tracking-tight">TeamUp.AI</div>
|
||||
<div className="text-xs text-sidebar-foreground/60">command center</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="bg-sidebar-border" />
|
||||
|
||||
<nav className="flex flex-1 flex-col gap-1 p-3">
|
||||
<NavItem icon={LayoutDashboard} label="Board" active />
|
||||
<NavItem icon={Inbox} label="Cartable" />
|
||||
<NavItem icon={Network} label="Org chart" muted />
|
||||
</nav>
|
||||
|
||||
<Separator className="bg-sidebar-border" />
|
||||
|
||||
<div className="flex items-center justify-between gap-2 p-3">
|
||||
<span className="truncate text-xs text-sidebar-foreground/70">{email ?? 'signed in'}</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={logout}
|
||||
className="text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
>
|
||||
<LogOut data-icon="inline-start" />
|
||||
Sign out
|
||||
</Button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main className="flex-1 overflow-auto">{children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function NavItem({
|
||||
icon: Icon,
|
||||
label,
|
||||
active,
|
||||
muted,
|
||||
}: {
|
||||
icon: LucideIcon
|
||||
label: string
|
||||
active?: boolean
|
||||
muted?: boolean
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm',
|
||||
active ? 'bg-sidebar-accent font-medium text-sidebar-accent-foreground' : 'text-sidebar-foreground/80',
|
||||
muted && 'opacity-50',
|
||||
)}
|
||||
>
|
||||
<Icon className="size-4" />
|
||||
{label}
|
||||
{muted && <span className="ml-auto text-[10px] uppercase tracking-wide opacity-70">soon</span>}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user