Frontend UI Engineering
Overview
This skill establishes high-fidelity standards for designing and implementing frontend components for the gtding project. It aims for a visually stunning, polished, and premium user experience that feels handcrafted by a professional engineer — avoiding all default "AI-generated" templates.
When to Use
Apply this skill when:
- Creating new UI components, forms, layout grids, or pages in the project.
- Modifying existing React components or adjusting CSS styles.
- Integrating Ant Design 6 theme components or adjusting typography and spacing.
- Optimizing interface state management or adding smooth transitions/micro-animations.
When NOT to Use:
- Writing core backend integrations, database scripts, or pure dev tooling scripts.
- Refactoring unit test suites without touching UI files.
Core Principles
1. The "No Modals" Absolute Guardrail
- Rule: Every screen, card editor, details pane, or configuration form MUST be implemented as a separate route using
React Router DOM 7.
- Action: Never write
<Modal> popups. Instead, redirect to /tasks/new, /tasks/:id/edit, etc. Keep history navigable!
2. Fight the "AI Aesthetic"
AI-generated interfaces look identical and cheap. Follow these strict counters to maintain a premium feel:
- Project Color Tokens: Avoid heavy purple/indigo default templates. Use harmonized Ant Design 6 color palettes and neutral, high-end dark/light modes.
- Subtle Gradients: Use flat solids or very subtle, smooth HSL-tailored gradients instead of harsh, high-contrast visual noise.
- Corner Radii Consistency: Rely on the defined Ant Design 6 theme border-radii. Avoid rounding everything with extreme values (like generic
rounded-2xl).
- Realistic Placeholder Copy: Never use
Lorem Ipsum or generic "Task 1", "Task 2". Use realistic task descriptions matching a GTD app (e.g., "Подготовить презентацию для Олега", "Купить молоко", "Написать тесты для TaskStore").
3. Universal Undo/Redo Support
- Rule: EVERY user action that mutates an entity (Task, Note, Project, Person, Tag, etc.) MUST be reversible via global
Ctrl+Z / Cmd+Z.
- Action: When adding new stores or mutation methods, ensure they push to their
undoRedoState, return canUndo/canRedo flags in updates, and integrate getLastUndoTimestamp() into the global useUndoRedoKeyboard listener (usually in MainLayout). The hotkey logic must properly handle alternative layouts (e.g., Russian 'я' and 'н', or rely on e.code === 'KeyZ').
Component Architecture Patterns
1. Prefer Composition over Configuration
Avoid massive components with dozens of layout configuration props. Use children composition:
// Good: Composable, readable, and highly maintainable
<Card>
<CardHeader>
<CardTitle>Текущие задачи</CardTitle>
</CardHeader>
<CardBody>
<TaskList tasks={tasks} />
</CardBody>
</Card>
// Avoid: Over-configured, rigid component
<Card
title="Текущие задачи"
headerSize="large"
bodyPadding="md"
bodyContent={<TaskList tasks={tasks} />}
/>
2. Separate Data Fetching from Presentation
Isolate data fetching or global state hooks from the layout render components (Container vs. Presentation):
// Container: handles Zustand state & hooks
export function TaskListContainer() {
const { tasks, isLoading } = useTaskStore();
if (isLoading) return <TaskListSkeleton />;
if (tasks.length === 0) return <EmptyState message="Все задачи выполнены!" />;
return <TaskList tasks={tasks} />;
}
// Presentation: handles rendering and styles
export function TaskList({ tasks }: { tasks: Task[] }) {
return (
<ul role="list" className="divide-y divide-gray-100">
{tasks.map(task => <TaskItem key={task.id} task={task} />)}
</ul>
);
}
State Management Decision Matrix
Always choose the simplest state container that fits:
- Local State (
useState): For transient UI state (toggles, input focus, local button hover states).
- URL Search Parameters (
searchParams): For filters, pagination, or query searches (keeps views easily shareable and bookmarkable).
- Global Store (
Zustand + Immer): For app-wide entity state (tasks, active projects, user contexts). Keep state modifications immutable with Immer helper actions.
1---2name: frontend-ui-engineering3description: Builds production-quality UIs in the GTDing project. Enforces robust React 19 patterns, Ant Design 6 tokens, and fights against cheap AI visual aesthetics.4---56# Frontend UI Engineering78## Overview9This skill establishes high-fidelity standards for designing and implementing frontend components for the `gtding` project. It aims for a visually stunning, polished, and premium user experience that feels handcrafted by a professional engineer — avoiding all default "AI-generated" templates.1011---1213## When to Use14Apply this skill when:15- Creating new UI components, forms, layout grids, or pages in the project.16- Modifying existing React components or adjusting CSS styles.17- Integrating Ant Design 6 theme components or adjusting typography and spacing.18- Optimizing interface state management or adding smooth transitions/micro-animations.1920**When NOT to Use:**21- Writing core backend integrations, database scripts, or pure dev tooling scripts.22- Refactoring unit test suites without touching UI files.2324---2526## Core Principles2728### 1. The "No Modals" Absolute Guardrail29- **Rule**: Every screen, card editor, details pane, or configuration form MUST be implemented as a separate route using `React Router DOM 7`. 30- **Action**: Never write `<Modal>` popups. Instead, redirect to `/tasks/new`, `/tasks/:id/edit`, etc. Keep history navigable!3132### 2. Fight the "AI Aesthetic"33AI-generated interfaces look identical and cheap. Follow these strict counters to maintain a premium feel:34- **Project Color Tokens**: Avoid heavy purple/indigo default templates. Use harmonized Ant Design 6 color palettes and neutral, high-end dark/light modes.35- **Subtle Gradients**: Use flat solids or very subtle, smooth HSL-tailored gradients instead of harsh, high-contrast visual noise.36- **Corner Radii Consistency**: Rely on the defined Ant Design 6 theme border-radii. Avoid rounding everything with extreme values (like generic `rounded-2xl`).37- **Realistic Placeholder Copy**: Never use `Lorem Ipsum` or generic "Task 1", "Task 2". Use realistic task descriptions matching a GTD app (e.g., *"Подготовить презентацию для Олега"*, *"Купить молоко"*, *"Написать тесты для TaskStore"*).3839### 3. Universal Undo/Redo Support40- **Rule**: EVERY user action that mutates an entity (Task, Note, Project, Person, Tag, etc.) MUST be reversible via global `Ctrl+Z` / `Cmd+Z`.41- **Action**: When adding new stores or mutation methods, ensure they push to their `undoRedoState`, return `canUndo`/`canRedo` flags in updates, and integrate `getLastUndoTimestamp()` into the global `useUndoRedoKeyboard` listener (usually in `MainLayout`). The hotkey logic must properly handle alternative layouts (e.g., Russian `'я'` and `'н'`, or rely on `e.code === 'KeyZ'`).4243---4445## Component Architecture Patterns4647### 1. Prefer Composition over Configuration48Avoid massive components with dozens of layout configuration props. Use children composition:4950```tsx51// Good: Composable, readable, and highly maintainable52<Card>53 <CardHeader>54 <CardTitle>Текущие задачи</CardTitle>55 </CardHeader>56 <CardBody>57 <TaskList tasks={tasks} />58 </CardBody>59</Card>6061// Avoid: Over-configured, rigid component62<Card63 title="Текущие задачи"64 headerSize="large"65 bodyPadding="md"66 bodyContent={<TaskList tasks={tasks} />}67/>68```6970### 2. Separate Data Fetching from Presentation71Isolate data fetching or global state hooks from the layout render components (Container vs. Presentation):7273```tsx74// Container: handles Zustand state & hooks75export function TaskListContainer() {76 const { tasks, isLoading } = useTaskStore();7778 if (isLoading) return <TaskListSkeleton />;79 if (tasks.length === 0) return <EmptyState message="Все задачи выполнены!" />;8081 return <TaskList tasks={tasks} />;82}8384// Presentation: handles rendering and styles85export function TaskList({ tasks }: { tasks: Task[] }) {86 return (87 <ul role="list" className="divide-y divide-gray-100">88 {tasks.map(task => <TaskItem key={task.id} task={task} />)}89 </ul>90 );91}92```9394---9596## State Management Decision Matrix97Always choose the simplest state container that fits:981. **Local State (`useState`)**: For transient UI state (toggles, input focus, local button hover states).992. **URL Search Parameters (`searchParams`)**: For filters, pagination, or query searches (keeps views easily shareable and bookmarkable).1003. **Global Store (`Zustand + Immer`)**: For app-wide entity state (tasks, active projects, user contexts). Keep state modifications immutable with Immer helper actions.