Improve sidebar, new chat, and share dialog (#190)

This commit is contained in:
Jared Palmer 2023-12-04 12:42:53 -05:00 committed by GitHub
parent 35e83dc87e
commit be90a40427
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 598 additions and 217 deletions

View file

@ -1,11 +1,10 @@
'use client'
import * as React from 'react'
import { useRouter } from 'next/navigation'
import * as React from 'react'
import { toast } from 'react-hot-toast'
import { type Chat, ServerActionResult } from '@/lib/types'
import { cn, formatDate } from '@/lib/utils'
import { ServerActionResult, type Chat } from '@/lib/types'
import {
AlertDialog,
AlertDialogAction,
@ -17,22 +16,8 @@ import {
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import {
IconShare,
IconSpinner,
IconTrash,
IconUsers
} from '@/components/ui/icons'
import Link from 'next/link'
import { badgeVariants } from '@/components/ui/badge'
import { IconShare, IconSpinner, IconTrash } from '@/components/ui/icons'
import { ChatShareDialog } from '@/components/chat-share-dialog'
import {
Tooltip,
TooltipContent,
@ -42,7 +27,7 @@ import {
interface SidebarActionsProps {
chat: Chat
removeChat: (args: { id: string; path: string }) => ServerActionResult<void>
shareChat: (chat: Chat) => ServerActionResult<Chat>
shareChat: (id: string) => ServerActionResult<Chat>
}
export function SidebarActions({
@ -50,34 +35,10 @@ export function SidebarActions({
removeChat,
shareChat
}: SidebarActionsProps) {
const router = useRouter()
const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)
const [shareDialogOpen, setShareDialogOpen] = React.useState(false)
const [isRemovePending, startRemoveTransition] = React.useTransition()
const [isSharePending, startShareTransition] = React.useTransition()
const router = useRouter()
const copyShareLink = React.useCallback(async (chat: Chat) => {
if (!chat.sharePath) {
return toast.error('Could not copy share link to clipboard')
}
const url = new URL(window.location.href)
url.pathname = chat.sharePath
navigator.clipboard.writeText(url.toString())
setShareDialogOpen(false)
toast.success('Share link copied to clipboard', {
style: {
borderRadius: '10px',
background: '#333',
color: '#fff',
fontSize: '14px'
},
iconTheme: {
primary: 'white',
secondary: 'black'
}
})
}, [])
return (
<>
@ -86,7 +47,7 @@ export function SidebarActions({
<TooltipTrigger asChild>
<Button
variant="ghost"
className="h-6 w-6 p-0 hover:bg-background"
className="w-6 h-6 p-0 hover:bg-background"
onClick={() => setShareDialogOpen(true)}
>
<IconShare />
@ -99,7 +60,7 @@ export function SidebarActions({
<TooltipTrigger asChild>
<Button
variant="ghost"
className="h-6 w-6 p-0 hover:bg-background"
className="w-6 h-6 p-0 hover:bg-background"
disabled={isRemovePending}
onClick={() => setDeleteDialogOpen(true)}
>
@ -110,68 +71,13 @@ export function SidebarActions({
<TooltipContent>Delete chat</TooltipContent>
</Tooltip>
</div>
<Dialog open={shareDialogOpen} onOpenChange={setShareDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Share link to chat</DialogTitle>
<DialogDescription>
Anyone with the URL will be able to view the shared chat.
</DialogDescription>
</DialogHeader>
<div className="space-y-1 rounded-md border p-4 text-sm">
<div className="font-medium">{chat.title}</div>
<div className="text-muted-foreground">
{formatDate(Number(chat.createdAt))} · {chat.messages.length}{' '}
messages
</div>
</div>
<DialogFooter className="items-center">
{chat.sharePath && (
<Link
href={chat.sharePath}
className={cn(
badgeVariants({ variant: 'secondary' }),
'mr-auto'
)}
target="_blank"
>
<IconUsers className="mr-2" />
{chat.sharePath}
</Link>
)}
<Button
disabled={isSharePending}
onClick={() => {
startShareTransition(async () => {
if (chat.sharePath) {
await new Promise(resolve => setTimeout(resolve, 500))
copyShareLink(chat)
return
}
const result = await shareChat(chat)
if (result && 'error' in result) {
toast.error(result.error)
return
}
copyShareLink(result)
})
}}
>
{isSharePending ? (
<>
<IconSpinner className="mr-2 animate-spin" />
Copying...
</>
) : (
<>Copy link</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<ChatShareDialog
chat={chat}
shareChat={shareChat}
open={shareDialogOpen}
onOpenChange={setShareDialogOpen}
onCopy={() => setShareDialogOpen(false)}
/>
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
@ -189,6 +95,7 @@ export function SidebarActions({
disabled={isRemovePending}
onClick={event => {
event.preventDefault()
// @ts-ignore
startRemoveTransition(async () => {
const result = await removeChat({
id: chat.id,