From c727096d020290942c39829ead350aa0cec2afff Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 00:41:57 +0000 Subject: [PATCH] Refactor comprehensive demo layout --- src/components/ComprehensiveDemoPage.tsx | 295 ++---------------- ...omprehensiveDemoArchitectureHighlights.tsx | 25 ++ .../ComprehensiveDemoDialogs.tsx | 78 +++++ .../ComprehensiveDemoHeader.tsx | 12 + .../ComprehensiveDemoStatsRow.tsx | 68 ++++ .../ComprehensiveDemoTaskList.tsx | 116 +++++++ src/components/comprehensive-demo/types.ts | 9 + src/data/comprehensive-demo.json | 65 ++++ 8 files changed, 404 insertions(+), 264 deletions(-) create mode 100644 src/components/comprehensive-demo/ComprehensiveDemoArchitectureHighlights.tsx create mode 100644 src/components/comprehensive-demo/ComprehensiveDemoDialogs.tsx create mode 100644 src/components/comprehensive-demo/ComprehensiveDemoHeader.tsx create mode 100644 src/components/comprehensive-demo/ComprehensiveDemoStatsRow.tsx create mode 100644 src/components/comprehensive-demo/ComprehensiveDemoTaskList.tsx create mode 100644 src/components/comprehensive-demo/types.ts create mode 100644 src/data/comprehensive-demo.json diff --git a/src/components/ComprehensiveDemoPage.tsx b/src/components/ComprehensiveDemoPage.tsx index 2ecea9d..d9b7192 100644 --- a/src/components/ComprehensiveDemoPage.tsx +++ b/src/components/ComprehensiveDemoPage.tsx @@ -1,26 +1,15 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { Checkbox } from '@/components/ui/checkbox' -import { Badge } from '@/components/ui/badge' -import { Separator } from '@/components/ui/separator' -import { Progress } from '@/components/ui/progress' -import { useCRUD, useSearch } from '@/hooks/data' +import { useState } from 'react' +import { useCRUD } from '@/hooks/data' import { useDialog } from '@/hooks/ui' import { useKV } from '@/hooks/use-kv' -import { SearchBar } from '@/components/molecules/SearchBar' -import { DataList, ActionButton, IconButton } from '@/components/atoms' -import { Plus, Trash, Check, Clock } from '@phosphor-icons/react' import { toast } from 'sonner' -import { cn } from '@/lib/utils' - -interface Todo { - id: number - text: string - completed: boolean - priority: 'low' | 'medium' | 'high' - createdAt: string -} +import strings from '@/data/comprehensive-demo.json' +import { ComprehensiveDemoHeader } from '@/components/comprehensive-demo/ComprehensiveDemoHeader' +import { ComprehensiveDemoStatsRow } from '@/components/comprehensive-demo/ComprehensiveDemoStatsRow' +import { ComprehensiveDemoTaskList } from '@/components/comprehensive-demo/ComprehensiveDemoTaskList' +import { ComprehensiveDemoArchitectureHighlights } from '@/components/comprehensive-demo/ComprehensiveDemoArchitectureHighlights' +import { ComprehensiveDemoDialogs } from '@/components/comprehensive-demo/ComprehensiveDemoDialogs' +import type { Priority, Todo } from '@/components/comprehensive-demo/types' export function ComprehensiveDemoPage() { const [todos, setTodos] = useKV('json-demo-todos', []) @@ -30,21 +19,9 @@ export function ComprehensiveDemoPage() { setItems: (updater) => setTodos(updater), }) - const { query, setQuery, filtered } = useSearch({ - items: todos, - searchFields: ['text' as keyof Todo], - }) - const newTodoDialog = useDialog() const [newTodoText, setNewTodoText] = useState('') - const [newTodoPriority, setNewTodoPriority] = useState<'low' | 'medium' | 'high'>('medium') - - const stats = { - total: todos.length, - completed: todos.filter(t => t.completed).length, - pending: todos.filter(t => !t.completed).length, - completionRate: todos.length > 0 ? (todos.filter(t => t.completed).length / todos.length) * 100 : 0, - } + const [newTodoPriority, setNewTodoPriority] = useState('medium') const handleAddTodo = () => { if (newTodoText.trim()) { @@ -58,7 +35,7 @@ export function ComprehensiveDemoPage() { setNewTodoText('') setNewTodoPriority('medium') newTodoDialog.close() - toast.success('Task added successfully!') + toast.success(strings.toast.added) } } @@ -66,248 +43,38 @@ export function ComprehensiveDemoPage() { const todo = todos.find(t => t.id === id) if (todo) { crud.update(id, { completed: !todo.completed }) - toast.success(todo.completed ? 'Task marked as pending' : 'Task completed!') + toast.success(todo.completed ? strings.toast.pending : strings.toast.completed) } } const handleDeleteTodo = (id: number) => { crud.delete(id) - toast.success('Task deleted') - } - - const getPriorityColor = (priority: string) => { - switch (priority) { - case 'high': return 'bg-red-500/10 text-red-600 border-red-500/20' - case 'medium': return 'bg-yellow-500/10 text-yellow-600 border-yellow-500/20' - case 'low': return 'bg-blue-500/10 text-blue-600 border-blue-500/20' - default: return 'bg-gray-500/10 text-gray-600 border-gray-500/20' - } + toast.success(strings.toast.deleted) } return (
- {/* Header */} -
-

- Advanced Task Manager -

-

- Demonstrating atomic components, custom hooks, and reactive state management -

-
- - {/* Stats Row */} -
- - -
-

Total Tasks

-

{stats.total}

-
-
-
- - - -
-
-

Completed

-

{stats.completed}

-
- -
-
-
- - - -
-
-

Pending

-

{stats.pending}

-
- -
-
-
- - - -
-

Completion

-

{Math.round(stats.completionRate)}%

- -
-
-
-
- - {/* Main Content */} - - -
-
- Your Tasks - Manage your tasks with advanced features -
- } - label="Add Task" - onClick={newTodoDialog.open} - /> -
-
- - {/* Search */} - - - - - {/* Task List */} - ( - - -
- handleToggleTodo(todo.id)} - className="mt-1" - /> -
-

- {todo.text} -

-
- - {todo.priority} - - - {new Date(todo.createdAt).toLocaleDateString()} - -
-
- } - onClick={() => handleDeleteTodo(todo.id)} - variant="ghost" - title="Delete task" - /> -
-
-
- )} - /> -
-
- - {/* Architecture Info */} - - - Architecture Highlights - What makes this demo special - - -
- -
-

