feat: show secondary search filters only when applied

Created by and Labels now stay hidden until they hold a value; a Filter
button at the right end of the bar lists the hidden ones and opens the
picked filter's dropdown immediately.
This commit is contained in:
Philipinho
2026-08-24 21:19:58 +01:00
parent cdfb48141f
commit da58bb382e
3 changed files with 99 additions and 22 deletions
@@ -21,6 +21,8 @@ type CreatorFilterMenuProps = {
| "top-end" | "top-end"
| "top"; | "top";
zIndex?: number; zIndex?: number;
opened?: boolean;
onOpenChange?: (opened: boolean) => void;
}; };
export function CreatorFilterMenu({ export function CreatorFilterMenu({
@@ -30,6 +32,8 @@ export function CreatorFilterMenu({
width = 280, width = 280,
position = "bottom-end", position = "bottom-end",
zIndex, zIndex,
opened,
onOpenChange,
}: CreatorFilterMenuProps) { }: CreatorFilterMenuProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
@@ -46,7 +50,14 @@ export function CreatorFilterMenu({
const users: IUser[] = (suggestion?.users as IUser[]) ?? []; const users: IUser[] = (suggestion?.users as IUser[]) ?? [];
return ( return (
<Menu shadow="md" width={width} position={position} zIndex={zIndex}> <Menu
shadow="md"
width={width}
position={position}
zIndex={zIndex}
opened={opened}
onChange={onOpenChange}
>
<Menu.Target>{children}</Menu.Target> <Menu.Target>{children}</Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>
<TextInput <TextInput
@@ -27,6 +27,8 @@ type LabelFilterMenuProps = {
| "top-end" | "top-end"
| "top"; | "top";
zIndex?: number; zIndex?: number;
opened?: boolean;
onOpenChange?: (opened: boolean) => void;
}; };
export function LabelFilterMenu({ export function LabelFilterMenu({
@@ -36,6 +38,8 @@ export function LabelFilterMenu({
width = 280, width = 280,
position = "bottom-end", position = "bottom-end",
zIndex, zIndex,
opened,
onOpenChange,
}: LabelFilterMenuProps) { }: LabelFilterMenuProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const scheme = useComputedColorScheme("light"); const scheme = useComputedColorScheme("light");
@@ -61,6 +65,8 @@ export function LabelFilterMenu({
width={width} width={width}
position={position} position={position}
zIndex={zIndex} zIndex={zIndex}
opened={opened}
onChange={onOpenChange}
closeOnItemClick={false} closeOnItemClick={false}
> >
<Menu.Target>{children}</Menu.Target> <Menu.Target>{children}</Menu.Target>
@@ -11,6 +11,7 @@ import {
import { import {
IconChevronDown, IconChevronDown,
IconBuilding, IconBuilding,
IconPlus,
IconFileDescription, IconFileDescription,
IconCheck, IconCheck,
IconUser, IconUser,
@@ -52,6 +53,7 @@ export function SearchSpotlightFilters({
null null
); );
const [selectedLabelIds, setSelectedLabelIds] = useState<string[]>([]); const [selectedLabelIds, setSelectedLabelIds] = useState<string[]>([]);
const [openedFilter, setOpenedFilter] = useState<string | null>(null);
const [workspace] = useAtom(workspaceAtom); const [workspace] = useAtom(workspaceAtom);
const { data: spacesData } = useGetSpacesQuery({ limit: 100 }); const { data: spacesData } = useGetSpacesQuery({ limit: 100 });
@@ -104,6 +106,24 @@ export function SearchSpotlightFilters({
} }
}; };
const showCreatorFilter = !!selectedCreatorId || openedFilter === "creator";
const showLabelFilter =
contentType !== "attachment" &&
(selectedLabelIds.length > 0 || openedFilter === "labels");
const addableFilters: { key: string; label: string; icon: typeof IconUser }[] =
[];
if (!showCreatorFilter) {
addableFilters.push({
key: "creator",
label: t("Created by"),
icon: IconUser,
});
}
if (contentType !== "attachment" && !showLabelFilter) {
addableFilters.push({ key: "labels", label: t("Labels"), icon: IconTag });
}
return ( return (
<div className={classes.filtersContainer}> <div className={classes.filtersContainer}>
{workspace?.settings?.ai?.search === true && ( {workspace?.settings?.ai?.search === true && (
@@ -219,35 +239,41 @@ export function SearchSpotlightFilters({
</Menu.Dropdown> </Menu.Dropdown>
</Menu> </Menu>
<CreatorFilterMenu {showCreatorFilter && (
value={selectedCreatorId} <CreatorFilterMenu
onChange={handleCreatorSelect} value={selectedCreatorId}
position="bottom-start" onChange={handleCreatorSelect}
width={250} position="bottom-start"
zIndex={getDefaultZIndex("max")} width={250}
> zIndex={getDefaultZIndex("max")}
<Button opened={openedFilter === "creator"}
variant="subtle" onOpenChange={(opened) => setOpenedFilter(opened ? "creator" : null)}
color="gray"
size="sm"
rightSection={<IconChevronDown size={14} />}
leftSection={<IconUser size={16} />}
className={classes.filterButton}
fw={500}
> >
{selectedCreatorId <Button
? `${t("Created by")}: ${selectedCreatorName || t("Unknown")}` variant="subtle"
: `${t("Created by")}: ${t("Anyone")}`} color="gray"
</Button> size="sm"
</CreatorFilterMenu> rightSection={<IconChevronDown size={14} />}
leftSection={<IconUser size={16} />}
className={classes.filterButton}
fw={500}
>
{selectedCreatorId
? `${t("Created by")}: ${selectedCreatorName || t("Unknown")}`
: `${t("Created by")}: ${t("Anyone")}`}
</Button>
</CreatorFilterMenu>
)}
{contentType !== "attachment" && ( {showLabelFilter && (
<LabelFilterMenu <LabelFilterMenu
value={selectedLabelIds} value={selectedLabelIds}
onChange={handleLabelsSelect} onChange={handleLabelsSelect}
position="bottom-start" position="bottom-start"
width={250} width={250}
zIndex={getDefaultZIndex("max")} zIndex={getDefaultZIndex("max")}
opened={openedFilter === "labels"}
onOpenChange={(opened) => setOpenedFilter(opened ? "labels" : null)}
> >
<Button <Button
variant="subtle" variant="subtle"
@@ -264,6 +290,40 @@ export function SearchSpotlightFilters({
</Button> </Button>
</LabelFilterMenu> </LabelFilterMenu>
)} )}
{addableFilters.length > 0 && (
<Menu
shadow="md"
width={200}
position="bottom-end"
zIndex={getDefaultZIndex("max")}
>
<Menu.Target>
<Button
variant="subtle"
color="gray"
size="sm"
leftSection={<IconPlus size={16} />}
className={classes.filterButton}
style={{ marginLeft: "auto" }}
fw={500}
>
{t("Filter")}
</Button>
</Menu.Target>
<Menu.Dropdown>
{addableFilters.map((filter) => (
<Menu.Item
key={filter.key}
leftSection={<filter.icon size={16} />}
onClick={() => setOpenedFilter(filter.key)}
>
{filter.label}
</Menu.Item>
))}
</Menu.Dropdown>
</Menu>
)}
</div> </div>
); );
} }