Files
mnote/wolai-frontend/src/store/search-palette.ts
T
2025-11-23 10:55:04 +08:00

110 lines
3.0 KiB
TypeScript

"use client";
import { create } from "zustand";
import type {
DocumentSearchFilters,
DocumentSearchResult,
DocumentSearchTimeField,
DocumentSearchTimeRange,
} from "@/types/search";
export type SearchPaletteMode = "search" | "reference";
export type ReferenceInsertMode = "inline" | "embed";
export type FilterKey = "titleOnly" | "exact" | "onlyCurrentPage" | "includeOcr";
interface SearchPaletteState {
open: boolean;
mode: SearchPaletteMode;
query: string;
filters: Omit<DocumentSearchFilters, "timeRange">;
timeRange: DocumentSearchTimeRange;
referenceMode: ReferenceInsertMode;
alias: string;
recent: DocumentSearchResult[];
setRecent: (items: DocumentSearchResult[]) => void;
openSearch: () => void;
openReference: (options?: { referenceMode?: ReferenceInsertMode; aliasSeed?: string }) => void;
close: () => void;
setQuery: (value: string) => void;
toggleFilter: (key: FilterKey) => void;
setTimeRange: (range: DocumentSearchTimeRange) => void;
setTimeField: (field: DocumentSearchTimeField) => void;
setCustomRange: (range: { from?: string; to?: string } | null) => void;
setReferenceMode: (mode: ReferenceInsertMode) => void;
setAlias: (value: string) => void;
rememberResult: (result: DocumentSearchResult) => void;
resetFilters: () => void;
}
const defaultFilters: Omit<DocumentSearchFilters, "timeRange"> = {
titleOnly: false,
exact: false,
onlyCurrentPage: false,
includeOcr: false,
timeField: "updated",
customRange: undefined,
};
export const useSearchPaletteStore = create<SearchPaletteState>((set) => ({
open: false,
mode: "search",
query: "",
filters: { ...defaultFilters },
timeRange: "any",
referenceMode: "inline",
alias: "",
recent: [],
setRecent: (items) => set({ recent: items.slice(0, 10) }),
openSearch: () =>
set((state) => ({
open: true,
mode: "search",
query: state.query,
})),
openReference: (options) =>
set({
open: true,
mode: "reference",
referenceMode: options?.referenceMode ?? "inline",
alias: options?.aliasSeed ?? "",
}),
close: () => set({ open: false }),
setQuery: (value) => set({ query: value }),
toggleFilter: (key) =>
set((state) => ({
filters: {
...state.filters,
[key]: !state.filters[key],
},
})),
setTimeRange: (range) => set({ timeRange: range }),
setTimeField: (field) =>
set((state) => ({
filters: {
...state.filters,
timeField: field,
},
})),
setCustomRange: (range) =>
set((state) => ({
filters: {
...state.filters,
customRange: range ?? undefined,
},
})),
setReferenceMode: (mode) => set({ referenceMode: mode }),
setAlias: (value) => set({ alias: value }),
rememberResult: (result) =>
set((state) => {
const existing = state.recent.filter((item) => item.id !== result.id);
return {
recent: [result, ...existing].slice(0, 10),
};
}),
resetFilters: () =>
set({
filters: { ...defaultFilters },
timeRange: "any",
}),
}));