Scrum4Me/app/styles/theme.css
Janpeter Visser 6cd98129f2
M14: TaskDialog (create/edit) + story auto-promotion (#21)
* chore(ST-1112): add deps for task dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add shared zod schema for task dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add missing MD3 tokens for task dialog

outline-variant, on-error-container, status-review (light + dark)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add saveTask and deleteTask server actions for TaskDialog

Unified create/edit action (saveTask) replaces separate formData-based
actions for the new TaskDialog. Uses shared zod schema, structured
SaveTaskResult union type, and context-aware revalidatePath for both
sprint and backlog routes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add TaskDialog component (create & edit mode)

Builds the full TaskDialog on top of the existing @base-ui/react
Dialog primitive. Covers create mode, edit mode (status field +
created_at metadata + delete), dirty-check AlertDialog, delete
confirm AlertDialog, Cmd+Enter submit, and per-field char counters.
Uses react-hook-form + zodResolver against the shared taskSchema.
Priority and status are extracted to PrioritySegmented and
StatusSelect sub-components using MD3 tokens throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): refactor task-list to open TaskDialog via URL params

Replaces inline create/edit forms with router.push navigation:
- Clicking a task row → ?editTask=<id>
- "+ Taak" button → ?newTask=1&storyId=<storyId>
Removes CreateTaskForm, EditSubmitButton, updateTaskAction, and
createTaskAction from the component. Status toggle and DnD remain
unchanged. Rows now have cursor-pointer and keyboard a11y.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): wire TaskDialog into sprint page via searchParams

Sprint page now reads ?newTask, ?storyId, and ?editTask query params.
For edit mode: fetches the task server-side with productAccessFilter
scope (invalid/foreign IDs redirect to closePath). Renders TaskDialog
when either param is present. closePath is the sprint route without
query params.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add Suspense skeleton for edit-mode task loading

Extracts task fetch into EditTaskLoader (async server component) so
the sprint board renders immediately while the task loads.
TaskDialogSkeleton shows 3 grey bars during the fetch. Invalid or
out-of-scope task IDs redirect to closePath.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): render description as markdown in task-detail-dialog

Solo task detail now renders description via react-markdown +
remark-gfm with prose styling. Sanitizes script/iframe elements.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(ST-1112): add saveTask/deleteTask server action tests

Covers all three demo-policy layers and cross-tenant scope:
demo blocked (403), unauthenticated blocked, validation 422,
edit cross-tenant forbidden, create cross-tenant forbidden,
and happy-path for both edit and create.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): add updateTaskStatusWithStoryPromotion helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1112): wire story-promotion into saveTask and PATCH /api/tasks/:id

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(ST-1112): add task-dialog doc and architecture note

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: extend allowed tools in settings.local.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1113): add 200ms animation-delay to TaskDialogSkeleton to prevent flicker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1114): add DirtyCloseGuard reusable component for dirty-form close confirmation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-1114): add shared Markdown wrapper, apply to task-detail and story-dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: allow grep -E pattern in settings.local.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 16:55:20 +02:00

393 lines
12 KiB
CSS

