feat: timeline multi-select, demand popover, resource hover card, merged tooltips, dark mode fixes
Major timeline enhancements: - Right-click drag multi-selection with floating action bar (batch delete/assign) - DemandPopover for demand strip details (replaces broken "Loading" modal) - ResourceHoverCard on name hover showing skills, rates, role, chapter - Merged heatmap+vacation tooltips into unified TimelineTooltip component - Fixed overbooking blink animation (date normalization, z-index ordering) - Fixed dark mode sticky column bleed-through in project view - System roles admin page, notification task management, performance review docs Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -35,7 +35,7 @@ const TABS: Array<{ id: WorkspaceTab; label: string }> = [
|
||||
|
||||
function EmptyState({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="rounded-3xl border border-dashed border-gray-200 bg-white px-5 py-10 text-center text-sm text-gray-400">
|
||||
<div className="rounded-3xl border border-dashed border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-5 py-10 text-center text-sm text-gray-400">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -53,8 +53,8 @@ function ActionNotice({
|
||||
className={clsx(
|
||||
"rounded-2xl border px-4 py-3 text-sm",
|
||||
tone === "success"
|
||||
? "border-emerald-200 bg-emerald-50 text-emerald-800"
|
||||
: "border-rose-200 bg-rose-50 text-rose-800",
|
||||
? "border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-800 dark:bg-emerald-950/50 dark:text-emerald-300"
|
||||
: "border-rose-200 bg-rose-50 text-rose-800 dark:border-rose-800 dark:bg-rose-950/50 dark:text-rose-300",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -182,7 +182,7 @@ export function EstimateWorkspaceClient({ estimateId }: { estimateId: string })
|
||||
<div className="mx-auto max-w-7xl space-y-6 p-6">
|
||||
<Link
|
||||
href="/estimates"
|
||||
className="inline-flex items-center gap-1 text-sm text-gray-500 transition-colors hover:text-gray-800"
|
||||
className="inline-flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 transition-colors hover:text-gray-800 dark:hover:text-gray-200"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
@@ -190,21 +190,21 @@ export function EstimateWorkspaceClient({ estimateId }: { estimateId: string })
|
||||
Back to Estimates
|
||||
</Link>
|
||||
|
||||
<div className="rounded-[28px] border border-gray-200 bg-gradient-to-br from-white via-white to-brand-50 p-6 shadow-sm">
|
||||
<div className="rounded-[28px] border border-gray-200 dark:border-gray-700 bg-gradient-to-br from-white via-white to-brand-50 dark:from-gray-900 dark:via-gray-900 dark:to-gray-900 p-6 shadow-sm dark:shadow-black/20">
|
||||
<div className="flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-brand-600">Estimate Workspace <InfoTooltip content="Central workspace for inspecting and editing an estimate's scope, staffing, financials, and version history." /></p>
|
||||
<h1 className="mt-2 text-3xl font-semibold text-gray-900">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-brand-600 dark:text-sky-400">Estimate Workspace <InfoTooltip content="Central workspace for inspecting and editing an estimate's scope, staffing, financials, and version history." /></p>
|
||||
<h1 className="mt-2 text-3xl font-semibold text-gray-900 dark:text-gray-50">
|
||||
{estimate?.name ?? "Loading estimate"}
|
||||
</h1>
|
||||
<p className="mt-2 max-w-3xl text-sm text-gray-600">
|
||||
<p className="mt-2 max-w-3xl text-sm text-gray-600 dark:text-gray-300">
|
||||
Use the tabs below to inspect the connected estimate structure, version context, and staffing breakdown without relying on spreadsheet tabs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{estimate && (
|
||||
<div className="flex flex-col gap-3 lg:items-end">
|
||||
<div className="grid gap-2 text-sm text-gray-500 lg:text-right">
|
||||
<div className="grid gap-2 text-sm text-gray-500 dark:text-gray-400 lg:text-right">
|
||||
<span>{estimate.project ? `${estimate.project.shortCode} - ${estimate.project.name}` : "Standalone estimate"}</span>
|
||||
<span>Updated {formatDateLong(estimate.updatedAt)}</span>
|
||||
</div>
|
||||
@@ -215,7 +215,7 @@ export function EstimateWorkspaceClient({ estimateId }: { estimateId: string })
|
||||
if (!editableTab && !isEditing) return;
|
||||
setIsEditing((current) => !current);
|
||||
}}
|
||||
className="rounded-2xl border border-brand-200 bg-white px-4 py-2 text-sm font-semibold text-brand-700 transition hover:border-brand-300 hover:bg-brand-50"
|
||||
className="rounded-2xl border border-brand-200 dark:border-sky-700 bg-white dark:bg-gray-800 px-4 py-2 text-sm font-semibold text-brand-700 dark:text-sky-300 transition hover:border-brand-300 dark:hover:border-sky-600 hover:bg-brand-50 dark:hover:bg-gray-700"
|
||||
>
|
||||
{isEditing ? "Close editor" : editableTab ? "Edit working draft" : "Draft editor available in editable tabs"}
|
||||
</button>
|
||||
@@ -238,7 +238,7 @@ export function EstimateWorkspaceClient({ estimateId }: { estimateId: string })
|
||||
{actionMessage && <ActionNotice tone="success">{actionMessage}</ActionNotice>}
|
||||
{actionError && <ActionNotice tone="error">{actionError}</ActionNotice>}
|
||||
|
||||
<div className="flex flex-wrap gap-2 border-b border-gray-200">
|
||||
<div className="flex flex-wrap gap-2 border-b border-gray-200 dark:border-gray-700">
|
||||
{TABS.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
@@ -247,8 +247,8 @@ export function EstimateWorkspaceClient({ estimateId }: { estimateId: string })
|
||||
className={clsx(
|
||||
"rounded-t-2xl border-b-2 px-4 py-3 text-sm font-medium transition-colors",
|
||||
tab === item.id
|
||||
? "border-brand-600 text-brand-700"
|
||||
: "border-transparent text-gray-500 hover:text-gray-800",
|
||||
? "border-brand-600 text-brand-700 dark:border-sky-400 dark:text-sky-300"
|
||||
: "border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200",
|
||||
)}
|
||||
>
|
||||
{item.label}
|
||||
|
||||
Reference in New Issue
Block a user