diff --git a/backend/app/schemas/epic.py b/backend/app/schemas/epic.py index 9936dde..0b08df4 100644 --- a/backend/app/schemas/epic.py +++ b/backend/app/schemas/epic.py @@ -27,7 +27,7 @@ class EpicCreateRequest(BaseModel): name: str = Field(..., min_length=1, max_length=200, description="Epic name") description: Optional[str] = Field(None, description="Epic description") - content: Optional[Any] = Field(None, description="Rich text content") + content: Optional[Any] = Field(..., min_length=1, description="Rich text content") color: Optional[str] = Field(None, max_length=7, description="Hex color code") pos: Optional[float] = Field(None, description="Position for ordering") depth_limit: Optional[int] = Field( diff --git a/backend/tests/routes/test_epics.py b/backend/tests/routes/test_epics.py index bd03689..be66696 100644 --- a/backend/tests/routes/test_epics.py +++ b/backend/tests/routes/test_epics.py @@ -92,7 +92,9 @@ class TestEpicRoutes: self, client, db_session, auth_headers, test_board ): """Test creating epic with only required fields""" - epic_data = {"name": "Minimal Epic"} + + new_content = [{"type": "heading", "children": [{"text": "Updated Content"}]}] + epic_data = {"name": "Minimal Epic", "content": new_content} response = client.post( f"/api/boards/{test_board.id}/epics", @@ -113,13 +115,18 @@ class TestEpicRoutes: ): """Test creating epic with parent epic""" # Create parent epic - parent_epic = Epic(name="Parent Epic", board_id=test_board.id) + parent_epic = Epic( + name="Parent Epic", + board_id=test_board.id, + content=[{"type": "heading", "children": [{"text": "Updated Content"}]}], + ) db_session.add(parent_epic) db_session.commit() epic_data = { "name": "Child Epic", "parent_epic_id": parent_epic.id, + "content": [{"type": "heading", "children": [{"text": "Updated Content"}]}], } response = client.post( @@ -139,8 +146,8 @@ class TestEpicRoutes: epic_data = { "name": "Epic with Completed List", "completed_list_id": test_list.id, + "content": [{"type": "heading", "children": [{"text": "Updated Content"}]}], } - response = client.post( f"/api/boards/{test_board.id}/epics", headers=auth_headers, @@ -153,7 +160,10 @@ class TestEpicRoutes: def test_create_epic_board_not_found(self, client, db_session, auth_headers): """Test creating epic for non-existent board""" - epic_data = {"name": "Test Epic"} + epic_data = { + "name": "Test Epic", + "content": [{"type": "heading", "children": [{"text": "Updated Content"}]}], + } response = client.post( "/api/boards/99999/epics", diff --git a/docs/figma-design-prompt.md b/docs/figma-design-prompt.md new file mode 100644 index 0000000..9f3d175 --- /dev/null +++ b/docs/figma-design-prompt.md @@ -0,0 +1,850 @@ +# Taskboard โ€” Figma AI Designer Prompt + +> Use this document as a design brief for generating UI flows, wireframes, and high-fidelity mockups in Figma with AI assistance. + +--- + +## 1. Application Overview + +**Taskboard** is a Trello-like Kanban project management web application. Users create Boards containing Lists (columns) and Cards (tasks). Cards support labels, checklists, comments, file attachments, due dates, card-to-card linking, and epic grouping. Boards also have **Epics** (large features spanning multiple cards) and **Wikis** (rich-text documentation pages). + +### Tech Stack +- **Frontend**: React 18 + TypeScript, Tailwind CSS (dark theme), React Router, @dnd-kit (drag-and-drop), Slate.js (rich text editor) +- **Backend**: Flask + SQLAlchemy + PostgreSQL +- **Auth**: JWT-based authentication + +### Design System Basics +- **Theme**: Dark mode by default +- **Background**: `gray-900` (#111827) for page backgrounds, `gray-800` (#1f2937) for card/panel surfaces, `gray-700` (#374151) for inputs and hover states +- **Accent color**: `blue-600` (#2563eb) primary, `blue-500` hover, `blue-400` for text links +- **Text**: `white` for headings, `gray-300` for body text, `gray-400` for secondary/muted text, `gray-500` for placeholders +- **Borders**: `gray-700` for subtle dividers +- **Destructive**: `red-500`/`red-600` for delete/danger actions +- **Success**: `green-500`/`green-600` +- **Border radius**: `rounded-lg` (8px) for cards and inputs, `rounded-md` (6px) for buttons, `rounded-full` for badges/chips +- **Spacing**: Tailwind's 4px base unit (p-4 = 16px, gap-6 = 24px) +- **Typography**: System font stack; headings bold (font-bold), body medium (font-medium) + +--- + +## 2. Navigation & Information Architecture + +### Global Navigation Bar (Navbar) +- **Logo**: "Taskboard" wordmark + icon (left side), links to `/boards` +- **Nav links** (desktop): "Home" โ†’ `/home`, "Boards" โ†’ `/boards` (only when logged in) +- **Auth section** (right side): + - Logged out: "Login" link + "Register" button (blue-600 filled) + - Logged in: Username display + "Logout" button +- **Mobile**: Hamburger menu icon that expands to show same links vertically +- **Height**: 64px (h-16), bg-gray-800 with bottom border-gray-700 + +### Board-Level Sidebar (BoardSidebar) +- Fixed position on the **right edge** of the viewport, vertically centered +- Contains links for the current board context: + - ๐Ÿ“‹ **Epics** โ†’ `/boards/:id/epics` + - ๐Ÿ“š **Wikis** โ†’ `/boards/:id/wikis` + - ๐Ÿ“œ **History** โ†’ `/boards/:id/history` +- Active item has blue-600 background; inactive has gray-800 with hover-gray-700 +- Pill-shaped tabs with rounded-l-lg (left rounded only, flush to right edge) + +### Full Route Map + +| Route | Page | Auth Required | +|-------|------|---------------| +| `/home` | Landing/Marketing page | No | +| `/login` | Login page | No | +| `/register` | Registration page | No | +| `/boards` | Board listing | Yes | +| `/boards/new` | Create new board | Yes | +| `/boards/:id` | Board detail (Kanban board view) | Yes | +| `/boards/:id/edit` | Edit board settings | Yes | +| `/boards/:id/epics` | Epics listing for board | Yes | +| `/boards/:id/epics/new` | Create new epic | Yes | +| `/boards/:id/epics/:epicId` | Epic detail page | Yes | +| `/boards/:id/epics/:epicId/edit` | Edit epic | Yes | +| `/boards/:id/wikis` | Wikis listing for board | Yes | +| `/boards/:id/wikis/new` | Create new wiki | Yes | +| `/boards/:id/wikis/:wikiId` | Wiki detail page | Yes | +| `/boards/:id/wikis/:wikiId/edit` | Edit wiki | Yes | +| `/boards/:id/cards/:cardId` | Card detail page | Yes | + +--- + +## 3. Data Models & Their Fields + +### User +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `email` | string (120) | Shown in auth forms | +| `username` | string (80) | Displayed in navbar, comments | +| `password_hash` | string | Never displayed | +| `first_name` | string (50) | Optional display | +| `last_name` | string (50) | Optional display | +| `is_active` | boolean | Account status | +| `is_admin` | boolean | Admin badge | +| `created_at` | datetime | Account creation date | +| `updated_at` | datetime | Last update | + +### Board +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Board title โ€” prominent heading | +| `description` | text | Subtitle/brief shown below title | +| `closed` | boolean | Archived indicator (badge or dimmed card) | +| `url` | string (500) | External URL reference | +| `short_link` | string (10) | Shareable short link | +| `short_url` | string (500) | Full short URL | +| `user_id` | FK โ†’ User | Board owner | +| `prefs` | JSONB | Board preferences (background, etc.) | +| `label_names` | JSONB | Label colorโ†’name mapping | +| `limits` | JSONB | Card/list limits | +| `date_last_activity` | datetime | "Last active" display | +| `date_last_view` | datetime | "Last viewed" display | +| `created_at` | datetime | Creation date | +| `updated_at` | datetime | Last update | + +### List (Column) +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Column header title | +| `closed` | boolean | Archived indicator | +| `pos` | float | Horizontal sort order | +| `board_id` | FK โ†’ Board | Parent board | +| `created_at` | datetime | โ€” | +| `updated_at` | datetime | โ€” | + +### Card (Task) +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Card title โ€” main heading on detail page | +| `description` | text | Multi-line description; editable inline | +| `closed` | boolean | Archived indicator | +| `due` | datetime | Due date โ€” shown as badge on card, date picker in editor | +| `due_complete` | boolean | Checkbox to mark due as done | +| `pos` | float | Sort position within list | +| `id_short` | integer | Short ID for display | +| `board_id` | FK โ†’ Board | Parent board | +| `list_id` | FK โ†’ List | Current list (shown as "In list [name]") | +| `epic_id` | FK โ†’ Epic | Assigned epic (nullable) | +| `badges` | JSONB | Stats (checklist count, comment count, attachment count) | +| `cover` | JSONB | Cover image settings | +| `desc_data` | JSONB | Rich description data | +| `date_last_activity` | datetime | โ€” | +| `created_at` | datetime | "Created [date]" display | +| `updated_at` | datetime | โ€” | + +### Label +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (100) | Label text (shown on hover) | +| `color` | string (50) | Color name (green, red, blue, etc.) โ€” rendered as colored chip/badge | +| `uses` | integer | Usage count | +| `board_id` | FK โ†’ Board | Parent board | + +### Checklist +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Checklist heading | +| `pos` | float | Sort order among checklists | +| `card_id` | FK โ†’ Card | Parent card | +| `board_id` | FK โ†’ Board | Parent board | + +### CheckItem +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (500) | Item text with checkbox | +| `pos` | float | Sort order | +| `state` | "complete" / "incomplete" | Checkbox state | +| `due` | datetime | Optional due date | +| `checklist_id` | FK โ†’ Checklist | Parent checklist | +| `user_id` | FK โ†’ User | Assigned user | + +### Comment +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `text` | text | Comment body text | +| `card_id` | FK โ†’ Card | Parent card | +| `user_id` | FK โ†’ User | Author (display username + timestamp) | +| `created_at` | datetime | "Posted [relative time]" | +| `updated_at` | datetime | "Edited" indicator | + +### FileAttachment +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `uuid` | string (36) | Public identifier | +| `filename` | string (255) | Storage filename | +| `original_name` | string (255) | Display name | +| `file_type` | string (50) | "image", "pdf", "document" โ€” determines icon/preview | +| `mime_type` | string (100) | MIME type | +| `file_size` | integer | Display as "KB", "MB" | +| `attachable_type` | string (50) | "Card", "Comment", "Epic" โ€” polymorphic parent | +| `attachable_id` | integer | ID of parent entity | +| `uploaded_by` | FK โ†’ User | Uploader | +| `thumbnail_url` | string | Thumbnail for images | +| `created_at` | datetime | Upload date | + +### Epic +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Epic title | +| `description` | text | Brief description | +| `content` | JSONB | Rich text content (Slate.js JSON) | +| `color` | string (7) | Hex color for epic badge (e.g., "#FF5733") | +| `closed` | boolean | Completed/archived indicator | +| `pos` | float | Sort order | +| `depth_limit` | integer | Max nesting depth (default 5) | +| `board_id` | FK โ†’ Board | Parent board | +| `parent_epic_id` | FK โ†’ Epic (nullable) | Parent epic for hierarchy | +| `completed_list_id` | FK โ†’ List (nullable) | Which list counts as "done" | +| `metrics` | JSONB | `{ card_count: 10, completed_cards_count: 7 }` โ€” progress bar | +| `date_last_activity` | datetime | โ€” | +| `created_at` | datetime | โ€” | +| `updated_at` | datetime | โ€” | + +### Wiki +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `name` | string (200) | Wiki page title | +| `slug` | string (255) | URL-friendly identifier | +| `content` | JSONB | Rich text content (Slate.js JSON) | +| `summary` | text | Brief description/abstract | +| `category` | string (100) | Category grouping label | +| `board_id` | FK โ†’ Board | Parent board | +| `created_by` | FK โ†’ User | Author | +| `updated_by` | FK โ†’ User | Last editor | +| `tags` | JSONB | Array of tag strings: `["security", "api"]` | +| `created_at` | datetime | โ€” | +| `updated_at` | datetime | โ€” | + +### CardLink (Card-to-Card Relationship) +| Field | Type | Display Notes | +|-------|------|---------------| +| `id` | integer | Internal | +| `parent_card_id` | FK โ†’ Card | Parent card | +| `child_card_id` | FK โ†’ Card | Child card | +| `created_by` | FK โ†’ User | Who linked them | +| `created_at` | datetime | When linked | + +--- + +## 4. Page-by-Page UI Specifications + +--- + +### PAGE 1: Landing / Home Page (`/home`) + +**Purpose**: Marketing landing page introducing Taskboard. Visible to all visitors. + +**Layout**: Full-width centered layout + +**Elements**: +- **Hero Section** + - Large heading: "Taskboard" with tagline (e.g., "Organize your work, your way") + - Two CTA buttons: "Get Started" โ†’ `/register` (blue-600 filled), "Login" โ†’ `/login` (outline/ghost) + - Optional illustration or screenshot mockup +- **Features Section** (optional) + - 3-4 feature cards in a grid: Kanban boards, Epics, Wikis, Card linking +- **Footer** with basic links + +**Interactions**: Click CTAs to navigate to auth pages + +--- + +### PAGE 2: Login Page (`/login`) + +**Purpose**: User authentication + +**Layout**: Narrow centered card on dark background + +**Elements**: +- "Taskboard" logo/wordmark at top +- Heading: "Sign in to your account" +- **Form fields**: + - **Email** โ€” text input with label, placeholder "you@example.com" + - **Password** โ€” password input with label, placeholder "โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข" +- **Submit button**: "Sign In" (full width, blue-600) +- **Link**: "Don't have an account? Register" โ†’ `/register` +- Error message area (red text, shown on failed login) + +--- + +### PAGE 3: Register Page (`/register`) + +**Purpose**: New user registration + +**Layout**: Narrow centered card on dark background + +**Elements**: +- "Taskboard" logo/wordmark at top +- Heading: "Create your account" +- **Form fields**: + - **Username** โ€” text input, placeholder "Choose a username" + - **Email** โ€” text input, placeholder "you@example.com" + - **Password** โ€” password input, placeholder "Create a password" + - **Confirm Password** โ€” password input, placeholder "Confirm your password" +- **Submit button**: "Create Account" (full width, blue-600) +- **Link**: "Already have an account? Sign in" โ†’ `/login` +- Validation error messages per field + +--- + +### PAGE 4: Boards List (`/boards`) + +**Purpose**: View all boards the user owns/participates in + +**Layout**: Wide page layout with padding + +**Elements**: +- **Page header**: + - Heading: "My Boards" + - Button: "+ New Board" (blue-600) โ†’ navigates to `/boards/new` +- **Board grid** (responsive: 1 col mobile, 2 col tablet, 3-4 col desktop): + - Each **Board card** shows: + - Board name (bold, white text) + - Description snippet (gray-400, truncated) + - Metadata: "Last active: [relative date]" or "Created [date]" + - Card count indicator (optional badge) + - Closed/archived boards shown dimmed or with "Archived" badge + - Click on board card โ†’ navigates to `/boards/:id` +- **Empty state**: "No boards yet. Create your first board to get started!" with CTA button + +--- + +### PAGE 5: Create Board (`/boards/new`) + +**Purpose**: Create a new Kanban board + +**Layout**: Narrow centered form + +**Elements**: +- Breadcrumb: "โ† Back to Boards" โ†’ `/boards` +- Heading: "Create New Board" +- **Form fields**: + - **Board Name** โ€” text input (required), placeholder "Enter board name" + - **Description** โ€” textarea, placeholder "Describe your board (optional)" +- **Buttons**: "Create Board" (blue-600), "Cancel" (gray-600, navigates back) + +--- + +### PAGE 6: Edit Board (`/boards/:id/edit`) + +**Purpose**: Edit board settings + +**Layout**: Narrow centered form + +**Elements**: +- Breadcrumb: "โ† Back to Board" โ†’ `/boards/:id` +- Heading: "Edit Board" +- **Form fields**: + - **Board Name** โ€” text input (pre-filled) + - **Description** โ€” textarea (pre-filled) + - **Closed** โ€” toggle/checkbox "Archive this board" +- **Buttons**: "Save Changes" (blue-600), "Cancel" (gray-600) + +--- + +### PAGE 7: Board Detail โ€” Kanban View (`/boards/:id`) โ˜… PRIMARY PAGE + +**Purpose**: The main Kanban board interface. This is the core of the application. + +**Layout**: Full-width, horizontally scrollable. BoardSidebar on right edge. + +**Elements**: +- **Top bar**: + - Breadcrumb: "โ† Back to Boards" โ†’ `/boards` + - Board name (h1, large, bold) + - Board description (gray-400, below name) + - Action buttons (right aligned): + - "Edit Board" (gray-700 button) โ†’ `/boards/:id/edit` + - "+ Add List" (blue-600 button) +- **Kanban board area** (horizontal flex container, scrollable): + - **List/Column** (each ~300px wide, bg-gray-800, rounded-lg): + - **Column header**: List name (bold), with dropdown menu (โ‹ฎ) for: Rename list, Delete list + - **Card list** (vertical, scrollable): + - Each **KanbanCard** shows: + - Card name (white, medium weight) + - Label chips (colored dots or small pills below name) + - Badges row: checklist icon + count, comment icon + count, attachment icon + count + - Due date badge (if set): date text, red if overdue, green if complete + - Epic badge (if assigned): colored pill with epic name + - Parent card indicator: "Linked from: [card name]" (gray-400 text) + - **"Add card" button** at bottom of list: "+ Add a card" (text button, gray-400) + - **"Add another list" card**: Dashed border placeholder at end of columns +- **Drag & Drop**: Cards can be dragged between lists and reordered within lists. Lists can be reordered horizontally. Show ghost/overlay of dragged item. + +**Interactions**: +- Click card โ†’ opens Card Preview Modal OR navigates to Card Detail +- Click "+ Add a card" โ†’ opens Create Card Modal +- Click "+ Add List" โ†’ opens Create List Modal +- Drag card/column to reorder + +--- + +### PAGE 8: Card Detail Page (`/boards/:id/cards/:cardId`) โ˜… KEY PAGE + +**Purpose**: Full detailed view and editing of a single card + +**Layout**: Narrow centered layout (max-width ~900px). Two-column grid: main content (2/3) + sidebar (1/3). + +**Elements**: + +**Top Section**: +- Breadcrumb: "โ† Back to Board" โ†’ `/boards/:id` +- Card name (h1, 3xl bold, inline-editable โ€” click edit icon to rename) +- Subtitle: "In list [list name] โ€ข Created [date]" +- **Action dropdown** (โ‹ฎ icon, top-right): Edit Name, Delete Card, Create Linked Card, Link Existing Card + +**Main Content (left 2/3)**: + +1. **Description Section** (bg-gray-800 card) + - Heading "Description" + "Edit" button + - Display mode: rendered text or "No description added yet." placeholder + - Edit mode: textarea with Save/Cancel buttons + +2. **Labels Section** + - Colored label chips attached to this card + - Button to add/remove labels (opens label picker dropdown) + - Label picker: list of board labels as colored rows, click to toggle + +3. **Epic Section** + - If assigned: colored epic badge with name, click to navigate to epic + - Button to assign/change epic (opens epic picker dropdown) + +4. **Linked Cards Section** + - List of linked parent/child cards with name and link icon + - Each link has "Unlink" button (ร—) + - Empty state: "No linked cards" + +5. **Checklists Section** + - Multiple checklists, each with: + - Checklist name heading + delete button (trash icon) + - Progress bar (percentage of completed items) + - List of CheckItems, each with: + - Checkbox (complete/incomplete) + - Item name (strikethrough when complete) + - Due date (if set) + - Action menu: Edit, Convert to Card, Delete + - "Add item" input at bottom + - "Add Checklist" button + +6. **Attachments Section** + - File upload area (drag & drop or click to browse) + - List of uploaded files: + - Image preview (thumbnail) for images + - File icon + name for documents/PDFs + - File name, size, upload date + - Actions: View, Download, Delete + +7. **Comments Section** + - Comment input: textarea + "Save" button + - List of comments (newest first): + - Author username + avatar placeholder + - Comment text + - Timestamp (relative: "2h ago") + - Actions: Edit (pencil icon), Delete (trash icon) + - Edit mode: inline textarea with Save/Cancel + +**Sidebar (right 1/3)** โ€” CardSidebar component: +- **Due Date**: Date display, "Mark complete" checkbox, date picker to change +- **List**: Current list name, dropdown to move card to another list +- **Epic**: Current epic or "None", link to epic detail +- **Created Date**: Full datetime +- **Last Activity**: Relative datetime +- **Card ID**: Short ID display + +**Modals accessible from this page**: +- Delete Card Modal +- Create Linked Card Modal (name + description fields) +- Link Existing Card Modal (search/select from board cards) +- Unlink Card Modal (confirmation) +- Create Checklist Modal +- Delete Checklist Modal +- Edit Check Item Modal + +--- + +### PAGE 9: Board Epics (`/boards/:id/epics`) + +**Purpose**: View and manage all epics for a board + +**Layout**: Wide page layout with BoardSidebar + +**Elements**: +- Breadcrumb: "โ† Back to Board" โ†’ `/boards/:id` +- Heading: "Epics" +- Button: "+ New Epic" (blue-600) โ†’ `/boards/:id/epics/new` +- **Epics list/table**: + - Each epic row/card shows: + - **Color dot** (epic color) + - **Epic name** (bold, links to detail page) + - **Description** snippet (truncated) + - **Progress bar**: `completed_cards_count / card_count` with percentage + - **Status**: Open/Closed badge + - **Last activity**: Relative date + - **Actions**: Edit (pencil), Delete (trash) + - Nested epics shown indented under parent +- **Empty state**: "No epics yet. Create an epic to group related cards." + +--- + +### PAGE 10: Create Epic (`/boards/:id/epics/new`) + +**Purpose**: Create a new epic + +**Layout**: Narrow centered form + +**Elements**: +- Breadcrumb: "โ† Back to Epics" โ†’ `/boards/:id/epics` +- Heading: "Create New Epic" +- **Form fields**: + - **Name** โ€” text input (required), placeholder "Epic name" + - **Description** โ€” textarea, placeholder "Brief description" + - **Color** โ€” color picker or preset color swatches (hex input) + - **Rich Text Content** โ€” Slate.js rich text editor with toolbar (bold, italic, lists, headings, links, images) + - **Parent Epic** โ€” dropdown select (nullable, "None" option) + - **Completed List** โ€” dropdown select (which list means "done") +- **Buttons**: "Create Epic" (blue-600), "Cancel" (gray-600) + +--- + +### PAGE 11: Edit Epic (`/boards/:id/epics/:epicId/edit`) + +**Purpose**: Edit an existing epic + +**Layout**: Same as Create Epic, pre-filled with existing data + +**Additional fields**: +- **Closed** โ€” toggle "Mark epic as completed/closed" + +--- + +### PAGE 12: Epic Detail (`/boards/:id/epics/:epicId`) + +**Purpose**: View full epic details with progress and linked cards + +**Layout**: Narrow centered layout + +**Elements**: +- Breadcrumb: "โ† Back to Epics" +- **Header**: + - Epic name (h1) with color dot + - Description (gray-300) + - Status badge: Open/Closed + - "Edit" button โ†’ edit page +- **Progress Section**: + - Progress bar showing `completed_cards_count / card_count` + - Percentage text +- **Rich Text Content**: Rendered Slate.js content (formatted text, images, links) +- **Linked Cards**: + - List of cards assigned to this epic + - Each card shows: name, current list, labels, due date + - Click card โ†’ navigates to card detail +- **Child Epics** (if any): + - Nested list of sub-epics with same info +- **Attachments** (if any): + - File list with preview/download + +--- + +### PAGE 13: Board Wikis (`/boards/:id/wikis`) + +**Purpose**: View and manage all wiki pages for a board + +**Layout**: Wide page layout with BoardSidebar + +**Elements**: +- Breadcrumb: "โ† Back to Board" โ†’ `/boards/:id` +- Heading: "Wikis" +- Button: "+ New Wiki" (blue-600) โ†’ `/boards/:id/wikis/new` +- **Wiki list/grid**: + - Each wiki card shows: + - **Wiki name** (bold, links to detail) + - **Summary** (truncated, gray-400) + - **Category** badge (if set) + - **Tags** as small pills/chips + - **Author**: Created by [username] + - **Last updated**: Relative date + - **Actions**: Edit (pencil), Delete (trash) +- **Empty state**: "No wiki pages yet. Create a wiki to document your project." + +--- + +### PAGE 14: Create Wiki (`/boards/:id/wikis/new`) + +**Purpose**: Create a new wiki page + +**Layout**: Wide page layout (to accommodate rich text editor) + +**Elements**: +- Breadcrumb: "โ† Back to Wikis" โ†’ `/boards/:id/wikis` +- Heading: "Create New Wiki" +- **Form fields**: + - **Name** โ€” text input (required), placeholder "Wiki page title" + - **Slug** โ€” text input, auto-generated from name, editable, placeholder "url-friendly-slug" + - **Summary** โ€” textarea, placeholder "Brief description" + - **Category** โ€” text input, placeholder "Category (optional)" + - **Tags** โ€” tag input (add/remove tags, shown as chips) + - **Content** โ€” Slate.js rich text editor (full width): + - Toolbar: Bold, Italic, Underline, Strikethrough, Headings (H1-H3), Bulleted List, Numbered List, Link, Image, Code Block, Quote + - Large editable area +- **Buttons**: "Create Wiki" (blue-600), "Cancel" (gray-600) + +--- + +### PAGE 15: Edit Wiki (`/boards/:id/wikis/:wikiId/edit`) + +**Purpose**: Edit an existing wiki page + +**Layout**: Same as Create Wiki, pre-filled with existing data + +--- + +### PAGE 16: Wiki Detail (`/boards/:id/wikis/:wikiId`) + +**Purpose**: View a wiki page's content + +**Layout**: Narrow centered layout + +**Elements**: +- Breadcrumb: "โ† Back to Wikis" +- **Header**: + - Wiki name (h1) + - Category badge (if set) + - Tags as colored chips + - Summary text (gray-300, italic) + - Metadata: "Created by [author] on [date] โ€ข Last updated [date] by [editor]" + - "Edit" button โ†’ edit page +- **Content**: Rendered Slate.js rich text (headings, paragraphs, lists, images, links, code blocks, quotes) +- **Linked Entities** (if any): + - "Linked Cards" section: list of linked cards with name and link + - "Linked Epics" section: list of linked epics with name and link + +--- + +## 5. Modal Catalog + +### Create List Modal +- **Triggered**: "+ Add List" button on board detail +- **Fields**: List Name (text input) +- **Actions**: "Create List" (blue-600), "Cancel" + +### Edit List Modal +- **Triggered**: Rename option from list dropdown menu +- **Fields**: List Name (text input, pre-filled) +- **Actions**: "Save" (blue-600), "Cancel" + +### Delete List Modal +- **Triggered**: Delete option from list dropdown menu +- **Content**: "Are you sure you want to delete '[list name]'? All cards in this list will be permanently deleted." +- **Actions**: "Delete" (red-600), "Cancel" + +### Create Card Modal +- **Triggered**: "+ Add a card" button at bottom of a list +- **Fields**: Card Name (text input, required), Description (textarea, optional) +- **Actions**: "Create Card" (blue-600), "Cancel" + +### Edit Card Modal +- **Triggered**: Edit action on card +- **Fields**: Card Name (text input), Description (textarea) +- **Actions**: "Save" (blue-600), "Cancel" + +### Delete Card Modal +- **Triggered**: Delete action from card dropdown +- **Content**: "Are you sure you want to delete '[card name]'? This action cannot be undone." +- **Actions**: "Delete" (red-600), "Cancel" + +### Card Preview Modal +- **Triggered**: Clicking a card on the Kanban board +- **Content**: Compact card view with name, description, labels, badges +- **Actions**: "View Full Details" (navigates to card detail), "Close" + +### Create Linked Card Modal +- **Triggered**: "Create Linked Card" from card action dropdown +- **Purpose**: Create a new card and automatically link it as a child +- **Fields**: Card Name (text input), Description (textarea) +- **Actions**: "Create & Link" (blue-600), "Cancel" + +### Link Existing Card Modal +- **Triggered**: "Link Existing Card" from card action dropdown +- **Purpose**: Search and select an existing card on the board to link +- **Fields**: Search input, list of matching cards with radio buttons +- **Actions**: "Link Card" (blue-600), "Cancel" + +### Unlink Card Modal +- **Triggered**: "Unlink" button on a linked card +- **Content**: "Are you sure you want to unlink '[card name]' from '[parent card name]'?" +- **Actions**: "Unlink" (red-600), "Cancel" + +### Create Checklist Modal +- **Triggered**: "Add Checklist" button in card checklists section +- **Fields**: Checklist Name (text input) +- **Actions**: "Add" (blue-600), "Cancel" + +### Delete Checklist Modal +- **Triggered**: Delete button on a checklist +- **Content**: "Are you sure you want to delete the checklist '[name]'? All items will be removed." +- **Actions**: "Delete" (red-600), "Cancel" + +### Edit Check Item Modal +- **Triggered**: Edit action on a checklist item +- **Fields**: Item Name (text input) +- **Actions**: "Save" (blue-600), "Cancel" + +### Create Label Modal +- **Triggered**: "Create new label" option in label picker +- **Fields**: Label Name (text input), Color (color swatches picker) +- **Actions**: "Create" (blue-600), "Cancel" + +--- + +## 6. Key User Flows + +### Flow 1: Registration & First Board +1. User visits `/home` โ†’ clicks "Get Started" +2. Fills registration form on `/register` โ†’ submits +3. Auto-logged in โ†’ redirected to `/boards` +4. Empty state shown โ†’ clicks "+ New Board" +5. Enters board name + description โ†’ clicks "Create Board" +6. Redirected to new board `/boards/:id` โ†’ empty board with no lists +7. Clicks "+ Add List" โ†’ enters list name (e.g., "To Do", "In Progress", "Done") +8. Repeats for more lists + +### Flow 2: Creating and Managing Cards +1. On board view, clicks "+ Add a card" in a list +2. Enters card name โ†’ creates card +3. Clicks card โ†’ card preview modal opens +4. Clicks "View Full Details" โ†’ navigates to Card Detail page +5. Adds description, assigns labels, sets due date +6. Adds checklist with items, checks off items +7. Adds comments +8. Uploads file attachments +9. Returns to board โ†’ sees updated card with badges + +### Flow 3: Card Linking +1. On Card Detail page, clicks action dropdown (โ‹ฎ) +2. Selects "Create Linked Card" โ†’ enters name/description โ†’ creates +3. OR selects "Link Existing Card" โ†’ searches board cards โ†’ selects one โ†’ links +4. Linked cards shown in "Linked Cards" section +5. Can unlink via ร— button โ†’ confirms in Unlink Card Modal + +### Flow 4: Epic Management +1. From board sidebar, clicks "Epics" +2. On epics page, clicks "+ New Epic" +3. Fills in name, description, color, rich content, assigns completed list +4. On board view, opens a card โ†’ assigns the epic +5. Epic metrics auto-update (card count, completion progress) + +### Flow 5: Wiki Documentation +1. From board sidebar, clicks "Wikis" +2. Clicks "+ New Wiki" +3. Enters title, summary, category, tags +4. Writes rich text content in editor +5. Saves โ†’ views rendered wiki page +6. Can link wiki to cards/epics + +### Flow 6: Drag & Drop on Board +1. User hovers over a card โ†’ cursor changes to grab +2. Drags card to new position in same list OR to different list +3. Ghost overlay follows cursor +4. On drop, card moves to new position/list +5. Lists can also be reordered by dragging column headers + +--- + +## 7. Component Inventory + +### Reusable UI Components +| Component | Description | +|-----------|-------------| +| **Navbar** | Top navigation with logo, links, auth controls | +| **BoardSidebar** | Fixed right-side nav for board sections | +| **KanbanColumn** | Vertical list container with header and card list | +| **SortableKanbanColumn** | Drag-enabled version of KanbanColumn | +| **KanbanCard** | Card summary shown in columns (name, badges, labels) | +| **BoardCard** | Board summary card for the boards listing page | +| **CardPreviewModal** | Quick card preview popup | +| **CardSidebar** | Right sidebar on card detail (due date, list, etc.) | +| **CardLabels** | Label chips display + picker | +| **LabelDropdown** | Dropdown for selecting/toggling labels | +| **CardEpics** | Epic assignment display + picker | +| **CardLinks** | Linked cards display with unlink action | +| **CardChecklists** | Checklists with checkable items, progress bars | +| **CardComments** | Comment thread with add/edit/delete | +| **CardAttachments** | File upload area + attachment list | +| **CardActionDropdown** | Context menu (โ‹ฎ) for card actions | +| **RichTextEditor** | Slate.js rich text editor with formatting toolbar | +| **RichTextContent** | Read-only rich text renderer | +| **SecureImage** | Authenticated image component (MinIO-backed) | +| **WidePageLayout** | Full-width page wrapper with standard padding | +| **NarrowPageLayout** | Centered narrow content wrapper (~900px max) | +| **DeleteCardModal** | Confirmation dialog for card deletion | +| **DeleteListModal** | Confirmation dialog for list deletion | +| **CreateListModal** | Form modal for creating a new list | +| **EditListModal** | Form modal for editing a list name | +| **CreateCardModal** | Form modal for creating a new card | +| **EditCardModal** | Form modal for editing card name/description | +| **CreateLinkedCardModal** | Form modal for creating + linking a card | +| **LinkExistingCardModal** | Search/select modal for linking existing cards | +| **UnlinkCardModal** | Confirmation modal for unlinking cards | +| **CreateChecklistModal** | Form modal for adding a checklist | +| **DeleteChecklistModal** | Confirmation modal for deleting a checklist | +| **EditCheckItemModal** | Form modal for editing a checklist item | +| **CreateLabelModal** | Form modal for creating a new label | +| **ProtectedRoute** | Auth guard wrapper component | + +--- + +## 8. States to Design + +For each page, please design these states: + +1. **Loading state**: Skeleton/spinner while data loads +2. **Empty state**: Helpful message + CTA when no data exists +3. **Populated state**: Normal data display +4. **Error state**: Error message display (toast notification pattern) +5. **Mobile responsive**: Stack layouts vertically, hamburger nav, full-width cards + +### Special States +- **Card dragging**: Ghost overlay of card at cursor position +- **Column dragging**: Ghost overlay of column at cursor position +- **Inline editing**: Input fields replacing display text (card name, description) +- **Modal overlay**: Dark backdrop with centered modal card +- **Toast notifications**: Top-right corner, auto-dismiss, types: success (green), error (red), info (blue) +- **Archived items**: Dimmed with "Archived" badge + +--- + +## 9. Responsive Breakpoints + +| Breakpoint | Width | Layout Changes | +|-----------|-------|----------------| +| Mobile | < 640px | Single column, hamburger nav, stacked cards, full-width modals | +| Tablet | 640-1024px | 2-column grids, collapsible sidebar | +| Desktop | > 1024px | Full kanban horizontal scroll, 3-column card detail, sidebar visible | + +--- + +## 10. Design Priorities + +1. **Board Detail (Kanban View)** โ€” This is the most-used page; prioritize its drag-and-drop UX +2. **Card Detail** โ€” Second most important; dense information layout +3. **Card Detail Modals** โ€” Many user workflows happen through modals +4. **Boards List** โ€” Entry point after login +5. **Epic Detail & Wiki Detail** โ€” Supporting features +6. **Auth Pages** โ€” Simple but must look polished +7. **Forms (Create/Edit)** โ€” Standard patterns, focus on rich text editor UX + +--- + +*End of design brief. Use this document to generate complete UI flows and page designs for the Taskboard application.* \ No newline at end of file diff --git a/frontend/src/components/slate-editor-components/index.tsx b/frontend/src/components/slate-editor-components/index.tsx index a9ac33d..3131ca4 100644 --- a/frontend/src/components/slate-editor-components/index.tsx +++ b/frontend/src/components/slate-editor-components/index.tsx @@ -466,8 +466,11 @@ export const Leaf = ({ attributes, children, leaf }: RenderLeafProps) => { const isAlignElement = (element: CustomElement): element is CustomElementWithAlign => { return 'align' in element; }; + export const SlateRenderElement = ({ attributes, children, element }: RenderElementProps) => { - switch (element.type) { + console.log('SlateRenderElement', element); + const elementType = element.type ? element.type.split(' ')[0] : ''; + switch (elementType) { case 'block-quote': return (
{children} ); + case 'code-line': + return ( + + {children} + + ); case 'bulleted-list': return (