<feed xmlns='http://www.w3.org/2005/Atom'>
<title>doot.git/internal/handlers/shopping_template_test.go, branch master</title>
<subtitle>doot — personal productivity web app
</subtitle>
<id>https://git.terst.org/doot.git/atom?h=master</id>
<link rel='self' href='https://git.terst.org/doot.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/'/>
<updated>2026-09-20T08:11:38+00:00</updated>
<entry>
<title>Make shopping items editable: tap to rename, move store/section, delete</title>
<updated>2026-09-20T08:11:38+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-09-20T08:11:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=c7b18e70ea87c287240243aed867b3a8b51689cb'/>
<id>urn:sha1:c7b18e70ea87c287240243aed867b3a8b51689cb</id>
<content type='text'>
Tapping an item outside shopping mode now opens an edit sheet. User-added items
can be renamed, moved between stores and sections, and deleted. PlanToEat items
show why they cannot be edited — the client is read-only, so presenting fields
that silently would not save is worse than saying so — and offer removal, which
marks them checked, the same mechanism shopping mode already uses.

This needed a store registry first. Stores previously existed only because some
item referenced them by name, with Trello's list names quietly acting as the
registry; removing Trello as a source made the gap visible. Without a registry
you cannot move an item into an empty store, and moving the last item out of a
store makes it vanish mid-edit. Migration 034 adds shopping_stores and
shopping_sections, seeded from the stores currently in use, and gives items a
section column — sections previously existed only as PlanToEat category
strings, so a user item could not be filed under one at all.

Registered stores and sections now appear in the list even when empty, which is
the whole point of the registry.

Two deliberate choices about destructive edges:
  * Renaming a store renames it and moves its items in one transaction. Items
    reference the store by name, so doing either alone orphans them.
  * Deleting a store or section keeps the items, moving them to Unassigned or
    clearing the section. Losing the list is far worse than re-filing an item.
  * An UPDATE matching no rows is an error, not a silent success, so a stale id
    cannot look like a saved edit.

Section options are rebuilt per store in the edit sheet rather than shipped as
one flat list, so a Costco item cannot be filed under a Safeway aisle.

18 new store tests, 11 handler tests.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
</content>
</entry>
<entry>
<title>Stop per-store add forms jumping to the bottom of the page</title>
<updated>2026-09-20T01:32:44+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-09-20T01:32:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=b970be11ee895c34e019231022e9e5244e4aec2f'/>
<id>urn:sha1:b970be11ee895c34e019231022e9e5244e4aec2f</id>
<content type='text'>
The inline "Add to &lt;store&gt;..." forms submitted with a bare
hx-swap="innerHTML" against #shopping-items-list. Those forms live *inside*
that target, so the swap destroys the form that submitted it and the page ends
up scrolled to the bottom rather than staying on the store being added to. The
quick-add form at the top never had this because it sits outside the target and
already carried an explicit scroll: modifier.

Each store section now has a stable id and its inline form scrolls back to it,
so adding to a store keeps that store in view.

Adds a `slug` template function for the id: store names are user data
("Trader Joe's", "Hardware Store") going straight into element ids, so anything
outside [a-z0-9-] is collapsed to a dash and an empty result becomes "unnamed"
rather than an invalid, shared anchor.

Tests render the real template with the real func map, and assert every inline
add form has a scroll target — the bug is trivially reintroduced by copying a
section.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
</content>
</entry>
</feed>
