194 lines
4.8 KiB
TypeScript
194 lines
4.8 KiB
TypeScript
import { Injectable, signal, computed } from '@angular/core';
|
|
|
|
/**
|
|
* Search preferences per context
|
|
*/
|
|
export interface SearchPreferences {
|
|
/** Case sensitive search */
|
|
caseSensitive: boolean;
|
|
/** Regex mode enabled */
|
|
regexMode: boolean;
|
|
/** Collapse all results by default */
|
|
collapseResults: boolean;
|
|
/** Show more context around matches */
|
|
showMoreContext: boolean;
|
|
/** Number of context lines (when showMoreContext is true) */
|
|
contextLines: number;
|
|
/** Explain search terms */
|
|
explainSearchTerms: boolean;
|
|
}
|
|
|
|
/**
|
|
* Default preferences
|
|
*/
|
|
const DEFAULT_PREFERENCES: SearchPreferences = {
|
|
caseSensitive: false,
|
|
regexMode: false,
|
|
collapseResults: false,
|
|
showMoreContext: false,
|
|
contextLines: 2,
|
|
explainSearchTerms: false
|
|
};
|
|
|
|
/**
|
|
* Search preferences service
|
|
* Manages persistent search preferences per context (vault, header, graph)
|
|
*/
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class SearchPreferencesService {
|
|
private readonly STORAGE_KEY = 'obsiviewer_search_preferences';
|
|
|
|
// Preferences by context
|
|
private preferencesMap = signal<Map<string, SearchPreferences>>(new Map());
|
|
|
|
constructor() {
|
|
this.loadFromStorage();
|
|
}
|
|
|
|
/**
|
|
* Get preferences for a specific context
|
|
*/
|
|
getPreferences(context: string = 'vault'): SearchPreferences {
|
|
const prefs = this.preferencesMap().get(context);
|
|
return prefs ? { ...prefs } : { ...DEFAULT_PREFERENCES };
|
|
}
|
|
|
|
/**
|
|
* Get preferences signal for a specific context
|
|
*/
|
|
getPreferencesSignal(context: string = 'vault') {
|
|
return computed(() => {
|
|
const prefs = this.preferencesMap().get(context);
|
|
return prefs ? { ...prefs } : { ...DEFAULT_PREFERENCES };
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update preferences for a specific context
|
|
*/
|
|
updatePreferences(context: string, updates: Partial<SearchPreferences>): void {
|
|
this.preferencesMap.update(map => {
|
|
const current = map.get(context) || { ...DEFAULT_PREFERENCES };
|
|
const updated = { ...current, ...updates };
|
|
map.set(context, updated);
|
|
return new Map(map);
|
|
});
|
|
|
|
this.saveToStorage();
|
|
}
|
|
|
|
/**
|
|
* Toggle a boolean preference
|
|
*/
|
|
togglePreference(
|
|
context: string,
|
|
key: keyof Pick<SearchPreferences, 'caseSensitive' | 'regexMode' | 'collapseResults' | 'showMoreContext' | 'explainSearchTerms'>
|
|
): void {
|
|
const current = this.getPreferences(context);
|
|
this.updatePreferences(context, {
|
|
[key]: !current[key]
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set context lines
|
|
*/
|
|
setContextLines(context: string, lines: number): void {
|
|
this.updatePreferences(context, { contextLines: Math.max(0, Math.min(10, lines)) });
|
|
}
|
|
|
|
/**
|
|
* Reset preferences for a context
|
|
*/
|
|
resetPreferences(context: string): void {
|
|
this.preferencesMap.update(map => {
|
|
map.set(context, { ...DEFAULT_PREFERENCES });
|
|
return new Map(map);
|
|
});
|
|
|
|
this.saveToStorage();
|
|
}
|
|
|
|
/**
|
|
* Reset all preferences
|
|
*/
|
|
resetAllPreferences(): void {
|
|
this.preferencesMap.set(new Map());
|
|
this.saveToStorage();
|
|
}
|
|
|
|
/**
|
|
* Load preferences from localStorage
|
|
*/
|
|
private loadFromStorage(): void {
|
|
try {
|
|
const stored = localStorage.getItem(this.STORAGE_KEY);
|
|
if (stored) {
|
|
const data = JSON.parse(stored);
|
|
const map = new Map<string, SearchPreferences>();
|
|
|
|
for (const [context, prefs] of Object.entries(data)) {
|
|
map.set(context, { ...DEFAULT_PREFERENCES, ...(prefs as any) });
|
|
}
|
|
|
|
this.preferencesMap.set(map);
|
|
}
|
|
} catch (e) {
|
|
console.error('Failed to load search preferences:', e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save preferences to localStorage
|
|
*/
|
|
private saveToStorage(): void {
|
|
try {
|
|
const data: Record<string, SearchPreferences> = {};
|
|
|
|
this.preferencesMap().forEach((prefs, context) => {
|
|
data[context] = prefs;
|
|
});
|
|
|
|
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(data));
|
|
} catch (e) {
|
|
console.error('Failed to save search preferences:', e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Export preferences as JSON
|
|
*/
|
|
exportPreferences(): string {
|
|
const data: Record<string, SearchPreferences> = {};
|
|
|
|
this.preferencesMap().forEach((prefs, context) => {
|
|
data[context] = prefs;
|
|
});
|
|
|
|
return JSON.stringify(data, null, 2);
|
|
}
|
|
|
|
/**
|
|
* Import preferences from JSON
|
|
*/
|
|
importPreferences(json: string): boolean {
|
|
try {
|
|
const data = JSON.parse(json);
|
|
const map = new Map<string, SearchPreferences>();
|
|
|
|
for (const [context, prefs] of Object.entries(data)) {
|
|
map.set(context, { ...DEFAULT_PREFERENCES, ...(prefs as any) });
|
|
}
|
|
|
|
this.preferencesMap.set(map);
|
|
this.saveToStorage();
|
|
return true;
|
|
} catch (e) {
|
|
console.error('Failed to import search preferences:', e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|