✨(frontend) add file type category filter

Replace the folder/file toggle in the topbar with a file type category
filter (text document, slides, spreadsheet, pdf, image, video, audio,
archive, other), wired to the backend category filter.
This commit is contained in:
Nicolas Clerc
2026-06-29 15:42:58 +02:00
parent b88bd752aa
commit 650a29a5ed
3 changed files with 81 additions and 4 deletions
@@ -39,6 +39,7 @@ export type ItemFilters = {
is_creator_me?: boolean;
ordering?: string;
is_favorite?: boolean;
category?: string;
};
export type PaginatedChildrenResult = {
@@ -1,4 +1,4 @@
import { Filter, FilterOption, IconSize } from "@gouvfr-lasuite/ui-kit";
import { FileIcon, Filter, FilterOption, IconSize } from "@gouvfr-lasuite/ui-kit";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import folderIcon from "@/assets/folder/folder.svg";
@@ -50,14 +50,62 @@ export const ExplorerFilters = () => {
return (
<div className="explorer__filters">
<ExplorerFilterType
value={filters?.type ?? null}
onChange={(value) => onChange("type", value)}
<ExplorerFilterCategory
value={filters?.category ?? null}
onChange={(value) => onChange("category", value)}
/>
</div>
);
};
// A representative mimetype per category, resolved to an icon by the ui-kit's
// getMimeCategory so filter options match the icons shown on items.
const CATEGORY_OPTIONS: { value: string; mimetype: string }[] = [
{ value: "doc", mimetype: "application/vnd.oasis.opendocument.text" },
{ value: "powerpoint", mimetype: "application/vnd.oasis.opendocument.presentation" },
{ value: "calc", mimetype: "application/vnd.oasis.opendocument.spreadsheet" },
{ value: "pdf", mimetype: "application/pdf" },
{ value: "image", mimetype: "image/png" },
{ value: "video", mimetype: "video/mp4" },
{ value: "audio", mimetype: "audio/mpeg" },
{ value: "archive", mimetype: "application/zip" },
{ value: "other", mimetype: "text/plain" },
];
export const ExplorerFilterCategory = (props: {
value: string | null;
onChange: (value: Key | null) => void;
}) => {
const { t } = useTranslation();
const options: FilterOption[] = useMemo(
() => [
// Reset sits at the top of the list, above the categories, as in the design.
{ ...getResetOption(t), showSeparator: true },
...CATEGORY_OPTIONS.map(({ value, mimetype }) => ({
label: t(`explorer.filters.category.options.${value}`),
value,
render: () => (
<div className="explorer__filters__item">
<FileIcon file={{ mimetype, title: "" }} size={IconSize.SMALL} />
{t(`explorer.filters.category.options.${value}`)}
</div>
),
})),
],
[t],
);
return (
<Filter
label={t("explorer.filters.category.label")}
options={options}
selectedKey={props.value ?? null} // undefined would trigger "uncontrolled components become controlled" warning.
onSelectionChange={props.onChange}
/>
);
};
export const ExplorerFilterType = (props: {
value: ItemType | null;
onChange: (value: Key | null) => void;
@@ -262,6 +262,20 @@
"reset": "Reset"
}
},
"category": {
"label": "Type",
"options": {
"doc": "Text document",
"powerpoint": "Slides",
"calc": "Spreadsheet",
"pdf": "PDF",
"image": "Image",
"video": "Video",
"audio": "Audio",
"archive": "Archive",
"other": "Other"
}
},
"workspace": {
"label": "Workspace"
},
@@ -867,6 +881,20 @@
"reset": "Réinitialiser"
}
},
"category": {
"label": "Type",
"options": {
"doc": "Document texte",
"powerpoint": "Présentation",
"calc": "Tableur",
"pdf": "PDF",
"image": "Image",
"video": "Vidéo",
"audio": "Audio",
"archive": "Archive",
"other": "Autre"
}
},
"workspace": {
"label": "Espace"
},