summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-26 19:00:36 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-26 19:00:36 -1000
commit70e6e51b6781a3986c51e3496b81c88665286872 (patch)
tree091d0eb9daa08f4e892486451a154a67fb8a3cfe /web
parentbbf12fc441ca36c423e865107d34df178e3d26de (diff)
Add shopping mode for focused single-store shopping (#34)
- Full-screen view for one store at a time - Tap items to toggle completion - Completed items greyed and sorted to bottom - Quick-add form at bottom of screen - Store switcher pills for easy navigation - "Shop" button on each store in shopping tab Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'web')
-rw-r--r--web/templates/partials/shopping-mode-items.html45
-rw-r--r--web/templates/partials/shopping-tab.html11
-rw-r--r--web/templates/shopping-mode.html93
3 files changed, 148 insertions, 1 deletions
diff --git a/web/templates/partials/shopping-mode-items.html b/web/templates/partials/shopping-mode-items.html
new file mode 100644
index 0000000..fdf0674
--- /dev/null
+++ b/web/templates/partials/shopping-mode-items.html
@@ -0,0 +1,45 @@
+{{define "shopping-mode-items"}}
+<div class="space-y-2">
+ {{if .Items}}
+ {{range .Items}}
+ <div class="item-row flex items-center gap-3 p-4 bg-white/5 rounded-xl border border-white/10 cursor-pointer {{if .Checked}}item-checked{{end}}"
+ hx-post="/shopping/mode/{{$.StoreName}}/toggle"
+ hx-vals='{"id":"{{.ID}}","source":"{{.Source}}","checked":{{if .Checked}}false{{else}}true{{end}}}'
+ hx-target="#shopping-items"
+ hx-swap="innerHTML">
+
+ <!-- Checkbox visual -->
+ <div class="w-6 h-6 rounded-full border-2 flex items-center justify-center flex-shrink-0
+ {{if .Checked}}bg-green-500/30 border-green-500{{else}}border-white/30{{end}}">
+ {{if .Checked}}
+ <svg class="w-4 h-4 text-green-400" fill="currentColor" viewBox="0 0 20 20">
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
+ </svg>
+ {{end}}
+ </div>
+
+ <!-- Item content -->
+ <div class="flex-1 min-w-0">
+ <span class="item-name text-white block">{{.Name}}</span>
+ {{if .Quantity}}
+ <span class="text-sm text-white/50">{{.Quantity}}</span>
+ {{end}}
+ </div>
+
+ <!-- Source badge -->
+ <span class="text-xs px-2 py-0.5 rounded flex-shrink-0
+ {{if eq .Source "trello"}}bg-blue-900/50 text-blue-300
+ {{else if eq .Source "user"}}bg-purple-900/50 text-purple-300
+ {{else}}bg-green-900/50 text-green-300{{end}}">
+ {{.Source}}
+ </span>
+ </div>
+ {{end}}
+ {{else}}
+ <div class="text-center py-16 text-white/50">
+ <p class="text-lg mb-2">No items</p>
+ <p class="text-sm">Add items using the form below</p>
+ </div>
+ {{end}}
+</div>
+{{end}}
diff --git a/web/templates/partials/shopping-tab.html b/web/templates/partials/shopping-tab.html
index f247f3d..4d0ac02 100644
--- a/web/templates/partials/shopping-tab.html
+++ b/web/templates/partials/shopping-tab.html
@@ -29,7 +29,16 @@
{{if .Stores}}
{{range .Stores}}
<section class="bg-panel backdrop-blur-sm rounded-xl p-4 sm:p-5">
- <h2 class="text-xl font-medium mb-4 text-white">{{.Name}}</h2>
+ <div class="flex items-center justify-between mb-4">
+ <h2 class="text-xl font-medium text-white">{{.Name}}</h2>
+ <a href="/shopping/mode/{{.Name}}"
+ class="px-3 py-1.5 bg-white/10 hover:bg-white/20 rounded-lg text-sm text-white/70 hover:text-white transition-colors flex items-center gap-1.5">
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
+ </svg>
+ Shop
+ </a>
+ </div>
{{range .Categories}}
<div class="mb-4 last:mb-0">
{{if .Name}}<h3 class="text-sm text-white/60 mb-2 uppercase tracking-wide">{{.Name}}</h3>{{end}}
diff --git a/web/templates/shopping-mode.html b/web/templates/shopping-mode.html
new file mode 100644
index 0000000..9e21ac6
--- /dev/null
+++ b/web/templates/shopping-mode.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+ <title>{{.StoreName}} - Shopping</title>
+ <link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
+ <link rel="stylesheet" href="/static/css/output.css">
+ <script src="/static/js/htmx.min.js"></script>
+ <style>
+ body {
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
+ min-height: 100vh;
+ margin: 0;
+ padding: 0;
+ }
+ .item-row {
+ transition: all 0.2s ease;
+ }
+ .item-row:active {
+ transform: scale(0.98);
+ background: rgba(255,255,255,0.15);
+ }
+ .item-checked {
+ opacity: 0.5;
+ }
+ .item-checked .item-name {
+ text-decoration: line-through;
+ color: rgba(255,255,255,0.4);
+ }
+ .store-switcher {
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+ .store-switcher::-webkit-scrollbar {
+ display: none;
+ }
+ </style>
+</head>
+<body class="text-white">
+ <!-- Header -->
+ <header class="sticky top-0 z-50 bg-black/40 backdrop-blur-lg border-b border-white/10">
+ <div class="flex items-center justify-between px-4 py-3">
+ <a href="/?tab=shopping" class="text-white/70 hover:text-white p-2 -ml-2">
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
+ </svg>
+ </a>
+ <h1 class="text-lg font-semibold">{{.StoreName}}</h1>
+ <div class="w-10"></div>
+ </div>
+
+ <!-- Store Switcher -->
+ {{if gt (len .StoreNames) 1}}
+ <div class="store-switcher flex gap-2 px-4 pb-3 overflow-x-auto">
+ {{range .StoreNames}}
+ <a href="/shopping/mode/{{.}}"
+ class="px-3 py-1.5 rounded-full text-sm whitespace-nowrap transition-colors
+ {{if eq . $.StoreName}}bg-white/20 text-white{{else}}bg-white/5 text-white/60 hover:bg-white/10{{end}}">
+ {{.}}
+ </a>
+ {{end}}
+ </div>
+ {{end}}
+ </header>
+
+ <!-- Items List -->
+ <main class="p-4" id="shopping-items">
+ {{template "shopping-mode-items" .}}
+ </main>
+
+ <!-- Quick Add Form (Fixed at Bottom) -->
+ <div class="fixed bottom-0 left-0 right-0 bg-black/60 backdrop-blur-lg border-t border-white/10 p-4">
+ <form hx-post="/shopping/add"
+ hx-target="#shopping-items"
+ hx-swap="innerHTML"
+ hx-on::after-request="this.reset()"
+ class="flex gap-2">
+ <input type="hidden" name="store" value="{{.StoreName}}">
+ <input type="hidden" name="mode" value="shopping-mode">
+ <input type="text" name="name" placeholder="Add item..."
+ class="flex-1 bg-white/10 border border-white/20 rounded-lg px-4 py-3 text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-white/30"
+ required autocomplete="off">
+ <button type="submit" class="bg-white/20 hover:bg-white/30 text-white px-5 py-3 rounded-lg font-medium transition-colors">
+ Add
+ </button>
+ </form>
+ </div>
+
+ <!-- Spacer for fixed bottom form -->
+ <div class="h-24"></div>
+</body>
+</html>