feat(search): advanced options on the form, filters and sorting on results - #104
Merged
Conversation
…sults The search form was a box, a forum and a sort order; the results page was a listing you could only re-run from the form. Both grow the half MyBB has had since 2006, and the results page grows the half it never had. **The form.** Behind a disclosure that opens itself when anything in it is set: a forum with *include subforums*, one or more authors by username, a date window, whether to match thread titles alone, and whether a result is a post or a thread. An author nobody answers to refuses the search by name rather than quietly matching everybody. **The results page.** A filter and sort panel built from the search's own facets — each forum and author with the number of results it would leave — plus one chip per filter that is on, each with an href that removes only itself. The filters live in the results URL as a *refinement* on the stored search, so changing them costs no search row and no flood interval, and the reader's original search stays where it was. A refinement narrows and never widens: a titles-only search cannot be refined back into the whole post, a week cannot be refined into a year, and a forum outside the search cannot be refined into it. `trimRefinement` drops anything that only repeats what the search already asked for, so "is this filtered?" has an answer and the panel never offers an option that would do nothing. `@meith/search` grows the vocabulary — sort, match, grouping, period, and the narrowing rules over them — so the app, the view and the REST route share one definition of what a filter is. The Postgres repository grows titles-only matching, real thread grouping (each thread represented by its best match under the current order), and `summarize()`: one bounded query returning the count and both facet breakdowns, computed without the forum and author filters so the counts hold still as a reader moves between them. The count reuses the 20,000-row window that already bounds ranking, and says so when it stops there. Theme API 0.13: three optional fields — `SearchFormModel.advanced`, `SearchResultsModel.refine`, and `within.hidden`. A theme that never reads them renders exactly what it rendered before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DC4qB9MRBHiseChyrnCTxR
"Every forum in this search" is wider than the select it sits in, so a three-column filter panel truncated it to "Every forum in this sea". The panel already says it filters *these results*; the option only has to say "not one of them in particular". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DC4qB9MRBHiseChyrnCTxR
Filtering and sorting arrived as a six-control grid in a card, which is most of a screen above a listing — a listing you cannot see is a listing you cannot read. The controls are the same; the shape is not. The order leaves the form and becomes three links in a segmented control: changing it is one decision and the commonest one, so it should not need a submit, and each href carries the filters already applied. The filters stay a GET form — several decisions at once, one apply — but the labels move beside their controls rather than above them, and the whole thing reads as one bar between the heading and the results. Anything on is a chip that removes itself, and "clear filters" appears beside apply only when there is something to clear. An earlier pass folded the filters behind a disclosure instead. It saved more space and was worse: a filter nobody can see is a filter nobody uses, and a reader looking at a narrowed page with nothing on screen to say so does not trust it. `SearchRefineModel` therefore carries no open/closed state at all — `sorts` and `sortsLabel` are new, and the model says in its own documentation that this is a strip and why hiding it is not the way to keep it one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DC4qB9MRBHiseChyrnCTxR
`search-light` and `search-dark` showed the results page before it had a filter strip, which is the half of the page this branch changed. `pnpm site:shots` wipes the directory and rephotographs the whole set against a freshly seeded demo board, so the other twelve are the same designs with different sample content and timestamps rather than deliberate changes; dues came out byte-identical and is absent from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DC4qB9MRBHiseChyrnCTxR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The search form was a box, a forum and a sort order; the results page was a
listing you could only re-run from the form. Both grow the half MyBB has had
since 2006, and the results page grows the half it never had.
The form. Behind a disclosure that opens itself when anything in it is
set: a forum with include subforums, one or more authors by username, a date
window, whether to match thread titles alone, and whether a result is a post
or a thread. An author nobody answers to refuses the search by name rather
than quietly matching everybody.
The results page. A filter and sort panel built from the search's own
facets — each forum and author with the number of results it would leave —
plus one chip per filter that is on, each with an href that removes only
itself. The filters live in the results URL as a refinement on the stored
search, so changing them costs no search row and no flood interval, and the
reader's original search stays where it was.
A refinement narrows and never widens: a titles-only search cannot be refined
back into the whole post, a week cannot be refined into a year, and a forum
outside the search cannot be refined into it.
trimRefinementdrops anythingthat only repeats what the search already asked for, so "is this filtered?"
has an answer and the panel never offers an option that would do nothing.
@meith/searchgrows the vocabulary — sort, match, grouping, period, and thenarrowing rules over them — so the app, the view and the REST route share one
definition of what a filter is. The Postgres repository grows titles-only
matching, real thread grouping (each thread represented by its best match
under the current order), and
summarize(): one bounded query returning thecount and both facet breakdowns, computed without the forum and author filters
so the counts hold still as a reader moves between them. The count reuses the
20,000-row window that already bounds ranking, and says so when it stops
there.
Theme API 0.13: three optional fields —
SearchFormModel.advanced,SearchResultsModel.refine, andwithin.hidden. A theme that never readsthem renders exactly what it rendered before.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01DC4qB9MRBHiseChyrnCTxR