feat(app): enhance attach transition

This commit is contained in:
ItzCrazyKns
2025-12-23 18:53:40 +05:30
parent b47f522bf2
commit 24c32ed881
2 changed files with 173 additions and 160 deletions

View File

@@ -16,6 +16,8 @@ import {
} from 'lucide-react'; } from 'lucide-react';
import { Fragment, useRef, useState } from 'react'; import { Fragment, useRef, useState } from 'react';
import { useChat } from '@/lib/hooks/useChat'; import { useChat } from '@/lib/hooks/useChat';
import { AnimatePresence } from 'motion/react';
import { motion } from 'framer-motion';
const Attach = () => { const Attach = () => {
const { files, setFiles, setFileIds, fileIds } = useChat(); const { files, setFiles, setFileIds, fileIds } = useChat();
@@ -53,29 +55,33 @@ const Attach = () => {
return loading ? ( return loading ? (
<div className="active:border-none hover:bg-light-200 hover:dark:bg-dark-200 p-2 rounded-lg focus:outline-none text-black/50 dark:text-white/50 transition duration-200"> <div className="active:border-none hover:bg-light-200 hover:dark:bg-dark-200 p-2 rounded-lg focus:outline-none text-black/50 dark:text-white/50 transition duration-200">
<LoaderCircle size={16} className="text-sky-400 animate-spin" /> <LoaderCircle size={16} className="text-sky-500 animate-spin" />
</div> </div>
) : files.length > 0 ? ( ) : files.length > 0 ? (
<Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg"> <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg">
{({ open }) => (
<>
<PopoverButton <PopoverButton
type="button" type="button"
className="active:border-none hover:bg-light-200 hover:dark:bg-dark-200 p-2 rounded-lg focus:outline-none headless-open:text-black dark:headless-open:text-white text-black/50 dark:text-white/50 active:scale-95 transition duration-200 hover:text-black dark:hover:text-white" className="active:border-none hover:bg-light-200 hover:dark:bg-dark-200 p-2 rounded-lg focus:outline-none headless-open:text-black dark:headless-open:text-white text-black/50 dark:text-white/50 active:scale-95 transition duration-200 hover:text-black dark:hover:text-white"
> >
<File size={16} className="text-sky-400" /> <File size={16} className="text-sky-500" />
</PopoverButton> </PopoverButton>
<Transition <AnimatePresence>
as={Fragment} {open && (
enter="transition ease-out duration-150" <PopoverPanel
enterFrom="opacity-0 translate-y-1" className="absolute z-10 w-64 md:w-[350px] right-0"
enterTo="opacity-100 translate-y-0" static
leave="transition ease-in duration-150" >
leaveFrom="opacity-100 translate-y-0" <motion.div
leaveTo="opacity-0 translate-y-1" initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.1, ease: 'easeOut' }}
className="origin-top-right bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col"
> >
<PopoverPanel className="absolute z-10 w-64 md:w-[350px] right-0">
<div className="bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col">
<div className="flex flex-row items-center justify-between px-3 py-2"> <div className="flex flex-row items-center justify-between px-3 py-2">
<h4 className="text-black dark:text-white font-medium text-sm"> <h4 className="text-black/70 dark:text-white/70 text-sm">
Attached files Attached files
</h4> </h4>
<div className="flex flex-row items-center space-x-4"> <div className="flex flex-row items-center space-x-4">
@@ -102,7 +108,7 @@ const Attach = () => {
}} }}
className="flex flex-row items-center space-x-1 text-black/70 dark:text-white/70 hover:text-black hover:dark:text-white transition duration-200 focus:outline-none" className="flex flex-row items-center space-x-1 text-black/70 dark:text-white/70 hover:text-black hover:dark:text-white transition duration-200 focus:outline-none"
> >
<Trash size={14} /> <Trash size={13} />
<p className="text-xs">Clear</p> <p className="text-xs">Clear</p>
</button> </button>
</div> </div>
@@ -114,15 +120,17 @@ const Attach = () => {
key={i} key={i}
className="flex flex-row items-center justify-start w-full space-x-3 p-3" className="flex flex-row items-center justify-start w-full space-x-3 p-3"
> >
<div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md"> <div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-9 h-9 rounded-md">
<File <File
size={16} size={16}
className="text-black/70 dark:text-white/70" className="text-black/70 dark:text-white/70"
/> />
</div> </div>
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-xs">
{file.fileName.length > 25 {file.fileName.length > 25
? file.fileName.replace(/\.\w+$/, '').substring(0, 25) + ? file.fileName
.replace(/\.\w+$/, '')
.substring(0, 25) +
'...' + '...' +
file.fileExtension file.fileExtension
: file.fileName} : file.fileName}
@@ -130,9 +138,12 @@ const Attach = () => {
</div> </div>
))} ))}
</div> </div>
</div> </motion.div>
</PopoverPanel> </PopoverPanel>
</Transition> )}
</AnimatePresence>
</>
)}
</Popover> </Popover>
) : ( ) : (
<button <button

View File

@@ -1,21 +1,14 @@
import { cn } from '@/lib/utils';
import { import {
Popover, Popover,
PopoverButton, PopoverButton,
PopoverPanel, PopoverPanel,
Transition, Transition,
} from '@headlessui/react'; } from '@headlessui/react';
import { import { File, LoaderCircle, Paperclip, Plus, Trash } from 'lucide-react';
CopyPlus,
File,
LoaderCircle,
Paperclip,
Plus,
Trash,
} from 'lucide-react';
import { Fragment, useRef, useState } from 'react'; import { Fragment, useRef, useState } from 'react';
import { File as FileType } from '../ChatWindow';
import { useChat } from '@/lib/hooks/useChat'; import { useChat } from '@/lib/hooks/useChat';
import { AnimatePresence } from 'motion/react';
import { motion } from 'framer-motion';
const AttachSmall = () => { const AttachSmall = () => {
const { files, setFiles, setFileIds, fileIds } = useChat(); const { files, setFiles, setFileIds, fileIds } = useChat();
@@ -53,29 +46,33 @@ const AttachSmall = () => {
return loading ? ( return loading ? (
<div className="flex flex-row items-center justify-between space-x-1 p-1 "> <div className="flex flex-row items-center justify-between space-x-1 p-1 ">
<LoaderCircle size={20} className="text-sky-400 animate-spin" /> <LoaderCircle size={20} className="text-sky-500 animate-spin" />
</div> </div>
) : files.length > 0 ? ( ) : files.length > 0 ? (
<Popover className="max-w-[15rem] md:max-w-md lg:max-w-lg"> <Popover className="max-w-[15rem] md:max-w-md lg:max-w-lg">
{({ open }) => (
<>
<PopoverButton <PopoverButton
type="button" type="button"
className="flex flex-row items-center justify-between space-x-1 p-1 text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary active:scale-95 transition duration-200 hover:text-black dark:hover:text-white" className="flex flex-row items-center justify-between space-x-1 p-1 text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary active:scale-95 transition duration-200 hover:text-black dark:hover:text-white"
> >
<File size={20} className="text-sky-400" /> <File size={20} className="text-sky-500" />
</PopoverButton> </PopoverButton>
<Transition <AnimatePresence>
as={Fragment} {open && (
enter="transition ease-out duration-150" <PopoverPanel
enterFrom="opacity-0 translate-y-1" className="absolute z-10 w-64 md:w-[350px] bottom-14"
enterTo="opacity-100 translate-y-0" static
leave="transition ease-in duration-150" >
leaveFrom="opacity-100 translate-y-0" <motion.div
leaveTo="opacity-0 translate-y-1" initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.1, ease: 'easeOut' }}
className="origin-bottom-left bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col"
> >
<PopoverPanel className="absolute z-10 w-64 md:w-[350px] bottom-14 -ml-3">
<div className="bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col">
<div className="flex flex-row items-center justify-between px-3 py-2"> <div className="flex flex-row items-center justify-between px-3 py-2">
<h4 className="text-black dark:text-white font-medium text-sm"> <h4 className="text-black/70 dark:text-white/70 font-medium text-sm">
Attached files Attached files
</h4> </h4>
<div className="flex flex-row items-center space-x-4"> <div className="flex flex-row items-center space-x-4">
@@ -92,7 +89,7 @@ const AttachSmall = () => {
multiple multiple
hidden hidden
/> />
<Plus size={18} /> <Plus size={16} />
<p className="text-xs">Add</p> <p className="text-xs">Add</p>
</button> </button>
<button <button
@@ -102,7 +99,7 @@ const AttachSmall = () => {
}} }}
className="flex flex-row items-center space-x-1 text-black/70 dark:text-white/70 hover:text-black hover:dark:text-white transition duration-200" className="flex flex-row items-center space-x-1 text-black/70 dark:text-white/70 hover:text-black hover:dark:text-white transition duration-200"
> >
<Trash size={14} /> <Trash size={13} />
<p className="text-xs">Clear</p> <p className="text-xs">Clear</p>
</button> </button>
</div> </div>
@@ -114,15 +111,17 @@ const AttachSmall = () => {
key={i} key={i}
className="flex flex-row items-center justify-start w-full space-x-3 p-3" className="flex flex-row items-center justify-start w-full space-x-3 p-3"
> >
<div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md"> <div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-9 h-9 rounded-md">
<File <File
size={16} size={16}
className="text-black/70 dark:text-white/70" className="text-black/70 dark:text-white/70"
/> />
</div> </div>
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-xs">
{file.fileName.length > 25 {file.fileName.length > 25
? file.fileName.replace(/\.\w+$/, '').substring(0, 25) + ? file.fileName
.replace(/\.\w+$/, '')
.substring(0, 25) +
'...' + '...' +
file.fileExtension file.fileExtension
: file.fileName} : file.fileName}
@@ -130,9 +129,12 @@ const AttachSmall = () => {
</div> </div>
))} ))}
</div> </div>
</div> </motion.div>
</PopoverPanel> </PopoverPanel>
</Transition> )}
</AnimatePresence>
</>
)}
</Popover> </Popover>
) : ( ) : (
<button <button