Eduards commited on
Commit
9f49c25
·
1 Parent(s): 6041155

Added export button

Browse files
app/components/chat/BaseChat.tsx CHANGED
@@ -12,12 +12,14 @@ import { Messages } from './Messages.client';
12
  import { SendButton } from './SendButton.client';
13
  import { APIKeyManager } from './APIKeyManager';
14
  import Cookies from 'js-cookie';
15
- import { importChat } from '~/utils/chatExport';
16
  import { toast } from 'react-toastify';
17
  import * as Tooltip from '@radix-ui/react-tooltip';
18
 
19
  import styles from './BaseChat.module.scss';
20
  import type { ProviderInfo } from '~/utils/types';
 
 
21
 
22
  const EXAMPLE_PROMPTS = [
23
  { text: 'Build a todo app in React using Tailwind' },
@@ -76,6 +78,7 @@ interface BaseChatProps {
76
  chatStarted?: boolean;
77
  isStreaming?: boolean;
78
  messages?: Message[];
 
79
  enhancingPrompt?: boolean;
80
  promptEnhanced?: boolean;
81
  input?: string;
@@ -101,6 +104,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
101
  enhancingPrompt = false,
102
  promptEnhanced = false,
103
  messages,
 
104
  input = '',
105
  model,
106
  setModel,
@@ -288,6 +292,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
288
  </>
289
  )}
290
  </IconButton>
 
291
  </div>
