summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-22 21:00:38 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-22 21:00:38 -1000
commit539122f3c80fe1f27348f0ddfc7fd428a58384b8 (patch)
tree069eadd594ac20df355f52fc13d435dcd26104f6
parentbedcd8a185e4197d087b2166afa79ff4dce25f7c (diff)
Add shopping quick-add feature
- Add Shopping tab to action modal (Ctrl+K) - Add /partials/shopping-lists endpoint to fetch lists from Shopping board - Store dropdown populated dynamically from Trello - Items added via existing unified-add endpoint Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
-rw-r--r--cmd/dashboard/main.go1
-rw-r--r--internal/handlers/handlers.go36
-rw-r--r--web/templates/index.html52
3 files changed, 88 insertions, 1 deletions
diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go
index 7645048..da49165 100644
--- a/cmd/dashboard/main.go
+++ b/cmd/dashboard/main.go
@@ -148,6 +148,7 @@ func main() {
// Unified Quick Add (for Tasks tab)
r.Post("/unified-add", h.HandleUnifiedAdd)
r.Get("/partials/lists", h.HandleGetListsOptions)
+ r.Get("/partials/shopping-lists", h.HandleGetShoppingLists)
// Task detail/edit
r.Get("/tasks/detail", h.HandleGetTaskDetail)
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 84a00fd..c44e771 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -1004,6 +1004,42 @@ func (h *Handler) HandleGetTaskDetail(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(html))
}
+// HandleGetShoppingLists returns the lists from the Shopping board for quick-add
+func (h *Handler) HandleGetShoppingLists(w http.ResponseWriter, r *http.Request) {
+ boards, err := h.store.GetBoards()
+ if err != nil {
+ http.Error(w, "Failed to get boards", http.StatusInternalServerError)
+ return
+ }
+
+ // Find the Shopping board
+ var shoppingBoardID string
+ for _, b := range boards {
+ if strings.EqualFold(b.Name, "Shopping") {
+ shoppingBoardID = b.ID
+ break
+ }
+ }
+
+ if shoppingBoardID == "" {
+ http.Error(w, "Shopping board not found", http.StatusNotFound)
+ return
+ }
+
+ // Get lists for the shopping board
+ lists, err := h.trelloClient.GetLists(r.Context(), shoppingBoardID)
+ if err != nil {
+ http.Error(w, "Failed to get lists", http.StatusInternalServerError)
+ log.Printf("Error fetching shopping lists: %v", err)
+ return
+ }
+
+ w.Header().Set("Content-Type", "text/html")
+ for _, list := range lists {
+ fmt.Fprintf(w, `<option value="%s">%s</option>`, list.ID, list.Name)
+ }
+}
+
// HandleUpdateTask updates a task description
func (h *Handler) HandleUpdateTask(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
diff --git a/web/templates/index.html b/web/templates/index.html
index f525a09..32c0857 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -87,7 +87,11 @@
<div class="flex gap-2">
<button onclick="switchActionTab('add')" id="tab-add"
class="px-3 py-1 rounded-lg text-sm font-medium bg-white/20 text-white">
- ✓ Quick Add
+ ✓ Task
+ </button>
+ <button onclick="switchActionTab('shopping')" id="tab-shopping"
+ class="px-3 py-1 rounded-lg text-sm font-medium text-white/60 hover:bg-white/10">
+ 🛒 Shopping
</button>
<button onclick="switchActionTab('bug')" id="tab-bug"
class="px-3 py-1 rounded-lg text-sm font-medium text-white/60 hover:bg-white/10">
@@ -125,6 +129,30 @@
</form>
</div>
+ <!-- Shopping Tab -->
+ <div id="panel-shopping" class="p-4 hidden">
+ <form hx-post="/unified-add"
+ hx-swap="none"
+ hx-on::after-request="if(event.detail.successful) { this.reset(); closeActionModal(); htmx.trigger(document.body, 'refresh-tasks'); }">
+ <input type="hidden" name="source" value="trello">
+ <input type="text"
+ name="title"
+ placeholder="Item name..."
+ class="w-full bg-black/40 border border-white/20 rounded-lg px-3 py-2 text-sm text-white placeholder-white/50 mb-3"
+ required>
+ <select name="list_id"
+ id="shopping-list-select"
+ class="w-full bg-black/40 border border-white/20 rounded-lg px-3 py-2 text-sm text-white mb-3"
+ required>
+ <option value="">Select store...</option>
+ </select>
+ <button type="submit"
+ class="w-full bg-green-900/50 hover:bg-green-900/70 text-green-300 px-4 py-2 rounded-lg text-sm font-medium">
+ Add to Shopping List
+ </button>
+ </form>
+ </div>
+
<!-- Bug Report Tab -->
<div id="panel-bug" class="p-4 hidden">
<form hx-post="/bugs"
@@ -171,13 +199,35 @@
}
function switchActionTab(tab) {
document.getElementById('panel-add').classList.toggle('hidden', tab !== 'add');
+ document.getElementById('panel-shopping').classList.toggle('hidden', tab !== 'shopping');
document.getElementById('panel-bug').classList.toggle('hidden', tab !== 'bug');
+ // Task tab styling
document.getElementById('tab-add').classList.toggle('bg-white/20', tab === 'add');
document.getElementById('tab-add').classList.toggle('text-white', tab === 'add');
document.getElementById('tab-add').classList.toggle('text-white/60', tab !== 'add');
+ // Shopping tab styling
+ document.getElementById('tab-shopping').classList.toggle('bg-green-900/50', tab === 'shopping');
+ document.getElementById('tab-shopping').classList.toggle('text-green-300', tab === 'shopping');
+ document.getElementById('tab-shopping').classList.toggle('text-white/60', tab !== 'shopping');
+ // Bug tab styling
document.getElementById('tab-bug').classList.toggle('bg-red-900/50', tab === 'bug');
document.getElementById('tab-bug').classList.toggle('text-red-300', tab === 'bug');
document.getElementById('tab-bug').classList.toggle('text-white/60', tab !== 'bug');
+ // Load shopping lists when switching to shopping tab
+ if (tab === 'shopping') {
+ loadShoppingLists();
+ }
+ }
+ function loadShoppingLists() {
+ var select = document.getElementById('shopping-list-select');
+ if (select.options.length <= 1) {
+ fetch('/partials/shopping-lists')
+ .then(function(r) { return r.text(); })
+ .then(function(html) {
+ select.innerHTML = '<option value="">Select store...</option>' + html;
+ })
+ .catch(function(e) { console.error('Failed to load shopping lists:', e); });
+ }
}
// Keyboard shortcut: Ctrl+K or Cmd+K
document.addEventListener('keydown', function(e) {