styled textarea

This commit is contained in:
Thomas G. Lopes 2025-06-17 15:38:07 +01:00
parent 845127fc1f
commit 31543d778d

View file

@ -180,7 +180,11 @@
return suggestions.length > 0 ? suggestions : undefined; return suggestions.length > 0 ? suggestions : undefined;
}); });
const popover = new Popover(); const popover = new Popover({
floatingConfig: {
computePosition: { placement: 'top' },
},
});
function completeRule(rule: Doc<'user_rules'>) { function completeRule(rule: Doc<'user_rules'>) {
if (!textarea) return; if (!textarea) return;
@ -252,6 +256,9 @@
} }
const textareaSize = new ElementSize(() => textarea); const textareaSize = new ElementSize(() => textarea);
let textareaWrapper = $state<HTMLDivElement>();
const wrapperSize = new ElementSize(() => textareaWrapper);
</script> </script>
<svelte:head> <svelte:head>
@ -278,11 +285,12 @@
></div> ></div>
<div class="flex flex-1 flex-col overflow-y-auto py-2"> <div class="flex flex-1 flex-col overflow-y-auto py-2">
{#each templateConversations as group, index (group.key)} {#each templateConversations as group, index (group.key)}
{@const IconComponent = group.icon}
{#if group.conversations.length > 0} {#if group.conversations.length > 0}
<div class="px-2 py-1" class:mt-2={index > 0}> <div class="px-2 py-1" class:mt-2={index > 0}>
<h3 class="text-heading text-xs font-medium"> <h3 class="text-heading text-xs font-medium">
{#if group.icon} {#if IconComponent}
<svelte:component this={group.icon} class="inline size-3" /> <IconComponent class="inline size-3" />
{/if} {/if}
{group.label} {group.label}
</h3> </h3>
@ -395,18 +403,22 @@
</Sidebar.Trigger> </Sidebar.Trigger>
<div class="relative"> <div class="relative">
<div class="h-screen overflow-y-auto"> <div class="h-screen overflow-y-auto">
<div class="mx-auto flex max-w-3xl flex-col"> <div
class="mx-auto flex max-w-3xl flex-col"
style:padding-bottom={wrapperSize.height + 'px'}
>
{@render children()} {@render children()}
</div> </div>
</div> </div>
<div <div
class="abs-x-center absolute bottom-0 left-1/2 mt-auto flex w-full max-w-3xl flex-col gap-1" class="abs-x-center absolute bottom-0 left-1/2 mt-auto flex w-full max-w-3xl flex-col gap-1"
bind:this={textareaWrapper}
> >
<ModelPicker class=" w-min " /> <div class="border-reflect bg-background/80 rounded-t-[20px] p-2 pb-0 backdrop-blur-lg">
<div class="h-2" aria-hidden="true"></div>
<form <form
class="relative min-h-18 w-full" class="bg-background/50 text-foreground outline-primary/10 dark:bg-secondary/20 relative flex w-full flex-col items-stretch gap-2 rounded-t-xl border border-b-0 border-white/70 px-3 pt-3 pb-3 outline outline-8 dark:border-white/10"
style="box-shadow: rgba(0, 0, 0, 0.1) 0px 80px 50px 0px, rgba(0, 0, 0, 0.07) 0px 50px 30px 0px, rgba(0, 0, 0, 0.06) 0px 30px 15px 0px, rgba(0, 0, 0, 0.04) 0px 15px 8px, rgba(0, 0, 0, 0.04) 0px 6px 4px, rgba(0, 0, 0, 0.02) 0px 2px 2px;"
onsubmit={(e) => { onsubmit={(e) => {
e.preventDefault(); e.preventDefault();
handleSubmit(); handleSubmit();
@ -448,13 +460,15 @@
</div> </div>
</div> </div>
{/if} {/if}
<div class="flex flex-grow flex-col">
<div class="flex flex-grow flex-row items-start">
<!-- TODO: Figure out better autofocus solution --> <!-- TODO: Figure out better autofocus solution -->
<!-- svelte-ignore a11y_autofocus --> <!-- svelte-ignore a11y_autofocus -->
<textarea <textarea
{...pick(popover.trigger, ['id', 'style', 'onfocusout', 'onfocus'])} {...pick(popover.trigger, ['id', 'style', 'onfocusout', 'onfocus'])}
bind:this={textarea} bind:this={textarea}
class="border-input bg-background ring-ring ring-offset-background max-h-64 min-h-18 w-full resize-none overflow-y-auto rounded-lg border p-2 text-sm ring-offset-2 outline-none focus-visible:ring-2" class="text-foreground placeholder:text-muted-foreground/60 max-h-64 min-h-[60px] w-full resize-none bg-transparent text-base leading-6 outline-none disabled:opacity-0"
placeholder="Ask me anything..." placeholder="Type your message here..."
name="message" name="message"
onkeydown={(e) => { onkeydown={(e) => {
if (e.key === 'Enter' && !e.shiftKey && !popover.open) { if (e.key === 'Enter' && !e.shiftKey && !popover.open) {
@ -491,11 +505,28 @@
autocomplete="off" autocomplete="off"
{@attach autosize.attachment} {@attach autosize.attachment}
></textarea> ></textarea>
<Button type="submit" size="icon" class="absolute right-1 bottom-1 size-8"> </div>
<SendIcon /> <div class="mt-2 -mb-px flex w-full flex-row-reverse justify-between">
<div class="-mt-0.5 -mr-0.5 flex items-center justify-center gap-2">
<Button
type="submit"
size="icon"
class="border-reflect button-reflect bg-primary hover:bg-primary/90 active:bg-primary text-primary-foreground relative h-9 w-9 rounded-lg p-2 font-semibold shadow"
>
<SendIcon class="!size-5" />
</Button> </Button>
</div>
<div class="flex flex-col gap-2 pr-2 sm:flex-row sm:items-center">
<ModelPicker />
</div>
</div>
</div>
</form> </form>
<div class="flex w-full place-items-center justify-between gap-2 pb-1"> </div>
</div>
<!-- Credits in bottom-right, only on large screens -->
<div class="fixed right-4 bottom-4 hidden flex-col items-end gap-1 lg:flex">
<span class="text-muted-foreground text-xs"> <span class="text-muted-foreground text-xs">
Crafted by <Icons.Svelte class="inline size-3" /> wizards. Crafted by <Icons.Svelte class="inline size-3" /> wizards.
</span> </span>
@ -504,6 +535,5 @@
</a> </a>
</div> </div>
</div> </div>
</div>
</Sidebar.Inset> </Sidebar.Inset>
</Sidebar.Root> </Sidebar.Root>