mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-26 17:52:59 +02:00
offload to files
This commit is contained in:
parent
cd94584278
commit
0f74dcda6c
@ -11,7 +11,7 @@ import { useNavigationActions, useNavigationState } from './NavigationContext';
|
|||||||
import { ToolId, isValidToolId } from '../types/toolId';
|
import { ToolId, isValidToolId } from '../types/toolId';
|
||||||
import { useNavigationUrlSync } from '../hooks/useUrlSync';
|
import { useNavigationUrlSync } from '../hooks/useUrlSync';
|
||||||
import { getDefaultWorkbench } from '../types/workbench';
|
import { getDefaultWorkbench } from '../types/workbench';
|
||||||
import { idToWords, scoreMatch, minScoreForQuery } from '../utils/fuzzySearch';
|
import { filterToolRegistryByQuery } from '../utils/toolSearch';
|
||||||
|
|
||||||
// State interface
|
// State interface
|
||||||
interface ToolWorkflowState {
|
interface ToolWorkflowState {
|
||||||
@ -219,54 +219,10 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
|||||||
setReaderMode(true);
|
setReaderMode(true);
|
||||||
}, [setReaderMode]);
|
}, [setReaderMode]);
|
||||||
|
|
||||||
// Filter tools based on search query with fuzzy matching (name and description)
|
// Filter tools based on search query with fuzzy matching (name, description, id, synonyms)
|
||||||
const filteredTools = useMemo(() => {
|
const filteredTools = useMemo(() => {
|
||||||
if (!toolRegistry) return [];
|
if (!toolRegistry) return [];
|
||||||
const entries = Object.entries(toolRegistry);
|
return filterToolRegistryByQuery(toolRegistry as Record<string, ToolRegistryEntry>, state.searchQuery);
|
||||||
if (!state.searchQuery.trim()) {
|
|
||||||
// Return in the new format even when not searching
|
|
||||||
return entries.map(([id, tool]) => ({ item: [id, tool] as [string, ToolRegistryEntry] }));
|
|
||||||
}
|
|
||||||
|
|
||||||
const threshold = minScoreForQuery(state.searchQuery);
|
|
||||||
const results: Array<{ item: [string, ToolRegistryEntry]; matchedText?: string; score: number }> = [];
|
|
||||||
|
|
||||||
for (const [id, tool] of entries) {
|
|
||||||
let best = 0;
|
|
||||||
let matchedText = '';
|
|
||||||
|
|
||||||
const candidates: string[] = [
|
|
||||||
idToWords(id),
|
|
||||||
tool.name || '',
|
|
||||||
tool.description || ''
|
|
||||||
];
|
|
||||||
for (const value of candidates) {
|
|
||||||
if (!value) continue;
|
|
||||||
const s = scoreMatch(state.searchQuery, value);
|
|
||||||
if (s > best) {
|
|
||||||
best = s;
|
|
||||||
matchedText = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(tool.synonyms)) {
|
|
||||||
for (const synonym of tool.synonyms) {
|
|
||||||
if (!synonym) continue;
|
|
||||||
const s = scoreMatch(state.searchQuery, synonym);
|
|
||||||
if (s > best) {
|
|
||||||
best = s;
|
|
||||||
matchedText = synonym;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best >= threshold) {
|
|
||||||
results.push({ item: [id, tool] as [string, ToolRegistryEntry], matchedText, score: best });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results.sort((a, b) => b.score - a.score);
|
|
||||||
return results.map(({ item, matchedText }) => ({ item, matchedText }));
|
|
||||||
}, [toolRegistry, state.searchQuery]);
|
}, [toolRegistry, state.searchQuery]);
|
||||||
|
|
||||||
const isPanelVisible = useMemo(() =>
|
const isPanelVisible = useMemo(() =>
|
||||||
|
@ -12,6 +12,7 @@ import RemoveBlanks from "../tools/RemoveBlanks";
|
|||||||
import RemovePages from "../tools/RemovePages";
|
import RemovePages from "../tools/RemovePages";
|
||||||
import RemovePassword from "../tools/RemovePassword";
|
import RemovePassword from "../tools/RemovePassword";
|
||||||
import { SubcategoryId, ToolCategoryId, ToolRegistry } from "./toolsTaxonomy";
|
import { SubcategoryId, ToolCategoryId, ToolRegistry } from "./toolsTaxonomy";
|
||||||
|
import { mergeSynonyms } from "../utils/toolSynonyms";
|
||||||
import AddWatermark from "../tools/AddWatermark";
|
import AddWatermark from "../tools/AddWatermark";
|
||||||
import Merge from '../tools/Merge';
|
import Merge from '../tools/Merge';
|
||||||
import Repair from "../tools/Repair";
|
import Repair from "../tools/Repair";
|
||||||
@ -146,31 +147,6 @@ export const CONVERT_SUPPORTED_FORMATS = [
|
|||||||
"pdf",
|
"pdf",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Helper function to get translated synonyms for a tool
|
|
||||||
const getTranslatedSynonyms = (t: any, toolId: string): string[] => {
|
|
||||||
try {
|
|
||||||
const tagsKey = `${toolId}.tags`;
|
|
||||||
const tags = t(tagsKey);
|
|
||||||
|
|
||||||
// If the translation key doesn't exist or returns the key itself, return empty array
|
|
||||||
if (!tags || tags === tagsKey) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split by comma and clean up the tags
|
|
||||||
return tags.split(',').map((tag: string) => tag.trim()).filter((tag: string) => tag.length > 0);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Failed to get translated synonyms for tool ${toolId}:`, error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to merge translated synonyms with existing synonyms
|
|
||||||
const mergeSynonyms = (t: any, toolId: string, existingSynonyms: string[] = []): string[] => {
|
|
||||||
const translatedSynonyms = getTranslatedSynonyms(t, toolId);
|
|
||||||
return [...translatedSynonyms, ...existingSynonyms];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hook to get the translated tool registry
|
// Hook to get the translated tool registry
|
||||||
export function useFlatToolRegistry(): ToolRegistry {
|
export function useFlatToolRegistry(): ToolRegistry {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -96,6 +96,9 @@ export function rankByFuzzy<T>(items: T[], query: string, getters: Array<(item:
|
|||||||
best = s;
|
best = s;
|
||||||
matchedText = value;
|
matchedText = value;
|
||||||
}
|
}
|
||||||
|
if (best >= 95) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (best >= threshold) results.push({ item, score: best, matchedText });
|
if (best >= threshold) results.push({ item, score: best, matchedText });
|
||||||
}
|
}
|
||||||
|
61
frontend/src/utils/toolSearch.ts
Normal file
61
frontend/src/utils/toolSearch.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { ToolRegistryEntry } from "../data/toolsTaxonomy";
|
||||||
|
import { idToWords, scoreMatch, minScoreForQuery } from "./fuzzySearch";
|
||||||
|
|
||||||
|
export interface RankedToolItem {
|
||||||
|
item: [string, ToolRegistryEntry];
|
||||||
|
matchedText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filterToolRegistryByQuery(
|
||||||
|
toolRegistry: Record<string, ToolRegistryEntry>,
|
||||||
|
query: string
|
||||||
|
): RankedToolItem[] {
|
||||||
|
const entries = Object.entries(toolRegistry);
|
||||||
|
if (!query.trim()) {
|
||||||
|
return entries.map(([id, tool]) => ({ item: [id, tool] as [string, ToolRegistryEntry] }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const threshold = minScoreForQuery(query);
|
||||||
|
const results: Array<{ item: [string, ToolRegistryEntry]; matchedText?: string; score: number }> = [];
|
||||||
|
|
||||||
|
for (const [id, tool] of entries) {
|
||||||
|
let best = 0;
|
||||||
|
let matchedText = '';
|
||||||
|
|
||||||
|
const candidates: string[] = [
|
||||||
|
idToWords(id),
|
||||||
|
tool.name || '',
|
||||||
|
tool.description || ''
|
||||||
|
];
|
||||||
|
for (const value of candidates) {
|
||||||
|
if (!value) continue;
|
||||||
|
const s = scoreMatch(query, value);
|
||||||
|
if (s > best) {
|
||||||
|
best = s;
|
||||||
|
matchedText = value;
|
||||||
|
}
|
||||||
|
if (best >= 95) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(tool.synonyms)) {
|
||||||
|
for (const synonym of tool.synonyms) {
|
||||||
|
if (!synonym) continue;
|
||||||
|
const s = scoreMatch(query, synonym);
|
||||||
|
if (s > best) {
|
||||||
|
best = s;
|
||||||
|
matchedText = synonym;
|
||||||
|
}
|
||||||
|
if (best >= 95) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best >= threshold) {
|
||||||
|
results.push({ item: [id, tool] as [string, ToolRegistryEntry], matchedText, score: best });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.sort((a, b) => b.score - a.score);
|
||||||
|
return results.map(({ item, matchedText }) => ({ item, matchedText }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
36
frontend/src/utils/toolSynonyms.ts
Normal file
36
frontend/src/utils/toolSynonyms.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { TFunction } from 'i18next';
|
||||||
|
|
||||||
|
// Helper function to get translated synonyms for a tool
|
||||||
|
export const getTranslatedSynonyms = (t: TFunction, toolId: string): string[] => {
|
||||||
|
try {
|
||||||
|
const tagsKey = `${toolId}.tags`;
|
||||||
|
const tags = t(tagsKey) as unknown as string;
|
||||||
|
|
||||||
|
// If the translation key doesn't exist or returns the key itself, return empty array
|
||||||
|
if (!tags || tags === tagsKey) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split by comma and clean up the tags
|
||||||
|
return tags
|
||||||
|
.split(',')
|
||||||
|
.map((tag: string) => tag.trim())
|
||||||
|
.filter((tag: string) => tag.length > 0);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn(`Failed to get translated synonyms for tool ${toolId}:`, error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to merge translated synonyms with existing synonyms
|
||||||
|
export const mergeSynonyms = (
|
||||||
|
t: TFunction,
|
||||||
|
toolId: string,
|
||||||
|
existingSynonyms: string[] = []
|
||||||
|
): string[] => {
|
||||||
|
const translatedSynonyms = getTranslatedSynonyms(t, toolId);
|
||||||
|
return [...translatedSynonyms, ...existingSynonyms];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user