chore(repo): initialize planarchy workspace

This commit is contained in:
2026-03-14 14:31:09 +01:00
commit dd55d0e78b
769 changed files with 166461 additions and 0 deletions
@@ -0,0 +1,154 @@
"use client";
import { clsx } from "clsx";
import { TimelineFilter, type TimelineFilters } from "./TimelineFilter.js";
interface TimelineToolbarProps {
viewMode: "resource" | "project";
onViewModeChange: (mode: "resource" | "project") => void;
filters: TimelineFilters;
onFiltersChange: (f: TimelineFilters) => void;
filterOpen: boolean;
onFilterOpenChange: (open: boolean) => void;
resourceCount: number;
projectCount: number;
totalAllocCount: number;
onNavigateBack: () => void;
onNavigateToday: () => void;
onNavigateForward: () => void;
canUndo?: boolean;
canRedo?: boolean;
onUndo?: () => void;
onRedo?: () => void;
}
export function TimelineToolbar({
viewMode,
onViewModeChange,
filters,
onFiltersChange,
filterOpen,
onFilterOpenChange,
resourceCount,
projectCount,
totalAllocCount,
onNavigateBack,
onNavigateToday,
onNavigateForward,
canUndo,
canRedo,
onUndo,
onRedo,
}: TimelineToolbarProps) {
const activeFilterCount = filters.chapters.length + filters.eids.length + filters.projectIds.length;
return (
<div className="flex items-center justify-between mb-2 gap-3">
<div className="text-sm text-gray-500">
{viewMode === "resource"
? `${resourceCount} resources · ${totalAllocCount} allocations`
: `${projectCount} projects`}
</div>
<div className="flex items-center gap-2">
{/* Timeline navigation */}
<div className="flex items-center gap-1">
<button
onClick={onNavigateBack}
className="px-2.5 py-1.5 text-sm rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors"
title="Previous 4 weeks"
>
</button>
<button
onClick={onNavigateToday}
className="px-3 py-1.5 text-sm rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors"
>
Today
</button>
<button
onClick={onNavigateForward}
className="px-2.5 py-1.5 text-sm rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors"
title="Next 4 weeks"
>
</button>
</div>
{/* Undo / Redo */}
{(onUndo ?? onRedo) && (
<div className="flex items-center gap-1">
<button
onClick={onUndo}
disabled={!canUndo}
title="Undo (Ctrl+Z)"
className="px-2 py-1.5 text-sm rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
>
</button>
<button
onClick={onRedo}
disabled={!canRedo}
title="Redo (Ctrl+Shift+Z / Ctrl+Y)"
className="px-2 py-1.5 text-sm rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
>
</button>
</div>
)}
{/* View mode toggle */}
<div className="flex rounded-lg border border-gray-200 overflow-hidden text-sm">
<button
onClick={() => onViewModeChange("resource")}
className={clsx(
"px-3 py-1.5 transition-colors",
viewMode === "resource"
? "bg-brand-600 text-white"
: "text-gray-600 hover:bg-gray-50",
)}
>
Resource view
</button>
<button
onClick={() => onViewModeChange("project")}
className={clsx(
"px-3 py-1.5 border-l border-gray-200 transition-colors",
viewMode === "project"
? "bg-brand-600 text-white"
: "text-gray-600 hover:bg-gray-50",
)}
>
Project view
</button>
</div>
{/* Filter */}
<div className="relative">
<button
onClick={() => onFilterOpenChange(!filterOpen)}
className={clsx(
"flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg border transition-colors",
filterOpen || activeFilterCount > 0
? "bg-brand-50 border-brand-300 text-brand-700"
: "border-gray-200 text-gray-600 hover:bg-gray-50",
)}
>
Filter
{activeFilterCount > 0 && (
<span className="w-4 h-4 rounded-full bg-brand-600 text-white text-xs flex items-center justify-center">
{activeFilterCount}
</span>
)}
</button>
<TimelineFilter
filters={filters}
onChange={onFiltersChange}
isOpen={filterOpen}
onClose={() => onFilterOpenChange(false)}
/>
</div>
</div>
</div>
);
}