Paket B: Globale Suche mit SQLite FTS5, BM25-Ranking, Zugriffsprüfung und Cmd+K-Palette

This commit is contained in:
sandrodach committed 2026-10-28 23:00:19 +01:00
1 parent 633bd6f1ef
commit 71fa53ead3
10 files changed
+1030 -55

No files matched your search

+78 -7
View File
@@ -23,6 +23,7 @@ import {
Flame,
Mic,
MicOff,
Search,
} from 'lucide-react';
import { AuthStatus, DashboardStats, PriorityLevel, SharedList, Thought, User, UserTheme } from './lib/types';
import {
@@ -55,6 +56,7 @@ import { GroupsView } from './features/teams/GroupsView';
import { useMobileActions } from './context/MobileActionContext';
import { MobileHeaderMenu } from './components/MobileHeaderMenu';
import { UserAvatar } from './components/UserAvatar';
import { CommandPalette } from './components/CommandPalette';
import { APP_VERSION } from './version';
type ActiveTab =
@@ -135,6 +137,8 @@ export const App: React.FC = () => {
const [selectedDocId, setSelectedDocId] = useState<string | null>(null);
const [selectedBlockId, setSelectedBlockId] = useState<string | null>(null);
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
const [selectedListId, setSelectedListId] = useState<string | null>(null);
const [showCommandPalette, setShowCommandPalette] = useState(false);
const [captureFocusCount, setCaptureFocusCount] = useState(0);
const [refreshRevision, setRefreshRevision] = useState(0);
@@ -593,6 +597,36 @@ export const App: React.FC = () => {
setActiveTab('tasks');
}, []);
const handleOpenList = (listId: string) => {
setSelectedListId(listId);
setActiveTab('lists');
};
// Global Command Palette shortcuts: Cmd+K / Ctrl+K, and '/' when not in input
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const el = e.target as HTMLElement;
const isEditing =
el.tagName === 'INPUT' ||
el.tagName === 'TEXTAREA' ||
el.isContentEditable;
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
e.preventDefault();
setShowCommandPalette((prev) => !prev);
return;
}
if (!isEditing && e.key === '/') {
e.preventDefault();
setShowCommandPalette(true);
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
const handleTriggerAddButton = () => {
triggerHaptic(20);
if (window.innerWidth < 640) {
@@ -709,6 +743,19 @@ export const App: React.FC = () => {
</button>
)}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setShowCommandPalette(true);
}}
className="w-11 h-11 rounded-full flex items-center justify-center text-muted hover:text-main bg-panel border border-border transition-transform active:scale-95 cursor-pointer"
title="Globale Suche"
aria-label="Globale Suche öffnen"
>
<Search className="w-4 h-4" />
</button>
<button
type="button"
onClick={() => {
@@ -749,12 +796,23 @@ export const App: React.FC = () => {
</div>
{/* Quick-Capture Input Bubble directly in Header (above Tabs) */}
<div className="flex-1 max-w-xl mx-auto">
<InstantCaptureBar
onCaptured={handleCaptured}
lists={lists}
autoFocusTrigger={captureFocusCount}
/>
<div className="flex-1 max-w-xl mx-auto flex items-center gap-2">
<div className="flex-1">
<InstantCaptureBar
onCaptured={handleCaptured}
lists={lists}
autoFocusTrigger={captureFocusCount}
/>
</div>
<button
type="button"
onClick={() => setShowCommandPalette(true)}
className="h-8 px-2.5 rounded-btn bg-panel border border-border text-muted hover:text-main flex items-center gap-1.5 text-xs transition-colors cursor-pointer shrink-0"
title="Globale Suche öffnen (Cmd+K oder /)"
>
<Search className="w-3.5 h-3.5" />
<span className="hidden lg:inline font-mono text-[10px] text-accent font-semibold">⌘K</span>
</button>
</div>
{/* User Profile Pill & Dropdown Menu */}
@@ -1020,7 +1078,11 @@ export const App: React.FC = () => {
)}
{activeTab === 'lists' && (
<SharedListsView onRefreshGlobal={refreshAll} currentUser={user} />
<SharedListsView
onRefreshGlobal={refreshAll}
currentUser={user}
initialListId={selectedListId}
/>
)}
{activeTab === 'groups' && (
@@ -1555,6 +1617,15 @@ export const App: React.FC = () => {
</div>
</div>
)}
{/* Global Command Palette (Cmd+K / Ctrl+K / '/') */}
<CommandPalette
isOpen={showCommandPalette}
onClose={() => setShowCommandPalette(false)}
onOpenDocument={handleOpenDocument}
onOpenTask={handleOpenTask}
onOpenList={handleOpenList}
/>
</div>
);
};