This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

web/components: give the textarea a floor instead of a ceiling

max-h-64 capped the field; min-h-64 gives it a comfortable starting height and
lets it grow. the text inset also moves from the wrapper onto the textarea, so
the scrollbar and the resize handle sit flush against the border rather than
floating inside the wrapper's padding — the icon slots and the loading spinner
now carry their own inset instead.

Signed-off-by: eti <eti@eti.tf>

author
eti
committer
dawn
date (Jul 31, 2026, 10:57 PM +0300) commit 1789fa54 parent 6fc71410 change-id vmxnkwur
+20 -5
+20 -5
web/src/lib/components/ui/Textarea.svelte
··· 3 3 4 4 export const textareaField = tv({ 5 5 slots: { 6 - root: "relative flex max-h-64 items-start gap-1 rounded border bg-background-default px-2.5 py-2 transition-colors", 6 + root: "relative flex min-h-64 items-start gap-1 rounded border bg-background-default transition-colors", 7 7 textarea: 8 - "min-h-24 flex-1 bg-transparent text-sm leading-6 outline-none placeholder:text-foreground-placeholder read-only:resize-none disabled:cursor-not-allowed disabled:resize-none" 8 + "min-h-24 flex-1 self-stretch bg-transparent py-2 text-sm leading-6 outline-none placeholder:text-foreground-placeholder read-only:resize-none disabled:cursor-not-allowed disabled:resize-none" 9 9 }, 10 10 variants: { 11 11 error: { ··· 77 77 }: Props = $props(); 78 78 79 79 const { root, textarea } = $derived(textareaField({ error, disabled, readonly, resizeable })); 80 + 81 + // The root no longer carries the text inset (so the scrollbar/resize handle can sit flush 82 + // against the border) — the textarea itself owns its horizontal padding, collapsing to 0 on 83 + // whichever side an icon (or the loading spinner) already provides the inset instead. 84 + const textareaPadding = $derived( 85 + [iconLeft ? "" : "pl-2.5", loading ? "pr-[1.875rem]" : iconRight ? "" : "pr-2.5"] 86 + .filter(Boolean) 87 + .join(" ") 88 + ); 80 89 </script> 81 90 82 91 <div class={root({ class: className })}> 83 92 {#if iconLeft} 84 93 {@const IconLeft = iconLeft} 85 - <IconLeft class="mt-0.5 mr-1 size-4 shrink-0 text-foreground-subtle" aria-hidden="true" /> 94 + <IconLeft 95 + class="mt-2.5 mr-1 ml-2.5 size-4 shrink-0 text-foreground-subtle" 96 + aria-hidden="true" 97 + /> 86 98 {/if} 87 99 <textarea 88 100 bind:this={element} ··· 91 103 {readonly} 92 104 aria-invalid={error} 93 105 aria-busy={loading} 94 - class={textarea({ class: loading ? "pr-5" : undefined })} 106 + class={textarea({ class: textareaPadding })} 95 107 {...rest}></textarea> 96 108 {#if loading} 97 109 <Spinner class="absolute top-2 right-2.5 size-4" /> 98 110 {:else if iconRight} 99 111 {@const IconRight = iconRight} 100 - <IconRight class="mt-0.5 ml-1 size-4 shrink-0 text-foreground-subtle" aria-hidden="true" /> 112 + <IconRight 113 + class="mt-2.5 mr-2.5 ml-1 size-4 shrink-0 text-foreground-subtle" 114 + aria-hidden="true" 115 + /> 101 116 {/if} 102 117 </div>