File size: 2,704 Bytes
93dd66e
 
3ba9c0c
93dd66e
 
 
 
 
 
3ba9c0c
 
93dd66e
 
 
 
 
 
 
 
 
 
 
 
3ba9c0c
 
 
93dd66e
 
 
 
 
 
 
 
 
3ba9c0c
93dd66e
3ba9c0c
93dd66e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3ba9c0c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as React from 'react';
import { type UseChatHelpers } from 'ai/react';

import { shareChat } from '@/app/actions';
import { Button } from '@/components/ui/button';
import { PromptForm } from '@/components/prompt-form';
import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom';
import { IconRefresh, IconShare, IconStop } from '@/components/ui/icons';
import { ChatShareDialog } from '@/components/chat-share-dialog';

export interface ChatPanelProps
	extends Pick<
		UseChatHelpers,
		| 'append'
		| 'isLoading'
		| 'reload'
		| 'messages'
		| 'stop'
		| 'input'
		| 'setInput'
	> {
	id?: string;
	title?: string;
}

export function ChatPanel({
	id,
	title,
	isLoading,
	stop,
	append,
	reload,
	input,
	setInput,
	messages,
}: ChatPanelProps) {
	const [shareDialogOpen, setShareDialogOpen] = React.useState(false);

	return (
		<div className="fixed inset-x-0 bottom-0 w-full bg-gradient-to-b from-muted/30 from-0% to-muted/30 to-50% animate-in duration-300 ease-in-out dark:from-background/10 dark:from-10% dark:to-background/80 peer-[[data-state=open]]:group-[]:lg:pl-[250px] peer-[[data-state=open]]:group-[]:xl:pl-[300px]">
			<ButtonScrollToBottom />
			<div className="mx-auto sm:max-w-3xl sm:px-4">
				<div className="flex items-center justify-center h-12">
					{isLoading ? (
						<Button
							variant="outline"
							onClick={() => stop()}
							className="bg-background"
						>
							<IconStop className="mr-2" />
							Stop generating
						</Button>
					) : (
						messages?.length >= 2 && (
							<div className="flex space-x-2">
								<Button variant="outline" onClick={() => reload()}>
									<IconRefresh className="mr-2" />
									Regenerate response
								</Button>
								{id && title ? (
									<>
										<Button
											variant="outline"
											onClick={() => setShareDialogOpen(true)}
										>
											<IconShare className="mr-2" />
											Share
										</Button>
										<ChatShareDialog
											open={shareDialogOpen}
											onOpenChange={setShareDialogOpen}
											onCopy={() => setShareDialogOpen(false)}
											shareChat={shareChat}
											chat={{
												id,
												title,
												messages,
											}}
										/>
									</>
								) : null}
							</div>
						)
					)}
				</div>
				<div className="px-4 py-2 space-y-4 border-t shadow-lg bg-background sm:rounded-t-xl sm:border md:py-4">
					<PromptForm
						onSubmit={async value => {
							await append({
								id,
								content: value,
								role: 'user',
							});
						}}
						input={input}
						setInput={setInput}
						isLoading={isLoading}
					/>
				</div>
			</div>
		</div>
	);
}