feat(filters): save current filter as smart collection — the bridge (item 3.5)

The bookshelf's save modal grows a second action: "Save as Collection"
POSTs the current (completed, scope-stamped) tree to
/api/collections — the same validated write path every tree
collection uses — and lands you on the new collection's page. The qf
engine then drives it everywhere: the shelf's live shelf-count, the
collections page, the replay chain for episode trees. The legacy
"Save Filter" (bookmark the wire params) stays as the sibling action.

This is the plan's bridge: a book search graduated into a live shelf
with one click, authored in the ONE filter system.
This commit is contained in:
John O'Keefe committed 2026-10-30 19:25:02 -04:00
1 parent 4f71eda6be
commit 94bd69d22d
3 files changed
+47 -3

No files matched your search

+7 -2
View File
@@ -268,6 +268,7 @@ templ BookShelf(
</button>
</div>
<form
id="save-filter-form"
hx-post="/api/saved-filters"
hx-target="#saved-filters-list"
hx-swap="beforeend"
@@ -276,13 +277,17 @@ templ BookShelf(
>
<div class="mb-4">
<label class="block text-xs font-semibold uppercase tracking-wide mb-2" style="color: var(--text-secondary)">Filter Name</label>
<input type="text" name="filter_name" placeholder="My Custom Filter" class="input" required/>
<input type="text" id="save-filter-name" name="filter_name" placeholder="My Custom Filter" class="input" required/>
<div id="filter-save-error" style="display: none; color: var(--status-danger); padding: 0.75rem; border-radius: 0.5rem; margin-top: 0.75rem;"></div>
<input type="hidden" name="resource_type" value="media-items"/>
</div>
<div class="flex justify-end gap-2">
<button type="button" @click="showSaveModal = false" class="btn btn-secondary">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
<button type="submit" class="btn btn-secondary">Save Filter</button>
<!-- Item 3.5: the bridge — the current tree becomes a live
smart collection (the qf engine drives it everywhere:
shelf, collections, play chains). -->
<button type="button" @click="saveFilterAsCollection()" class="btn btn-primary">Save as Collection</button>
</div>
<input type="hidden" name="limit" value="50"/>
<input type="hidden" name="offset" value="0"/>