Tags et favoris, filtres dans l'explorateur

- DATA_DIR/.meta.json : tags et favoris par chemin, suivis aux renommages,
  déplacements, copies (tags seuls) et suppressions.
- API : GET /api/tags, POST /api/meta/favorite, POST /api/meta/tags ; Entry
  porte tags et favorite ; /api/search accepte tag= et fav=true (q facultatif).
- Tags comparés sans casse ni accents, écriture existante conservée ; ils
  participent à la recherche texte.
- Explorateur : ligne de filtres (Favoris, tags avec leur nombre), étoile et
  tags sur les éléments, menu Favori / Tags…, actions sur la sélection,
  dialogue Tags (ajout, retrait, suggestions).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6J7vKwXx7uopxKhWfFJpm
This commit is contained in:
claude BotandClaude Opus 5.5 committed 2026-10-07 18:06:45 +02:00
1 parent c78df092c1
commit c1ea1e84a7
13 files changed
+880 -33

No files matched your search

+27 -2
View File
@@ -6,6 +6,19 @@ export interface Entry {
isDir: boolean;
size: number;
modTime: string;
tags?: string[];
favorite?: boolean;
}
export interface TagCount {
name: string;
count: number;
}
/** Filtres de recherche : tag exact et/ou favoris seulement. */
export interface SearchFilter {
tag?: string | null;
fav?: boolean;
}
/** Résultat de recherche ; snippet = extrait du contenu qui correspond. */
@@ -77,8 +90,20 @@ export const api = {
list: async (dir: string): Promise<Entry[]> =>
(await request(`/api/list?path=${q(dir)}`)).json(),
search: async (text: string): Promise<Hit[]> =>
(await request(`/api/search?q=${q(text)}`)).json(),
search: async (text: string, f: SearchFilter = {}): Promise<Hit[]> =>
(
await request(`/api/search?q=${q(text)}${f.tag ? `&tag=${q(f.tag)}` : ""}${f.fav ? "&fav=true" : ""}`)
).json(),
tags: async (): Promise<TagCount[]> => (await request("/api/tags")).json(),
setFavorite: async (paths: string[], favorite: boolean): Promise<void> => {
await request("/api/meta/favorite", json({ paths, favorite }));
},
editTags: async (paths: string[], add: string[], remove: string[]): Promise<void> => {
await request("/api/meta/tags", json({ paths, add, remove }));
},
read: async (path: string): Promise<{ text: string; etag: string }> => {
const res = await request(`/api/file?path=${q(path)}`);