summaryrefslogtreecommitdiff
path: root/web/templates
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-12 14:28:50 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-12 14:28:50 -1000
commit06c7485a7d05de86f9898e388161e8d932d5f3e6 (patch)
tree376083a75278c9758f53c0062742062dedb75633 /web/templates
parent9ef5b7f37883f846f105da9dc5d2ba1415e594e3 (diff)
Modernize frontend with tabs, HTMX, and Tailwind build pipeline
Complete UI overhaul implementing modern design patterns with HTMX for dynamic updates, proper Tailwind build pipeline, and improved UX. Build Pipeline: - Add npm + PostCSS + Tailwind CSS configuration - Custom design system with brand colors - Compiled CSS: 27KB (vs 3MB CDN), 99% reduction - Makefile for unified build commands - Inter font for improved typography Tab Interface: - Separate Tasks tab from Notes tab using HTMX - Partial page updates without full refreshes - Tab state management with proper refresh handling - New endpoints: /tabs/tasks, /tabs/notes, /tabs/refresh Template Architecture: - Modular partials system (7 reusable components) - Cleaner separation of concerns Empty Board Management: - Active boards in main 3-column grid - Empty boards in collapsible section - Reduces visual clutter Visual Design Enhancements: - Inter font, brand color accents - Improved typography hierarchy and spacing - Enhanced card styling with hover effects Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'web/templates')
-rw-r--r--web/templates/index.html193
-rw-r--r--web/templates/partials/error-banner.html12
-rw-r--r--web/templates/partials/notes-tab.html22
-rw-r--r--web/templates/partials/obsidian-notes.html30
-rw-r--r--web/templates/partials/plantoeat-meals.html35
-rw-r--r--web/templates/partials/tasks-tab.html22
-rw-r--r--web/templates/partials/todoist-tasks.html58
-rw-r--r--web/templates/partials/trello-boards.html72
8 files changed, 283 insertions, 161 deletions
diff --git a/web/templates/index.html b/web/templates/index.html
index 7668a94..2d35b37 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -4,182 +4,53 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Personal Dashboard</title>
- <link rel="stylesheet" href="/static/css/styles.css">
- <script src="https://cdn.tailwindcss.com"></script>
+ <link rel="stylesheet" href="/static/css/output.css">
</head>
-<body class="bg-gray-100 min-h-screen">
- <div class="container mx-auto px-4 py-8 max-w-7xl">
+<body class="min-h-screen">
+ <div class="content-max-width py-8">
<!-- Header -->
- <header class="mb-8 flex justify-between items-center">
- <h1 class="text-3xl font-bold text-gray-800">Personal Dashboard</h1>
+ <header class="mb-8 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
+ <h1 class="text-4xl font-bold text-gray-900">Personal Dashboard</h1>
<div class="flex items-center gap-4">
<span class="text-sm text-gray-600">
Last updated: <span id="last-updated">{{.LastUpdated.Format "3:04 PM"}}</span>
</span>
- <button onclick="refreshData()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition">
- Refresh
+ <button onclick="refreshData()"
+ class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg transition-colors font-medium no-print">
+ <span id="refresh-text">Refresh</span>
</button>
</div>
</header>
- <!-- Error Messages -->
- {{if .Errors}}
- <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-lg mb-6">
- <p class="font-bold">Errors:</p>
- <ul class="list-disc list-inside">
- {{range .Errors}}
- <li>{{.}}</li>
- {{end}}
- </ul>
- </div>
- {{end}}
-
- <!-- Main Grid -->
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
- <!-- Trello Boards Section (PRIORITY) -->
- <div class="lg:col-span-3">
- {{if .Boards}}
- <div class="bg-white rounded-lg shadow-md p-6 mb-6">
- <h2 class="text-xl font-semibold mb-4 text-gray-800">📋 Trello Boards</h2>
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
- {{range .Boards}}
- <div class="border border-gray-300 rounded-lg p-4 bg-gradient-to-br from-blue-50 to-white">
- <h3 class="font-bold text-lg text-gray-800 mb-3">{{.Name}}</h3>
- {{if .Cards}}
- <div class="space-y-2 max-h-96 overflow-y-auto">
- {{range .Cards}}
- <div class="bg-white border border-gray-200 rounded p-3 hover:shadow-md transition">
- <p class="font-medium text-gray-800 text-sm">{{.Name}}</p>
- {{if .ListName}}
- <span class="inline-block mt-1 text-xs bg-gray-200 text-gray-700 px-2 py-1 rounded">
- {{.ListName}}
- </span>
- {{end}}
- {{if .DueDate}}
- <span class="inline-block mt-1 text-xs bg-red-100 text-red-800 px-2 py-1 rounded">
- Due: {{.DueDate.Format "Jan 2"}}
- </span>
- {{end}}
- {{if .URL}}
- <a href="{{.URL}}" target="_blank" class="text-blue-600 hover:text-blue-800 text-xs mt-1 inline-block">
- View →
- </a>
- {{end}}
- </div>
- {{end}}
- </div>
- {{else}}
- <p class="text-gray-500 text-sm text-center py-4">No cards</p>
- {{end}}
- </div>
- {{end}}
- </div>
- </div>
- {{end}}
- </div>
-
- <!-- Tasks Section -->
- <div class="lg:col-span-2">
- <div class="bg-white rounded-lg shadow-md p-6">
- <h2 class="text-xl font-semibold mb-4 text-gray-800">✓ Todoist Tasks</h2>
-
- {{if .Tasks}}
- <div class="space-y-3">
- {{range .Tasks}}
- <div class="flex items-start gap-3 p-3 hover:bg-gray-50 rounded-lg transition">
- <input type="checkbox" {{if .Completed}}checked{{end}}
- class="mt-1 h-5 w-5 text-blue-600 rounded" disabled>
- <div class="flex-1">
- <p class="font-medium text-gray-800 {{if .Completed}}line-through text-gray-500{{end}}">
- {{.Content}}
- </p>
- {{if .Description}}
- <p class="text-sm text-gray-600 mt-1">{{.Description}}</p>
- {{end}}
- <div class="flex gap-2 mt-2 text-xs text-gray-500">
- {{if .ProjectName}}
- <span class="bg-gray-200 px-2 py-1 rounded">{{.ProjectName}}</span>
- {{end}}
- {{if .DueDate}}
- <span class="bg-yellow-100 text-yellow-800 px-2 py-1 rounded">
- Due: {{.DueDate.Format "Jan 2"}}
- </span>
- {{end}}
- {{range .Labels}}
- <span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">{{.}}</span>
- {{end}}
- </div>
- </div>
- {{if .URL}}
- <a href="{{.URL}}" target="_blank" class="text-blue-600 hover:text-blue-800">
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
- </svg>
- </a>
- {{end}}
- </div>
- {{end}}
- </div>
- {{else}}
- <p class="text-gray-500 text-center py-8">No tasks found</p>
- {{end}}
- </div>
- </div>
-
- <!-- Meals Section -->
- <div>
- <div class="bg-white rounded-lg shadow-md p-6">
- <h2 class="text-xl font-semibold mb-4 text-gray-800">Upcoming Meals</h2>
-
- {{if .Meals}}
- <div class="space-y-3">
- {{range .Meals}}
- <div class="border-l-4 border-green-500 pl-3 py-2">
- <p class="font-medium text-gray-800">{{.RecipeName}}</p>
- <div class="flex justify-between items-center mt-1">
- <span class="text-sm text-gray-600">{{.Date.Format "Mon, Jan 2"}}</span>
- <span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded capitalize">
- {{.MealType}}
- </span>
- </div>
- </div>
- {{end}}
- </div>
- {{else}}
- <p class="text-gray-500 text-center py-8">No meals planned</p>
- {{end}}
- </div>
- </div>
+ <!-- Tab Navigation -->
+ <div class="border-b border-gray-200 mb-8 no-print">
+ <nav class="-mb-px flex space-x-8">
+ <button
+ class="tab-button tab-button-active"
+ hx-get="/tabs/tasks"
+ hx-target="#tab-content"
+ hx-push-url="false"
+ onclick="setActiveTab(this)">
+ 📋 Tasks & Planning
+ </button>
+ <button
+ class="tab-button"
+ hx-get="/tabs/notes"
+ hx-target="#tab-content"
+ hx-push-url="false"
+ onclick="setActiveTab(this)">
+ 📝 Notes
+ </button>
+ </nav>
</div>
- <!-- Notes Section -->
- {{if .Notes}}
- <div class="mt-6">
- <div class="bg-white rounded-lg shadow-md p-6">
- <h2 class="text-xl font-semibold mb-4 text-gray-800">Recent Notes</h2>
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
- {{range .Notes}}
- <div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition">
- <h3 class="font-semibold text-gray-800 mb-2">{{.Title}}</h3>
- <p class="text-sm text-gray-600 mb-2 line-clamp-3">{{.Content}}</p>
- <div class="flex justify-between items-center text-xs text-gray-500">
- <span>{{.Modified.Format "Jan 2, 3:04 PM"}}</span>
- {{if .Tags}}
- <div class="flex gap-1">
- {{range .Tags}}
- <span class="bg-purple-100 text-purple-800 px-2 py-1 rounded">#{{.}}</span>
- {{end}}
- </div>
- {{end}}
- </div>
- </div>
- {{end}}
- </div>
- </div>
+ <!-- Tab Content -->
+ <div id="tab-content">
+ {{template "tasks-tab" .}}
</div>
- {{end}}
</div>
+ <script src="/static/js/htmx.min.js"></script>
<script src="/static/js/app.js"></script>
</body>
</html>
diff --git a/web/templates/partials/error-banner.html b/web/templates/partials/error-banner.html
new file mode 100644
index 0000000..eb4c08d
--- /dev/null
+++ b/web/templates/partials/error-banner.html
@@ -0,0 +1,12 @@
+{{define "error-banner"}}
+{{if .Errors}}
+<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-lg mb-6">
+ <p class="font-bold">Errors:</p>
+ <ul class="list-disc list-inside">
+ {{range .Errors}}
+ <li>{{.}}</li>
+ {{end}}
+ </ul>
+</div>
+{{end}}
+{{end}}
diff --git a/web/templates/partials/notes-tab.html b/web/templates/partials/notes-tab.html
new file mode 100644
index 0000000..526f387
--- /dev/null
+++ b/web/templates/partials/notes-tab.html
@@ -0,0 +1,22 @@
+{{define "notes-tab"}}
+<div class="space-y-10">
+ <!-- Error Messages -->
+ {{template "error-banner" .}}
+
+ <!-- Obsidian Notes Section -->
+ {{if .Notes}}
+ {{template "obsidian-notes" .}}
+ {{else}}
+ <div class="text-center py-20">
+ <svg class="mx-auto h-16 w-16 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
+ d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
+ </svg>
+ <h3 class="mt-6 text-xl font-medium text-gray-900">No notes found</h3>
+ <p class="mt-2 text-sm text-gray-500 max-w-md mx-auto">
+ Configure your Obsidian vault path in the settings to see your recent notes displayed here.
+ </p>
+ </div>
+ {{end}}
+</div>
+{{end}}
diff --git a/web/templates/partials/obsidian-notes.html b/web/templates/partials/obsidian-notes.html
new file mode 100644
index 0000000..268a0fe
--- /dev/null
+++ b/web/templates/partials/obsidian-notes.html
@@ -0,0 +1,30 @@
+{{define "obsidian-notes"}}
+{{if .Notes}}
+<section class="section-spacing">
+ <!-- Section Header with Brand Color -->
+ <div class="flex items-center gap-3 mb-6">
+ <div class="w-1 h-8 bg-obsidian rounded"></div>
+ <h2 class="text-2xl font-bold text-gray-900">Recent Notes</h2>
+ </div>
+
+ <div class="card-grid">
+ {{range .Notes}}
+ <div class="note-card">
+ <h3 class="font-semibold text-gray-900 mb-2">{{.Title}}</h3>
+ <p class="text-sm text-gray-600 mb-3 line-clamp-3">{{.Content}}</p>
+ <div class="flex justify-between items-center text-xs">
+ <span class="text-gray-500">{{.Modified.Format "Jan 2, 3:04 PM"}}</span>
+ {{if .Tags}}
+ <div class="flex gap-1 flex-wrap">
+ {{range .Tags}}
+ <span class="badge bg-purple-100 text-purple-800">#{{.}}</span>
+ {{end}}
+ </div>
+ {{end}}
+ </div>
+ </div>
+ {{end}}
+ </div>
+</section>
+{{end}}
+{{end}}
diff --git a/web/templates/partials/plantoeat-meals.html b/web/templates/partials/plantoeat-meals.html
new file mode 100644
index 0000000..78e403e
--- /dev/null
+++ b/web/templates/partials/plantoeat-meals.html
@@ -0,0 +1,35 @@
+{{define "plantoeat-meals"}}
+<section class="card">
+ <!-- Section Header with Brand Color -->
+ <div class="flex items-center gap-3 mb-6">
+ <div class="w-1 h-8 bg-plantoeat rounded"></div>
+ <h2 class="text-2xl font-bold text-gray-900">Upcoming Meals</h2>
+ </div>
+
+ {{if .Meals}}
+ <div class="space-y-3">
+ {{range .Meals}}
+ <div class="border-l-4 border-plantoeat bg-green-50/50 pl-4 py-3 rounded-r-lg hover:bg-green-50 transition-colors">
+ <p class="font-medium text-gray-900">{{.RecipeName}}</p>
+ <div class="flex justify-between items-center mt-2">
+ <span class="text-sm text-gray-600">{{.Date.Format "Mon, Jan 2"}}</span>
+ <span class="badge bg-green-100 text-green-800 capitalize">
+ {{.MealType}}
+ </span>
+ </div>
+ </div>
+ {{end}}
+ </div>
+ {{else}}
+ <div class="text-center py-16">
+ <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9" />
+ </svg>
+ <h3 class="mt-4 text-lg font-medium text-gray-900">No meals planned</h3>
+ <p class="mt-2 text-sm text-gray-500">
+ Schedule your meals to see them here.
+ </p>
+ </div>
+ {{end}}
+</section>
+{{end}}
diff --git a/web/templates/partials/tasks-tab.html b/web/templates/partials/tasks-tab.html
new file mode 100644
index 0000000..5678193
--- /dev/null
+++ b/web/templates/partials/tasks-tab.html
@@ -0,0 +1,22 @@
+{{define "tasks-tab"}}
+<div class="space-y-10">
+ <!-- Error Messages -->
+ {{template "error-banner" .}}
+
+ <!-- Trello Boards Section -->
+ {{template "trello-boards" .}}
+
+ <!-- Todoist + PlanToEat Grid -->
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
+ <!-- Todoist (2 cols) -->
+ <div class="lg:col-span-2">
+ {{template "todoist-tasks" .}}
+ </div>
+
+ <!-- PlanToEat (1 col) -->
+ <div>
+ {{template "plantoeat-meals" .}}
+ </div>
+ </div>
+</div>
+{{end}}
diff --git a/web/templates/partials/todoist-tasks.html b/web/templates/partials/todoist-tasks.html
new file mode 100644
index 0000000..7595ac7
--- /dev/null
+++ b/web/templates/partials/todoist-tasks.html
@@ -0,0 +1,58 @@
+{{define "todoist-tasks"}}
+<section class="card">
+ <!-- Section Header with Brand Color -->
+ <div class="flex items-center gap-3 mb-6">
+ <div class="w-1 h-8 bg-todoist rounded"></div>
+ <h2 class="text-2xl font-bold text-gray-900">Todoist Tasks</h2>
+ </div>
+
+ {{if .Tasks}}
+ <div class="space-y-3">
+ {{range .Tasks}}
+ <div class="task-item">
+ <input type="checkbox" {{if .Completed}}checked{{end}}
+ class="mt-1 h-5 w-5 text-todoist rounded border-gray-300" disabled>
+ <div class="flex-1">
+ <p class="font-medium text-gray-900 {{if .Completed}}line-through text-gray-500{{end}}">
+ {{.Content}}
+ </p>
+ {{if .Description}}
+ <p class="text-sm text-gray-600 mt-1">{{.Description}}</p>
+ {{end}}
+ <div class="flex flex-wrap gap-2 mt-2">
+ {{if .ProjectName}}
+ <span class="badge bg-gray-100 text-gray-700">{{.ProjectName}}</span>
+ {{end}}
+ {{if .DueDate}}
+ <span class="badge bg-yellow-100 text-yellow-800">
+ Due: {{.DueDate.Format "Jan 2"}}
+ </span>
+ {{end}}
+ {{range .Labels}}
+ <span class="badge bg-blue-100 text-blue-800">{{.}}</span>
+ {{end}}
+ </div>
+ </div>
+ {{if .URL}}
+ <a href="{{.URL}}" target="_blank" class="text-todoist hover:text-todoist/80 transition-colors">
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
+ </svg>
+ </a>
+ {{end}}
+ </div>
+ {{end}}
+ </div>
+ {{else}}
+ <div class="text-center py-16">
+ <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
+ </svg>
+ <h3 class="mt-4 text-lg font-medium text-gray-900">No tasks found</h3>
+ <p class="mt-2 text-sm text-gray-500">
+ All tasks completed or no tasks available.
+ </p>
+ </div>
+ {{end}}
+</section>
+{{end}}
diff --git a/web/templates/partials/trello-boards.html b/web/templates/partials/trello-boards.html
new file mode 100644
index 0000000..bd460cf
--- /dev/null
+++ b/web/templates/partials/trello-boards.html
@@ -0,0 +1,72 @@
+{{define "trello-boards"}}
+{{if .Boards}}
+<section class="card section-spacing">
+ <!-- Section Header with Brand Color -->
+ <div class="flex items-center gap-3 mb-6">
+ <div class="w-1 h-8 bg-trello rounded"></div>
+ <h2 class="text-2xl font-bold text-gray-900">Trello Boards</h2>
+ </div>
+
+ <!-- Active Boards Grid (boards with cards) -->
+ <div class="card-grid mb-6">
+ {{range .Boards}}
+ {{if .Cards}}
+ <div class="board-card">
+ <h3 class="font-bold text-lg text-gray-900 mb-4">{{.Name}}</h3>
+ <div class="space-y-3 max-h-96 overflow-y-auto scrollbar-thin">
+ {{range .Cards}}
+ <div class="trello-card-item">
+ <p class="font-medium text-sm text-gray-900 mb-2">{{.Name}}</p>
+ <div class="flex flex-wrap gap-2 items-center">
+ {{if .ListName}}
+ <span class="badge bg-gray-100 text-gray-700">
+ {{.ListName}}
+ </span>
+ {{end}}
+ {{if .DueDate}}
+ <span class="badge bg-red-100 text-red-800">
+ Due: {{.DueDate.Format "Jan 2"}}
+ </span>
+ {{end}}
+ {{if .URL}}
+ <a href="{{.URL}}" target="_blank"
+ class="text-trello hover:text-trello/80 text-xs font-medium ml-auto transition-colors">
+ View →
+ </a>
+ {{end}}
+ </div>
+ </div>
+ {{end}}
+ </div>
+ </div>
+ {{end}}
+ {{end}}
+ </div>
+
+ <!-- Empty Boards Collapsible (boards without cards) -->
+ <details class="mt-6 border-t border-gray-200 pt-6">
+ <summary class="cursor-pointer flex items-center justify-between group">
+ <span class="text-sm font-medium text-gray-600 group-hover:text-gray-900 transition-colors">
+ Empty Boards
+ </span>
+ <svg class="w-5 h-5 text-gray-400 group-hover:text-gray-600 transition-all"
+ fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
+ </svg>
+ </summary>
+ <div class="mt-4">
+ <div class="card-grid">
+ {{range .Boards}}
+ {{if not .Cards}}
+ <div class="border border-gray-200 rounded-lg p-4 bg-gray-50 opacity-70 hover:opacity-100 transition-opacity">
+ <h3 class="font-semibold text-gray-700">{{.Name}}</h3>
+ <p class="text-sm text-gray-500 mt-2">No cards</p>
+ </div>
+ {{end}}
+ {{end}}
+ </div>
+ </div>
+ </details>
+</section>
+{{end}}
+{{end}}