Dev #5
@@ -3189,119 +3189,9 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
|
|
||||||
const isEmpty = docs.length === 0 && allFolderPaths.length === 0;
|
const isEmpty = docs.length === 0 && allFolderPaths.length === 0;
|
||||||
|
|
||||||
return (
|
const renderExplorerBody = () => (
|
||||||
<div className="w-full space-y-2">
|
|
||||||
|
|
||||||
{/* Top Navigation Mode Switcher: Notizen & Outliner vs. Globales To-Do Dashboard (Desktop) */}
|
|
||||||
<div className="hidden sm:flex flex-wrap items-center justify-between gap-2 border-b border-border pb-2">
|
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setWorkspaceMode('editor')}
|
|
||||||
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
|
||||||
workspaceMode === 'editor'
|
|
||||||
? 'bg-panel border-accent text-main'
|
|
||||||
: 'bg-canvas border-border text-muted hover:text-main'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Layers className="w-3.5 h-3.5 text-accent" />
|
|
||||||
<span>Notizen</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setWorkspaceMode('tags')}
|
|
||||||
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
|
||||||
workspaceMode === 'tags'
|
|
||||||
? '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>Themen & Hashtags</span>
|
|
||||||
{workspaceTags.length > 0 && (
|
|
||||||
<span className="badge-neutral font-mono text-[10px]">
|
|
||||||
{workspaceTags.length}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setWorkspaceMode('todos')}
|
|
||||||
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
|
||||||
workspaceMode === 'todos'
|
|
||||||
? 'bg-panel border-accent text-main'
|
|
||||||
: 'bg-canvas border-border text-muted hover:text-main'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<CheckSquare className="w-3.5 h-3.5 text-accent" />
|
|
||||||
<span>Globale To-Dos</span>
|
|
||||||
<span className="badge-neutral font-mono text-[10px]">
|
|
||||||
{allWorkspaceTodos.filter((t) => !t.block.checked).length}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2 text-xs text-muted">
|
|
||||||
{workspaceMode === 'editor' && selectedDoc && (
|
|
||||||
<>
|
<>
|
||||||
<span className="badge-accent">
|
<div className="p-2.5 sm:p-2 panel-header space-y-2 flex-shrink-0">
|
||||||
<Check className="w-3 h-3" />
|
|
||||||
{saveState === 'saving' ? 'Speichert…' : 'Gespeichert'}
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleExportMarkdown}
|
|
||||||
className="btn-action h-8 px-2.5 text-xs flex items-center gap-1.5"
|
|
||||||
title="Als Logseq/Markdown-Datei (.md) herunterladen"
|
|
||||||
>
|
|
||||||
<Download className="w-3.5 h-3.5 text-accent" />
|
|
||||||
<span>Export (.md)</span>
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ===================================================================== */}
|
|
||||||
{/* VIEW MODE 1: LOGSEQ OUTLINER & EXPLORER */}
|
|
||||||
{/* ===================================================================== */}
|
|
||||||
{workspaceMode === 'editor' && (
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-2">
|
|
||||||
{/* Mobile Backdrop for File Tree Slide-Over Drawer */}
|
|
||||||
{showMobileFileDrawer && (
|
|
||||||
<div
|
|
||||||
className="fixed inset-0 !m-0 bg-black/50 backdrop-blur-xs z-40 lg:hidden animate-in fade-in duration-150"
|
|
||||||
onClick={() => setShowMobileFileDrawer(false)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Left Document & Folder Explorer Tree (Desktop Sidebar + Mobile Slide-Over Drawer) */}
|
|
||||||
<div
|
|
||||||
className={`${
|
|
||||||
showMobileFileDrawer
|
|
||||||
? 'fixed inset-y-0 left-0 z-50 w-[86vw] max-w-sm bg-panel border-r border-border shadow-2xl flex'
|
|
||||||
: 'hidden lg:flex'
|
|
||||||
} lg:col-span-4 panel-surface flex-col self-start max-h-screen lg:max-h-none`}
|
|
||||||
>
|
|
||||||
{/* Mobile Drawer Top Header */}
|
|
||||||
<div className="flex lg:hidden items-center justify-between px-3.5 py-3 border-b border-border bg-panel">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<FolderTree className="w-4 h-4 text-accent" />
|
|
||||||
<span className="text-sm font-bold text-main">Dateibaum & Ordner</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setShowMobileFileDrawer(false)}
|
|
||||||
className="p-1.5 text-muted hover:text-main rounded-btn"
|
|
||||||
title="Schließen"
|
|
||||||
>
|
|
||||||
<X className="w-5 h-5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-2.5 sm:p-2 panel-header space-y-2">
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted absolute left-2.5 top-1/2 -translate-y-1/2" />
|
<Search className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted absolute left-2.5 top-1/2 -translate-y-1/2" />
|
||||||
<input
|
<input
|
||||||
@@ -3320,7 +3210,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
setShowMobileFileDrawer(false);
|
setShowMobileFileDrawer(false);
|
||||||
handleCreateDoc(null);
|
handleCreateDoc(null);
|
||||||
}}
|
}}
|
||||||
className="flex-1 btn-action min-h-[38px] sm:min-h-0 justify-center"
|
className="flex-1 btn-action min-h-[38px] sm:min-h-0 justify-center cursor-pointer"
|
||||||
title="Neue Datei erstellen"
|
title="Neue Datei erstellen"
|
||||||
>
|
>
|
||||||
<FilePlus className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted" />
|
<FilePlus className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted" />
|
||||||
@@ -3330,7 +3220,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleStartCreateFolder(null)}
|
onClick={() => handleStartCreateFolder(null)}
|
||||||
className="flex-1 btn-action min-h-[38px] sm:min-h-0 justify-center"
|
className="flex-1 btn-action min-h-[38px] sm:min-h-0 justify-center cursor-pointer"
|
||||||
title="Neuen Ordner erstellen"
|
title="Neuen Ordner erstellen"
|
||||||
>
|
>
|
||||||
<FolderPlus className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted" />
|
<FolderPlus className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted" />
|
||||||
@@ -3340,7 +3230,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isCreatingFolder && newFolderParent === null && (
|
{isCreatingFolder && newFolderParent === null && (
|
||||||
<div className="p-2 panel-header bg-canvas flex items-center gap-1.5">
|
<div className="p-2 panel-header bg-canvas flex items-center gap-1.5 flex-shrink-0">
|
||||||
<Folder className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted flex-shrink-0" />
|
<Folder className="w-4 h-4 sm:w-3.5 sm:h-3.5 text-muted flex-shrink-0" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -3357,26 +3247,25 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleConfirmCreateFolder}
|
onClick={handleConfirmCreateFolder}
|
||||||
className="p-1.5 sm:p-1 text-accent hover:text-main rounded-btn"
|
className="p-1.5 sm:p-1 text-accent hover:text-main rounded-btn cursor-pointer"
|
||||||
title="Bestätigen"
|
|
||||||
>
|
>
|
||||||
<Check className="w-4 h-4 sm:w-3.5 sm:h-3.5" />
|
<Check className="w-4 h-4 sm:w-3 sm:h-3" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsCreatingFolder(false)}
|
onClick={() => setIsCreatingFolder(false)}
|
||||||
className="p-1.5 sm:p-1 text-muted hover:text-main rounded-btn"
|
className="p-1.5 sm:p-1 text-muted hover:text-main rounded-btn cursor-pointer"
|
||||||
title="Abbrechen"
|
|
||||||
>
|
>
|
||||||
<X className="w-4 h-4 sm:w-3.5 sm:h-3.5" />
|
<X className="w-4 h-4 sm:w-3 sm:h-3" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Empty workspace state */}
|
||||||
{isEmpty ? (
|
{isEmpty ? (
|
||||||
<div className="p-6 my-3 mx-2 border border-dashed border-border bg-canvas/50 text-center rounded-card">
|
<div className="p-4 text-center text-xs text-muted space-y-2 flex-1">
|
||||||
<Folder className="w-7 h-7 text-faint mx-auto mb-2" />
|
<Folder className="w-8 h-8 text-faint mx-auto" />
|
||||||
<h5 className="text-xs font-semibold text-muted mb-1">Keine Dateien vorhanden</h5>
|
<p className="font-semibold text-main">Noch keine Notizen</p>
|
||||||
<p className="text-[11px] text-faint mb-3 max-w-xs mx-auto leading-relaxed">
|
<p className="text-[11px] text-faint mb-3 max-w-xs mx-auto leading-relaxed">
|
||||||
Erstelle eine neue Datei oder lege Ordner an, um deine Dokumente übersichtlich zu strukturieren.
|
Erstelle eine neue Datei oder lege Ordner an, um deine Dokumente übersichtlich zu strukturieren.
|
||||||
</p>
|
</p>
|
||||||
@@ -3387,7 +3276,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
setShowMobileFileDrawer(false);
|
setShowMobileFileDrawer(false);
|
||||||
handleCreateDoc(null);
|
handleCreateDoc(null);
|
||||||
}}
|
}}
|
||||||
className="btn-action min-h-[38px] sm:min-h-0"
|
className="btn-action min-h-[38px] sm:min-h-0 cursor-pointer"
|
||||||
>
|
>
|
||||||
<FilePlus className="w-3.5 h-3.5 text-muted" />
|
<FilePlus className="w-3.5 h-3.5 text-muted" />
|
||||||
<span>Neue Datei</span>
|
<span>Neue Datei</span>
|
||||||
@@ -3395,7 +3284,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleStartCreateFolder(null)}
|
onClick={() => handleStartCreateFolder(null)}
|
||||||
className="btn-action min-h-[38px] sm:min-h-0"
|
className="btn-action min-h-[38px] sm:min-h-0 cursor-pointer"
|
||||||
>
|
>
|
||||||
<FolderPlus className="w-3.5 h-3.5 text-muted" />
|
<FolderPlus className="w-3.5 h-3.5 text-muted" />
|
||||||
<span>Neuer Ordner</span>
|
<span>Neuer Ordner</span>
|
||||||
@@ -3569,8 +3458,128 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full space-y-2">
|
||||||
|
|
||||||
|
{/* Top Navigation Mode Switcher: Notizen & Outliner vs. Globales To-Do Dashboard (Desktop) */}
|
||||||
|
<div className="hidden sm:flex flex-wrap items-center justify-between gap-2 border-b border-border pb-2">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setWorkspaceMode('editor')}
|
||||||
|
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
||||||
|
workspaceMode === 'editor'
|
||||||
|
? 'bg-panel border-accent text-main'
|
||||||
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Layers className="w-3.5 h-3.5 text-accent" />
|
||||||
|
<span>Notizen</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setWorkspaceMode('tags')}
|
||||||
|
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
||||||
|
workspaceMode === 'tags'
|
||||||
|
? '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>Themen & Hashtags</span>
|
||||||
|
{workspaceTags.length > 0 && (
|
||||||
|
<span className="badge-neutral font-mono text-[10px]">
|
||||||
|
{workspaceTags.length}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setWorkspaceMode('todos')}
|
||||||
|
className={`h-8 px-3 text-xs font-medium border rounded-btn flex items-center gap-1.5 transition-colors ${
|
||||||
|
workspaceMode === 'todos'
|
||||||
|
? 'bg-panel border-accent text-main'
|
||||||
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<CheckSquare className="w-3.5 h-3.5 text-accent" />
|
||||||
|
<span>Globale To-Dos</span>
|
||||||
|
<span className="badge-neutral font-mono text-[10px]">
|
||||||
|
{allWorkspaceTodos.filter((t) => !t.block.checked).length}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-xs text-muted">
|
||||||
|
{workspaceMode === 'editor' && selectedDoc && (
|
||||||
|
<>
|
||||||
|
<span className="badge-accent">
|
||||||
|
<Check className="w-3 h-3" />
|
||||||
|
{saveState === 'saving' ? 'Speichert…' : 'Gespeichert'}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleExportMarkdown}
|
||||||
|
className="btn-action h-8 px-2.5 text-xs flex items-center gap-1.5"
|
||||||
|
title="Als Logseq/Markdown-Datei (.md) herunterladen"
|
||||||
|
>
|
||||||
|
<Download className="w-3.5 h-3.5 text-accent" />
|
||||||
|
<span>Export (.md)</span>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ===================================================================== */}
|
||||||
|
{/* VIEW MODE 1: LOGSEQ OUTLINER & EXPLORER */}
|
||||||
|
{/* ===================================================================== */}
|
||||||
|
{workspaceMode === 'editor' && (
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-2">
|
||||||
|
{/* Mobile Centered Floating Explorer Dialog ("in der Mitte schweben") */}
|
||||||
|
{showMobileFileDrawer && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 !m-0 z-50 flex items-center justify-center p-3.5 sm:p-4 bg-black/60 backdrop-blur-xs lg:hidden animate-in fade-in duration-150"
|
||||||
|
onClick={() => setShowMobileFileDrawer(false)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="w-full max-w-md max-h-[85vh] bg-panel border border-border rounded-2xl shadow-panel flex flex-col overflow-hidden animate-in zoom-in-95 duration-150"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{/* Mobile Dialog Header */}
|
||||||
|
<div className="flex items-center justify-between px-4 py-3 border-b border-border bg-panel flex-shrink-0">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="w-7 h-7 rounded-btn bg-accent/15 text-accent flex items-center justify-center">
|
||||||
|
<FolderTree className="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
<span className="text-sm font-semibold text-main">Dateibaum & Ordner</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowMobileFileDrawer(false)}
|
||||||
|
className="p-1.5 text-faint hover:text-main rounded-btn transition-colors cursor-pointer"
|
||||||
|
title="Schließen"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto flex flex-col">
|
||||||
|
{renderExplorerBody()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Desktop Left Document & Folder Explorer Tree (Sidebar) */}
|
||||||
|
<div className="hidden lg:flex lg:col-span-4 panel-surface flex-col self-start max-h-screen lg:max-h-none">
|
||||||
|
{renderExplorerBody()}
|
||||||
|
</div>
|
||||||
{/* Right Logseq Outliner Editor */}
|
{/* Right Logseq Outliner Editor */}
|
||||||
<div className="lg:col-span-8">
|
<div className="lg:col-span-8">
|
||||||
{selectedDoc ? (
|
{selectedDoc ? (
|
||||||
|
|||||||
Reference in new issue
Block a user