Dev #2

Merged
sandrodach merged 37 commits from dev into main 2026-10-25 12:14:23 +01:00
4 changed files with 61 additions and 16 deletions
Showing only changes of commit e6a791bcca - Show all commits

No files matched your search

@@ -37,11 +37,29 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
const [isListening, setIsListening] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [justSavedLabel, setJustSavedLabel] = useState<string | null>(null);
const [isMultiline, setIsMultiline] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const containerRef = useRef<HTMLFormElement>(null);
const recognitionRef = useRef<any>(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<InstantCaptureBarProps> = ({
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<InstantCaptureBarProps> = ({
// 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<InstantCaptureBarProps> = ({
return (
<div className="w-full">
<form ref={containerRef} onSubmit={handleSubmit} className="relative">
{/* Quick-Capture Input Bar (Radius controlled by --radius-pill) */}
{/* Quick-Capture Input Bar (Radius controlled by --radius-pill / multiline) */}
<div
className={`flex items-center h-9 pl-1.5 pr-1.5 bg-panel border capture-pill rounded-full transition-colors duration-150 ${
className={`flex ${
isMultiline ? 'items-end py-1.5' : 'items-center h-9'
} pl-1.5 pr-1.5 bg-panel border capture-pill ${
isMultiline ? 'capture-bar-multiline' : 'rounded-full'
} transition-all duration-150 ${
isListening
? 'border-accent bg-panel'
: 'border-border focus-within:border-accent'
}`}
>
<div className="w-6 h-6 capture-pill rounded-full bg-accent text-on-accent flex items-center justify-center mr-2 flex-shrink-0">
<div
className={`w-6 h-6 capture-pill rounded-full bg-accent text-on-accent flex items-center justify-center mr-2 flex-shrink-0 ${
isMultiline ? 'self-start mt-1' : ''
}`}
>
<Sparkles className="w-3 h-3" />
</div>
<input
<textarea
ref={inputRef}
type="text"
rows={1}
value={content}
onChange={(e) => 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<InstantCaptureBarProps> = ({
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"
/>
<div className="flex items-center gap-1 ml-2 flex-shrink-0">
<div
className={`flex items-center gap-1 ml-2 flex-shrink-0 ${
isMultiline ? 'self-end mb-0.5' : ''
}`}
>
{/* Target & Options Toggle Pill */}
<button
type="button"
+2 -2
View File
@@ -645,7 +645,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
className="panel-surface p-2.5 space-y-2 hover:border-strong transition-colors"
>
<div className="flex items-start justify-between gap-2">
<p className="text-xs font-medium text-main break-words flex-1 leading-snug">
<p className="text-xs font-medium text-main break-words flex-1 leading-snug whitespace-pre-wrap">
{task.content}
</p>
<button
@@ -752,7 +752,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
className="bg-panel border border-accent-border p-2.5 space-y-2 hover:border-accent transition-colors"
>
<div className="flex items-start justify-between gap-2">
<p className="text-xs font-medium text-main break-words flex-1 leading-snug">
<p className="text-xs font-medium text-main break-words flex-1 leading-snug whitespace-pre-wrap">
{task.content}
</p>
<button
+1 -1
View File
@@ -400,7 +400,7 @@ export const TriageDeck: React.FC<TriageDeckProps> = ({
</div>
</div>
) : (
<p className="text-base sm:text-xl font-medium text-main leading-relaxed break-words">
<p className="text-base sm:text-xl font-medium text-main leading-relaxed break-words whitespace-pre-wrap">
{activeCard.content}
</p>
)}
+6
View File
@@ -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);