feat(navigator): search-scope filter chips replace the dropdown (P4 wave 1b)

NavigatorFilterChipsView renders the 5 SearchFilterOptions (anything /
room.name / owner / tag / group) as pill chips instead of a <select>.
Active chip uses bg-primary; the chips sit on their own row above the
search input. Drives the existing searchFilterIndex local state — the
debounce effect already rebuilds the query:value string from it, so no
behavioural change to how searches are issued.

Deferred to wave 1c: saved-search chip row (replacing the 600px sidebar).
That one needs care — a saved-search click sends NavigatorSearchComposer
directly, which P2's accept-filter (result.code must match currentTabCode)
can reject; the chip version must route through setTab/setFilter instead.
Wants browser verification.

navigator suites 28/28, lint:hooks clean, no new typecheck errors.
This commit is contained in:
simoleo89
2026-05-28 18:06:29 +02:00
parent 3bce0c0191
commit d5e64ada25
2 changed files with 35 additions and 9 deletions
@@ -0,0 +1,32 @@
import { FC } from 'react';
import { LocalizeText, SearchFilterOptions } from '../../../../api';
interface NavigatorFilterChipsViewProps
{
value: number;
onChange: (index: number) => void;
}
export const NavigatorFilterChipsView: FC<NavigatorFilterChipsViewProps> = props =>
{
const { value, onChange } = props;
return (
<div className="flex flex-wrap gap-1">
{ SearchFilterOptions.map((filter, index) =>
{
const isActive = (value === index);
return (
<button
key={ index }
type="button"
onClick={ () => onChange(index) }
className={ `px-2 py-0.5 rounded-full text-[11px] border cursor-pointer transition-colors ${ isActive ? 'bg-primary text-white border-primary' : 'bg-card-grid-item text-gray-600 border-card-grid-item-border hover:bg-primary hover:text-white hover:border-primary' }` }>
{ LocalizeText('navigator.filter.' + filter.name) }
</button>
);
}) }
</div>
);
};
@@ -4,6 +4,7 @@ import { FaSearch } from 'react-icons/fa';
import { INavigatorSearchFilter, LocalizeText, SearchFilterOptions } from '../../../../api';
import { Button } from '../../../../common';
import { useNavigatorData, useNavigatorUiStore } from '../../../../hooks';
import { NavigatorFilterChipsView } from './NavigatorFilterChipsView';
interface NavigatorSearchViewProps
{
@@ -77,15 +78,8 @@ export const NavigatorSearchView: FC<NavigatorSearchViewProps> = props =>
};
return (
<div className="flex w-full gap-1">
<div className="flex shrink-0">
<select className="form-select" value={ searchFilterIndex } onChange={ event => setSearchFilterIndex(parseInt(event.target.value)) }>
{ SearchFilterOptions.map((filter, index) =>
{
return <option key={ index } value={ index }>{ LocalizeText('navigator.filter.' + filter.name) }</option>;
}) }
</select>
</div>
<div className="flex w-full flex-col gap-1">
<NavigatorFilterChipsView value={ searchFilterIndex } onChange={ setSearchFilterIndex } />
<div className="flex w-full gap-1">
<input className="w-full form-control" placeholder={ LocalizeText('navigator.filter.input.placeholder') } type="text" value={ inputText } onChange={ event => setInputText(event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
<Button variant="primary" onClick={ processSearch }>