Custom Hooks

-

- useCRUD for data management, useSearch for filtering, useDialog for modals -

-
-
-
- -
-

Atomic Components

-

- ActionButton, IconButton, DataList, SearchBar - all under 150 LOC -

-
-
-
- -
-

KV Persistence

-

- All data persists between sessions using the Spark KV store -

-
-
-
- -
-

Reactive State

-

- Computed stats update automatically when todos change -

-
-
-
-
+ + + +
- {/* Add Todo Dialog */} - {newTodoDialog.isOpen && ( -
- - - Add New Task - Create a new task with priority - - -
- - setNewTodoText(e.target.value)} - placeholder="What needs to be done?" - onKeyDown={(e) => e.key === 'Enter' && handleAddTodo()} - autoFocus - /> -
-
- -
- {(['low', 'medium', 'high'] as const).map((priority) => ( - - ))} -
-
-
- - -
-
-
-
- )} +
) } - -// Missing import -import { useState } from 'react' diff --git a/src/components/comprehensive-demo/ComprehensiveDemoArchitectureHighlights.tsx b/src/components/comprehensive-demo/ComprehensiveDemoArchitectureHighlights.tsx new file mode 100644 index 0000000..b4869a9 --- /dev/null +++ b/src/components/comprehensive-demo/ComprehensiveDemoArchitectureHighlights.tsx @@ -0,0 +1,25 @@ +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Check } from '@phosphor-icons/react' +import strings from '@/data/comprehensive-demo.json' + +export function ComprehensiveDemoArchitectureHighlights() { + return ( + + + {strings.architecture.title} + {strings.architecture.description} + + + {strings.architecture.items.map((item) => ( +
+ +
+

{item.title}

+

{item.description}

