diff --git a/CHANGELOG.md b/CHANGELOG.md index e029955..7b132fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ## [Unreleased] +## [0.60.0] - 2026-11-02 + +### Changed +- Desktop: Das Fenster scrollt nicht mehr als Ganzes. Kopfleiste und Fußzeile stehen fest, nur der Bereich dazwischen scrollt; der Scrollbalken beginnt unter der Kopfleiste. Damit verschiebt sich beim Seitenwechsel nichts mehr, und der Rand neben der Kopfleiste braucht keine Sonderbehandlung. +- Triage am Desktop: Kachel und Knöpfe bleiben stehen, die Warteschlange füllt den restlichen Platz und scrollt in sich. + +### Fixed +- Chrome: Die Kopfleiste scrollte seit 0.59.3 beim Scrollen mit aus dem Bild. + ## [0.59.3] - 2026-11-02 ### Fixed @@ -869,7 +878,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.59.3...dev +[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.60.0...dev +[0.60.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.3...v0.60.0 [0.59.3]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.2...v0.59.3 [0.59.2]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.1...v0.59.2 [0.59.1]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.0...v0.59.1 diff --git a/README.md b/README.md index 780f83c..8e9de70 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.59.3-16a34a?style=flat-square)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v0.60.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 f61c721..2f5f1bd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "mindsift-frontend", - "version": "0.59.3", + "version": "0.60.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mindsift-frontend", - "version": "0.59.3", + "version": "0.60.0", "license": "AGPL-3.0-only", "dependencies": { "@fontsource-variable/inter": "5.3.0", diff --git a/frontend/package.json b/frontend/package.json index 74d6e48..4ef3748 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "mindsift-frontend", "private": true, - "version": "0.59.3", + "version": "0.60.0", "license": "AGPL-3.0-only", "type": "module", "scripts": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index aa9439b..071770e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -206,21 +206,12 @@ export const App: React.FC = () => { const [showProfileMenu, setShowProfileMenu] = useState(false); const connection = useConnectionState(); - // Height of the app header as --app-header-h: the page background paints the header colour up to there, - // so the scrollbar gutter on the right continues the header instead of showing the page colour - const [headerEl, setHeaderEl] = useState(null); + // Desktop: the window does not scroll; this area under the header does (phones keep the window scroll) + const scrollAreaRef = useRef(null); + // A new page starts at its top (the desktop scroll area would otherwise keep the old page's position) useEffect(() => { - if (!headerEl || typeof ResizeObserver === 'undefined') return; - const root = document.documentElement; - const update = () => root.style.setProperty('--app-header-h', `${headerEl.offsetHeight}px`); - update(); - const observer = new ResizeObserver(update); - observer.observe(headerEl); - return () => { - observer.disconnect(); - root.style.removeProperty('--app-header-h'); - }; - }, [headerEl]); + scrollAreaRef.current?.scrollTo?.({ top: 0 }); + }, [activeTab]); const [showAbout, setShowAbout] = useState(false); const [showTriageTrash, setShowTriageTrash] = useState(false); const { update: availableUpdate, dismiss: dismissUpdate } = useUpdateCheck(); @@ -848,7 +839,7 @@ export const App: React.FC = () => { if (isPhoneWidth()) { openMobileTriageCapture(); } else { - window.scrollTo({ top: 0, behavior: 'smooth' }); + scrollAreaRef.current?.scrollTo?.({ top: 0, behavior: 'smooth' }); setCaptureFocusCount((c) => c + 1); } }; @@ -920,13 +911,12 @@ export const App: React.FC = () => { return (
{/* Top Header Bar: Floating on mobile, solid panel on desktop */}
{/* Mobile Header: Floating Bar with Logo Action Dropdown Left & Profile Avatar Right */} @@ -1306,14 +1296,36 @@ export const App: React.FC = () => { )} {/* Main Container */} - {/* The workspace fills the window exactly and scrolls only inside the note, never the page */} + {/* Desktop: the window never scrolls, only this area under the header (room for the scrollbar kept on + both sides, so the content stays centred under the header and nothing shifts between pages). The + workspace fills it exactly and scrolls only inside the note. Phones scroll the window as before. */} +
setActiveTab('triage')}> -
+
{activeTab === 'triage' && ( {
+
= ({ setKanbanColHeight(null); return; } - // From the board's top to the window's bottom; then take back what still overflows (footer, paddings) - const top = el.getBoundingClientRect().top + window.scrollY; - setKanbanColHeight(Math.max(320, window.innerHeight - top - 16)); + // From the board's top to the bottom of the app's scroll area (the desktop window itself does not + // scroll); then take back what still overflows (paddings) + const area = el.closest('[data-app-scroll]'); + const areaTop = area ? area.getBoundingClientRect().top - area.scrollTop : -window.scrollY; + const areaHeight = area ? area.clientHeight : window.innerHeight; + const top = el.getBoundingClientRect().top - areaTop; + setKanbanColHeight(Math.max(320, areaHeight - top - 16)); requestAnimationFrame(() => { - const over = document.documentElement.scrollHeight - window.innerHeight; + const over = area ? area.scrollHeight - area.clientHeight : document.documentElement.scrollHeight - window.innerHeight; if (over > 0) setKanbanColHeight((h) => (h ? Math.max(320, h - over) : h)); }); }; diff --git a/frontend/src/features/triage/TriageDeck.tsx b/frontend/src/features/triage/TriageDeck.tsx index ff0c62f..eca3de5 100644 --- a/frontend/src/features/triage/TriageDeck.tsx +++ b/frontend/src/features/triage/TriageDeck.tsx @@ -488,7 +488,9 @@ export const TriageDeck: React.FC = ({ } return ( -
+ // Desktop: a column filling the height under the header; card and buttons keep their size, the queue + // takes the rest and scrolls inside (the page only scrolls when the window is too low even for that) +
{/* Top Deck Status & Undo Bar */}
@@ -931,7 +933,7 @@ export const TriageDeck: React.FC = ({ {/* Waiting Quick Dump Queue List (Touch-sized & Swipeable Left/Right) */} {cards.length > 1 && ( -
+
{/* Phones: the queue stays folded so the card and its buttons fit on the screen */} {/* Folds open/closed on phones; always open from sm upwards */}
-
+
@@ -970,7 +972,7 @@ export const TriageDeck: React.FC = ({
-
+
{cards.slice(1).map((item) => (