feat(capture): quick dump list row follows the target (task lists for tasks)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-11-01 11:29:06 +01:00
1 parent 83b3f27b3e
commit c851b8e3ba
3 files changed
+131 -9

No files matched your search

@@ -15,8 +15,9 @@ import {
Flame,
Loader2,
} from 'lucide-react';
import { PriorityLevel, SharedList, Thought } from '../../lib/types';
import { PriorityLevel, SharedList, TaskList, Thought } from '../../lib/types';
import { api, triggerHaptic } from '../../lib/api';
import { readViewSession, writeViewSession } from '../../lib/viewSession';
import { useVoiceInput } from '../../lib/useVoiceInput';
import { VoiceWave } from '../../components/VoiceWave';
@@ -47,7 +48,12 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
const [priority, setPriority] = useState<PriorityLevel>('normal');
const [dueDate, setDueDate] = useState('');
const [target, setTarget] = useState<CaptureTarget>(fixedTarget || 'inbox');
const [targetListId, setTargetListId] = useState<string>('');
// Last chosen list per target, for this tab (lib/viewSession)
const remembered = useMemo(() => readViewSession<{ listId: string; taskListId: string }>('capture'), []);
const [targetListId, setTargetListId] = useState<string>(remembered.listId || '');
const [targetTaskListId, setTargetTaskListId] = useState<string>(remembered.taskListId || '');
const [taskLists, setTaskLists] = useState<TaskList[]>([]);
const writableTaskLists = useMemo(() => taskLists.filter((l) => l.permission !== 'viewer'), [taskLists]);
const [showOptions, setShowOptions] = useState(defaultShowOptions || hideTargetPicker);
const [voiceError, setVoiceError] = useState<string | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -104,6 +110,22 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
}
}, [writableLists, targetListId]);
useEffect(() => {
writeViewSession('capture', { listId: targetListId, taskListId: targetTaskListId });
}, [targetListId, targetTaskListId]);
// Task lists only matter once the options are open; loaded each time, so new lists show up
useEffect(() => {
if (!showOptions || hideTargetPicker) return;
api
.getTaskLists()
.then((tl) => setTaskLists(Array.isArray(tl) ? tl : []))
.catch(() => {});
}, [showOptions, hideTargetPicker]);
// A remembered task list that is gone (deleted, access removed) falls back to all tasks
const selectedTaskList = writableTaskLists.find((l) => l.id === targetTaskListId);
// Close dropdown on outside click
useEffect(() => {
if (inlineOptions) return;
@@ -151,7 +173,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
const executeCapture = async (
overrideTarget?: CaptureTarget,
overrideListId?: string
overrideListId?: string,
overrideTaskListId?: string
) => {
const trimmed = content.trim();
if (!trimmed || isSubmitting) return;
@@ -200,6 +223,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
{
target: effectiveTarget,
targetListId: effectiveTarget === 'list_item' ? effectiveListId : '',
taskListId:
effectiveTarget === 'task' ? (overrideTaskListId ?? (selectedTaskList ? selectedTaskList.id : '')) : '',
}
);
onCaptured(created, effectiveTarget);
@@ -219,7 +244,7 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
const selectedList = writableLists.find((l) => l.id === targetListId) || writableLists[0];
const getTargetLabel = () => {
if (target === 'task') return 'Direkt-Aufgabe';
if (target === 'task') return selectedTaskList ? `${selectedTaskList.icon || '📋'} ${selectedTaskList.title}` : 'Direkt-Aufgabe';
if (target === 'list_item') return selectedList ? `${selectedList.icon} ${selectedList.title}` : 'Auf Liste';
if (target === 'document') return 'Direkt-Notiz';
return 'Quick Dump';
@@ -430,7 +455,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
type="button"
onClick={() => {
setTarget('task');
if (content.trim()) {
// With task lists the row below picks one (and saves); otherwise save right away
if (content.trim() && writableTaskLists.length === 0) {
executeCapture('task');
}
}}
@@ -441,7 +467,7 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
}`}
>
<CheckSquare className="w-3.5 h-3.5 text-accent flex-shrink-0" />
<span className="truncate">Direkt als Aufgabe</span>
<span className="truncate">Direkt als Aufgabe{writableTaskLists.length > 0 ? '…' : ''}</span>
</button>
{/* Option 3: Direct List Item */}
@@ -484,15 +510,48 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
</div>
</div>
{/* Optional Sub-Row: Shared List Picker */}
{writableLists.length > 0 && (
{/* Sub-row for a direct task: which task list */}
{target === 'task' && writableTaskLists.length > 0 && (
<div className="pt-2 border-t border-border flex flex-wrap items-center gap-1.5">
<span className="text-muted mr-1 flex items-center gap-1">
<CheckSquare className="w-3 h-3 text-accent" />
Aufgabenliste:
</span>
{[{ id: '', icon: '📥', title: 'Alle Aufgaben' }, ...writableTaskLists].map((tl) => {
const isSelected = (selectedTaskList?.id || '') === tl.id;
return (
<button
key={tl.id || 'all'}
type="button"
onClick={() => {
setTargetTaskListId(tl.id);
if (content.trim()) {
executeCapture('task', undefined, tl.id);
}
}}
className={`min-h-[30px] px-2.5 border rounded-btn text-xs flex items-center gap-1.5 transition-colors cursor-pointer ${
isSelected
? 'bg-accent text-on-accent border-accent font-medium'
: 'bg-canvas border-border text-muted hover:text-main hover:bg-panel-hover'
}`}
>
<span>{tl.icon || '📋'}</span>
<span>{tl.title}</span>
</button>
);
})}
</div>
)}
{/* Sub-row for a list item: which list (shopping, checklist …) */}
{target === 'list_item' && writableLists.length > 0 && (
<div className="pt-2 border-t border-border flex flex-wrap items-center gap-1.5">
<span className="text-muted mr-1 flex items-center gap-1">
<ShoppingCart className="w-3 h-3 text-accent" />
Liste:
</span>
{writableLists.map((lst) => {
const isSelected = target === 'list_item' && targetListId === lst.id;
const isSelected = targetListId === lst.id;
return (
<button
key={lst.id}