+
+
+ ))} +
+
+ ) +} diff --git a/src/components/comprehensive-demo/ComprehensiveDemoDialogs.tsx b/src/components/comprehensive-demo/ComprehensiveDemoDialogs.tsx new file mode 100644 index 0000000..667c156 --- /dev/null +++ b/src/components/comprehensive-demo/ComprehensiveDemoDialogs.tsx @@ -0,0 +1,78 @@ +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import strings from '@/data/comprehensive-demo.json' +import type { Priority } from './types' + +interface ComprehensiveDemoDialogsProps { + isOpen: boolean + newTodoText: string + newTodoPriority: Priority + onNewTodoTextChange: (value: string) => void + onNewTodoPriorityChange: (value: Priority) => void + onAdd: () => void + onClose: () => void +} + +const priorities: Priority[] = ['low', 'medium', 'high'] + +export function ComprehensiveDemoDialogs({ + isOpen, + newTodoText, + newTodoPriority, + onNewTodoTextChange, + onNewTodoPriorityChange, + onAdd, + onClose, +}: ComprehensiveDemoDialogsProps) { + if (!isOpen) { + return null + } + + return ( +
+ + + {strings.dialog.title} + {strings.dialog.description} + + +
+ + onNewTodoTextChange(event.target.value)} + placeholder={strings.dialog.taskDescriptionPlaceholder} + onKeyDown={(event) => event.key === 'Enter' && onAdd()} + autoFocus + /> +
+
+ +
+ {priorities.map((priority) => ( + + ))} +
+
+
+ + +
+
+
+
+ ) +} diff --git a/src/components/comprehensive-demo/ComprehensiveDemoHeader.tsx b/src/components/comprehensive-demo/ComprehensiveDemoHeader.tsx new file mode 100644 index 0000000..12c18f7 --- /dev/null +++ b/src/components/comprehensive-demo/ComprehensiveDemoHeader.tsx @@ -0,0 +1,12 @@ +import strings from '@/data/comprehensive-demo.json' + +export function ComprehensiveDemoHeader() { + return ( +
+

+ {strings.header.title} +

+

{strings.header.subtitle}

+
+ ) +} diff --git a/src/components/comprehensive-demo/ComprehensiveDemoStatsRow.tsx b/src/components/comprehensive-demo/ComprehensiveDemoStatsRow.tsx new file mode 100644 index 0000000..b56b2ae --- /dev/null +++ b/src/components/comprehensive-demo/ComprehensiveDemoStatsRow.tsx @@ -0,0 +1,68 @@ +import { useMemo } from 'react' +import { Card, CardContent } from '@/components/ui/card' +import { Progress } from '@/components/ui/progress' +import { Check, Clock } from '@phosphor-icons/react' +import strings from '@/data/comprehensive-demo.json' +import type { Todo } from './types' + +interface ComprehensiveDemoStatsRowProps { + todos: Todo[] +} + +export function ComprehensiveDemoStatsRow({ todos }: ComprehensiveDemoStatsRowProps) { + const stats = useMemo(() => { + const total = todos.length + const completed = todos.filter((todo) => todo.completed).length + const pending = total - completed + const completionRate = total > 0 ? (completed / total) * 100 : 0 + + return { total, completed, pending, completionRate } + }, [todos]) + + return ( +
+ + +
+

{strings.stats.total}

+

{stats.total}

+
+
+
+ + + +
+
+

{strings.stats.completed}

+

{stats.completed}

+
+ +
+
+
+ + + +
+
+

{strings.stats.pending}

+

{stats.pending}

+
+ +
+
+
+ + + +
+

{strings.stats.completion}

+

{Math.round(stats.completionRate)}%

+ +
+
+
+
+ ) +} diff --git a/src/components/comprehensive-demo/ComprehensiveDemoTaskList.tsx b/src/components/comprehensive-demo/ComprehensiveDemoTaskList.tsx new file mode 100644 index 0000000..fe156c5 --- /dev/null +++ b/src/components/comprehensive-demo/ComprehensiveDemoTaskList.tsx @@ -0,0 +1,116 @@ +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Checkbox } from '@/components/ui/checkbox' +import { Badge } from '@/components/ui/badge' +import { Separator } from '@/components/ui/separator' +import { SearchBar } from '@/components/molecules/SearchBar' +import { DataList, ActionButton, IconButton } from '@/components/atoms' +import { Trash, Plus } from '@phosphor-icons/react' +import { useSearch } from '@/hooks/data' +import { cn } from '@/lib/utils' +import strings from '@/data/comprehensive-demo.json' +import type { Todo } from './types' + +interface ComprehensiveDemoTaskListProps { + todos: Todo[] + onAdd: () => void + onToggle: (id: number) => void + onDelete: (id: number) => void +} + +const priorityLabels = strings.priorityLabels as Record + +const getPriorityColor = (priority: Todo['priority']) => { + switch (priority) { + case 'high': + return 'bg-red-500/10 text-red-600 border-red-500/20' + case 'medium': + return 'bg-yellow-500/10 text-yellow-600 border-yellow-500/20' + case 'low': + return 'bg-blue-500/10 text-blue-600 border-blue-500/20' + default: + return 'bg-gray-500/10 text-gray-600 border-gray-500/20' + } +} + +export function ComprehensiveDemoTaskList({ + todos, + onAdd, + onToggle, + onDelete, +}: ComprehensiveDemoTaskListProps) { + const { query, setQuery, filtered } = useSearch({ + items: todos, + searchFields: ['text' as keyof Todo], + }) + + return ( + + +
+
+ {strings.taskCard.title} + {strings.taskCard.description} +
+ } + label={strings.taskCard.addTask} + onClick={onAdd} + /> +
+
+ + + + + + ( + + +
+ onToggle(todo.id)} + className="mt-1" + /> +
+

+ {todo.text} +

+
+ + {priorityLabels[todo.priority]} + + + {new Date(todo.createdAt).toLocaleDateString()} + +
+
+ } + onClick={() => onDelete(todo.id)} + variant="ghost" + title={strings.taskCard.deleteTitle} + /> +
+
+
+ )} + /> +
+
+ ) +} diff --git a/src/components/comprehensive-demo/types.ts b/src/components/comprehensive-demo/types.ts new file mode 100644 index 0000000..4ab4ccd --- /dev/null +++ b/src/components/comprehensive-demo/types.ts @@ -0,0 +1,9 @@ +export type Priority = 'low' | 'medium' | 'high' + +export interface Todo { + id: number + text: string + completed: boolean + priority: Priority + createdAt: string +} diff --git a/src/data/comprehensive-demo.json b/src/data/comprehensive-demo.json new file mode 100644 index 0000000..c4c4d06 --- /dev/null +++ b/src/data/comprehensive-demo.json @@ -0,0 +1,65 @@ +{ + "header": { + "title": "Advanced Task Manager", + "subtitle": "Demonstrating atomic components, custom hooks, and reactive state management" + }, + "stats": { + "total": "Total Tasks", + "completed": "Completed", + "pending": "Pending", + "completion": "Completion" + }, + "taskCard": { + "title": "Your Tasks", + "description": "Manage your tasks with advanced features", + "addTask": "Add Task", + "searchPlaceholder": "Search tasks...", + "empty": { + "noMatch": "No tasks match your search", + "noTasks": "No tasks yet. Click \"Add Task\" to get started!" + }, + "deleteTitle": "Delete task" + }, + "architecture": { + "title": "Architecture Highlights", + "description": "What makes this demo special", + "items": [ + { + "title": "Custom Hooks", + "description": "useCRUD for data management, useSearch for filtering, useDialog for modals" + }, + { + "title": "Atomic Components", + "description": "ActionButton, IconButton, DataList, SearchBar - all under 150 LOC" + }, + { + "title": "KV Persistence", + "description": "All data persists between sessions using the Spark KV store" + }, + { + "title": "Reactive State", + "description": "Computed stats update automatically when todos change" + } + ] + }, + "dialog": { + "title": "Add New Task", + "description": "Create a new task with priority", + "taskDescriptionLabel": "Task Description", + "taskDescriptionPlaceholder": "What needs to be done?", + "priorityLabel": "Priority", + "addButton": "Add Task", + "cancelButton": "Cancel" + }, + "priorityLabels": { + "low": "low", + "medium": "medium", + "high": "high" + }, + "toast": { + "added": "Task added successfully!", + "pending": "Task marked as pending", + "completed": "Task completed!", + "deleted": "Task deleted" + } +}