diff --git a/app/globals.css b/app/globals.css index a2dc41e..c797661 100644 --- a/app/globals.css +++ b/app/globals.css @@ -24,3 +24,26 @@ body { color: var(--foreground); font-family: Arial, Helvetica, sans-serif; } + +.mainContainer { + max-width: 56rem; + margin-left: auto; + margin-right: auto; + padding: 2.5rem 1rem; + min-height: 100vh; + display: flex; + flex-direction: column; + gap: 2rem; + background-color: #ffffff; + /* White background */ + color: #18181b; + /* Dark text for clear contrast */ +} + +@media (prefers-color-scheme: dark) { + .mainContainer { + background-color: #ffffff; + /* Or keep #ffffff if you want light mode background even in OS dark mode */ + color: #18181b; + } +} \ No newline at end of file diff --git a/app/page.module.css b/app/page.module.css new file mode 100644 index 0000000..546badc --- /dev/null +++ b/app/page.module.css @@ -0,0 +1,104 @@ +/* Container & Page Layout */ +.mainContainer { + max-width: 56rem; + /* 896px */ + margin-left: auto; + margin-right: auto; + padding: 2.5rem 1rem; + min-height: 100vh; + display: flex; + flex-direction: column; + gap: 2rem; + background-color: #ffffff; + color: #000000; +} + + + +/* Header Section */ +.header { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.title { + font-size: 1.875rem; + line-height: 2.25rem; + font-weight: 700; + letter-spacing: -0.025em; + color: #0000df; +} + +@media (prefers-color-scheme: dark) { + .title { + color: #0808ee; + } +} + +.subtitle { + font-size: 0.875rem; + color: #04045f; +} + +@media (prefers-color-scheme: dark) { + .subtitle { + color: #15154b; + } +} + +/* Task List Section */ +.section { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.sectionTitle { + font-size: 1.125rem; + font-weight: 600; + color: #5a5ab4; +} + +@media (prefers-color-scheme: dark) { + .sectionTitle { + color: #9494d6; + } +} + +/* Empty State Card */ +.emptyState { + text-align: center; + padding: 3rem 1rem; + border: 1px dashed #4141aa; + border-radius: 0.75rem; +} + +@media (prefers-color-scheme: dark) { + .emptyState { + border-color: #27272a; + } +} + +.emptyText { + color: #71717a; +} + +@media (prefers-color-scheme: dark) { + .emptyText { + color: #a1a1aa; + } +} + +/* Grid Layout for Task Cards */ +.taskGrid { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; +} + +@media (min-width: 768px) { + .taskGrid { + grid-template-columns: repeat(2, 1fr); + } +} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 6761c5c..8b4e76b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,33 +1,25 @@ -// Next.js Server Component (no 'use client' needed here) -// This page runs on the server, reads from SQLite directly, and renders HTML - import { getTasks } from '@/src/lib/tasks'; import TaskForm from '@/src/lib/components/TaskForm'; import TaskCard from '@/src/lib/components/TaskCard'; import TaskFilterToolbar from '@/src/lib/components/TaskFilterToolbar'; +import styles from './page.module.css'; -// Next.js 15 page props for async searchParams interface PageProps { searchParams: Promise<{ sortBy?: 'due_date' | 'topic' | 'status' }>; } export default async function HomePage({ searchParams }: PageProps) { - // Await search parameters from the URL (e.g., ?sortBy=topic) const params = await searchParams; const sortBy = params.sortBy || 'due_date'; - - // Direct SQLite query on the server to get active tasks sorted const tasks = getTasks(sortBy); return ( -
+
{/* Header */} -
-

- 📝 Todo App -

-

- Local-first SQLite task manager with dynamic overdue detection. +

+

Todo App

+

+ Local-first task manager with dynamic overdue detection.

@@ -38,19 +30,19 @@ export default async function HomePage({ searchParams }: PageProps) { {/* List of Tasks */} -
-

+
+

Tasks ({tasks.length})

{/* Empty state if no tasks exist */} {tasks.length === 0 ? ( -
-

No active tasks found. Create one above!

+
+

No active tasks found. Create one above!

) : ( /* Render grid of task cards */ -
+
{tasks.map(task => ( ))} diff --git a/src/lib/components/TaskCard.module.css b/src/lib/components/TaskCard.module.css index 1981cd7..8f10c46 100644 --- a/src/lib/components/TaskCard.module.css +++ b/src/lib/components/TaskCard.module.css @@ -2,8 +2,8 @@ .cardContainer { padding: 1.25rem; border-radius: 0.75rem; - border: 1px solid #e4e4e7; - background-color: #ffffff; + border: 1px solid #c6c6cc; + background-color: #e6e1e1; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); transition: all 0.2s ease-in-out; } @@ -12,12 +12,7 @@ opacity: 0.5; } -@media (prefers-color-scheme: dark) { - .cardContainer { - background-color: #18181b; - border-color: #27272a; - } -} + /* Header Section */ .header { @@ -30,15 +25,11 @@ .title { font-weight: 600; font-size: 1.125rem; - color: #18181b; + color: #0303e0; margin: 0; } -@media (prefers-color-scheme: dark) { - .title { - color: #f4f4f5; - } -} + /* Status Badges */ .badge { @@ -50,33 +41,20 @@ .statusComplete { background-color: #d1fae5; - color: #065f46; + color: #02c28c; } .statusInProgress { background-color: #fef3c7; - color: #92400e; + color: #884216; } .statusTodo { - background-color: #dbeafe; - color: #1e40af; + background-color: #fcfdff; + color: #4570ff; } -@media (prefers-color-scheme: dark) { - .statusComplete { - background-color: #022c22; - color: #6ee7b7; - } - .statusInProgress { - background-color: #451a03; - color: #fcd34d; - } - .statusTodo { - background-color: #172554; - color: #93c5fd; - } -} + /* Description */ .description { @@ -89,11 +67,6 @@ overflow: hidden; } -@media (prefers-color-scheme: dark) { - .description { - color: #a1a1aa; - } -} /* Footer Section */ .footer { @@ -109,12 +82,7 @@ padding-top: 0.75rem; } -@media (prefers-color-scheme: dark) { - .footer { - border-color: #27272a; - color: #a1a1aa; - } -} + .metaGroup { display: flex; @@ -130,33 +98,28 @@ color: #3f3f46; } -@media (prefers-color-scheme: dark) { - .topicTag { - background-color: #27272a; - color: #d4d4d8; - } -} - /* Overdue Badge */ .overdueBadge { background-color: #fee2e2; color: #b91c1c; padding: 0.125rem 0.5rem; - border-radius: 0.25rem; + border-radius: 15px; font-weight: 600; animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } -@media (prefers-color-scheme: dark) { - .overdueBadge { - background-color: #450a0a; - color: #fca5a5; - } -} + @keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: .5; } + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: .5; + } } /* Actions Section */ @@ -187,7 +150,7 @@ padding: 0.375rem 0.75rem; border-radius: 0.25rem; background-color: #fef2f2; - color: #dc2626; + color: #96a2e4; font-weight: 500; border: none; cursor: pointer; @@ -195,27 +158,10 @@ } .btnArchive:hover { - background-color: #fee2e2; + background-color: #f18484; } .btnArchive:disabled { opacity: 0.5; cursor: not-allowed; -} - -@media (prefers-color-scheme: dark) { - .btnEdit { - background-color: #27272a; - color: #e4e4e7; - } - .btnEdit:hover { - background-color: #3f3f46; - } - .btnArchive { - background-color: rgba(69, 10, 10, 0.5); - color: #f87171; - } - .btnArchive:hover { - background-color: rgba(127, 29, 29, 0.5); - } -} +} \ No newline at end of file