diff --git a/frontend/src/features/capture/InstantCaptureBar.tsx b/frontend/src/features/capture/InstantCaptureBar.tsx index 8f0d0a1..83b7419 100644 --- a/frontend/src/features/capture/InstantCaptureBar.tsx +++ b/frontend/src/features/capture/InstantCaptureBar.tsx @@ -37,11 +37,29 @@ export const InstantCaptureBar: React.FC = ({ const [isListening, setIsListening] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [justSavedLabel, setJustSavedLabel] = useState(null); + const [isMultiline, setIsMultiline] = useState(false); - const inputRef = useRef(null); + const inputRef = useRef(null); const containerRef = useRef(null); const recognitionRef = useRef(null); + const adjustHeight = (el?: HTMLTextAreaElement | null) => { + const targetEl = el || inputRef.current; + if (!targetEl) return; + targetEl.style.height = 'auto'; + if (targetEl.value) { + const scrollH = targetEl.scrollHeight; + targetEl.style.height = `${Math.min(scrollH, 140)}px`; + setIsMultiline(targetEl.value.includes('\n') || scrollH > 28); + } else { + setIsMultiline(false); + } + }; + + useEffect(() => { + adjustHeight(); + }, [content]); + useEffect(() => { inputRef.current?.focus(); }, [autoFocusTrigger]); @@ -77,6 +95,7 @@ export const InstantCaptureBar: React.FC = ({ inputRef.current?.focus(); } else if (e.key === 'Escape' && document.activeElement === inputRef.current) { setContent(''); + setIsMultiline(false); setShowOptions(false); inputRef.current?.blur(); } @@ -154,12 +173,16 @@ export const InstantCaptureBar: React.FC = ({ // Optimistically clear input immediately so the UI feels instant (<10ms) in all browsers setContent(''); + setIsMultiline(false); setPriority('normal'); setDueDate(''); setTarget('inbox'); setShowOptions(false); setIsSubmitting(true); triggerHaptic(15); + if (inputRef.current) { + inputRef.current.style.height = 'auto'; + } const savedMsg = effectiveTarget === 'task' @@ -210,25 +233,36 @@ export const InstantCaptureBar: React.FC = ({ return (
- {/* Quick-Capture Input Bar (Radius controlled by --radius-pill) */} + {/* Quick-Capture Input Bar (Radius controlled by --radius-pill / multiline) */}
-
+
- setContent(e.target.value)} + onChange={(e) => { + setContent(e.target.value); + adjustHeight(e.target); + }} onKeyDown={(e) => { - if (e.key === 'Enter' && !e.shiftKey) { + if (e.key === 'Enter' && (!e.shiftKey || e.ctrlKey || e.metaKey)) { e.preventDefault(); executeCapture(); } @@ -237,18 +271,23 @@ export const InstantCaptureBar: React.FC = ({ isListening ? 'Ich höre zu…' : target === 'task' - ? 'Neue Aufgabe direkt anlegen… (Enter)' + ? 'Neue Aufgabe direkt anlegen… (Enter / Shift+Enter für Mehrzeiler)' : target === 'list_item' ? `Eintrag direkt zu "${selectedList?.title || 'Liste'}" hinzufügen…` : target === 'document' - ? 'Neue Workspace-Notiz direkt anlegen…' - : 'Quick Dump: Gedanke einfach reinrotzen & später swipen… (C / Enter)' + ? 'Neue Workspace-Notiz direkt anlegen… (Enter / Shift+Enter für Mehrzeiler)' + : 'Quick Dump: Gedanke reinrotzen… (C / Enter, Shift+Enter für Mehrzeiler)' } - className="w-full bg-transparent text-main placeholder-faint text-xs sm:text-sm focus:outline-none" + className="w-full bg-transparent text-main placeholder-faint text-xs sm:text-sm focus:outline-none resize-none leading-5 py-0.5 overflow-y-auto" + style={{ minHeight: '22px', maxHeight: '140px' }} autoComplete="off" /> -
+
{/* Target & Options Toggle Pill */}
) : ( -

+

{activeCard.content}

)} diff --git a/frontend/src/index.css b/frontend/src/index.css index e8ee468..261721a 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -84,6 +84,12 @@ body { border-radius: 9999px !important; } + /* Quick-Capture-Blase bei mehrzeiliger Eingabe (Shift+Enter) */ + .capture-bar-multiline, + .capture-bar-multiline.bg-panel.border { + border-radius: 18px !important; + } + /* Aufgaben-Checkboxen */ .checkbox-square { border-radius: var(--radius-checkbox);