feat(workspace): align workspace UI with tasks and lists, add top tabs and collapsible sidebar
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s

This commit is contained in:
sandrodach committed 2026-10-27 10:55:42 +01:00
1 parent 7baab8faa2
commit 59ddca91f3
2 files changed
+252 -362

No files matched your search

@@ -4,7 +4,7 @@ import {
Users, Users,
Trash2, Trash2,
Download, Download,
Folder as FolderIcon, FileText,
Radio, Radio,
Loader2, Loader2,
ArrowLeft, ArrowLeft,
@@ -162,7 +162,6 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
const [loading, setLoading] = useState<boolean>(!initialDoc); const [loading, setLoading] = useState<boolean>(!initialDoc);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [showEmojiPicker, setShowEmojiPicker] = useState<boolean>(false); const [showEmojiPicker, setShowEmojiPicker] = useState<boolean>(false);
const [showFolderMenu, setShowFolderMenu] = useState<boolean>(false);
const [zoomedBlockId, setZoomedBlockId] = useState<string | null>(null); const [zoomedBlockId, setZoomedBlockId] = useState<string | null>(null);
const titleInputRef = useRef<HTMLInputElement | null>(null); const titleInputRef = useRef<HTMLInputElement | null>(null);
@@ -543,18 +542,6 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
} }
}; };
const handleMoveToFolder = async (folderPath: string) => {
setShowFolderMenu(false);
if (!doc || !canEdit) return;
try {
const updated = await api.moveDocument(doc.id, folderPath);
setDoc(updated);
onDocMetadataChange(updated);
} catch {
// ignore
}
};
const handleExportMarkdown = () => { const handleExportMarkdown = () => {
const lines: string[] = [`# ${title || 'Unbenannte Notiz'}`, '']; const lines: string[] = [`# ${title || 'Unbenannte Notiz'}`, ''];
for (const b of blocks) { for (const b of blocks) {
@@ -626,46 +613,58 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
</button> </button>
)} )}
{/* Folder Selector */} {/* Breadcrumbs Navigation (Fokus-Modus) or Doc Indicator */}
<div className="relative"> {zoomedBlock && breadcrumbs.length > 0 ? (
<button <nav
type="button" aria-label="Breadcrumb Navigation"
onClick={() => canEdit && setShowFolderMenu((prev) => !prev)} className="flex items-center flex-wrap gap-1 text-xs text-muted"
className="btn-action inline-flex items-center gap-1.5 px-2 py-1 text-xs text-muted hover:text-main"
title="Ordner wechseln"
> >
<FolderIcon className="w-3.5 h-3.5 text-accent" /> <button
<span className="truncate max-w-[140px]"> type="button"
{doc?.folderPath ? doc.folderPath : 'Hauptebene'} onClick={() => setZoomedBlockId(null)}
</span> className="hover:text-accent inline-flex items-center gap-1 font-medium transition-colors cursor-pointer"
</button> title="Zurück zum Hauptdokument"
>
<Home className="w-3.5 h-3.5 text-accent shrink-0" />
<span className="truncate max-w-[130px]">
{title || doc?.title || 'Dokument'}
</span>
</button>
{showFolderMenu && canEdit && ( {breadcrumbs.slice(1).map((crumb, idx) => {
<div className="absolute left-0 mt-1 w-52 bg-canvas shadow-panel border border-border rounded-card py-1 z-30 max-h-60 overflow-y-auto"> const isCurrent = idx === breadcrumbs.length - 2;
<button return (
type="button" <React.Fragment key={crumb.id || idx}>
onClick={() => handleMoveToFolder('')} <ChevronRight className="w-3 h-3 text-faint shrink-0" />
className={`w-full text-left px-3 py-1.5 text-xs hover:bg-panel-elevated ${ {isCurrent ? (
!doc?.folderPath ? 'font-bold text-accent' : 'text-main' <span
}`} className="font-bold text-accent truncate max-w-[160px]"
> title={crumb.title}
/ (Hauptebene) >
</button> {crumb.title || 'Punkt'}
{availableFolders.map((folder) => ( </span>
<button ) : (
key={folder} <button
type="button" type="button"
onClick={() => handleMoveToFolder(folder)} onClick={() => setZoomedBlockId(crumb.id)}
className={`w-full text-left px-3 py-1.5 text-xs hover:bg-panel-elevated truncate ${ className="hover:text-main truncate max-w-[120px] transition-colors cursor-pointer"
doc?.folderPath === folder ? 'font-bold text-accent' : 'text-main' title={`Zoom zu "${crumb.title}"`}
}`} >
> {crumb.title || 'Punkt'}
📁 {folder} </button>
</button> )}
))} </React.Fragment>
</div> );
)} })}
</div> </nav>
) : (
<div className="flex items-center gap-1.5 text-xs text-muted">
<FileText className="w-3.5 h-3.5 text-accent shrink-0" />
<span className="truncate max-w-[180px] font-medium text-main">
{title || doc?.title || 'Dokument'}
</span>
</div>
)}
{/* Read-only indicator */} {/* Read-only indicator */}
{!canEdit && ( {!canEdit && (
@@ -821,52 +820,6 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
FOKUS-MODUS & ZOOM-IN (HOISTED SUBTREE VIEW) FOKUS-MODUS & ZOOM-IN (HOISTED SUBTREE VIEW)
========================================================================= */ ========================================================================= */
<div className="space-y-3"> <div className="space-y-3">
{/* Clickable Breadcrumb Bar */}
{breadcrumbs.length > 0 && (
<nav
aria-label="Breadcrumb Navigation"
className="flex items-center flex-wrap gap-1.5 py-1.5 px-3 bg-canvas border border-border rounded-btn text-xs text-muted"
>
<button
type="button"
onClick={() => setZoomedBlockId(null)}
className="hover:text-accent inline-flex items-center gap-1 font-medium transition-colors"
title="Zurück zum Hauptdokument"
>
<Home className="w-3.5 h-3.5 text-accent" />
<span className="truncate max-w-[120px]">
{title || doc?.title || 'Dokument'}
</span>
</button>
{breadcrumbs.slice(1).map((crumb, idx) => {
const isCurrent = idx === breadcrumbs.length - 2;
return (
<React.Fragment key={crumb.id || idx}>
<ChevronRight className="w-3 h-3 text-faint shrink-0" />
{isCurrent ? (
<span
className="font-bold text-accent truncate max-w-[200px]"
title={crumb.title}
>
{crumb.title || 'Punkt'}
</span>
) : (
<button
type="button"
onClick={() => setZoomedBlockId(crumb.id)}
className="hover:text-main truncate max-w-[140px] transition-colors"
title={`Zoom zu "${crumb.title}"`}
>
{crumb.title || 'Punkt'}
</button>
)}
</React.Fragment>
);
})}
</nav>
)}
{/* Prominent Zoomed Ast-Heading */} {/* Prominent Zoomed Ast-Heading */}
<div className="flex items-start justify-between gap-3 pb-4 mb-2 border-b border-border"> <div className="flex items-start justify-between gap-3 pb-4 mb-2 border-b border-border">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
+201 -264
View File
@@ -19,6 +19,9 @@ import {
Sparkles, Sparkles,
ArrowLeft, ArrowLeft,
CheckSquare, CheckSquare,
PanelLeftClose,
PanelLeftOpen,
ChevronLeft,
} from 'lucide-react'; } from 'lucide-react';
import { import {
Document, Document,
@@ -268,6 +271,23 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
const [newFolderName, setNewFolderName] = useState<string>(''); const [newFolderName, setNewFolderName] = useState<string>('');
const [newFolderIsShared, setNewFolderIsShared] = useState<boolean>(false); const [newFolderIsShared, setNewFolderIsShared] = useState<boolean>(false);
const [mobileShowDetail, setMobileShowDetail] = useState<boolean>(Boolean(initialDocId)); const [mobileShowDetail, setMobileShowDetail] = useState<boolean>(Boolean(initialDocId));
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState<boolean>(() => {
try {
return localStorage.getItem('mindsift:workspace_sidebar_collapsed') === 'true';
} catch {
return false;
}
});
const toggleSidebar = useCallback(() => {
setIsSidebarCollapsed((prev) => {
const next = !prev;
try {
localStorage.setItem('mindsift:workspace_sidebar_collapsed', String(next));
} catch {}
return next;
});
}, []);
// Drag and Drop state // Drag and Drop state
const [draggingDocId, setDraggingDocId] = useState<string | null>(null); const [draggingDocId, setDraggingDocId] = useState<string | null>(null);
@@ -1003,117 +1023,155 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
}, [tagsSummary, tagSearchQuery, tagSortBy]); }, [tagsSummary, tagSearchQuery, tagSortBy]);
return ( return (
<div className="flex h-[calc(100vh-4rem)] bg-canvas rounded-card border border-border overflow-hidden shadow-panel"> <div className="w-full space-y-3">
{/* LEFT MASTER SIDEBAR */} {/* Top Header: Workspace Tabs & Actions */}
<aside <div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-2">
className={`${ {/* Workspace selector tabs */}
mobileShowDetail ? 'hidden lg:flex' : 'flex' <div className="flex flex-wrap items-center gap-1">
} w-full lg:w-72 xl:w-80 shrink-0 flex-col bg-canvas border-r border-border`} <button
> type="button"
{/* Sidebar Header & Actions */} onClick={() => setSubView('editor')}
<div className="p-3 border-b border-border space-y-2"> className={`h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer ${
<div className="flex items-center justify-between"> subView === 'editor'
<h2 className="text-xs font-bold text-main uppercase tracking-wider"> ? 'bg-panel border-accent text-main'
Notizen & Outliner : 'bg-canvas border-border text-muted hover:text-main'
</h2> }`}
<div className="flex items-center gap-1"> >
<button <FileText className="w-3.5 h-3.5 text-accent" />
type="button" <span>Notizen</span>
onClick={() => setShowNewFolderModal(true)} {docs.length > 0 && <span className="ml-1 badge-neutral text-[10px]">{docs.length}</span>}
className="btn-action p-1 text-muted hover:text-main" </button>
title="Neuer Ordner"
> <button
<FolderPlus className="w-4 h-4" /> type="button"
</button> onClick={() => {
<button setSubView('todos');
type="button" setMobileShowDetail(true);
onClick={() => handleCreateDocument('')} }}
className="h-7 px-2.5 bg-canvas hover:bg-panel border border-border border-dashed rounded-btn text-xs text-muted hover:text-main inline-flex items-center gap-1 transition-colors cursor-pointer" className={`h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer ${
title="Neue Notiz anlegen" subView === 'todos'
> ? 'bg-panel border-accent text-main'
<Plus className="w-3.5 h-3.5" /> : 'bg-canvas border-border text-muted hover:text-main'
<span>Notiz</span> }`}
</button> >
<Check className="w-3.5 h-3.5 text-status-ok" />
<span>To-Dos</span>
{totalOpenTodos > 0 && <span className="ml-1 badge-neutral text-[10px]">{totalOpenTodos}</span>}
</button>
<button
type="button"
onClick={() => {
setSubView('tags');
setMobileShowDetail(true);
}}
className={`h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer ${
subView === 'tags' || subView === 'tag_detail'
? 'bg-panel border-accent text-main'
: 'bg-canvas border-border text-muted hover:text-main'
}`}
>
<Hash className="w-3.5 h-3.5 text-accent" />
<span>Hashtags</span>
{tagsSummary.length > 0 && <span className="ml-1 badge-neutral text-[10px]">{tagsSummary.length}</span>}
</button>
</div>
{/* Right Action buttons */}
<div className="flex items-center gap-2">
{subView === 'editor' && (
<button
type="button"
onClick={toggleSidebar}
className={`hidden sm:flex h-8 px-2.5 text-xs font-medium border rounded-btn transition-colors items-center gap-1.5 cursor-pointer ${
isSidebarCollapsed
? 'bg-panel border-accent text-accent'
: 'bg-canvas border-border text-muted hover:text-main'
}`}
title={isSidebarCollapsed ? 'Ordnerleiste einblenden' : 'Ordnerleiste einklappen'}
>
{isSidebarCollapsed ? (
<PanelLeftOpen className="w-3.5 h-3.5" />
) : (
<PanelLeftClose className="w-3.5 h-3.5" />
)}
<span>{isSidebarCollapsed ? 'Ordner anzeigen' : 'Ordner einklappen'}</span>
</button>
)}
<button
type="button"
onClick={() => handleCreateDocument('')}
className="h-8 px-2.5 bg-canvas hover:bg-panel border border-border border-dashed rounded-btn text-xs text-muted hover:text-main flex items-center gap-1 transition-colors cursor-pointer"
title="Neue Notiz anlegen"
>
<Plus className="w-3.5 h-3.5" />
<span>Neue Notiz</span>
</button>
</div>
</div>
{/* Main Workspace Split Pane */}
<div className="flex h-[calc(100vh-7.5rem)] bg-canvas rounded-card border border-border overflow-hidden shadow-panel">
{/* LEFT MASTER SIDEBAR */}
<aside
className={`${
isSidebarCollapsed
? 'hidden'
: mobileShowDetail
? 'hidden lg:flex'
: 'flex'
} w-full lg:w-72 xl:w-80 shrink-0 flex-col bg-canvas border-r border-border transition-all duration-200`}
>
{/* Sidebar Header & Actions */}
<div className="p-3 border-b border-border space-y-2">
<div className="flex items-center justify-between">
<h2 className="text-xs font-bold text-main uppercase tracking-wider">
Notizen & Outliner
</h2>
<div className="flex items-center gap-1">
<button
type="button"
onClick={() => setShowNewFolderModal(true)}
className="btn-action p-1 text-muted hover:text-main"
title="Neuer Ordner"
>
<FolderPlus className="w-4 h-4" />
</button>
<button
type="button"
onClick={() => handleCreateDocument('')}
className="h-7 px-2.5 bg-canvas hover:bg-panel border border-border border-dashed rounded-btn text-xs text-muted hover:text-main inline-flex items-center gap-1 transition-colors cursor-pointer"
title="Neue Notiz anlegen"
>
<Plus className="w-3.5 h-3.5" />
<span>Notiz</span>
</button>
</div>
</div>
{/* Search Input */}
<div className="relative">
<Search className="w-3.5 h-3.5 text-faint absolute left-2.5 top-1/2 -translate-y-1/2" />
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Notizen oder #Tags suchen…"
className="input-field w-full pl-8 pr-6 py-1 text-xs"
/>
{searchQuery && (
<button
type="button"
onClick={() => setSearchQuery('')}
className="absolute right-2 top-1/2 -translate-y-1/2 text-faint hover:text-main"
>
<X className="w-3.5 h-3.5" />
</button>
)}
</div> </div>
</div> </div>
{/* Search Input */}
<div className="relative">
<Search className="w-3.5 h-3.5 text-faint absolute left-2.5 top-1/2 -translate-y-1/2" />
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Notizen oder #Tags suchen…"
className="input-field w-full pl-8 pr-6 py-1 text-xs"
/>
{searchQuery && (
<button
type="button"
onClick={() => setSearchQuery('')}
className="absolute right-2 top-1/2 -translate-y-1/2 text-faint hover:text-main"
>
<X className="w-3.5 h-3.5" />
</button>
)}
</div>
{/* Sub-view Switcher: Notizen vs. To-Dos vs. Hashtags */}
<div className="grid grid-cols-3 gap-1 p-0.5 rounded-btn bg-canvas border border-border text-xs">
<button
type="button"
onClick={() => setSubView('editor')}
className={`py-1.5 px-1 rounded-btn font-medium transition-colors flex items-center justify-center gap-1 cursor-pointer truncate ${
subView === 'editor'
? 'bg-panel-elevated text-main font-semibold shadow-xs'
: 'text-muted hover:text-main'
}`}
title="Notizen & Dokumente"
>
<FileText className="w-3.5 h-3.5 text-accent shrink-0" />
<span className="truncate">Notizen</span>
</button>
<button
type="button"
onClick={() => {
setSubView('todos');
setMobileShowDetail(true);
}}
className={`py-1.5 px-1 rounded-btn font-medium transition-colors flex items-center justify-center gap-1 cursor-pointer truncate ${
subView === 'todos'
? 'bg-panel-elevated text-main font-semibold shadow-xs'
: 'text-muted hover:text-main'
}`}
title="To-Dos Rollup"
>
<Check className="w-3.5 h-3.5 text-status-ok shrink-0" />
<span className="truncate">To-Dos</span>
{totalOpenTodos > 0 && (
<span className="badge-neutral text-[9px] px-1 py-0">{totalOpenTodos}</span>
)}
</button>
<button
type="button"
onClick={() => {
setSubView('tags');
setMobileShowDetail(true);
}}
className={`py-1.5 px-1 rounded-btn font-medium transition-colors flex items-center justify-center gap-1 cursor-pointer truncate ${
subView === 'tags' || subView === 'tag_detail'
? 'bg-panel-elevated text-main font-semibold shadow-xs'
: 'text-muted hover:text-main'
}`}
title="Hashtag Kacheln & Übersicht"
>
<Hash className="w-3.5 h-3.5 text-accent shrink-0" />
<span className="truncate">Hashtags</span>
{tagsSummary.length > 0 && (
<span className="badge-neutral text-[9px] px-1 py-0">{tagsSummary.length}</span>
)}
</button>
</div>
</div>
{/* Scrollable Navigation Tree */} {/* Scrollable Navigation Tree */}
<div className="flex-1 overflow-y-auto p-2 space-y-3"> <div className="flex-1 overflow-y-auto p-2 space-y-3">
{/* Drop target for moving docs or folders to root */} {/* Drop target for moving docs or folders to root */}
@@ -1273,7 +1331,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
{/* RIGHT DETAIL AREA (STRICTLY ISOLATED BY KEY) */} {/* RIGHT DETAIL AREA (STRICTLY ISOLATED BY KEY) */}
<main <main
className={`${ className={`${
mobileShowDetail ? 'flex' : 'hidden lg:flex' mobileShowDetail ? 'flex' : isSidebarCollapsed ? 'flex' : 'hidden lg:flex'
} flex-1 flex-col min-w-0 h-full overflow-hidden bg-canvas`} } flex-1 flex-col min-w-0 h-full overflow-hidden bg-canvas`}
> >
{subView === 'editor' && selectedDocId ? ( {subView === 'editor' && selectedDocId ? (
@@ -1298,49 +1356,6 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
========================================================================= */ ========================================================================= */
<div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas"> <div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas">
<div className="max-w-4xl mx-auto space-y-5"> <div className="max-w-4xl mx-auto space-y-5">
{/* Top Navigation Tabs */}
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-3">
<div className="flex flex-wrap items-center gap-1.5">
<button
type="button"
onClick={() => setSubView('editor')}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main"
>
<FileText className="w-3.5 h-3.5 text-accent" />
<span>Notizen</span>
<span className="badge-neutral text-[10px]">{docs.length}</span>
</button>
<button
type="button"
onClick={() => {
setSubView('todos');
setMobileShowDetail(true);
}}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main"
>
<Check className="w-3.5 h-3.5 text-status-ok" />
<span>To-Dos</span>
<span className="badge-neutral text-[10px]">{totalOpenTodos}</span>
</button>
<button
type="button"
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-panel border-accent text-main font-semibold shadow-xs"
>
<Hash className="w-3.5 h-3.5 text-accent" />
<span>Hashtags</span>
<span className="badge-neutral text-[10px]">{tagsSummary.length}</span>
</button>
</div>
<button
type="button"
onClick={() => setSubView('editor')}
className="btn-action px-3 py-1 text-xs text-main cursor-pointer"
>
Zum Editor
</button>
</div>
{/* Header with Title and Search Controls */} {/* Header with Title and Search Controls */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div> <div>
@@ -1507,58 +1522,16 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
) : subView === 'tag_detail' && selectedTag ? ( ) : subView === 'tag_detail' && selectedTag ? (
<div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas"> <div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas">
<div className="max-w-3xl mx-auto space-y-4"> <div className="max-w-3xl mx-auto space-y-4">
{/* Top Navigation Tabs */} {/* Back to all tags */}
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-3"> <div className="flex items-center justify-between border-b border-border pb-3">
<div className="flex flex-wrap items-center gap-1.5"> <button
<button type="button"
type="button" onClick={() => setSubView('tags')}
onClick={() => setSubView('editor')} className="btn-action inline-flex items-center gap-1.5 px-2.5 py-1 text-xs text-muted hover:text-main cursor-pointer"
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main" >
> <ArrowLeft className="w-3.5 h-3.5" />
<FileText className="w-3.5 h-3.5 text-accent" /> <span>Alle Hashtag-Kacheln</span>
<span>Notizen</span> </button>
<span className="badge-neutral text-[10px]">{docs.length}</span>
</button>
<button
type="button"
onClick={() => {
setSubView('todos');
setMobileShowDetail(true);
}}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main"
>
<Check className="w-3.5 h-3.5 text-status-ok" />
<span>To-Dos</span>
<span className="badge-neutral text-[10px]">{totalOpenTodos}</span>
</button>
<button
type="button"
onClick={() => setSubView('tags')}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-panel border-accent text-main font-semibold shadow-xs"
>
<Hash className="w-3.5 h-3.5 text-accent" />
<span>Hashtags</span>
<span className="badge-neutral text-[10px]">{tagsSummary.length}</span>
</button>
</div>
<div className="flex items-center gap-1.5">
<button
type="button"
onClick={() => setSubView('tags')}
className="btn-action inline-flex items-center gap-1 px-2.5 py-1 text-xs text-muted hover:text-main cursor-pointer"
>
<ArrowLeft className="w-3.5 h-3.5" />
<span>Alle Kacheln</span>
</button>
<button
type="button"
onClick={() => setSubView('editor')}
className="btn-action px-3 py-1 text-xs text-main cursor-pointer"
>
Zum Editor
</button>
</div>
</div> </div>
{/* Tag Context Header */} {/* Tag Context Header */}
@@ -1755,49 +1728,6 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
) : subView === 'todos' ? ( ) : subView === 'todos' ? (
<div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas"> <div className="flex-1 overflow-y-auto p-4 sm:p-8 bg-canvas">
<div className="max-w-3xl mx-auto space-y-4"> <div className="max-w-3xl mx-auto space-y-4">
{/* Top Navigation Tabs */}
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-3">
<div className="flex flex-wrap items-center gap-1.5">
<button
type="button"
onClick={() => setSubView('editor')}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main"
>
<FileText className="w-3.5 h-3.5 text-accent" />
<span>Notizen</span>
<span className="badge-neutral text-[10px]">{docs.length}</span>
</button>
<button
type="button"
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-panel border-accent text-main font-semibold shadow-xs"
>
<Check className="w-3.5 h-3.5 text-status-ok" />
<span>To-Dos</span>
<span className="badge-neutral text-[10px]">{totalOpenTodos}</span>
</button>
<button
type="button"
onClick={() => {
setSubView('tags');
setMobileShowDetail(true);
}}
className="h-8 px-3 text-xs font-medium border rounded-btn transition-colors flex items-center gap-1.5 cursor-pointer bg-canvas border-border text-muted hover:text-main"
>
<Hash className="w-3.5 h-3.5 text-accent" />
<span>Hashtags</span>
<span className="badge-neutral text-[10px]">{tagsSummary.length}</span>
</button>
</div>
<button
type="button"
onClick={() => setSubView('editor')}
className="btn-action px-3 py-1 text-xs text-main cursor-pointer"
>
Zum Editor
</button>
</div>
<div className="flex flex-col sm:flex-row sm:items-center justify-between border-b border-border pb-3 gap-2"> <div className="flex flex-col sm:flex-row sm:items-center justify-between border-b border-border pb-3 gap-2">
<div> <div>
<h2 className="text-lg font-bold text-main"> <h2 className="text-lg font-bold text-main">
@@ -1865,14 +1795,6 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
<span>Ordner</span> <span>Ordner</span>
</button> </button>
</div> </div>
<button
type="button"
onClick={() => setSubView('editor')}
className="btn-action px-3 py-1 text-xs text-main cursor-pointer"
>
Zum Editor
</button>
</div> </div>
</div> </div>
@@ -2272,16 +2194,30 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
Keine Notiz ausgewählt Keine Notiz ausgewählt
</h3> </h3>
<p className="text-xs text-muted max-w-sm mb-3"> <p className="text-xs text-muted max-w-sm mb-3">
Wähle links in der Seitenleiste eine bestehende Notiz aus oder erstelle eine neue. {isSidebarCollapsed
? 'Die Ordnerleiste ist eingeklappt. Blende sie ein oder erstelle eine neue Notiz.'
: 'Wähle links in der Seitenleiste eine bestehende Notiz aus oder erstelle eine neue.'}
</p> </p>
<button <div className="flex items-center gap-2">
type="button" {isSidebarCollapsed && (
onClick={() => handleCreateDocument('')} <button
className="btn-primary inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold" type="button"
> onClick={toggleSidebar}
<Plus className="w-3.5 h-3.5" /> className="btn-action inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold cursor-pointer"
<span>Notiz erstellen</span> >
</button> <PanelLeftOpen className="w-3.5 h-3.5" />
<span>Ordner anzeigen</span>
</button>
)}
<button
type="button"
onClick={() => handleCreateDocument('')}
className="btn-primary inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold"
>
<Plus className="w-3.5 h-3.5" />
<span>Notiz erstellen</span>
</button>
</div>
</div> </div>
)} )}
</main> </main>
@@ -2402,6 +2338,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
}} }}
/> />
)} )}
</div>
</div> </div>
); );
}; };