fix(filters): browse with no rules works, popup under the input, no sticky headers (user report)

- Blank typed queries rode the STATIC autocomplete path for the classic
  six fields, where a single space similarity-matches into nothing —
  clicking an empty value box with no other filters said 'No matching
  values' in a library full of values. Blank = browse now always rides
  the composed engine (which trims and answers the top values); static
  keeps its pinned contract for real typed queries. Regression-pinned:
  browse with no rules lists the field's values.
- The value popup now drops BELOW the input (top: 100%), not over it.
- Field-menu group headers lost position:sticky — the search box alone
  stays pinned.
This commit is contained in:
John O'Keefe committed 2026-10-20 16:01:10 -04:00
1 parent 4c03116ec7
commit 9c006a9a2f
3 files changed
+20 -6

No files matched your search

+10
View File
@@ -526,6 +526,16 @@ func TestFilterSuggestionsUnderRules(t *testing.T) {
assert.NotContains(t, valuesOf(results), "spacewestern", "zero-match values never offered")
assert.NotContains(t, valuesOf(results), "history", "values outside the rules never offered")
// Browse with NO other rules in place: the blank query still lists
// the field's values (the static similarity path would answer a
// single space with nothing). Regression for the empty-browse bug.
status, results = suggest("genre", " ", "")
require.Equal(t, http.StatusOK, status)
assert.Contains(t, valuesOf(results), "fantasy", "browse with no rules lists the field's values")
status, results = suggest("author", " ", "")
require.Equal(t, http.StatusOK, status)
assert.Contains(t, valuesOf(results), "Amara Voss", "author browse with no rules")
// Library field menu: visibility-scoped, id values + name display
// (this test's fixture libraries are named "Test Builder Sug …").
status, results = suggest("library", "Test Builder", "")
+8 -3
View File
@@ -2648,9 +2648,14 @@ func (mh *MediaHandler) handleFieldValuesSearch(c *echo.Context, userID pgtype.U
tree = t
}
// Static path: the classic six with no rule tree (unchanged
// contract — the tag-dropdown island and deep links still ride it).
staticSix := tree == nil
// Static path: the classic six with a REAL typed query and no rule
// tree (unchanged contract — the tag-dropdown island and deep links
// still ride it). A BLANK typed query is BROWSE (the builder's
// click-the-box top-values list): the static queries would
// similarity-match a single space into nothing, so browse rides the
// composed engine, which trims the query and answers the top values
// under the rules.
staticSix := tree == nil && strings.TrimSpace(searchQuery) != ""
if staticSix {
switch fieldType {
case "author", "genre", "tags", "narrator", "series", "language":
+2 -3
View File
@@ -1962,6 +1962,8 @@
.fb-menu-value {
width: 16rem;
left: 0;
top: 100%;
margin-top: 0.25rem;
}
.fb-menu-group {
font-size: 0.65rem;
@@ -1974,9 +1976,6 @@
background-color: color-mix(in srgb, var(--text-primary) 5%, transparent);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
z-index: 1;
}
.fb-menu-filter-wrap {
padding: 0.4rem 0.5rem;