Merge pull request #44 from selop/feature/delivery-instructions

Enhances floating generate box UX
This commit is contained in:
Jamie Pine
2026-02-02 17:58:19 -08:00
committed by GitHub
@@ -1,6 +1,6 @@
import { useMatchRoute } from '@tanstack/react-router'; import { useMatchRoute } from '@tanstack/react-router';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { Loader2, MessageSquare, Sparkles } from 'lucide-react'; import { Loader2, SlidersHorizontal, Sparkles } from 'lucide-react';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form'; import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form';
@@ -187,7 +187,7 @@ export function FloatingGenerateBox({
}} }}
> >
<motion.div <motion.div
className="bg-background/30 backdrop-blur-2xl border border-accent/20 rounded-[2rem] shadow-2xl hover:bg-background/40 hover:border-accent/20 transition-all duration-300 overflow-hidden p-3" className="bg-background/30 backdrop-blur-2xl border border-accent/20 rounded-[2rem] shadow-2xl hover:bg-background/40 hover:border-accent/20 transition-all duration-300 p-3"
transition={{ duration: 0.6, ease: 'easeInOut' }} transition={{ duration: 0.6, ease: 'easeInOut' }}
> >
<Form {...form}> <Form {...form}>
@@ -274,7 +274,7 @@ export function FloatingGenerateBox({
field.ref(node); field.ref(node);
} }
}} }}
placeholder="Add delivery instructions..." placeholder="e.g. very happy and excited"
className="resize-none bg-transparent border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0 outline-none ring-0 rounded-2xl text-sm placeholder:text-muted-foreground/60 w-full" className="resize-none bg-transparent border-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:outline-none focus:ring-0 outline-none ring-0 rounded-2xl text-sm placeholder:text-muted-foreground/60 w-full"
style={{ style={{
minHeight: isExpanded ? '100px' : '32px', minHeight: isExpanded ? '100px' : '32px',
@@ -294,6 +294,7 @@ export function FloatingGenerateBox({
</motion.div> </motion.div>
<div className="relative shrink-0"> <div className="relative shrink-0">
<div className="group relative">
<Button <Button
type="submit" type="submit"
disabled={isPending || !selectedProfileId} disabled={isPending || !selectedProfileId}
@@ -306,6 +307,14 @@ export function FloatingGenerateBox({
<Sparkles className="h-4 w-4" /> <Sparkles className="h-4 w-4" />
)} )}
</Button> </Button>
<span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 whitespace-nowrap rounded-md bg-popover px-3 py-1.5 text-xs text-popover-foreground border border-border opacity-0 transition-opacity group-hover:opacity-100 z-[9999]">
{isPending
? 'Generating...'
: !selectedProfileId
? 'Select a voice profile first'
: 'Generate speech'}
</span>
</div>
<AnimatePresence> <AnimatePresence>
{isExpanded && ( {isExpanded && (
<motion.div <motion.div
@@ -315,6 +324,7 @@ export function FloatingGenerateBox({
transition={{ duration: 0.2 }} transition={{ duration: 0.2 }}
className="absolute top-0 right-[calc(100%+0.5rem)]" className="absolute top-0 right-[calc(100%+0.5rem)]"
> >
<div className="group relative">
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
@@ -327,8 +337,12 @@ export function FloatingGenerateBox({
: 'bg-card border border-border hover:bg-background/50', : 'bg-card border border-border hover:bg-background/50',
)} )}
> >
<MessageSquare className="h-4 w-4" /> <SlidersHorizontal className="h-4 w-4" />
</Button> </Button>
<span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 whitespace-nowrap rounded-md bg-popover px-3 py-1.5 text-xs text-popover-foreground border border-border opacity-0 transition-opacity group-hover:opacity-100 z-[9999]">
Fine tune instructions
</span>
</div>
</motion.div> </motion.div>
)} )}
</AnimatePresence> </AnimatePresence>