@custom-variant dark (&:is(.dark *));
:root {
--font-size: 16px;
/* MD3 Surface Colors */
--background: #fdfcff;
--foreground: #1b1b1f;
--surface: #fdfcff;
--surface-dim: #dbd9e0;
--surface-bright: #fdfcff;
--surface-container-lowest: #ffffff;
--surface-container-low: #f7f5fc;
--surface-container: #f1eff6;
--surface-container-high: #ebeaf0;
--surface-container-highest: #e6e3ea;
/* MD3 Primary Color (Blue - Productivity) */
--primary: #0061a4;
--primary-foreground: #ffffff;
--primary-container: #d1e4ff;
--primary-container-foreground: #001d36;
--on-primary: #ffffff;
/* MD3 Secondary Color (Purple - Planning) */
--secondary: #5b5e71;
--secondary-foreground: #ffffff;
--secondary-container: #dfe1f9;
--secondary-container-foreground: #181b2c;
--on-secondary: #ffffff;
/* MD3 Tertiary Color (Teal - Progress) */
--tertiary: #006874;
--tertiary-foreground: #ffffff;
--tertiary-container: #97f0ff;
--tertiary-container-foreground: #001f24;
/* Semantic State Colors */
--success: #006e1c;
--success-foreground: #ffffff;
--success-container: #92f894;
--success-container-foreground: #002204;
--warning: #735b00;
--warning-foreground: #ffffff;
--warning-container: #ffdf9d;
--warning-container-foreground: #231b00;
--error: #ba1a1a;
--error-foreground: #ffffff;
--error-container: #ffdad6;
--error-container-foreground: #410002;
--info: #006493;
--info-foreground: #ffffff;
--info-container: #c9e6ff;
--info-container-foreground: #001e2f;
/* Legacy shadcn mappings */
--card: var(--surface-container-low);
--card-foreground: var(--foreground);
--popover: var(--surface-container);
--popover-foreground: var(--foreground);
--muted: var(--surface-container-high);
--muted-foreground: #45464f;
--accent: var(--secondary-container);
--accent-foreground: var(--secondary-container-foreground);
--destructive: var(--error);
--destructive-foreground: var(--error-foreground);
--border: #c5c6d0;
--input: transparent;
--input-background: var(--surface-container);
--switch-background: #79767d;
--ring: var(--primary);
/* MD3 Outline Variant */
--outline-variant: #c5c6d0;
/* MD3 On-Error-Container */
--on-error-container: #410002;
/* Project Management Specific Colors */
--status-todo: #6750a4;
--status-in-progress: #0061a4;
--status-review: #7b5ea7;
--status-done: #006e1c;
--status-blocked: #ba1a1a;
--priority-critical: #ba1a1a;
--priority-high: #c75300;
--priority-medium: #735b00;
--priority-low: #006874;
/* Chart Colors */
--chart-1: var(--primary);
--chart-2: var(--secondary);
--chart-3: var(--tertiary);
--chart-4: var(--success);
--chart-5: var(--warning);
--font-weight-medium: 500;
--font-weight-normal: 400;
--radius: 0.75rem;
/* Sidebar */
--sidebar: var(--surface-container-low);
--sidebar-foreground: var(--foreground);
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-foreground);
--sidebar-accent: var(--surface-container-high);
--sidebar-accent-foreground: var(--foreground);
--sidebar-border: var(--border);
--sidebar-ring: var(--primary);
}
.dark {
/* MD3 Dark Surface Colors */
--background: #1b1b1f;
--foreground: #e4e1e9;
--surface: #1b1b1f;
--surface-dim: #1b1b1f;
--surface-bright: #413f47;
--surface-container-lowest: #0f0e13;
--surface-container-low: #232227;
--surface-container: #27262b;
--surface-container-high: #322f36;
--surface-container-highest: #3d3a41;
/* MD3 Primary Color (Blue) */
--primary: #9fcbfa;
--primary-foreground: #003257;
--primary-container: #00497b;
--primary-container-foreground: #d1e4ff;
--on-primary: #003257;
/* MD3 Secondary Color (Purple) */
--secondary: #c3c4dd;
--secondary-foreground: #2c2f42;
--secondary-container: #434659;
--secondary-container-foreground: #dfe1f9;
--on-secondary: #2c2f42;
/* MD3 Tertiary Color (Teal) */
--tertiary: #4fd8eb;
--tertiary-foreground: #00363d;
--tertiary-container: #004f58;
--tertiary-container-foreground: #97f0ff;
/* Semantic State Colors */
--success: #77db77;
--success-foreground: #00390a;
--success-container: #005313;
--success-container-foreground: #92f894;
--warning: #efc047;
--warning-foreground: #3c2f00;
--warning-container: #574400;
--warning-container-foreground: #ffdf9d;
--error: #ffb4ab;
--error-foreground: #690005;
--error-container: #93000a;
--error-container-foreground: #ffdad6;
--info: #87ceff;
--info-foreground: #00344d;
--info-container: #004c6d;
--info-container-foreground: #c9e6ff;
/* Legacy shadcn mappings */
--card: var(--surface-container-low);
--card-foreground: var(--foreground);
--popover: var(--surface-container);
--popover-foreground: var(--foreground);
--muted: var(--surface-container-high);
--muted-foreground: #c5c6d0;
--accent: var(--secondary-container);
--accent-foreground: var(--secondary-container-foreground);
--destructive: var(--error);
--destructive-foreground: var(--error-container-foreground);
--border: #45464f;
--input: transparent;
--input-background: var(--surface-container);
--switch-background: #898790;
--ring: var(--primary);
/* MD3 Outline Variant */
--outline-variant: #45464f;
/* MD3 On-Error-Container */
--on-error-container: #ffdad6;
/* Project Management Specific Colors */
--status-todo: #cfbdfe;
--status-in-progress: #9fcbfa;
--status-review: #c9b6ef;
--status-done: #77db77;
--status-blocked: #ffb4ab;
--priority-critical: #ffb4ab;
--priority-high: #ffb68d;
--priority-medium: #efc047;
--priority-low: #4fd8eb;
/* Chart Colors */
--chart-1: var(--primary);
--chart-2: var(--secondary);
--chart-3: var(--tertiary);
--chart-4: var(--success);
--chart-5: var(--warning);
/* Sidebar */
--sidebar: var(--surface-container-low);
--sidebar-foreground: var(--foreground);
--sidebar-primary: var(--primary);
--sidebar-primary-foreground: var(--primary-container);
--sidebar-accent: var(--surface-container-high);
--sidebar-accent-foreground: var(--foreground);
--sidebar-border: var(--border);
--sidebar-ring: var(--primary);
}
@theme inline {
/* Base colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
/* MD3 Surface colors */
--color-surface: var(--surface);
--color-surface-dim: var(--surface-dim);
--color-surface-bright: var(--surface-bright);
--color-surface-container-lowest: var(--surface-container-lowest);
--color-surface-container-low: var(--surface-container-low);
--color-surface-container: var(--surface-container);
--color-surface-container-high: var(--surface-container-high);
--color-surface-container-highest: var(--surface-container-highest);
/* MD3 Primary color */
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-primary-container: var(--primary-container);
--color-primary-container-foreground: var(--primary-container-foreground);
--color-on-primary: var(--on-primary);
/* MD3 Secondary color */
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary-container: var(--secondary-container);
--color-secondary-container-foreground: var(--secondary-container-foreground);
--color-on-secondary: var(--on-secondary);
/* MD3 Tertiary color */
--color-tertiary: var(--tertiary);
--color-tertiary-foreground: var(--tertiary-foreground);
--color-tertiary-container: var(--tertiary-container);
--color-tertiary-container-foreground: var(--tertiary-container-foreground);
/* Semantic states */
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-success-container: var(--success-container);
--color-success-container-foreground: var(--success-container-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-warning-container: var(--warning-container);
--color-warning-container-foreground: var(--warning-container-foreground);
--color-error: var(--error);
--color-error-foreground: var(--error-foreground);
--color-error-container: var(--error-container);
--color-error-container-foreground: var(--error-container-foreground);
--color-on-error-container: var(--on-error-container);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
--color-info-container: var(--info-container);
--color-info-container-foreground: var(--info-container-foreground);
/* Legacy shadcn */
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-outline-variant: var(--outline-variant);
--color-border: var(--border);
--color-input: var(--input);
--color-input-background: var(--input-background);
--color-switch-background: var(--switch-background);
--color-ring: var(--ring);
/* Project management colors */
--color-status-todo: var(--status-todo);
--color-status-in-progress: var(--status-in-progress);
--color-status-review: var(--status-review);
--color-status-done: var(--status-done);
--color-status-blocked: var(--status-blocked);
--color-priority-critical: var(--priority-critical);
--color-priority-high: var(--priority-high);
--color-priority-medium: var(--priority-medium);
--color-priority-low: var(--priority-low);
/* Charts */
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
/* Radius */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* Sidebar */
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
/**
* Default typography styles for HTML elements (h1-h4, p, label, button, input).
* These are in @layer base, so Tailwind utility classes (like text-sm, text-lg) automatically override them.
*/
html {
font-size: var(--font-size);
}
h1 {
font-size: var(--text-2xl);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h2 {
font-size: var(--text-xl);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h3 {
font-size: var(--text-lg);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h4 {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
label {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
button {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
input {
font-size: var(--text-base);
font-weight: var(--font-weight-normal);
line-height: 1.5;
}
}