Gemini: full emoji picker (desktop + mobile bottom sheet), global search with SQLite FTS5 and Cmd+K palette (access-checked), demo mode resets the database on every start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
928 lines
43 KiB
TypeScript
928 lines
43 KiB
TypeScript
import React, { useMemo, useState } from 'react';
|
||
import {
|
||
Search,
|
||
Layers,
|
||
FileText,
|
||
CheckSquare,
|
||
Keyboard,
|
||
Pin,
|
||
FolderTree,
|
||
Sparkles,
|
||
Command,
|
||
Users,
|
||
Mic,
|
||
ShoppingCart,
|
||
Columns,
|
||
Tag,
|
||
Link as LinkIcon,
|
||
Bell,
|
||
Lock,
|
||
ArrowLeft,
|
||
X,
|
||
Smartphone,
|
||
RotateCcw,
|
||
Heading1,
|
||
ListTodo,
|
||
Code,
|
||
Download,
|
||
Flame,
|
||
Check,
|
||
} from 'lucide-react';
|
||
import { AboutModal } from '../../components/AboutModal';
|
||
|
||
interface HelpViewProps {
|
||
onBack?: () => void;
|
||
}
|
||
|
||
type HelpCategory =
|
||
| 'all'
|
||
| 'workspace'
|
||
| 'triage'
|
||
| 'tasks'
|
||
| 'lists'
|
||
| 'collaboration'
|
||
| 'shortcuts';
|
||
|
||
interface DocCard {
|
||
id: string;
|
||
category: HelpCategory;
|
||
title: string;
|
||
subtitle?: string;
|
||
icon: React.ComponentType<{ className?: string }>;
|
||
keywords: string[];
|
||
content: React.ReactNode;
|
||
}
|
||
|
||
export const HelpView: React.FC<HelpViewProps> = ({ onBack }) => {
|
||
const [activeCategory, setActiveCategory] = useState<HelpCategory>('all');
|
||
const [searchQuery, setSearchQuery] = useState('');
|
||
const [showAbout, setShowAbout] = useState(false);
|
||
|
||
// Documentation sections & cards data
|
||
const cards: DocCard[] = useMemo(
|
||
() => [
|
||
// WORKSPACE & OUTLINER
|
||
{
|
||
id: 'workspace-architecture',
|
||
category: 'workspace',
|
||
title: 'Hierarchischer Outliner & Offline-Sync',
|
||
subtitle: 'Atomare Speicherung mit kollaborativem Echtzeit-Abgleich',
|
||
icon: FileText,
|
||
keywords: [
|
||
'workspace',
|
||
'outliner',
|
||
'datenbank',
|
||
'sqlite',
|
||
'offline',
|
||
'indexeddb',
|
||
'export',
|
||
'markdown',
|
||
'speichern',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
In MindSift ist jede Notiz ein strukturierter, hierarchischer Outliner.
|
||
Deine Notizen werden sicher und versioniert in der <strong className="text-main">SQLite-Datenbank</strong> abgelegt
|
||
und im Browser per <strong className="text-main">IndexedDB</strong> zwischengespeichert.
|
||
</p>
|
||
<ul className="space-y-1 list-disc list-inside">
|
||
<li>
|
||
<strong className="text-main">Volle Offline-Fähigkeit:</strong> Du kannst auch ohne Internetverbindung nahtlos weiterarbeiten;
|
||
Änderungen synchronisieren sich automatisch, sobald du wieder online bist.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Markdown-Export:</strong> Über das Download-Symbol (<Download className="w-3 h-3 inline text-accent" />) im Kopf der Notiz kannst du den aktuellen Stand jederzeit als Standard-Markdown-Datei (<code className="font-mono text-accent">.md</code>) auf deinen Rechner exportieren.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-keyboard',
|
||
category: 'workspace',
|
||
title: 'Tastaturbedienung im Notizen-Editor',
|
||
subtitle: 'Flüssiges Schreiben und Gliedern ohne die Maus zu berühren',
|
||
icon: Keyboard,
|
||
keywords: [
|
||
'tastatur',
|
||
'shortcuts',
|
||
'enter',
|
||
'tab',
|
||
'shift',
|
||
'backspace',
|
||
'outliner',
|
||
'einrücken',
|
||
'ausrücken',
|
||
'undo',
|
||
'redo',
|
||
'pfeiltasten',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Enter</kbd> : Erzeugt sofort einen neuen Bullet-Point auf derselben Ebene. Ist der Punkt leer und eingerückt, rückt er eine Ebene nach links aus.
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Tab</kbd> : Rückt den aktuellen Bullet-Point nach rechts ein und ordnet ihn dem vorherigen Punkt unter.
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Shift + Tab</kbd> : Rückt den Bullet-Point nach links aus (verringert die Einrückungstiefe).
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Shift + Enter</kbd> : Erzeugt einen weichen Zeilenumbruch innerhalb desselben Textblocks.
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Backspace</kbd> : Auf einem leeren Block löscht die Taste diesen sofort. Am Textanfang wird der Block mit dem vorherigen zusammengeführt.
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">↑ / ↓</kbd> : Springt flüssig zum vorherigen bzw. nächsten Block, wenn sich der Cursor ganz am Anfang oder Ende des Textes befindet.
|
||
</li>
|
||
<li>
|
||
<kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Strg + Z</kbd> / <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Cmd + Z</kbd> : Mehrstufiges Notiz-Undo. Wiederholen mit <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Strg + Y</kbd> bzw. <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Strg + Shift + Z</kbd>.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-slash-and-autoformat',
|
||
category: 'workspace',
|
||
title: 'Slash-Befehle (/) & Auto-Formatierung',
|
||
subtitle: 'Block-Typen wechseln und Markdown direkt beim Tippen formatieren',
|
||
icon: Command,
|
||
keywords: [
|
||
'slash',
|
||
'befehle',
|
||
'commands',
|
||
'todo',
|
||
'link',
|
||
'h1',
|
||
'h2',
|
||
'h3',
|
||
'code',
|
||
'callout',
|
||
'divider',
|
||
'auto-formatting',
|
||
],
|
||
content: (
|
||
<div className="space-y-3 text-muted leading-relaxed">
|
||
<div>
|
||
<p className="mb-1.5">
|
||
Tippe <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">/</code> in einen Block, um das Menü für Blocktypen zu öffnen:
|
||
</p>
|
||
<div className="grid grid-cols-2 gap-1.5 font-mono text-[11px]">
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<ListTodo className="w-3.5 h-3.5 text-accent" />
|
||
<span>/todo (Checkbox-Aufgabe)</span>
|
||
</div>
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<LinkIcon className="w-3.5 h-3.5 text-accent" />
|
||
<span>/link (Notiz verknüpfen)</span>
|
||
</div>
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<Heading1 className="w-3.5 h-3.5 text-accent" />
|
||
<span>/h1, /h2, /h3 (Überschriften)</span>
|
||
</div>
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<Code className="w-3.5 h-3.5 text-accent" />
|
||
<span>/code (Code-Block)</span>
|
||
</div>
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<span className="text-accent font-bold">💬</span>
|
||
<span>/callout (Hinweis-Box)</span>
|
||
</div>
|
||
<div className="p-1.5 bg-panel rounded border border-border flex items-center gap-1.5 text-main">
|
||
<span className="text-accent font-bold">—</span>
|
||
<span>/divider (Trennlinie)</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="pt-2 border-t border-border">
|
||
<span className="font-semibold text-main block mb-1">Blitz-Formatierung beim Schreiben:</span>
|
||
<ul className="space-y-1 text-xs">
|
||
<li><code className="text-accent font-mono">[] </code> oder <code className="text-accent font-mono">[ ] </code> am Zeilenanfang wandelt die Zeile sofort in eine Todo-Checkbox um.</li>
|
||
<li><code className="text-accent font-mono">[x] </code> wandelt sie in eine erledigte Todo-Checkbox um.</li>
|
||
<li><code className="text-accent font-mono"># </code>, <code className="text-accent font-mono">## </code> oder <code className="text-accent font-mono">### </code> am Zeilenanfang formatiert den Block sofort als Überschrift.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-wikilinks-tags',
|
||
category: 'workspace',
|
||
title: 'WikiLinks ([[...]]), Hashtags (#) & Tag-Seiten',
|
||
subtitle: 'Wissen bidirektional vernetzen und thematisch filtern',
|
||
icon: Tag,
|
||
keywords: [
|
||
'wikilinks',
|
||
'links',
|
||
'vernetzung',
|
||
'hashtags',
|
||
'tags',
|
||
'filter',
|
||
'schlagwörter',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Notizen und Gedanken können in MindSift auf vielfältige Weise miteinander verknüpft werden:
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">WikiLinks:</strong> Schreibe <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">[[Name der Notiz]]</code>, um eine direkte Verknüpfung zu einer anderen Notiz herzustellen. Ein Klick darauf öffnet die Zielnotiz unmittelbar.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Hashtags:</strong> Tippe <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">#Projekt</code> oder <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">#Wichtig</code> an beliebiger Stelle in den Text. Hashtags werden farbig hervorgehoben und indiziert.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Ansicht „Tags & Filter“:</strong> Im oberen Workspace-Reiter findest du die Tag-Übersicht. Hier siehst du alle verwendeten Hashtags, kannst Fundstellen aus allen Dokumenten gebündelt durchsuchen und sogar eigene freie Notizen auf Tag-Seiten hinterlegen.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-zoom-drag',
|
||
category: 'workspace',
|
||
title: 'Zoom-Hoisting, Drag & Drop und Favoriten',
|
||
subtitle: 'Fokus behalten und Notizen flexibel sortieren',
|
||
icon: Pin,
|
||
keywords: [
|
||
'hoisting',
|
||
'zoom',
|
||
'drag',
|
||
'drop',
|
||
'ordner',
|
||
'verschieben',
|
||
'anpinnen',
|
||
'breadcrumbs',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Zoom-Hoisting:</strong> Klicke direkt auf den Bullet-Punkt (<code className="text-accent">•</code>) eines Blocks, um exklusiv in diesen Ast hineinzuzoomen. Die Breadcrumb-Navigation am oberen Rand führt dich jederzeit stufenweise zurück.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Blöcke verschieben:</strong> Packe einen Bullet-Punkt mit gedrückter Maustaste, um ihn samt aller untergeordneten Punkte an eine neue Stelle zu ziehen.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Ordner-Navigation:</strong> Notizen im linken Datei-Explorer lassen sich per Drag & Drop bequem in Unterordner einsortieren.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Angepinnte Favoriten:</strong> Mit dem Stecknadel-Symbol heftest du wichtige Notizen dauerhaft ganz oben im Explorer an.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-collab-locks',
|
||
category: 'workspace',
|
||
title: 'Echtzeit-Zusammenarbeit, Sperren & Konflikte',
|
||
subtitle: 'Gemeinsames Arbeiten ohne versehentliches Überschreiben',
|
||
icon: Lock,
|
||
keywords: [
|
||
'kollaboration',
|
||
'sperren',
|
||
'schloss',
|
||
'konflikte',
|
||
'live',
|
||
'presence',
|
||
'sharing',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
MindSift unterstützt kooperatives Arbeiten an Dokumenten mit integriertem Schutz vor Datenverlust:
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Block-Sperren:</strong> Bearbeitet jemand einen Bullet-Point, wird dieser mit einem Schloss-Symbol und dem Benutzernamen gekennzeichnet. Andere Nutzer können diesen Punkt temporär nicht überschreiben.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Konfliktkopien:</strong> Sollten Änderungen zeitgleich oder offline entstehen, überschreibt der Server niemals still deine Eingaben. Stattdessen erscheint ein gelb hervorgehobener Konfliktblock mit zwei Schaltflächen: <em>„Übernehmen“</em> oder <em>„Verwerfen“</em>.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Verbindungsanzeige:</strong> Neben dem Notiztitel siehst du immer den Verbindungsmodus (z.B. <em>Live</em>, <em>Long-Polling</em> oder <em>Offline</em>).
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-global-todos',
|
||
category: 'workspace',
|
||
title: 'Globale To-Dos Rollup & Aufgaben-Verknüpfung',
|
||
subtitle: 'Alle offenen Aufgaben aus sämtlichen Notizen an einem Ort',
|
||
icon: CheckSquare,
|
||
keywords: [
|
||
'rollup',
|
||
'todos',
|
||
'checkboxen',
|
||
'enhanced task',
|
||
'global',
|
||
'aufgaben',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Im Workspace-Tab <strong className="text-main">„Globale To-Dos“</strong> werden automatisch sämtliche unerledigten Checkboxen (<code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">- [ ]</code>) aus allen deinen Notizen gesammelt.
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Zweiseitige Synchronisation:</strong> Hakst du eine Aufgabe in der globalen To-Do-Liste ab, wird der Block in der Quell-Notiz in Echtzeit aktualisiert.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Verknüpfte Aufgaben (Enhanced Tasks):</strong> Ausgewählte Notiz-Aufgaben können zusätzlich als vollwertige Aufgaben im Aufgaben- und Kanban-Bereich geführt werden.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'workspace-search-cmdk',
|
||
category: 'workspace',
|
||
title: 'Globale Suche & Command Palette (Cmd+K)',
|
||
subtitle: 'FTS5-Volltextsuche in Notizen, Blöcken, Aufgaben und Listen',
|
||
icon: Command,
|
||
keywords: [
|
||
'suche',
|
||
'search',
|
||
'command',
|
||
'palette',
|
||
'cmdk',
|
||
'find',
|
||
'fts',
|
||
'volltext',
|
||
'tastatur',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Drücke <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Cmd + K</kbd> / <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Strg + K</kbd> oder <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">/</kbd> (wenn kein Textfeld aktiv ist), um die globale Suche zu öffnen:
|
||
</p>
|
||
<ul className="space-y-1.5 list-disc list-inside">
|
||
<li>
|
||
<strong className="text-main">Volltextsuche (FTS5):</strong> Durchsucht Notiz-Titel und Blöcke, Aufgaben und Listeneinträge blitzschnell mit Relevanz-Ranking (BM25) und Präfixsuche.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Sicherheit:</strong> Zeigt nur Inhalte, auf die du tatsächlich Zugriff hast (eigene sowie freigegebene Notizen, Aufgabenlisten und Listen).
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Tastaturnavigation:</strong> Mit <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">↑</kbd> und <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">↓</kbd> blättern, mit <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">Enter</kbd> Treffer direkt öffnen (Notizen direkt am gefundenen Block).
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
|
||
// TRIAGE & QUICK DUMP
|
||
{
|
||
id: 'triage-capture',
|
||
category: 'triage',
|
||
title: 'Blitz-Erfassung (Instant Capture Bar)',
|
||
subtitle: 'Gedanken in unter 1 Sekunde festhalten – per Tastatur oder Sprache',
|
||
icon: Layers,
|
||
keywords: [
|
||
'capture',
|
||
'schnellerfassung',
|
||
'diktat',
|
||
'sprache',
|
||
'mikrofon',
|
||
'inbox',
|
||
'posteingang',
|
||
'c',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Die Schnellerfassungsleiste am oberen Bildschirmrand sorgt dafür, dass kein flüchtiger Gedanke verloren geht:
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Sofortiger Fokus:</strong> Drücke irgendwo in der App <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">C</kbd> oder <kbd className="px-1.5 py-0.5 bg-panel border border-border rounded font-mono text-[11px] text-accent">/</kbd> (sofern du nicht bereits in einem Textfeld tippst).
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Sprach-Diktat:</strong> Klicke auf das Mikrofon-Symbol (<Mic className="w-3.5 h-3.5 inline text-accent" />) für kontinuierliche Spracheingabe über die Web Speech API. Gesprochene Gedanken werden automatisch mit dem Tag <code className="text-accent font-mono">#diktat</code> versehen.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Ziel-Auswahl:</strong> Gedanken landen standardmäßig im Posteingang. Über die Optionen kannst du sie jedoch sofort als <strong className="text-main">Aufgabe</strong> (mit Priorität und Fälligkeit), <strong className="text-main">Listeneintrag</strong> (z.B. auf die Einkaufsliste) oder <strong className="text-main">neue Notiz</strong> routen.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'triage-deck-decisions',
|
||
category: 'triage',
|
||
title: 'Triage-Deck: Entscheiden mit 1 Taste oder Wischgeste',
|
||
subtitle: 'Posteingang in Rekordzeit abarbeiten und den Kopf frei halten',
|
||
icon: Sparkles,
|
||
keywords: [
|
||
'triage',
|
||
'deck',
|
||
'h',
|
||
'l',
|
||
't',
|
||
'd',
|
||
'leertaste',
|
||
'swipe',
|
||
'wischen',
|
||
'papierkorb',
|
||
'gesten',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Im Triage-Deck wird jeder gesammelte Gedanke Karte für Karte vorgelegt. Du entscheidest blitzschnell:
|
||
</p>
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 text-xs pt-1">
|
||
<div className="p-2.5 bg-panel border border-border rounded">
|
||
<span className="font-semibold text-main block mb-1">Tastatur (Desktop):</span>
|
||
<ul className="space-y-1 font-mono text-[11px]">
|
||
<li><strong className="text-status-err">H</strong> oder <strong>←</strong> : Wegwerfen (Papierkorb)</li>
|
||
<li><strong className="text-accent">L</strong> oder <strong>→</strong> : Als Aufgabe anlegen</li>
|
||
<li><strong className="text-main">T</strong> : Mit Fälligkeit / Termin</li>
|
||
<li><strong className="text-main">D</strong> : In Workspace-Notiz wandeln</li>
|
||
<li><strong className="text-muted">Leertaste</strong> : Später (ans Stapelende)</li>
|
||
</ul>
|
||
</div>
|
||
<div className="p-2.5 bg-panel border border-border rounded">
|
||
<span className="font-semibold text-main block mb-1">Wischgesten (Touch & Mobile):</span>
|
||
<ul className="space-y-1 text-xs">
|
||
<li><strong className="text-status-err">Nach links wischen:</strong> Wegwerfen</li>
|
||
<li><strong className="text-accent">Nach rechts wischen:</strong> Als Aufgabe übernehmen</li>
|
||
<li><strong className="text-main">Gedrückt halten:</strong> Menü öffnen (Termin, Liste, Notiz)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'triage-webhooks',
|
||
category: 'triage',
|
||
title: 'Externe Erfassung per Webhooks & API',
|
||
subtitle: 'Gedanken von Siri, Home Assistant, n8n oder curl einspeisen',
|
||
icon: Bell,
|
||
keywords: [
|
||
'webhooks',
|
||
'api',
|
||
'token',
|
||
'home assistant',
|
||
'siri',
|
||
'shortcuts',
|
||
'automation',
|
||
'curl',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Unter <em className="text-main">Benutzereinstellungen → Webhooks & API</em> kannst du persönliche API-Schlüssel generieren.
|
||
</p>
|
||
<p>
|
||
Über den Endpunkt <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">POST /api/v1/webhooks/ingest</code> kannst du Gedanken aus iOS-Kurzbefehlen, Smart-Home-Systemen oder Drittanwendungen einspeisen. Sie werden automatisch mit dem Tag <code className="text-accent font-mono">#webhook</code> markiert.
|
||
</p>
|
||
</div>
|
||
),
|
||
},
|
||
|
||
// TASKS & KANBAN
|
||
{
|
||
id: 'tasks-kanban',
|
||
category: 'tasks',
|
||
title: 'Listenansicht & Flexibles Kanban-Board',
|
||
subtitle: 'Aufgaben visualisieren und mit anpassbaren Spalten steuern',
|
||
icon: Columns,
|
||
keywords: [
|
||
'aufgaben',
|
||
'tasks',
|
||
'kanban',
|
||
'board',
|
||
'spalten',
|
||
'drag',
|
||
'drop',
|
||
'listen',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Aufgaben können flexibel in einer klassischen <strong className="text-main">Listenansicht</strong> oder im interaktiven <strong className="text-main">Kanban-Board</strong> verwaltet werden:
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Ansicht umschalten:</strong> Nutze den Umschalter oben rechts zwischen Liste und Kanban.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Eigene Kanban-Spalten:</strong> Über die Spaltenverwaltung kannst du für jede Aufgabenliste individuelle Phasen definieren (z.B. <em>Backlog</em>, <em>In Bearbeitung</em>, <em>Review</em>, <em>Erledigt</em>) inklusive Farben und Erledigt-Status.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Drag & Drop:</strong> Ziehe Aufgabenkarten mühelos zwischen den Spalten umher. Das Verschieben in eine Erledigt-Spalte hakt die Aufgabe automatisch ab.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
id: 'tasks-details-alarms',
|
||
category: 'tasks',
|
||
title: 'Teilaufgaben, Fälligkeiten & Automatische Alarme',
|
||
subtitle: 'Checklisten mit Fortschrittsbalken, Markdown-Notizen und Benachrichtigungen',
|
||
icon: CheckSquare,
|
||
keywords: [
|
||
'subtasks',
|
||
'unteraufgaben',
|
||
'alarme',
|
||
'benachrichtigungen',
|
||
'mail',
|
||
'discord',
|
||
'termin',
|
||
'fälligkeit',
|
||
'priorität',
|
||
'zuweisen',
|
||
'zugewiesen',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Teilaufgaben (Subtasks):</strong> Erstelle innerhalb jeder Aufgabe eine Checkliste mit sichtbarem Fortschrittsbalken (z.B. „3 von 5 erledigt“).
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Prioritäten & Notizen:</strong> Vergib Prioritäten (<em className="text-accent">Dringend</em>, <em className="text-main">Wichtig</em>, <em>Normal</em>) und hinterlege detaillierte Markdown-Notizen.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Zuweisen:</strong> In geteilten Aufgabenlisten weist du eine Aufgabe einer oder mehreren Personen mit Zugriff zu (Namen tippen, Enter). Die Zugewiesenen erscheinen als kleine Profilbilder an der Aufgabe; wer den Zugriff auf die Liste verliert, wird automatisch entfernt.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Automatische Alarme:</strong> Ist ein Fälligkeitsdatum erreicht, kann MindSift dich automatisch per <strong className="text-main">E-Mail</strong>, <strong className="text-main">Discord-Webhook</strong> oder individuellem HTTP-Webhook benachrichtigen. Konfigurierbar in deinen Benutzereinstellungen.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
|
||
// LISTS & SHOPPING
|
||
{
|
||
id: 'lists-shared-shopping',
|
||
category: 'lists',
|
||
title: 'Geteilte Listen, Mengenangaben & Hashtag-Kategorien',
|
||
subtitle: 'Echtzeit-Einkaufslisten, Packlisten und Checklisten',
|
||
icon: ShoppingCart,
|
||
keywords: [
|
||
'listen',
|
||
'einkauf',
|
||
'shopping',
|
||
'checkliste',
|
||
'mengen',
|
||
'kategorien',
|
||
'hashtag',
|
||
'realtime',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<p>
|
||
Geteilte Listen eignen sich perfekt für Einkäufe, Packlisten und gemeinsame Besorgungen:
|
||
</p>
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Automatische Mengenerkennung:</strong> Eingaben wie <code className="text-accent font-mono">2x Bio-Milch</code> oder <code className="text-accent font-mono">500g Pasta</code> trennen Menge und Bezeichnung automatisch.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Kategorisierung per Hashtag:</strong> Ergänze einen Hashtag wie <code className="text-accent font-mono">#Kühlregal</code> oder <code className="text-accent font-mono">#Gemüse</code>. Die Liste gruppiert die Artikel automatisch in entsprechende Abschnitte.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Live-Abgleich & Erledigte aufräumen:</strong> Abgehakte Artikel werden in Echtzeit synchronisiert und zeigen an, wer sie erledigt hat. Mit dem Aufräumen-Button entfernst du erledigte Artikel gesammelt.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
|
||
// APPEARANCE: CUSTOM THEMES
|
||
{
|
||
id: 'workspace-custom-themes',
|
||
category: 'workspace',
|
||
title: 'Darstellung & eigene Themes',
|
||
subtitle: 'Fertige Designs wählen oder ein eigenes CSS-Theme hochladen',
|
||
icon: Sparkles,
|
||
keywords: ['theme', 'design', 'farben', 'css', 'dunkel', 'hell', 'darstellung'],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Theme wechseln:</strong> Im Profilmenü oben rechts oder unter <em>Kontoeinstellungen → Darstellung & Themes</em>.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Eigenes Theme:</strong> Vorlage herunterladen oder einfügen, Farben und Rundungen anpassen, als <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">.css</code>-Datei hochladen oder einfügen und „Speichern & aktivieren“. Das Theme greift sofort und steht dir auf allen Geräten zur Verfügung.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
|
||
// COLLABORATION: ORGANIZATIONS, GROUPS & SHARING
|
||
{
|
||
id: 'collab-teams-sharing',
|
||
category: 'collaboration',
|
||
title: 'Organisationen, Gruppen & Freigaben',
|
||
subtitle: 'Wer wen sieht, und Notizen, Ordner und Listen sicher teilen',
|
||
icon: Users,
|
||
keywords: [
|
||
'teams',
|
||
'gruppen',
|
||
'organisation',
|
||
'sichtbarkeit',
|
||
'privat',
|
||
'freigabe',
|
||
'sharing',
|
||
'berechtigungen',
|
||
'bearbeiter',
|
||
'leser',
|
||
'ordner',
|
||
],
|
||
content: (
|
||
<div className="space-y-2 text-muted leading-relaxed">
|
||
<ul className="space-y-1.5">
|
||
<li>
|
||
<strong className="text-main">Wer wen sieht:</strong> Das legt der Server-Admin fest. Je nach Einstellung siehst du alle Nutzer, nur die Mitglieder deiner <em>Organisation</em> oder niemanden (Modus „Privat“: kein Teilen, keine Gruppen). Organisationen verwaltet nur der Server-Admin; jeder gehört höchstens einer an.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Gruppen:</strong> Fasse Personen, die du sehen kannst, zu Gruppen zusammen (z. B. Familie, WG, Projekt) und teile mit allen auf einmal. Wer eine Gruppe anlegt, ist ihr Admin; mit einer Gruppe teilen kann nur, wer selbst Mitglied ist.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Nur der Eigentümer teilt:</strong> Bearbeiter können Inhalte ändern, aber nicht weiterteilen. Eine Freigabe an dich kannst du jederzeit selbst verlassen. Wechselt jemand die Organisation oder verlässt eine Gruppe, fallen seine Freigaben dort automatisch weg.
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Rollen (Bearbeiter vs. Leser):</strong> Beim Teilen von Notizen, Ordnern oder Listen wählst du zwischen <em>Bearbeiter</em> (Vollzugriff auf Inhalte und Checklisten) und <em>Nur Lesen</em> (reine Ansicht mit Live-Updates).
|
||
</li>
|
||
<li>
|
||
<strong className="text-main">Dezentrale Ordnerablage:</strong> Jeder Empfänger kann geteilte Dokumente und Ordner in seine eigene Verzeichnisstruktur einhängen, ohne die Organisation des Eigentümers zu verändern.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
),
|
||
},
|
||
],
|
||
[]
|
||
);
|
||
|
||
// Filtered cards based on active category & search query
|
||
const filteredCards = useMemo(() => {
|
||
let result = cards;
|
||
if (activeCategory !== 'all' && activeCategory !== 'shortcuts') {
|
||
result = result.filter((card) => card.category === activeCategory);
|
||
}
|
||
|
||
if (searchQuery.trim()) {
|
||
const q = searchQuery.toLowerCase().trim();
|
||
result = result.filter((card) => {
|
||
const titleMatch = card.title.toLowerCase().includes(q);
|
||
const subMatch = card.subtitle?.toLowerCase().includes(q) || false;
|
||
const kwMatch = card.keywords.some((kw) => kw.toLowerCase().includes(q));
|
||
return titleMatch || subMatch || kwMatch;
|
||
});
|
||
}
|
||
|
||
return result;
|
||
}, [cards, activeCategory, searchQuery]);
|
||
|
||
// Keyboard shortcuts table data
|
||
const shortcuts = useMemo(
|
||
() => [
|
||
{ key: 'Cmd + K / Strg + K oder /', scope: 'Global', desc: 'Globale Volltextsuche (Command Palette) öffnen' },
|
||
{ key: 'C', scope: 'Global', desc: 'Fokus sofort in die Schnellerfassungsleiste setzen' },
|
||
{ key: 'Enter', scope: 'Schnellerfassung', desc: 'Gedanken blitzschnell speichern' },
|
||
{ key: 'Esc', scope: 'Schnellerfassung', desc: 'Eingabe leeren & Optionen schließen' },
|
||
{ key: 'Enter', scope: 'Workspace Outliner', desc: 'Neuen Bullet-Point anlegen (oder leeren Block ausrücken)' },
|
||
{ key: 'Tab', scope: 'Workspace Outliner', desc: 'Bullet-Point einrücken (unterordnen)' },
|
||
{ key: 'Shift + Tab', scope: 'Workspace Outliner', desc: 'Bullet-Point nach links ausrücken' },
|
||
{ key: 'Shift + Enter', scope: 'Workspace Outliner', desc: 'Weicher Zeilenumbruch innerhalb des Blocks' },
|
||
{ key: 'Backspace', scope: 'Workspace Outliner', desc: 'Auf leerem Block: Block löschen; Am Anfang: Zusammenführen' },
|
||
{ key: '↑ / ↓', scope: 'Workspace Outliner', desc: 'Zum vorherigen / nächsten Block navigieren' },
|
||
{ key: 'Strg + Z / Cmd + Z', scope: 'Workspace Outliner', desc: 'Letzte Notiz-Aktion rückgängig machen' },
|
||
{ key: 'Strg + Y / Strg + Shift + Z', scope: 'Workspace Outliner', desc: 'Rückgängig gemachte Aktion wiederholen' },
|
||
{ key: '/', scope: 'Workspace Outliner', desc: 'Slash-Menü öffnen (/todo, /link, /h1, /code, ...)' },
|
||
{ key: '[] oder [ ] am Anfang', scope: 'Workspace Outliner', desc: 'Sofort in Todo-Checkbox umwandeln' },
|
||
{ key: '[x] am Anfang', scope: 'Workspace Outliner', desc: 'Sofort in erledigte Todo-Checkbox umwandeln' },
|
||
{ key: '#, ##, ### am Anfang', scope: 'Workspace Outliner', desc: 'Sofort in H1, H2 oder H3 Überschrift wandeln' },
|
||
{ key: '[[Notiztitel]]', scope: 'Workspace Outliner', desc: 'Interaktiven WikiLink zu Notiz einbetten' },
|
||
{ key: '#Tagname', scope: 'Workspace / Listen', desc: 'Inline-Hashtag für globale Vernetzung oder Kategorisierung' },
|
||
{ key: 'H oder ←', scope: 'Triage-Deck', desc: 'Gedanken verwerfen (in den Papierkorb)' },
|
||
{ key: 'L oder →', scope: 'Triage-Deck', desc: 'Gedanken sofort zur Aufgabe machen' },
|
||
{ key: 'T', scope: 'Triage-Deck', desc: 'Aufgabe mit Fälligkeitsdatum / Termin anlegen' },
|
||
{ key: 'D', scope: 'Triage-Deck', desc: 'Gedanken in Notizdokument umwandeln' },
|
||
{ key: 'Leertaste', scope: 'Triage-Deck', desc: 'Karte überspringen („Später" – ans Ende des Stapels)' },
|
||
{ key: 'Swipe links', scope: 'Triage (Touch/Mobile)', desc: 'Gedanken verwerfen' },
|
||
{ key: 'Swipe rechts', scope: 'Triage (Touch/Mobile)', desc: 'Gedanken als Aufgabe übernehmen' },
|
||
{ key: 'Gedrückt halten', scope: 'Triage (Touch/Mobile)', desc: 'Aktionsmenü öffnen (Termin, Liste, Notiz)' },
|
||
],
|
||
[]
|
||
);
|
||
|
||
const filteredShortcuts = useMemo(() => {
|
||
if (!searchQuery.trim()) return shortcuts;
|
||
const q = searchQuery.toLowerCase().trim();
|
||
return shortcuts.filter(
|
||
(s) =>
|
||
s.key.toLowerCase().includes(q) ||
|
||
s.scope.toLowerCase().includes(q) ||
|
||
s.desc.toLowerCase().includes(q)
|
||
);
|
||
}, [shortcuts, searchQuery]);
|
||
|
||
return (
|
||
<div className="w-full space-y-4 pb-12">
|
||
{/* Header Bar */}
|
||
<div className="panel-surface p-4 flex flex-wrap items-center justify-between gap-3">
|
||
<div className="flex items-center gap-3">
|
||
{onBack && (
|
||
<button
|
||
type="button"
|
||
onClick={onBack}
|
||
className="btn-icon"
|
||
title="Zurück"
|
||
>
|
||
<ArrowLeft className="w-4 h-4" />
|
||
</button>
|
||
)}
|
||
<div>
|
||
<h1 className="text-base sm:text-lg font-bold text-main flex items-center gap-2">
|
||
<FileText className="w-4 h-4 text-accent" />
|
||
<span>Hilfe & Dokumentation</span>
|
||
</h1>
|
||
<p className="text-xs text-muted">
|
||
Tastaturbedienung, Outliner-Notizen, Triage, Kanban-Board und Zusammenarbeit
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Search Input */}
|
||
<div className="relative w-full sm:w-72">
|
||
<Search className="w-3.5 h-3.5 text-muted absolute left-2.5 top-1/2 -translate-y-1/2" />
|
||
<input
|
||
type="text"
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
placeholder="In Hilfe & Kürzeln suchen…"
|
||
className="w-full h-8 pl-8 pr-8 input-field text-xs bg-canvas"
|
||
/>
|
||
{searchQuery && (
|
||
<button
|
||
type="button"
|
||
onClick={() => setSearchQuery('')}
|
||
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted hover:text-main"
|
||
title="Suche leeren"
|
||
>
|
||
<X className="w-3.5 h-3.5" />
|
||
</button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Category Filter Pills */}
|
||
<div className="flex flex-wrap items-center gap-1.5">
|
||
{[
|
||
{ id: 'all', label: 'Alle Themen', icon: Sparkles },
|
||
{ id: 'workspace', label: 'Workspace & Notizen', icon: FileText },
|
||
{ id: 'triage', label: 'Schnellerfassung & Triage', icon: Layers },
|
||
{ id: 'tasks', label: 'Aufgaben & Kanban', icon: CheckSquare },
|
||
{ id: 'lists', label: 'Geteilte Listen', icon: ShoppingCart },
|
||
{ id: 'collaboration', label: 'Gruppen & Freigaben', icon: Users },
|
||
{ id: 'shortcuts', label: 'Tastatur-Kürzel & Gesten', icon: Keyboard },
|
||
].map((cat) => {
|
||
const Icon = cat.icon;
|
||
const isActive = activeCategory === cat.id;
|
||
return (
|
||
<button
|
||
key={cat.id}
|
||
type="button"
|
||
onClick={() => setActiveCategory(cat.id as HelpCategory)}
|
||
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors cursor-pointer ${
|
||
isActive
|
||
? 'bg-panel-elevated border-accent text-main font-semibold'
|
||
: 'bg-panel border-border text-muted hover:text-main'
|
||
}`}
|
||
>
|
||
<Icon className="w-3.5 h-3.5 text-accent" />
|
||
<span>{cat.label}</span>
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* Active Search Status Banner */}
|
||
{searchQuery && (
|
||
<div className="flex items-center justify-between text-xs text-muted px-1">
|
||
<span>
|
||
Suchergebnisse für <strong className="text-main">„{searchQuery}“</strong>: {filteredCards.length} Hilfekarten
|
||
{activeCategory === 'all' || activeCategory === 'shortcuts' ? `, ${filteredShortcuts.length} Tastenkürzel` : ''}
|
||
</span>
|
||
<button
|
||
type="button"
|
||
onClick={() => setSearchQuery('')}
|
||
className="text-accent hover:underline cursor-pointer"
|
||
>
|
||
Filter zurücksetzen
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{/* Grid of Documentation Cards */}
|
||
{activeCategory !== 'shortcuts' && (
|
||
<div className="space-y-4">
|
||
{filteredCards.length > 0 ? (
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{filteredCards.map((card) => {
|
||
const Icon = card.icon;
|
||
return (
|
||
<div
|
||
key={card.id}
|
||
className="panel-surface p-4 rounded-card border border-border flex flex-col justify-between space-y-3"
|
||
>
|
||
<div>
|
||
<div className="flex items-start gap-2.5 mb-2">
|
||
<div className="p-1.5 bg-canvas border border-border rounded-btn shrink-0 mt-0.5">
|
||
<Icon className="w-4 h-4 text-accent" />
|
||
</div>
|
||
<div>
|
||
<h3 className="font-bold text-main text-sm">{card.title}</h3>
|
||
{card.subtitle && (
|
||
<p className="text-[11px] text-muted">{card.subtitle}</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="text-xs pt-1">{card.content}</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
) : (
|
||
<div className="panel-surface p-8 text-center space-y-2 border border-border rounded-card">
|
||
<Search className="w-6 h-6 text-muted mx-auto" />
|
||
<p className="text-sm font-semibold text-main">Keine passenden Hilfethemen gefunden</p>
|
||
<p className="text-xs text-muted">
|
||
Versuche einen anderen Suchbegriff oder wechsle zur Kategorie „Alle Themen“.
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* SHORTCUTS CHEAT SHEET */}
|
||
{(activeCategory === 'all' || activeCategory === 'shortcuts') && (
|
||
<div className="panel-surface p-5 space-y-4 rounded-card border border-border">
|
||
<div className="border-b border-border pb-2.5 flex items-center justify-between">
|
||
<div>
|
||
<h2 className="text-sm font-bold text-main flex items-center gap-2">
|
||
<Keyboard className="w-4 h-4 text-accent" />
|
||
<span>Tastatur-Kürzel & Gesten Gesamtübersicht</span>
|
||
</h2>
|
||
<p className="text-xs text-muted mt-0.5">
|
||
Schneller arbeiten ohne Maus: Alle Hotkeys und Mobile-Gesten auf einen Blick.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-left text-xs border-collapse">
|
||
<thead>
|
||
<tr className="border-b border-border text-muted">
|
||
<th className="py-2 px-3 font-semibold w-1/3">Taste / Geste</th>
|
||
<th className="py-2 px-3 font-semibold w-1/4">Bereich</th>
|
||
<th className="py-2 px-3 font-semibold">Funktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-border text-main">
|
||
{filteredShortcuts.map((sc, i) => (
|
||
<tr key={i} className="hover:bg-canvas/50 transition-colors">
|
||
<td className="py-2 px-3 font-mono text-accent font-medium">{sc.key}</td>
|
||
<td className="py-2 px-3 text-muted">
|
||
<span className="px-1.5 py-0.5 bg-canvas border border-border rounded text-[11px]">
|
||
{sc.scope}
|
||
</span>
|
||
</td>
|
||
<td className="py-2 px-3 text-main">{sc.desc}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="flex justify-center pt-2">
|
||
<button type="button" onClick={() => setShowAbout(true)} className="text-[11px] text-muted hover:text-main hover:underline underline-offset-2">
|
||
Über MindSift
|
||
</button>
|
||
</div>
|
||
{showAbout && <AboutModal onClose={() => setShowAbout(false)} />}
|
||
</div>
|
||
);
|
||
};
|