fix(podcasts+ui): user-test round 3 — five browser-reported defects
1. Add-modal 'Download order' never revealed: the CSS sibling selector
(#podcast-download-all:checked ~ .podcast-add-order) can't fire —
the checkbox was nested inside a wrapper div, so the select row was
no SIBLING of the input. Restructured: input, label, and order row
are now siblings under one flex-wrap wrapper.
2. Order + auto-download dropdowns always displayed the LAST option
('Newest first'/'Newest') regardless of the saved value: templ's
selected={ boolExpr } compiles to selected="false" — and the mere
PRESENCE of the attribute selects the option, so every option was
selected and the browser honored the last. Sweep to the boolean-
attribute form selected?={...} (omits on false) across
podcast_detail (14), book_detail_modals (10: manga type/reading
direction selects + abridged/explicit checkboxes — same defect,
always-checked), collection_modal (2: hide-finished/show-up-next
always-checked). Values were SAVING correctly all along; this was
pure display. audio_reader/collections :selected/:checked are
Alpine bindings — unaffected.
3. Remove Feed (and every hx-confirm) still showed the browser dialog
for signed-in users: the global confirm modal rendered at the end
of SidebarSignIn — signed-IN pages have no SidebarSignIn, so no
#confirm-modal existed and confirmDialog() degraded to
window.confirm. Moved the modal into Header proper (rendered on
every page, after </aside>).
4. Facet bar at scale: values now carry feed COUNTS, sort by frequency
DESC then alphabetically, cap at 6 chips per group flat, and the
rest collapse into a native <details> '+N more' expander — hundreds
of hosts/tags degrade gracefully instead of a wall of chips.
Verified live on the dev instance (order select reflects the saved
override, override row persists, reveal fires, modal renders on
signed-in pages). Podcast + logout + media-pin suites green; vitest
167 green.
This commit is contained in:
1 parent
15f41e6fd4
commit
2fd0828c06
13 files changed
+1004
-948
No files matched your search
@@ -403,32 +403,41 @@ func podcastOrderForFeed(cfg *Config, c *echo.Context, feedID string) string {
|
||||
}
|
||||
|
||||
// facetValuesFromCards derives the filter bar values.
|
||||
func facetValuesFromCards(feeds []templates.PodcastFeedCard) map[string][]string {
|
||||
hosts, tags, langs := map[string]bool{}, map[string]bool{}, map[string]bool{}
|
||||
// facetValuesFromCards derives the filter-bar values with feed counts,
|
||||
// sorted by frequency DESC then alphabetically — the top of each group
|
||||
// is what a user with hundreds of feeds actually filters by.
|
||||
func facetValuesFromCards(feeds []templates.PodcastFeedCard) map[string][]templates.FacetValue {
|
||||
hosts, tags, langs := map[string]int{}, map[string]int{}, map[string]int{}
|
||||
for _, f := range feeds {
|
||||
if f.Host != "" {
|
||||
hosts[f.Host] = true
|
||||
hosts[f.Host]++
|
||||
}
|
||||
for _, t := range f.Tags {
|
||||
tags[t] = true
|
||||
tags[t]++
|
||||
}
|
||||
if f.Language != "" {
|
||||
langs[f.Language] = true
|
||||
langs[f.Language]++
|
||||
}
|
||||
}
|
||||
return map[string][]string{
|
||||
"hosts": sortedSet(hosts),
|
||||
"tags": sortedSet(tags),
|
||||
"language": sortedSet(langs),
|
||||
return map[string][]templates.FacetValue{
|
||||
"hosts": sortedFacet(hosts),
|
||||
"tags": sortedFacet(tags),
|
||||
"language": sortedFacet(langs),
|
||||
}
|
||||
}
|
||||
|
||||
func sortedSet(set map[string]bool) []string {
|
||||
out := make([]string, 0, len(set))
|
||||
for k := range set {
|
||||
out = append(out, k)
|
||||
// sortedFacet: count DESC, then value ASC (stable, scannable).
|
||||
func sortedFacet(set map[string]int) []templates.FacetValue {
|
||||
out := make([]templates.FacetValue, 0, len(set))
|
||||
for k, n := range set {
|
||||
out = append(out, templates.FacetValue{Value: k, Count: n})
|
||||
}
|
||||
sort.Strings(out)
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
if out[i].Count != out[j].Count {
|
||||
return out[i].Count > out[j].Count
|
||||
}
|
||||
return out[i].Value < out[j].Value
|
||||
})
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user