diff --git a/CHANGELOG.md b/CHANGELOG.md index dde1774..f468745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ## [0.16.1] - 2026-10-31 +### Changed +- README-Screenshots aufgeräumt: Nur noch das Titelbild ist diagonal hell/dunkel geteilt, Handy und übrige Ansichten zeigen jeweils ein Theme. Neu ist ein Raster mit den Farbfamilien Fjord, Terrakotta, Polarized und Suri (je hell/dunkel diagonal, im Kanban-Board). + ### Fixed - Einstellungen am Handy: Bei der Tageszusammenfassung ragten die Kanal-Schalter (E-Mail, Discord, Webhook, Push) rechts aus dem Bild. Am Handy stehen sie jetzt zu zweit untereinander. diff --git a/README.md b/README.md index f83ce25..feae067 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.15.0-16a34a?style=flat-square)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/Version-v0.16.1-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. @@ -14,7 +14,7 @@ MindSift Triage am Desktop, links hell, rechts dunkel

-Alle Screenshots zeigen links das helle und rechts das dunkle Theme. +Links das helle, rechts das dunkle Theme. [Philosophie](#-die-philosophie) • [Funktionen](#-funktionen) • [Schnellstart](#-schnellstart) • [Betrieb](#-betrieb--konfiguration) • [Entwicklung](#-entwicklung) • [Dokumentation](#-dokumentation) @@ -43,9 +43,9 @@ Die meisten Notiz- und Aufgaben-Apps verlangen Struktur im falschen Moment: Wenn * Papierkorb mit Wiederherstellen.

- MindSift Triage am Smartphone + MindSift Triage am Smartphone, helles Theme    - MindSift Notiz am Smartphone + MindSift Notiz am Smartphone, dunkles Theme

### ✅ Aufgaben & Kanban @@ -115,6 +115,17 @@ Technik dahinter: [Doku/modules/collaboration.md](Doku/modules/collaboration.md) * **Fünf Farbfamilien** mit je einer hellen und dunklen Variante: Klassik, Fjord, Terrakotta, Polarized, Suri. Hell/Dunkel auf Wunsch „Wie System“, dazu eine eigene Akzentfarbe, Ecken rund oder eckig und Knöpfe mit oder ohne Rahmen (pro Gerät). Für eigene Themes gibt es einen Theme-Manager (eine CSS-Datei). * **Installierbar als App (PWA)** auf Smartphone und Desktop. Sie startet auch ohne Netz mit dem zuletzt geladenen Stand; offline erfasste Gedanken und abgehakte Aufgaben oder Listeneinträge werden nachgereicht, sobald die Verbindung wieder da ist. + + + + + + + + + +
Farbfamilie Fjord, links hell, rechts dunkel
Fjord
Farbfamilie Terrakotta, links hell, rechts dunkel
Terrakotta
Farbfamilie Polarized, links hell, rechts dunkel
Polarized
Farbfamilie Suri, links hell, rechts dunkel
Suri
+ ### 🔌 Integrationen * **Eingehend (API-Key):** `POST /api/v1/webhooks/ingest` legt Gedanken, Aufgaben oder Listeneinträge aus Smarthome, Skripten oder Automationen an. diff --git a/e2e/screenshots.mjs b/e2e/screenshots.mjs index e5dc4c5..aa9c590 100644 --- a/e2e/screenshots.mjs +++ b/e2e/screenshots.mjs @@ -1,6 +1,7 @@ // Takes the README screenshots from a fresh server in demo mode (sample data of admin/admin). -// Every picture is taken twice in the same state – light and dark theme – and the two halves are -// joined along a slanted diagonal (light left, dark right). +// The title picture and the colour-family grid are taken twice in the same state – light and dark +// theme – and joined along a slanted diagonal (light left, dark right); the others are plain light +// or dark pictures. // Usage: e2e/screenshots.sh (builds the image) or MINDSIFT_URL=… SHOTS_DIR=… node screenshots.mjs // Theme pair: SHOT_LIGHT / SHOT_DARK (default: light / dark, the "Klassik" family) import fs from 'node:fs'; @@ -13,6 +14,13 @@ const DARK = process.env.SHOT_DARK || 'dark'; const DESKTOP = { viewport: { width: 1518, height: 886 }, deviceScaleFactor: 2 }; const MOBILE = { viewport: { width: 390, height: 844 }, deviceScaleFactor: 2, isMobile: true, hasTouch: true }; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +// Colour families for the theme grid in the README (Klassik is the title picture) +const FAMILIES = [ + ['fjord', 'fjord', 'fjord-night'], + ['terracotta', 'terracotta', 'terracotta-night'], + ['polarized', 'polarized-light', 'polarized'], + ['suri', 'suri-light', 'suri'], +]; async function login(user) { const res = await fetch(`${BASE}/api/v1/auth/login`, { @@ -57,10 +65,11 @@ async function setTheme(page, id, dark) { } let composer; -// Light picture on the left of the diagonal, dark on the right, a thin line between them -async function compose(lightPng, darkPng, file) { +// Light picture on the left of the diagonal, dark on the right, a thin line between them; +// scale < 1 shrinks the result (small pictures of the theme grid) +async function compose(lightPng, darkPng, file, scale = 1) { const dataUrl = await composer.evaluate( - async ([light, dark]) => { + async ([light, dark, scale]) => { const load = (b64) => new Promise((resolve) => { const img = new Image(); @@ -68,13 +77,14 @@ async function compose(lightPng, darkPng, file) { img.src = 'data:image/png;base64,' + b64; }); const [a, b] = await Promise.all([load(light), load(dark)]); - const w = a.naturalWidth; - const h = a.naturalHeight; + const w = Math.round(a.naturalWidth * scale); + const h = Math.round(a.naturalHeight * scale); const canvas = document.createElement('canvas'); canvas.width = w; canvas.height = h; const ctx = canvas.getContext('2d'); - ctx.drawImage(b, 0, 0); + ctx.imageSmoothingQuality = 'high'; + ctx.drawImage(b, 0, 0, w, h); const top = w * 0.58; const bottom = w * 0.42; ctx.save(); @@ -85,7 +95,7 @@ async function compose(lightPng, darkPng, file) { ctx.lineTo(0, h); ctx.closePath(); ctx.clip(); - ctx.drawImage(a, 0, 0); + ctx.drawImage(a, 0, 0, w, h); ctx.restore(); ctx.strokeStyle = 'rgba(255, 255, 255, 0.9)'; ctx.lineWidth = Math.max(2, w / 600); @@ -97,19 +107,30 @@ async function compose(lightPng, darkPng, file) { ctx.stroke(); return canvas.toDataURL('image/png'); }, - [lightPng.toString('base64'), darkPng.toString('base64')] + [lightPng.toString('base64'), darkPng.toString('base64'), scale] ); fs.writeFileSync(`${OUT}/${file}`, Buffer.from(dataUrl.split(',')[1], 'base64')); } -async function shot(page, file) { +// Diagonal light/dark picture +async function shot(page, file, { light = LIGHT, dark = DARK, scale = 1 } = {}) { await sleep(800); // animations await page.mouse.move(0, 0); - await setTheme(page, LIGHT, false); - const light = await page.screenshot(); - await setTheme(page, DARK, true); - const dark = await page.screenshot(); - await compose(light, dark, file); + await setTheme(page, light, false); + const lightPng = await page.screenshot(); + await setTheme(page, dark, true); + const darkPng = await page.screenshot(); + await compose(lightPng, darkPng, file, scale); + console.log(`OK ${file}`); +} + +// Plain picture in one theme ('light' or 'dark' of the chosen pair) +async function plain(page, file, mode) { + await sleep(800); + await page.mouse.move(0, 0); + if (mode === 'light') await setTheme(page, LIGHT, false); + else await setTheme(page, DARK, true); + await page.screenshot({ path: `${OUT}/${file}` }); console.log(`OK ${file}`); } @@ -126,7 +147,11 @@ const main = async () => { await tab(page, 'Aufgaben'); await page.getByText('Homelab', { exact: true }).first().click().catch(() => {}); await page.getByRole('button', { name: /Kanban|Board/ }).first().click().catch(() => {}); - await shot(page, 'aufgaben_desktop.png'); + await plain(page, 'aufgaben_desktop.png', 'dark'); + // Colour families: the board fills the width, so both halves of the diagonal show content + for (const [family, light, dark] of FAMILIES) { + await shot(page, `Theme_${family}.png`, { light, dark, scale: 0.5 }); + } // The demo user edits a bullet of the shared note, so the screenshot shows lock and presence const other = await open(browser, user, DESKTOP); @@ -142,7 +167,7 @@ const main = async () => { await page.waitForFunction(() => document.querySelectorAll('textarea').length > 5, null, { timeout: 10000 }); await page.getByText('User', { exact: false }).first().waitFor({ timeout: 15000 }).catch(() => {}); await sleep(2000); - await shot(page, 'workspace_desktop.png'); + await plain(page, 'workspace_desktop.png', 'light'); // Journal: a few days with entries, the calendar in the sidebar const H = { Authorization: `Bearer ${admin}`, 'Content-Type': 'application/json' }; @@ -171,22 +196,22 @@ const main = async () => { await page.getByRole('button', { name: 'Heute' }).click().catch(() => {}); await page.mouse.click(1000, 860); await sleep(2500); - await shot(page, 'journal_desktop.png'); + await plain(page, 'journal_desktop.png', 'dark'); await page.getByRole('button', { name: 'Journal', exact: true }).click(); // close it again await tab(page, 'Listen'); await page.getByText('Wocheneinkauf', { exact: true }).first().click().catch(() => {}); - await shot(page, 'Listen_desktop.png'); + await plain(page, 'Listen_desktop.png', 'light'); const mobile = await open(browser, admin, MOBILE); await mobile.getByText('Später im Browser weiter nutzen').click({ timeout: 5000 }).catch(() => {}); // install prompt - await shot(mobile, 'Mobile_Triage.png'); + await plain(mobile, 'Mobile_Triage.png', 'light'); await tab(mobile, 'Workspace'); await sleep(600); await mobile.getByText(/^Homelab 2\.0/).first().click(); await sleep(1500); - await shot(mobile, 'Mobile_Workspace.png'); + await plain(mobile, 'Mobile_Workspace.png', 'dark'); await browser.close(); }; diff --git a/e2e/screenshots.sh b/e2e/screenshots.sh index 195b913..0818b7f 100755 --- a/e2e/screenshots.sh +++ b/e2e/screenshots.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Builds MindSift, starts it in demo mode with a fresh database and renews the README screenshots -# in screenshots/ (light and dark theme joined along a diagonal). Requires podman (or docker via -# ENGINE=docker). Usage: e2e/screenshots.sh, other theme pair: SHOT_LIGHT=fjord SHOT_DARK=fjord-night +# in screenshots/ (title picture and colour-family grid: light and dark joined along a diagonal). +# Requires podman (or docker via ENGINE=docker). Usage: e2e/screenshots.sh, other theme pair: SHOT_LIGHT=fjord SHOT_DARK=fjord-night set -euo pipefail ENGINE="${ENGINE:-podman}" ROOT="$(cd "$(dirname "$0")/.." && pwd)" diff --git a/screenshots/Listen_desktop.png b/screenshots/Listen_desktop.png index 28bfcd4..a710cf9 100644 Binary files a/screenshots/Listen_desktop.png and b/screenshots/Listen_desktop.png differ diff --git a/screenshots/Mobile_Triage.png b/screenshots/Mobile_Triage.png index 2277c1e..f4a0fbc 100644 Binary files a/screenshots/Mobile_Triage.png and b/screenshots/Mobile_Triage.png differ diff --git a/screenshots/Mobile_Workspace.png b/screenshots/Mobile_Workspace.png index 02f0640..4eb91f3 100644 Binary files a/screenshots/Mobile_Workspace.png and b/screenshots/Mobile_Workspace.png differ diff --git a/screenshots/Theme_fjord.png b/screenshots/Theme_fjord.png new file mode 100644 index 0000000..619d1e6 Binary files /dev/null and b/screenshots/Theme_fjord.png differ diff --git a/screenshots/Theme_polarized.png b/screenshots/Theme_polarized.png new file mode 100644 index 0000000..6b679e8 Binary files /dev/null and b/screenshots/Theme_polarized.png differ diff --git a/screenshots/Theme_suri.png b/screenshots/Theme_suri.png new file mode 100644 index 0000000..95735b4 Binary files /dev/null and b/screenshots/Theme_suri.png differ diff --git a/screenshots/Theme_terracotta.png b/screenshots/Theme_terracotta.png new file mode 100644 index 0000000..6fa4fab Binary files /dev/null and b/screenshots/Theme_terracotta.png differ diff --git a/screenshots/Triage_desktop.png b/screenshots/Triage_desktop.png index fadce1b..8b5bc85 100644 Binary files a/screenshots/Triage_desktop.png and b/screenshots/Triage_desktop.png differ diff --git a/screenshots/aufgaben_desktop.png b/screenshots/aufgaben_desktop.png index 7459b86..14fa99f 100644 Binary files a/screenshots/aufgaben_desktop.png and b/screenshots/aufgaben_desktop.png differ diff --git a/screenshots/journal_desktop.png b/screenshots/journal_desktop.png index a71b549..7beb4fa 100644 Binary files a/screenshots/journal_desktop.png and b/screenshots/journal_desktop.png differ diff --git a/screenshots/workspace_desktop.png b/screenshots/workspace_desktop.png index 30eb193..1363ec5 100644 Binary files a/screenshots/workspace_desktop.png and b/screenshots/workspace_desktop.png differ