From e618bb5a3263e1a7e37defe97146f565cab344b2 Mon Sep 17 00:00:00 2001 From: Sandro Date: Tue, 3 Nov 2026 06:32:30 +0100 Subject: [PATCH 1/4] feat(workspace): tab row scrolls away and snaps; pinnable focus-mode bars A wheel step over the workspace background (tab row, margins) pushes the tab row (notes, to-dos, hashtags) out at the top so the note fills the area, like the Kanban bar; note and sidebar keep scrolling only themselves. In focus mode the header and the folder sidebar can be pinned; the header's shadow is lighter. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 7 + README.md | 2 +- .../src/features/workspace/WorkspaceView.tsx | 136 ++++++++++++++++-- 3 files changed, 129 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b50ca73..a8c1735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ## [Unreleased] +### Added +- Notizen (Desktop): Scrollen im Hintergrund (über der Leiste mit Notizen, To-Dos und Hashtags oder am Rand neben der Notiz) schiebt diese Leiste oben heraus und rastet ein, sodass die Notiz den ganzen Bereich nutzt – wie beim Kanban. Hochscrollen dort holt sie zurück. In der Notiz und in der Ordnerleiste scrollt das Mausrad wie bisher nur deren Inhalt. +- Fokus-Modus: Die Ordnerleiste links und die Leiste oben haben einen Pin. Angepinnt bleiben sie stehen, statt wieder wegzugleiten; die Einstellung bleibt erhalten. + +### Changed +- Fokus-Modus: Die obere Leiste wirft nur noch einen leichten Schatten. + ## [0.66.0] - 2026-11-02 ### Added diff --git a/README.md b/README.md index 94098ec..2ab3aa8 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Die meisten Notiz- und Aufgaben-Apps verlangen Struktur im falschen Moment: Wenn ### 📝 Workspace: Outliner-Notizen * Jeder Gedanke ein Bullet: `Enter`, `Tab`/`Shift+Tab`, Ein-/Ausklappen, Drag & Drop ganzer Äste; am Handy eine Leiste über der Tastatur zum Ein-/Ausrücken und Verschieben. Text lässt sich mit der Maus über mehrere Punkte markieren und wie in einem Texteditor löschen, ersetzen oder kopieren. -* **Zoom-Fokus** per Klick auf den Bullet, Breadcrumbs zum Zurücknavigieren; **Fokus-Modus** (`Strg+Umschalt+F`) zeigt nur die Notiz in Lesebreite, Ordner gleiten bei Bedarf von links herein. +* **Zoom-Fokus** per Klick auf den Bullet, Breadcrumbs zum Zurücknavigieren; **Fokus-Modus** (`Strg+Umschalt+F`) zeigt nur die Notiz in Lesebreite, Ordner gleiten bei Bedarf von links herein, Ordnerleiste und obere Leiste lassen sich anpinnen. Am Desktop schiebt Scrollen im Hintergrund (neben der Notiz) die Leiste mit Notizen, To-Dos und Hashtags nach oben heraus. * **Journal:** eine Notiz pro Tag, alle Tage untereinander (heute oben, ältere laden beim Scrollen nach), mit Kalender zum Springen; einzelne Tage lassen sich teilen. Pro Gerät abschaltbar. * Blocktypen und Slash-Befehle: `/todo`, `/number` (nummerierte Liste: 1., a., i.), `/link`, `/h1`–`/h3`, `/code` (mit Syntax-Hervorhebung), `/callout`, `/divider`, `/extract`, `/image`, `/audio`, `/diktat`. * **Bilder & Audio in Notizen:** `/image` (Datei, Kamera, Zwischenablage oder Link), `/audio` (Sprachnotiz oder Datei-Upload) und `/diktat` (Live-Transkription). diff --git a/frontend/src/features/workspace/WorkspaceView.tsx b/frontend/src/features/workspace/WorkspaceView.tsx index 3df14a2..1a8de74 100644 --- a/frontend/src/features/workspace/WorkspaceView.tsx +++ b/frontend/src/features/workspace/WorkspaceView.tsx @@ -25,6 +25,7 @@ import { Loader2, CalendarDays, Minimize2, + PinOff, } from 'lucide-react'; import { Document, @@ -474,6 +475,14 @@ export const WorkspaceView: React.FC = ({ // Focus mode: the folder sidebar slides in from the left (button, title click or mouse at the edge) const [zenSidebar, setZenSidebar] = useState<'closed' | 'click' | 'hover'>('closed'); const [zenActionsTarget, setZenActionsTarget] = useState(null); + // Focus mode: header and sidebar can be pinned so they stay instead of sliding back (kept across sessions) + const [zenPinTop, setZenPinTop] = useState(() => localStorage.getItem('mindsift_zen_pin_top') === '1'); + const [zenPinSide, setZenPinSide] = useState(() => localStorage.getItem('mindsift_zen_pin_side') === '1'); + useEffect(() => { + localStorage.setItem('mindsift_zen_pin_top', zenPinTop ? '1' : '0'); + localStorage.setItem('mindsift_zen_pin_side', zenPinSide ? '1' : '0'); + }, [zenPinTop, zenPinSide]); + const zenSideOpen = zenPinSide || zenSidebar !== 'closed'; // Drag and Drop state @@ -1232,6 +1241,49 @@ export const WorkspaceView: React.FC = ({ return () => window.removeEventListener('keydown', onKey); }, [canFocus, focusMode, zenSidebar]); + // Desktop: a wheel step down over the background (the tab row, the margins beside and below the workspace) + // pushes the tab row (notes, to-dos, hashtags) out at the top and snaps, so the note fills the whole area, + // like the bar above the Kanban board; a step up brings it back. Over the note and the folder sidebar the + // wheel only scrolls them. The workspace is higher than the app's scroll area by the row (wsBar); that + // area stays overflow-hidden and is only scrolled from here. + const workspaceRootRef = useRef(null); + const tabRowRef = useRef(null); + const [wsBar, setWsBar] = useState(0); + useEffect(() => { + const row = tabRowRef.current; + if (!row || typeof ResizeObserver === 'undefined') return; + // offsetHeight is 0 on phones (the row is hidden there); 12 px is the gap below it + const measure = () => setWsBar(row.offsetHeight ? row.offsetHeight + 12 : 0); + measure(); + const ro = new ResizeObserver(measure); + ro.observe(row); + return () => ro.disconnect(); + }, []); + useEffect(() => { + const root = workspaceRootRef.current; + const area = root?.closest('[data-app-scroll]'); + if (!root || !area || !wsBar || focusMode) return; + let pending = 0; // trackpads send many small steps: move only once they add up + let lockedUntil = 0; + const onWheel = (e: WheelEvent) => { + if (e.ctrlKey || e.shiftKey || isPhoneWidth()) return; + if ((e.target as HTMLElement).closest?.('[data-ws-pane]')) return; + const dy = e.deltaMode === 1 ? e.deltaY * 16 : e.deltaY; + if (dy === 0) return; + const max = area.scrollHeight - area.clientHeight; + if (dy > 0 ? area.scrollTop >= max - 1 : area.scrollTop <= 0) return; + e.preventDefault(); + if (Date.now() < lockedUntil) return; + pending += dy; + if (Math.abs(pending) < 40) return; + pending = 0; + lockedUntil = Date.now() + 450; + area.scrollTo({ top: dy > 0 ? max : 0, behavior: 'smooth' }); + }; + area.addEventListener('wheel', onWheel, { passive: false }); + return () => area.removeEventListener('wheel', onWheel); + }, [wsBar, focusMode]); + const allFolderPaths = useMemo(() => { const set = new Set(folders); for (const d of docs) { @@ -1612,10 +1664,14 @@ export const WorkspaceView: React.FC = ({ }, [tagsSummary, tagSearchQuery, tagSortBy]); return ( -
+
{/* Top Header: Workspace Tabs & Actions */} {/* Phones: the views are switched in the menu at the top, so the row is hidden there */} -
+
{/* Workspace selector tabs & left sidebar toggle */}
@@ -1873,6 +1943,20 @@ export const WorkspaceView: React.FC = ({ {[selectedDocObj?.icon, selectedDocObj?.title].filter(Boolean).join(' ')}
+
{/* Wide screens: touching the left edge opens the sidebar (the note sits far from it) */}
setZenSidebar((v) => (v === 'closed' ? 'hover' : v))} aria-hidden /> - {zenSidebar === 'click' && ( + {zenSidebar === 'click' && !zenPinSide && (
setZenSidebar('closed')} aria-hidden /> )} + {/* Focus mode: pin the sliding sidebar so it stays beside the note */} + {focusMode && ( + + )}
From 8439ae1ccf16f685c582342c8881e1fb5b0e1d42 Mon Sep 17 00:00:00 2001 From: Sandro Date: Tue, 3 Nov 2026 06:42:57 +0100 Subject: [PATCH 2/4] chore: release v0.67.0 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 5 ++++- README.md | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c1735..107fbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ## [Unreleased] +## [0.67.0] - 2026-11-03 + ### Added - Notizen (Desktop): Scrollen im Hintergrund (über der Leiste mit Notizen, To-Dos und Hashtags oder am Rand neben der Notiz) schiebt diese Leiste oben heraus und rastet ein, sodass die Notiz den ganzen Bereich nutzt – wie beim Kanban. Hochscrollen dort holt sie zurück. In der Notiz und in der Ordnerleiste scrollt das Mausrad wie bisher nur deren Inhalt. - Fokus-Modus: Die Ordnerleiste links und die Leiste oben haben einen Pin. Angepinnt bleiben sie stehen, statt wieder wegzugleiten; die Einstellung bleibt erhalten. @@ -943,7 +945,8 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V - Geteilte Listen (Einkaufs-, Pack- und Checklisten) mit `#Kategorie`-Gruppierung, Mengenangaben und Echtzeit-Abhaken. - Benutzer-, Gruppen- und Admin-Verwaltung (Ersteinrichtungs-Assistent, Einladungscodes, Profilbilder, persönliche API-Keys & Webhook-Ingest `/api/v1/webhooks/ingest`, JSON-Datenexport) sowie CSS-Theme-Engine mit 4 Themes (`Dark`, `Light`, `High Contrast`, `Soft`) und PWA-Unterstützung. -[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.66.0...dev +[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.67.0...dev +[0.67.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.66.0...v0.67.0 [0.66.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.65.0...v0.66.0 [0.65.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.64.1...v0.65.0 [0.64.1]: https://git.dsit.me/sandrodach/MindSift/compare/v0.64.0...v0.64.1 diff --git a/README.md b/README.md index 2ab3aa8..49df642 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Self-Hosted](https://img.shields.io/badge/100%25-Self--Hosted-2563eb?style=flat-square)](#) [![Docker](https://img.shields.io/badge/Deployment-Single%20Container-2496ed?style=flat-square&logo=docker&logoColor=white)](#-schnellstart) [![SQLite](https://img.shields.io/badge/Daten-SQLite-003b57?style=flat-square&logo=sqlite&logoColor=white)](#-deine-daten-gehören-dir) -[![Version](https://img.shields.io/badge/Version-v0.66.0-16a34a?style=flat-square)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v0.67.0-16a34a?style=flat-square)](CHANGELOG.md) **MindSift** ist eine selbst gehostete Schaltstelle für spontane Gedanken, Aufgaben mit Kanban-Board, hierarchische Outliner-Notizen, die mehrere Personen gleichzeitig bearbeiten können, und gemeinsame Listen. Alles läuft als ein einzelner Container mit eingebetteter SQLite-Datenbank, auf deinem eigenen Server. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 229e497..603b7a5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "mindsift-frontend", - "version": "0.66.0", + "version": "0.67.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mindsift-frontend", - "version": "0.66.0", + "version": "0.67.0", "license": "AGPL-3.0-only", "dependencies": { "@fontsource-variable/inter": "5.3.0", diff --git a/frontend/package.json b/frontend/package.json index bb2bfef..ff586fc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "mindsift-frontend", "private": true, - "version": "0.66.0", + "version": "0.67.0", "license": "AGPL-3.0-only", "type": "module", "scripts": { From ab1cef65a1b7812e967db167c11ebfa90b299c61 Mon Sep 17 00:00:00 2001 From: Sandro Date: Tue, 3 Nov 2026 06:46:06 +0100 Subject: [PATCH 3/4] feat(tasks): greyed-out "add task" with a hint for list-only columns in "Alle Aufgaben" Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + frontend/src/features/triage/TasksView.tsx | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 107fbb1..3d3e687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ### Changed - Fokus-Modus: Die obere Leiste wirft nur noch einen leichten Schatten. +- Kanban in „Alle Aufgaben“: Bei Spalten, die es nur in Aufgabenlisten gibt, ist „Aufgabe hinzufügen“ jetzt ausgegraut sichtbar statt einfach zu fehlen. Ein Hinweis beim Drüberfahren nennt die Listen, in denen man dort Aufgaben anlegen kann. ## [0.66.0] - 2026-11-02 diff --git a/frontend/src/features/triage/TasksView.tsx b/frontend/src/features/triage/TasksView.tsx index c943016..02336b3 100644 --- a/frontend/src/features/triage/TasksView.tsx +++ b/frontend/src/features/triage/TasksView.tsx @@ -3138,13 +3138,25 @@ export const TasksView: React.FC = ({ )}
- {/* Quick Add Task to Column */} - {!isSelectedListReadOnly && activeColumns.some((c) => boardIdOf(c) === col.id) && ( -
+ {/* Quick Add Task to Column. In "Alle Aufgaben" a new task has no list: a column only lists + have shows the button greyed out, with a hint where the column is */} + {!isSelectedListReadOnly && ( +
boardIdOf(c) === col.id) + ? undefined + : `Neue Aufgaben hier landen ohne Liste, und dort gibt es diese Spalte nicht. Zum Anlegen die Liste öffnen: ${safeTaskLists + .filter((l) => (Array.isArray(l.columns) ? l.columns : []).some((c) => boardIdOf(c) === col.id)) + .map((l) => `„${l.title}“`) + .join(', ')}` + } + >