Add completion buttons to agenda tasks
Agenda items were plain links — completing a task required navigating
to the series page. Reuses the existing complete-form/button pattern
at a smaller scale so users can check off upcoming tasks in place.

Also tightens flash bar layout: centers items vertically, spreads
undo/close to edges via flex, and reduces inline padding.

Assisted-by: Claude Opus 4.6 via Claude Code
change xtlpyvtqnkmmpyyonyyvkyurwvmsnool
commit 87f9a9de2485fe2a5774a60e6e0d2a4bfc21f42f
author Alpha Chen <alpha@kejadlen.dev>
date
parent 00a83be6
diff --git a/lib/ketchup/views/dashboard.rb b/lib/ketchup/views/dashboard.rb
index e784314..ed64475 100644
--- a/lib/ketchup/views/dashboard.rb
+++ b/lib/ketchup/views/dashboard.rb
@@ -115,10 +115,17 @@ module Views
             div(class: "agenda-day-header") { friendly_day(date, offset) }
             day_tasks.each do |task|
               task_name = task[:note].lines.first&.strip || task[:note]
-              a(
-                href: "/series/#{task[:series_id]}",
-                class: "agenda-day-pill"
-              ) { task_name }
+              complete_path = "/series/#{task[:series_id]}/tasks/#{task[:id]}/complete"
+
+              div(class: "agenda-task") do
+                form(method: "post", action: complete_path, class: "complete-form") do
+                  input(type: "hidden", name: "_csrf", value: @csrf.call(complete_path))
+                  input(type: "hidden", name: "return_to", value: "/")
+                  button(type: "submit", title: "Complete", class: "complete-btn",
+                         **{ "aria-label": "Complete #{task_name}" }) { "\u2713" }
+                end
+                a(href: "/series/#{task[:series_id]}", class: "agenda-day-pill") { task_name }
+              end
             end
           end
         end
diff --git a/public/css/app.css b/public/css/app.css
index 5d27525..166ed55 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -113,15 +113,20 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   right: var(--space-s);
   z-index: 100;
   display: flex;
-  align-items: baseline;
+  align-items: center;
   gap: var(--space-xs);
-  padding: var(--space-xs) var(--space-l);
+  padding: var(--space-xs) var(--space-s);
   color: #333;
   font-size: var(--step--2);
   background: #fff;
   border: 1px solid #ddd;
   border-radius: 6px;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  min-width: 20rem;
+}
+
+.flash-message {
+  flex: 1;
 }
 
 
@@ -257,22 +262,35 @@ h2 { font-size: var(--step-0); font-weight: 600; }
   color: #222;
 }
 
+.agenda-task {
+  display: flex;
+  align-items: center;
+  gap: var(--space-2xs);
+  margin-block-end: 3px;
+}
+
+.agenda-task .complete-btn {
+  width: 14px;
+  height: 14px;
+  font-size: 10px;
+  border-width: 1px;
+  top: 0;
+}
+
 .agenda-day-pill {
   display: block;
   font-size: var(--step--2);
-  padding: 3px 6px;
-  background: #f0f0f0;
+  padding: 3px 0;
   color: #222;
-  border-radius: 4px;
-  margin-block-end: 3px;
   text-decoration: none;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
+  min-width: 0;
 }
 
 .agenda-day-pill:hover {
-  background: #e8e8e8;
+  color: #555;
 }
 
 /* -------------------- */