feat(tasks): dictate into a task's detail notes
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m40s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m40s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b48f0f2d59
commit
ae96aa5f2b
5 files changed
+35
-7
No files matched your search
+7
-1
@@ -6,6 +6,11 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.46.0] - 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Aufgaben: Mikrofon bei den Detailnotizen (rechts in der Kopfzeile). Diktierter Text wird an die Notiz angehängt und öffnet dafür das Bearbeitungsfeld; gespeichert wird wie gewohnt mit „Notiz speichern“.
|
||||||
|
|
||||||
## [0.45.2] - 2026-11-01
|
## [0.45.2] - 2026-11-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
@@ -739,7 +744,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.
|
- 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.
|
- 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.45.2...dev
|
[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.46.0...dev
|
||||||
|
[0.46.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.45.2...v0.46.0
|
||||||
[0.45.2]: https://git.dsit.me/sandrodach/MindSift/compare/v0.45.1...v0.45.2
|
[0.45.2]: https://git.dsit.me/sandrodach/MindSift/compare/v0.45.1...v0.45.2
|
||||||
[0.45.1]: https://git.dsit.me/sandrodach/MindSift/compare/v0.45.0...v0.45.1
|
[0.45.1]: https://git.dsit.me/sandrodach/MindSift/compare/v0.45.0...v0.45.1
|
||||||
[0.45.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.44.0...v0.45.0
|
[0.45.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.44.0...v0.45.0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[](#)
|
[](#)
|
||||||
[](#-schnellstart)
|
[](#-schnellstart)
|
||||||
[](#-deine-daten-gehören-dir)
|
[](#-deine-daten-gehören-dir)
|
||||||
[](CHANGELOG.md)
|
[](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.
|
**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.
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"version": "0.45.2",
|
"version": "0.46.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"version": "0.45.2",
|
"version": "0.46.0",
|
||||||
"license": "Unlicense",
|
"license": "Unlicense",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/inter": "5.3.0",
|
"@fontsource-variable/inter": "5.3.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.45.2",
|
"version": "0.46.0",
|
||||||
"license": "Unlicense",
|
"license": "Unlicense",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
X,
|
X,
|
||||||
Check,
|
Check,
|
||||||
@@ -24,6 +24,7 @@ import { columnDotClass } from './ManageColumnsModal';
|
|||||||
import { UserAutocomplete } from '../UserAutocomplete';
|
import { UserAutocomplete } from '../UserAutocomplete';
|
||||||
import { api, triggerHaptic } from '../../lib/api';
|
import { api, triggerHaptic } from '../../lib/api';
|
||||||
import { MarkdownViewer } from '../../lib/markdown';
|
import { MarkdownViewer } from '../../lib/markdown';
|
||||||
|
import { VoiceInputButton } from '../../components/VoiceInputButton';
|
||||||
import { addDays, joinDue, splitDue } from '../../lib/due';
|
import { addDays, joinDue, splitDue } from '../../lib/due';
|
||||||
|
|
||||||
interface TaskDetailModalProps {
|
interface TaskDetailModalProps {
|
||||||
@@ -90,6 +91,11 @@ const TaskDetailModalContent: React.FC<TaskDetailModalProps & { task: Thought }>
|
|||||||
el.style.height = 'auto';
|
el.style.height = 'auto';
|
||||||
el.style.height = `${el.scrollHeight + 2}px`;
|
el.style.height = `${el.scrollHeight + 2}px`;
|
||||||
}, []);
|
}, []);
|
||||||
|
// Dictated text changes the draft without an input event, so the field grows here as well
|
||||||
|
const notesRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEditingNotes) growNotes(notesRef.current);
|
||||||
|
}, [notesDraft, isEditingNotes, growNotes]);
|
||||||
|
|
||||||
const [newSubtaskTitle, setNewSubtaskTitle] = useState('');
|
const [newSubtaskTitle, setNewSubtaskTitle] = useState('');
|
||||||
const [newTagDraft, setNewTagDraft] = useState('');
|
const [newTagDraft, setNewTagDraft] = useState('');
|
||||||
@@ -814,6 +820,7 @@ const TaskDetailModalContent: React.FC<TaskDetailModalProps & { task: Thought }>
|
|||||||
<FileText className="w-3.5 h-3.5 text-accent" />
|
<FileText className="w-3.5 h-3.5 text-accent" />
|
||||||
<span>Detailnotizen:</span>
|
<span>Detailnotizen:</span>
|
||||||
</label>
|
</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
{!readOnly && !isEditingNotes && task.notes && (
|
{!readOnly && !isEditingNotes && task.notes && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -826,6 +833,18 @@ const TaskDetailModalContent: React.FC<TaskDetailModalProps & { task: Thought }>
|
|||||||
Bearbeiten
|
Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{/* Dictate into the notes: opens the field and appends; saved with "Notiz speichern" */}
|
||||||
|
{!readOnly && (
|
||||||
|
<VoiceInputButton
|
||||||
|
value={isEditingNotes ? notesDraft : task.notes || ''}
|
||||||
|
onChange={(text) => {
|
||||||
|
setNotesDraft(text);
|
||||||
|
setIsEditingNotes(true);
|
||||||
|
}}
|
||||||
|
focusRef={notesRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isEditingNotes ? (
|
{isEditingNotes ? (
|
||||||
@@ -836,7 +855,10 @@ const TaskDetailModalContent: React.FC<TaskDetailModalProps & { task: Thought }>
|
|||||||
placeholder="Detailnotizen eingeben… (Markdown unterstützt)"
|
placeholder="Detailnotizen eingeben… (Markdown unterstützt)"
|
||||||
rows={6}
|
rows={6}
|
||||||
autoFocus
|
autoFocus
|
||||||
ref={growNotes}
|
ref={(el) => {
|
||||||
|
notesRef.current = el;
|
||||||
|
growNotes(el);
|
||||||
|
}}
|
||||||
onInput={(e) => growNotes(e.currentTarget)}
|
onInput={(e) => growNotes(e.currentTarget)}
|
||||||
className="w-full input-field p-2.5 text-xs font-mono leading-relaxed resize-none min-h-[100px] lg:min-h-[260px] overflow-hidden"
|
className="w-full input-field p-2.5 text-xs font-mono leading-relaxed resize-none min-h-[100px] lg:min-h-[260px] overflow-hidden"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user