292
  {input.length > 3 ? (
293
  <div className="text-xs text-bolt-elements-textTertiary">
 
12
  import { SendButton } from './SendButton.client';
13
  import { APIKeyManager } from './APIKeyManager';
14
  import Cookies from 'js-cookie';
15
+ import { exportChat, importChat } from '~/utils/chatExport';
16
  import { toast } from 'react-toastify';
17
  import * as Tooltip from '@radix-ui/react-tooltip';
18
 
19
  import styles from './BaseChat.module.scss';
20
  import type { ProviderInfo } from '~/utils/types';
21
+ import WithTooltip from '~/components/ui/Tooltip';
22
+ import { ExportChatButton } from '~/components/chat/ExportChatButton';
23
 
24
  const EXAMPLE_PROMPTS = [
25
  { text: 'Build a todo app in React using Tailwind' },
 
78
  chatStarted?: boolean;
79
  isStreaming?: boolean;
80
  messages?: Message[];
81
+ description?: string;
82
  enhancingPrompt?: boolean;
83
  promptEnhanced?: boolean;
84
  input?: string;
 
104
  enhancingPrompt = false,
105
  promptEnhanced = false,
106
  messages,
107
+ description,
108
  input = '',
109
  model,
110
  setModel,
 
292
  </>
293
  )}
294
  </IconButton>
295
+ <ClientOnly>{() => <ExportChatButton description={description} messages={messages}/>}</ClientOnly>
296
  </div>
297
  {input.length > 3 ? (
298
  <div className="text-xs text-bolt-elements-textTertiary">
app/components/chat/Chat.client.tsx CHANGED
@@ -7,7 +7,7 @@ import { useAnimate } from 'framer-motion';
7
  import { memo, useEffect, useRef, useState } from 'react';
8
  import { cssTransition, toast, ToastContainer } from 'react-toastify';
9
  import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
10
- import { useChatHistory } from '~/lib/persistence';
11
  import { chatStore } from '~/lib/stores/chat';
12
  import { workbenchStore } from '~/lib/stores/workbench';
13
  import { fileModificationsToHTML } from '~/utils/diff';
@@ -29,10 +29,11 @@ export function Chat() {
29
  renderLogger.trace('Chat');
30
 
31
  const { ready, initialMessages, storeMessageHistory } = useChatHistory();
 
32
 
33
  return (
34
  <>
35
- {ready && <ChatImpl initialMessages={initialMessages} storeMessageHistory={storeMessageHistory} />}
36
  <ToastContainer
37
  closeButton={({ closeToast }) => {
38
  return (
@@ -69,7 +70,7 @@ interface ChatProps {
69
  storeMessageHistory: (messages: Message[]) => Promise<void>;
70
  }
71
 
72
- export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProps) => {
73
  useShortcuts();
74
 
75
  const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -252,6 +253,7 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
252
  scrollRef={scrollRef}
253
  handleInputChange={handleInputChange}
254
  handleStop={abort}
 
255
  messages={messages.map((message, i) => {
256
  if (message.role === 'user') {
257
  return message;
 
7
  import { memo, useEffect, useRef, useState } from 'react';
8
  import { cssTransition, toast, ToastContainer } from 'react-toastify';
9
  import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
10
+ import { description, useChatHistory } from '~/lib/persistence';
11
  import { chatStore } from '~/lib/stores/chat';
12
  import { workbenchStore } from '~/lib/stores/workbench';
13
  import { fileModificationsToHTML } from '~/utils/diff';
 
29
  renderLogger.trace('Chat');
30
 
31
  const { ready, initialMessages, storeMessageHistory } = useChatHistory();
32
+ const title = useStore(description);
33
 
34
  return (
35
  <>
36
+ {ready && <ChatImpl description={title} initialMessages={initialMessages} storeMessageHistory={storeMessageHistory} />}
37
  <ToastContainer
38
  closeButton={({ closeToast }) => {
39
  return (
 
70
  storeMessageHistory: (messages: Message[]) => Promise<void>;
71
  }
72
 
73
+ export const ChatImpl = memo(({ description, initialMessages, storeMessageHistory }: ChatProps) => {
74
  useShortcuts();
75
 
76
  const textareaRef = useRef<HTMLTextAreaElement>(null);
 
253
  scrollRef={scrollRef}
254
  handleInputChange={handleInputChange}
255
  handleStop={abort}
256
+ description={description}
257
  messages={messages.map((message, i) => {
258
  if (message.role === 'user') {
259
  return message;
app/components/chat/ExportChatButton.tsx ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import WithTooltip from '~/components/ui/Tooltip';
2
+ import { IconButton } from '~/components/ui/IconButton';
3
+ import { exportChat } from '~/utils/chatExport';
4
+ import React from 'react';
5
+ import type { Message } from 'ai';
6
+
7
+ export const ExportChatButton = ({description, messages}: {description: string, messages: Message[]}) => {
8
+ return (<WithTooltip tooltip="Export Chat">
9
+ <IconButton
10
+ title="Export Chat"
11
+ onClick={() => exportChat(messages || [], description)}
12
+ >
13
+ <div className="i-ph:download-simple text-xl"></div>
14
+ </IconButton>
15
+ </WithTooltip>);
16
+ }
app/components/ui/Tooltip.tsx CHANGED
@@ -1,7 +1,17 @@
1
  import React from 'react';
2
  import * as Tooltip from '@radix-ui/react-tooltip';
 
3
 
4
- const WithTooltip = ({ tooltip, children, sideOffset = 5, className = '', arrowClassName = '', tooltipStyle = {} }) => {
 
 
 
 
 
 
 
 
 
5
  return (
6
  <Tooltip.Root>
7
  <Tooltip.Trigger asChild>
 
1
  import React from 'react';
2
  import * as Tooltip from '@radix-ui/react-tooltip';
3
+ import type {ReactNode} from 'react';
4
 
5
+ interface ToolTipProps {
6
+ tooltip: string,
7
+ children: ReactNode | ReactNode[];
8
+ sideOffset?: number,
9
+ className?: string,
10
+ arrowClassName?: string,
11
+ tooltipStyle?: any, //TODO better type
12
+ }
13
+
14
+ const WithTooltip = ({ tooltip, children, sideOffset = 5, className = '', arrowClassName = '', tooltipStyle = {} }: ToolTipProps) => {
15
  return (
16
  <Tooltip.Root>
17
  <Tooltip.Trigger asChild>