mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 01:21:24 +02:00
refactor(shared-ui): extract search-core for highlight + debounce
Both QuickInputBar (InputBar.svelte), CommandBar.svelte, and GlobalSpotlight were duplicating syntax highlighting and the 150ms search debounce. Pull these into a new `packages/shared-ui/src/search-core/` module so the two input surfaces stay in sync on feel and matching rules. - search-core/highlight.ts — HighlightPattern type, locale-aware getHighlightPatterns(), and the shared highlightText() (HTML-escape + span wrap). Patterns were previously in quick-input/highlightPatterns.ts + inline in CommandBar.svelte. - search-core/config.ts — SEARCH_DEBOUNCE_MS = 150. Used from InputBar, CommandBar, GlobalSpotlight, and apps/mana web SearchEngine. - quick-input/highlightPatterns.ts + types.ts become thin back-compat re-exports. - Public surface: @mana/shared-ui now exports getHighlightPatterns, highlightText, SEARCH_DEBOUNCE_MS, and the HighlightPattern type. No UX change. UIs still live in their own files (per earlier split recommendation: shared backend, separate surfaces). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ad1659f036
commit
24eb8b3b7f
10 changed files with 161 additions and 204 deletions
|
|
@ -2,47 +2,9 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import type { CommandBarItem, QuickAction, CreatePreview } from './CommandBar.types';
|
||||
import { Heart, MagnifyingGlass, Plus } from '@mana/shared-icons';
|
||||
import { getHighlightPatterns, highlightText, SEARCH_DEBOUNCE_MS } from '../search-core';
|
||||
|
||||
// Syntax highlighting patterns for command keywords
|
||||
interface HighlightPattern {
|
||||
pattern: RegExp;
|
||||
className: string;
|
||||
}
|
||||
|
||||
const HIGHLIGHT_PATTERNS: HighlightPattern[] = [
|
||||
// Priority keywords (Todo) - with specific colors per level
|
||||
{ pattern: /(!{3,}|!?dringend)\b/gi, className: 'hl-priority-urgent' },
|
||||
{ pattern: /(!{2}|!?wichtig)\b/gi, className: 'hl-priority-high' },
|
||||
{ pattern: /!?normal\b/gi, className: 'hl-priority-medium' },
|
||||
{ pattern: /!?sp[aä]ter\b/gi, className: 'hl-priority-low' },
|
||||
// Tags
|
||||
{ pattern: /#\w+/g, className: 'hl-tag' },
|
||||
// Projects/Calendars/Companies (@reference)
|
||||
{ pattern: /@\w+/g, className: 'hl-reference' },
|
||||
// Date keywords
|
||||
{
|
||||
pattern:
|
||||
/\b(heute|morgen|übermorgen|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag|nächsten?\s+\w+|in\s+\d+\s+tagen?)\b/gi,
|
||||
className: 'hl-date',
|
||||
},
|
||||
// Time patterns
|
||||
{ pattern: /\b(\d{1,2}:\d{2}|um\s+\d{1,2}(\s*uhr)?|\d{1,2}\s*uhr)\b/gi, className: 'hl-time' },
|
||||
];
|
||||
|
||||
function highlightText(text: string): string {
|
||||
if (!text) return '';
|
||||
|
||||
let result = text;
|
||||
// Escape HTML first
|
||||
result = result.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
|
||||
// Apply highlights (process in order, avoiding double-highlighting)
|
||||
for (const { pattern, className } of HIGHLIGHT_PATTERNS) {
|
||||
result = result.replace(pattern, (match) => `<span class="${className}">${match}</span>`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
const HIGHLIGHT_PATTERNS = getHighlightPatterns('de');
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
|
@ -89,7 +51,7 @@
|
|||
);
|
||||
|
||||
// Highlighted text for overlay
|
||||
let highlightedQuery = $derived(highlightText(searchQuery));
|
||||
let highlightedQuery = $derived(highlightText(searchQuery, HIGHLIGHT_PATTERNS));
|
||||
|
||||
// Check if create option is selected (it's always first when available)
|
||||
let isCreateSelected = $derived(selectedIndex === 0 && createPreview !== null);
|
||||
|
|
@ -126,7 +88,7 @@
|
|||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}, 150);
|
||||
}, SEARCH_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
async function handleCreate() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue