110 lines
3.0 KiB
TypeScript
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",
|
|
}),
|
|
}));
|