mirror of
https://github.com/hoornet/vega.git
synced 2026-07-25 01:38:11 -07:00
feat: collapse compose box to a single line when idle (#6)
The posting area was always full-height, which felt oversized (reported on macOS). It now shows a single line when empty and unfocused, and expands to full height + toolbar on focus or when it has content. Uses focus-within blur semantics so clicking the emoji/attach/poll/post controls doesn't collapse it mid-interaction, and resets the auto-resize inline height on collapse. A saved draft starts expanded. Part of #6
This commit is contained in:
@@ -25,9 +25,23 @@ export function ComposeBox({ onPublished, onNoteInjected }: { onPublished?: () =
|
||||
const [showEmoji, setShowEmoji] = useState(false);
|
||||
const [isPoll, setIsPoll] = useState(false);
|
||||
const [pollOptions, setPollOptions] = useState<string[]>(["", ""]);
|
||||
const [focused, setFocused] = useState(false);
|
||||
const autoResize = useAutoResize(3, 12);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
// Collapse the compose box to a single line when it's idle (empty + not
|
||||
// focused), expand to full height + toolbar on focus or when there's
|
||||
// content. Keeps the feed header compact (issue #6).
|
||||
const expanded = focused || text.trim().length > 0 || attachments.length > 0 || isPoll;
|
||||
|
||||
// When the box collapses, clear the inline height useAutoResize set so the
|
||||
// rows={1} attribute governs the single-line height again.
|
||||
useEffect(() => {
|
||||
if (!expanded && textareaRef.current) {
|
||||
textareaRef.current.style.height = "";
|
||||
}
|
||||
}, [expanded]);
|
||||
|
||||
const { profile, npub } = useUserStore();
|
||||
const avatar = typeof profile?.picture === "string" ? profile.picture : undefined;
|
||||
const name = profileName(profile, npub ? shortenPubkey(npub) : "");
|
||||
@@ -244,7 +258,15 @@ export function ComposeBox({ onPublished, onNoteInjected }: { onPublished?: () =
|
||||
</div>
|
||||
|
||||
{/* Input area */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<div
|
||||
className="flex-1 min-w-0"
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={(e) => {
|
||||
// Keep expanded while focus moves to a child control (emoji,
|
||||
// attach, poll, post); only collapse when focus truly leaves.
|
||||
if (!e.currentTarget.contains(e.relatedTarget as Node)) setFocused(false);
|
||||
}}
|
||||
>
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
data-compose
|
||||
@@ -255,7 +277,7 @@ export function ComposeBox({ onPublished, onNoteInjected }: { onPublished?: () =
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
placeholder="What's on your mind?"
|
||||
rows={3}
|
||||
rows={expanded ? 3 : 1}
|
||||
className="w-full bg-transparent text-text text-[13px] placeholder:text-text-dim resize-none focus:outline-none leading-relaxed"
|
||||
/>
|
||||
|
||||
@@ -298,6 +320,7 @@ export function ComposeBox({ onPublished, onNoteInjected }: { onPublished?: () =
|
||||
<p className="text-danger text-[11px] mb-2">{error}</p>
|
||||
)}
|
||||
|
||||
{expanded && (
|
||||
<div className="flex flex-wrap items-center justify-between gap-y-1 mt-1">
|
||||
<span className={`text-[10px] ${overLimit ? "text-danger" : warnLimit ? "text-warning" : "text-text-dim"}`}>
|
||||
{uploading ? (
|
||||
@@ -353,6 +376,7 @@ export function ComposeBox({ onPublished, onNoteInjected }: { onPublished?: () =
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user