[taskboard] improve kanban layout density
This commit is contained in:
@@ -25,7 +25,7 @@ export function AppShell({
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(34,211,238,0.18),_transparent_30%),radial-gradient(circle_at_top_right,_rgba(245,158,11,0.14),_transparent_28%),linear-gradient(180deg,#07111f_0%,#091321_44%,#0f172a_100%)] text-foreground">
|
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(34,211,238,0.18),_transparent_30%),radial-gradient(circle_at_top_right,_rgba(245,158,11,0.14),_transparent_28%),linear-gradient(180deg,#07111f_0%,#091321_44%,#0f172a_100%)] text-foreground">
|
||||||
<header className="border-b border-white/10 bg-slate-950/60 backdrop-blur-xl">
|
<header className="border-b border-white/10 bg-slate-950/60 backdrop-blur-xl">
|
||||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-6 py-6">
|
<div className="mx-auto flex w-full max-w-[1760px] items-center justify-between px-6 py-6">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-xs uppercase tracking-[0.3em] text-cyan-300/80">
|
<p className="font-mono text-xs uppercase tracking-[0.3em] text-cyan-300/80">
|
||||||
OpenClaw Taskboard
|
OpenClaw Taskboard
|
||||||
@@ -40,8 +40,8 @@ export function AppShell({
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="mx-auto grid max-w-7xl gap-6 px-6 py-8 lg:grid-cols-[240px_minmax(0,1fr)]">
|
<div className="mx-auto grid w-full max-w-[1760px] gap-6 px-6 py-8 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[252px_minmax(0,1fr)]">
|
||||||
<nav className="space-y-2">
|
<nav className="space-y-2 lg:sticky lg:top-8 lg:self-start">
|
||||||
{navItems.map((item) => {
|
{navItems.map((item) => {
|
||||||
const Icon = item.icon;
|
const Icon = item.icon;
|
||||||
const isActive = pathname === item.href;
|
const isActive = pathname === item.href;
|
||||||
@@ -63,7 +63,7 @@ export function AppShell({
|
|||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main>{children}</main>
|
<main className="min-w-0">{children}</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export function TasksClient({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="grid gap-4 xl:grid-cols-[minmax(0,1.2fr)_360px]">
|
<div className="grid gap-4 2xl:grid-cols-[minmax(0,1.35fr)_380px]">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Unified Task Intake</CardTitle>
|
<CardTitle>Unified Task Intake</CardTitle>
|
||||||
@@ -312,27 +312,41 @@ export function TasksClient({
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<div className="grid gap-4 xl:grid-cols-5">
|
<div className="space-y-3">
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-lg font-semibold text-white">Task Board</h2>
|
||||||
|
<p className="text-sm text-slate-400">
|
||||||
|
Columns keep a readable width and scroll horizontally when the viewport is narrower than the full board.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Badge variant="outline">{tasks.length} total tasks</Badge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="overflow-x-auto pb-3">
|
||||||
|
<div className="flex min-w-max gap-4">
|
||||||
{COLUMNS.map((column) => {
|
{COLUMNS.map((column) => {
|
||||||
const columnTasks = tasks.filter((task) => task.status === column);
|
const columnTasks = tasks.filter((task) => task.status === column);
|
||||||
return (
|
return (
|
||||||
<Card className="min-h-[420px]" key={column}>
|
<Card className="flex min-h-[560px] w-[340px] shrink-0 flex-col border-white/10 bg-slate-950/35 xl:w-[360px]" key={column}>
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<CardTitle className="flex items-center justify-between text-base">
|
<CardTitle className="flex items-center justify-between text-base">
|
||||||
<span>{column}</span>
|
<span>{column}</span>
|
||||||
<Badge variant="secondary">{columnTasks.length}</Badge>
|
<Badge variant="secondary">{columnTasks.length}</Badge>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-3">
|
<CardContent className="flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto">
|
||||||
{columnTasks.map((task) => (
|
{columnTasks.map((task) => (
|
||||||
<div className="rounded-xl border border-white/10 bg-slate-950/40 p-4" key={task.id}>
|
<div className="min-w-0 rounded-xl border border-white/10 bg-slate-950/40 p-4" key={task.id}>
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<h3 className="font-medium text-white">{task.title}</h3>
|
<h3 className="min-w-0 break-words font-medium text-white">{task.title}</h3>
|
||||||
<Badge variant={task.priority === "Critical" ? "warning" : "outline"}>
|
<Badge variant={task.priority === "Critical" ? "warning" : "outline"}>
|
||||||
{task.priority}
|
{task.priority}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-sm text-slate-300">{task.description || "No description"}</p>
|
<p className="mt-2 break-words text-sm leading-6 text-slate-300">
|
||||||
|
{task.description || "No description"}
|
||||||
|
</p>
|
||||||
<div className="mt-3 flex flex-wrap gap-2 text-xs text-slate-400">
|
<div className="mt-3 flex flex-wrap gap-2 text-xs text-slate-400">
|
||||||
<Badge variant={familyVariant(task.family)}>{task.family || "manual"}</Badge>
|
<Badge variant={familyVariant(task.family)}>{task.family || "manual"}</Badge>
|
||||||
<Badge variant="secondary">{task.assignee || "Unassigned"}</Badge>
|
<Badge variant="secondary">{task.assignee || "Unassigned"}</Badge>
|
||||||
@@ -346,11 +360,11 @@ export function TasksClient({
|
|||||||
<dl className="mt-3 grid gap-1 text-xs text-slate-400">
|
<dl className="mt-3 grid gap-1 text-xs text-slate-400">
|
||||||
<div className="flex justify-between gap-2">
|
<div className="flex justify-between gap-2">
|
||||||
<dt>Host</dt>
|
<dt>Host</dt>
|
||||||
<dd>{task.target_host || "n/a"}</dd>
|
<dd className="break-words text-right">{task.target_host || "n/a"}</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between gap-2">
|
<div className="flex justify-between gap-2">
|
||||||
<dt>Channel</dt>
|
<dt>Channel</dt>
|
||||||
<dd className="text-right">{task.target_channel || "n/a"}</dd>
|
<dd className="break-all text-right">{task.target_channel || "n/a"}</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
{task.result_summary ? (
|
{task.result_summary ? (
|
||||||
@@ -358,7 +372,7 @@ export function TasksClient({
|
|||||||
<p className="text-xs uppercase tracking-[0.2em] text-emerald-300/80">Latest Result</p>
|
<p className="text-xs uppercase tracking-[0.2em] text-emerald-300/80">Latest Result</p>
|
||||||
<p className="mt-1 text-sm text-slate-200">{task.result_summary}</p>
|
<p className="mt-1 text-sm text-slate-200">{task.result_summary}</p>
|
||||||
{task.result_detail ? (
|
{task.result_detail ? (
|
||||||
<p className="mt-1 text-xs text-slate-400">{task.result_detail}</p>
|
<p className="mt-1 break-words text-xs leading-5 text-slate-400">{task.result_detail}</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -385,6 +399,8 @@ export function TasksClient({
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user