summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-08-12 23:35:47 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-08-12 23:35:47 +0000
commit2509dde6aa372a505b186657706f4d21bd391807 (patch)
treee4147991747b8dd14d0b8654b2b8e50717b666bd /web
parent3e8ad60431d6cc783f9f7c555bfde5db54ebec75 (diff)
Add task title editing/deletion, timeline click-to-open, widget app launch
Task-detail modal was description-only with no delete affordance; HandleUpdateTask now saves the title too and a Delete button hits a new DELETE /tasks/{id} route backed by store.DeleteNativeTask, which repairs chain_position/unlocks the successor when the deleted task belongs to a chain. Timeline tab task/card/gtask rows now open the same detail modal as the Tasks tab. Android widget's "TODAY" header is now a tap target that launches DashboardActivity, since nothing previously opened the full app from the widget.
Diffstat (limited to 'web')
-rw-r--r--web/templates/partials/task-detail.html15
-rw-r--r--web/templates/partials/timeline-tab.html32
2 files changed, 42 insertions, 5 deletions
diff --git a/web/templates/partials/task-detail.html b/web/templates/partials/task-detail.html
index 135c38f..abcc5b9 100644
--- a/web/templates/partials/task-detail.html
+++ b/web/templates/partials/task-detail.html
@@ -1,15 +1,28 @@
{{define "task-detail"}}
<div class="p-4">
- <h3 class="font-semibold text-white mb-3">{{.Title}}</h3>
<form hx-post="/tasks/update" hx-swap="none" hx-on::after-request="if(event.detail.successful) { closeTaskModal(); htmx.trigger(document.body, 'refresh-tasks'); }">
<input type="hidden" name="id" value="{{.ID}}">
<input type="hidden" name="source" value="{{.Source}}">
+ <label class="block text-sm font-medium text-white/70 mb-1">Title</label>
+ <input type="text" name="title" value="{{.Title}}" required
+ class="w-full bg-input border border-white/20 rounded-lg px-3 py-2 text-sm font-semibold text-white placeholder-white/50 mb-3">
<label class="block text-sm font-medium text-white/70 mb-1">Description</label>
<textarea name="description" class="w-full bg-input border border-white/20 rounded-lg px-3 py-2 text-sm text-white placeholder-white/50 mb-3 h-32">{{.Description}}</textarea>
<button type="submit" class="w-full bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg text-sm font-medium">Save</button>
</form>
{{if .IsDoot}}
+ <button type="button"
+ class="w-full mt-3 bg-red-500/10 hover:bg-red-500/20 text-red-300 px-4 py-2 rounded-lg text-sm font-medium"
+ hx-delete="/tasks/{{.ID}}?source={{.Source}}"
+ hx-confirm="Delete this task? This can't be undone."
+ hx-swap="none"
+ hx-on::after-request="if(event.detail.successful) { closeTaskModal(); htmx.trigger(document.body, 'refresh-tasks'); }">
+ Delete Task
+ </button>
+ {{end}}
+
+ {{if .IsDoot}}
<div class="mt-4 pt-4 border-t border-white/10">
<h4 class="text-sm font-medium text-white/70 mb-2">Recurrence</h4>
{{if .RecurrenceFreq}}
diff --git a/web/templates/partials/timeline-tab.html b/web/templates/partials/timeline-tab.html
index d6f410e..c232001 100644
--- a/web/templates/partials/timeline-tab.html
+++ b/web/templates/partials/timeline-tab.html
@@ -147,7 +147,13 @@
hx-swap="outerHTML"
class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0">
{{end}}
- <span class="{{if .IsCompleted}}line-through text-white/50{{end}}">{{.Title}}{{multiDayLabel .}}</span>
+ <span class="{{if .IsCompleted}}line-through text-white/50{{end}} {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}cursor-pointer hover:underline{{end}}"
+ {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}
+ hx-get="/tasks/detail?id={{.ID}}&source={{.Source}}"
+ hx-target="#task-edit-content"
+ hx-swap="innerHTML"
+ onclick="document.getElementById('task-edit-modal').classList.remove('hidden')"
+ {{end}}>{{.Title}}{{multiDayLabel .}}</span>
{{if .IsOverdue}}<span class="overdue-badge">overdue</span>{{end}}
{{if .ChainTotal}}<span class="chain-badge">{{.ChainPosition}}/{{.ChainTotal}}</span>{{end}}
{{if eq .BucketState "active"}}<span class="chain-badge" style="cursor:pointer" hx-post="/defer-atom" hx-vals='{"id": "{{.ID}}"}' hx-swap="none">defer</span>{{end}}
@@ -203,7 +209,13 @@
onclick="event.stopPropagation();"
class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0">
{{end}}
- <span class="calendar-event-title {{if .IsCompleted}}line-through text-white/50{{end}}">{{.Title}}</span>
+ <span class="calendar-event-title {{if .IsCompleted}}line-through text-white/50{{end}} {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}cursor-pointer hover:underline{{end}}"
+ {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}
+ hx-get="/tasks/detail?id={{.ID}}&source={{.Source}}"
+ hx-target="#task-edit-content"
+ hx-swap="innerHTML"
+ onclick="event.stopPropagation(); document.getElementById('task-edit-modal').classList.remove('hidden')"
+ {{end}}>{{.Title}}</span>
{{if .ChainTotal}}<span class="chain-badge">{{.ChainPosition}}/{{.ChainTotal}}</span>{{end}}
{{if eq .BucketState "active"}}<span class="chain-badge" style="cursor:pointer" hx-post="/defer-atom" hx-vals='{"id": "{{.ID}}"}' hx-swap="none">defer</span>{{end}}
</div>
@@ -253,7 +265,13 @@
class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer shrink-0">
{{end}}
<!-- Title -->
- <span class="flex-1 text-sm text-white/80 {{if .IsCompleted}}line-through text-white/40{{end}} truncate">
+ <span class="flex-1 text-sm text-white/80 {{if .IsCompleted}}line-through text-white/40{{end}} truncate {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}cursor-pointer hover:underline{{end}}"
+ {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}
+ hx-get="/tasks/detail?id={{.ID}}&source={{.Source}}"
+ hx-target="#task-edit-content"
+ hx-swap="innerHTML"
+ onclick="document.getElementById('task-edit-modal').classList.remove('hidden')"
+ {{end}}>
{{.Title}}{{multiDayLabel .}}
{{if and (eq .MultiDayVariant "") .EndTime}}<span class="text-white/30 text-xs ml-1">– {{.EndTime.Format "3:04 PM"}}</span>{{end}}
{{if .ChainTotal}}<span class="chain-badge">{{.ChainPosition}}/{{.ChainTotal}}</span>{{end}}
@@ -330,7 +348,13 @@
<div class="flex-1 min-w-0">
<div class="flex items-start justify-between gap-2">
- <h3 class="text-sm text-white font-medium break-words {{if .IsCompleted}}line-through text-white/50{{end}}">{{.Title}}</h3>
+ <h3 class="text-sm text-white font-medium break-words {{if .IsCompleted}}line-through text-white/50{{end}} {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}cursor-pointer hover:underline{{end}}"
+ {{if or (eq .Type "task") (eq .Type "card") (eq .Type "gtask")}}
+ hx-get="/tasks/detail?id={{.ID}}&source={{.Source}}"
+ hx-target="#task-edit-content"
+ hx-swap="innerHTML"
+ onclick="document.getElementById('task-edit-modal').classList.remove('hidden')"
+ {{end}}>{{.Title}}</h3>
{{if .URL}}
<a href="{{.URL}}" target="_blank" class="text-white/50 hover:text-white flex-shrink-0">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">