diff --git a/src/SessionMessages/MessageActions.tsx b/src/SessionMessages/MessageActions.tsx new file mode 100644 index 0000000..1a7f0b8 --- /dev/null +++ b/src/SessionMessages/MessageActions.tsx @@ -0,0 +1,159 @@ +import { SessionsContext } from '@/SessionsContext'; +import { Slot } from '@radix-ui/react-slot'; +import { cn, IconButton } from 'reablocks'; +import { + FC, + PropsWithChildren, + ReactElement, + ReactNode, + useContext +} from 'react'; +import CopyIcon from '@/assets/copy.svg?react'; +import ThumbsDownIcon from '@/assets/thumbs-down.svg?react'; +import ThumbUpIcon from '@/assets/thumbs-up.svg?react'; +import RefreshIcon from '@/assets/refresh.svg?react'; + +export interface MessageActionsProps extends PropsWithChildren { + /** + * Question to be copied + */ + question: string; + + /** + * Response to be copied + */ + response?: string; + + /** + * Icon to show for copy. + */ + copyIcon?: ReactElement; + + /** + * Icon to show for thumbs up. + */ + thumbsUpIcon?: ReactElement; + + /** + * Icon to show for thumbs down. + */ + thumbsDownIcon?: ReactElement; + + /** + * Icon to show for refresh. + */ + refreshIcon?: ReactElement; + + /** + * Callback function to handle copying. + */ + onCopy?: () => void; + + /** + * Callback function to handle upvoting. + */ + onUpvote?: () => void; + + /** + * Callback function to handle downvoting. + */ + onDownvote?: () => void; + + /** + * Callback function to handle refreshing. + */ + onRefresh?: () => void; + + /** + * Children to render as MessageAction slot. + */ + children?: ReactNode; +} + +export const MessageActions: FC = ({ + children, + ...props +}) => { + const { theme } = useContext(SessionsContext); + const { + question, + response, + copyIcon = , + thumbsUpIcon = , + thumbsDownIcon = , + refreshIcon = , + onCopy, + onUpvote, + onDownvote, + onRefresh + } = props; + const Comp = children ? Slot : 'div'; + + const handleCopy = (text: string) => { + navigator.clipboard + .writeText(text) + .then(() => { + console.log('Text copied to clipboard'); + }) + .catch(err => { + console.error('Could not copy text: ', err); + }); + }; + + return ( + (copyIcon || thumbsDownIcon || thumbsUpIcon || refreshIcon) && ( + + {children || ( + <> + {copyIcon && ( + handleCopy(`${question}\n${response}`) + } + > + {copyIcon} + + )} + {thumbsUpIcon && ( + + {thumbsUpIcon} + + )} + {thumbsDownIcon && ( + + {thumbsDownIcon} + + )} + {refreshIcon && ( + + {refreshIcon} + + )} + + )} + + ) + ); +}; diff --git a/src/SessionMessages/MessageFile.tsx b/src/SessionMessages/MessageFile.tsx index 2fd69ad..5e5610a 100644 --- a/src/SessionMessages/MessageFile.tsx +++ b/src/SessionMessages/MessageFile.tsx @@ -4,11 +4,11 @@ import { SessionsContext } from '@/SessionsContext'; import { Ellipsis, cn } from 'reablocks'; import FileIcon from '@/assets/file.svg?react'; -interface MessageFileProps extends ConversationFile { - /** +export interface MessageFileProps extends ConversationFile { + /** * Icon to show for delete. */ - fileIcon?: ReactElement; + fileIcon?: ReactElement; /** * Limit for the name. diff --git a/src/SessionMessages/MessageFiles.tsx b/src/SessionMessages/MessageFiles.tsx new file mode 100644 index 0000000..3be27ac --- /dev/null +++ b/src/SessionMessages/MessageFiles.tsx @@ -0,0 +1,39 @@ +import { SessionsContext } from '@/SessionsContext'; +import { ConversationFile } from '@/types'; +import { cn } from 'reablocks'; +import { FC, PropsWithChildren, ReactNode, useContext } from 'react'; +import { MessageFile } from './MessageFile'; +import { Slot } from '@radix-ui/react-slot'; + +interface MessageFilesProps extends PropsWithChildren { + /** + * Files to render. + */ + files: ConversationFile[]; + + /** + * Children to render as MessageFile slot. + */ + children?: ReactNode; +} + +export const MessageFiles: FC = ({ files, children }) => { + const { theme } = useContext(SessionsContext); + const Comp = children ? Slot : MessageFile; + + if (!files || files.length === 0) { + return null; + } + + return ( + files.length > 0 && ( +
+ {files.map((file, index) => ( + + {children} + + ))} +
+ ) + ); +}; diff --git a/src/SessionMessages/MessageQuestion.tsx b/src/SessionMessages/MessageQuestion.tsx new file mode 100644 index 0000000..c2f8817 --- /dev/null +++ b/src/SessionMessages/MessageQuestion.tsx @@ -0,0 +1,38 @@ +import { SessionsContext } from '@/SessionsContext'; +import { Slot } from '@radix-ui/react-slot'; +import { cn } from 'reablocks'; +import { FC, PropsWithChildren, ReactNode, useContext } from 'react'; +import { Markdown } from '@/Markdown'; +import { PluggableList } from 'react-markdown/lib'; +import remarkGfm from 'remark-gfm'; +import remarkYoutube from 'remark-youtube'; + +export interface MessageQuestionProps extends PropsWithChildren { + /** + * Question to render. + */ + question: string; + + /** + * Children to render as MessageQuestion slot. + */ + children?: ReactNode; +} + +export const MessageQuestion: FC = ({ + question, + children +}) => { + const { theme, remarkPlugins = [remarkGfm, remarkYoutube] } = + useContext(SessionsContext); + const Comp = children ? Slot : 'div'; + return ( + + {children || ( + + {question} + + )} + + ); +}; diff --git a/src/SessionMessages/MessageResponse.tsx b/src/SessionMessages/MessageResponse.tsx new file mode 100644 index 0000000..47c040a --- /dev/null +++ b/src/SessionMessages/MessageResponse.tsx @@ -0,0 +1,58 @@ +import { SessionsContext } from '@/SessionsContext'; +import { Slot } from '@radix-ui/react-slot'; +import { motion } from 'framer-motion'; +import { cn } from 'reablocks'; +import { FC, ReactNode, useContext } from 'react'; +import { Markdown } from '@/Markdown'; +import { PluggableList } from 'react-markdown/lib'; +import remarkGfm from 'remark-gfm'; +import remarkYoutube from 'remark-youtube'; + +export interface MessageResponseProps { + /** + * Response to render. + */ + response: string; + + /** + * Whether the response is loading. + */ + isLoading?: boolean; + + /** + * Children to render as MessageResponse slot. + */ + children?: ReactNode; +} + +export const MessageResponse: FC = ({ + response, + isLoading, + children +}) => { + const { theme, remarkPlugins = [remarkGfm, remarkYoutube] } = + useContext(SessionsContext); + const Comp = children ? Slot : 'div'; + return ( + + {children || ( + <> + + {response} + + {isLoading && ( + + )} + + )} + + ); +}; diff --git a/src/SessionMessages/MessageSource.tsx b/src/SessionMessages/MessageSource.tsx index 881a1ca..07cb5b7 100644 --- a/src/SessionMessages/MessageSource.tsx +++ b/src/SessionMessages/MessageSource.tsx @@ -3,7 +3,7 @@ import { ConversationSource } from '@/types'; import { SessionsContext } from '@/SessionsContext'; import { Ellipsis, cn } from 'reablocks'; -interface MessageSourceProps extends ConversationSource { +export interface MessageSourceProps extends ConversationSource { /** * Limit for the title. */ diff --git a/src/SessionMessages/MessageSources.tsx b/src/SessionMessages/MessageSources.tsx new file mode 100644 index 0000000..21c56c0 --- /dev/null +++ b/src/SessionMessages/MessageSources.tsx @@ -0,0 +1,43 @@ +import { SessionsContext } from '@/SessionsContext'; +import { ConversationSource } from '@/types'; +import { cn } from 'reablocks'; +import { FC, PropsWithChildren, ReactNode, useContext } from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { MessageSource } from './MessageSource'; + +interface MessageSourcesProps extends PropsWithChildren { + /** + * Sources to render. + */ + sources: ConversationSource[]; + + /** + * Children to render as MessageSource slot. + */ + children?: ReactNode; +} + +export const MessageSources: FC = ({ + sources, + children +}) => { + const { theme } = useContext(SessionsContext); + const Comp = children ? Slot : MessageSource; + + if (!sources || sources.length === 0) { + return null; + } + + return ( + sources && + sources.length > 0 && ( +
+ {sources.map((source, index) => ( + + {children} + + ))} +
+ ) + ); +}; diff --git a/src/SessionMessages/SessionMessage.tsx b/src/SessionMessages/SessionMessage.tsx index 81125c8..ed99f55 100644 --- a/src/SessionMessages/SessionMessage.tsx +++ b/src/SessionMessages/SessionMessage.tsx @@ -1,169 +1,74 @@ -import { FC, ReactElement, useContext } from 'react'; +import { FC, PropsWithChildren, useContext } from 'react'; import { SessionsContext } from '@/SessionsContext'; -import { Card, IconButton, cn } from 'reablocks'; -import remarkGfm from 'remark-gfm'; +import { Card, cn } from 'reablocks'; import CopyIcon from '@/assets/copy.svg?react'; import ThumbsDownIcon from '@/assets/thumbs-down.svg?react'; import ThumbUpIcon from '@/assets/thumbs-up.svg?react'; import RefreshIcon from '@/assets/refresh.svg?react'; -import { PluggableList } from 'react-markdown/lib'; -import { Markdown } from '@/Markdown'; -import remarkYoutube from 'remark-youtube'; import { Conversation } from '@/types'; -import { MessageSource } from './MessageSource'; -import { MessageFile } from './MessageFile'; import { motion } from 'framer-motion'; +import { MessageQuestion } from './MessageQuestion'; +import { MessageResponse } from './MessageResponse'; +import { MessageFiles } from './MessageFiles'; +import { MessageSources } from './MessageSources'; +import { MessageActions } from './MessageActions'; -export interface SessionMessageProps extends Conversation { - /** - * Icon to show for copy. - */ - copyIcon?: ReactElement; - - /** - * Icon to show for thumbs up. - */ - thumbsUpIcon?: ReactElement; - - /** - * Icon to show for thumbs down. - */ - thumbsDownIcon?: ReactElement; - - /** - * Icon to show for refresh. - */ - refreshIcon?: ReactElement; - - /** - * Whether to display a loading state. - */ - isLoading?: boolean; - - /** - * Callback function to handle upvoting. - */ - onUpvote?: () => void; +const messageVariants = { + hidden: { + opacity: 0, + y: 20 + }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.4 + } + } +}; +interface SessionMessageProps extends PropsWithChildren { /** - * Callback function to handle downvoting. + * Conversation to render. */ - onDownvote?: () => void; + conversation: Conversation; /** - * Callback function to handle refreshing. + * Whether the message is the last one in the list. */ - onRefresh?: () => void; + isLast?: boolean; } export const SessionMessage: FC = ({ - question = '', - response = '', - copyIcon = , - thumbsUpIcon = , - thumbsDownIcon = , - refreshIcon = , - isLoading, - sources, - files, - onUpvote, - onDownvote, - onRefresh + conversation, + isLast, + children }) => { - const { theme, remarkPlugins = [remarkGfm, remarkYoutube] } = useContext(SessionsContext); - - const handleCopy = (text: string) => { - navigator.clipboard - .writeText(text) - .then(() => { - console.log('Text copied to clipboard'); - }) - .catch(err => { - console.error('Could not copy text: ', err); - }); - }; + const { theme, isLoading } = useContext(SessionsContext); return ( - - {files?.length > 0 && ( -
- {files.map((file, index) => ( - - ))} -
- )} -
- - {question} - -
-
- - {response} - - {isLoading && ( - + + + {children || ( + <> + + + + + } + thumbsUpIcon={} + thumbsDownIcon={} + refreshIcon={} + /> + )} -
- {sources && sources.length > 0 && ( -
- {sources.map((source, index) => ( - - ))} -
- )} - {(copyIcon || thumbsDownIcon || thumbsUpIcon || refreshIcon) && ( -
- {copyIcon && ( - handleCopy(`${question}\n${response}`)} - > - {copyIcon} - - )} - {thumbsUpIcon && ( - - {thumbsUpIcon} - - )} - {thumbsDownIcon && ( - - {thumbsDownIcon} - - )} - {refreshIcon && ( - - {refreshIcon} - - )} -
- )} -
+ + ); }; diff --git a/src/SessionMessages/SessionMessagePanel.tsx b/src/SessionMessages/SessionMessagePanel.tsx new file mode 100644 index 0000000..3bef877 --- /dev/null +++ b/src/SessionMessages/SessionMessagePanel.tsx @@ -0,0 +1,13 @@ +import { FC, PropsWithChildren, useContext } from 'react'; +import { cn } from 'reablocks'; +import { SessionsContext } from '@/SessionsContext'; + +export const SessionMessagePanel: FC = ({ children }) => { + const { theme } = useContext(SessionsContext); + + return ( +
+
{children}
+
+ ); +}; diff --git a/src/SessionMessages/SessionMessages.tsx b/src/SessionMessages/SessionMessages.tsx index bd60105..8ad3f79 100644 --- a/src/SessionMessages/SessionMessages.tsx +++ b/src/SessionMessages/SessionMessages.tsx @@ -1,5 +1,4 @@ import React, { - PropsWithChildren, ReactNode, useContext, useEffect, @@ -10,9 +9,10 @@ import React, { import { SessionEmpty } from './SessionEmpty'; import { SessionMessage } from './SessionMessage'; import { SessionsContext } from '@/SessionsContext'; -import { Button, cn, DateFormat, Ellipsis, useInfinityList } from 'reablocks'; +import { Button, cn, useInfinityList } from 'reablocks'; import { Slot } from '@radix-ui/react-slot'; import { AnimatePresence, motion } from 'framer-motion'; +import { Conversation } from '@/types'; const containerVariants = { hidden: {}, @@ -23,21 +23,8 @@ const containerVariants = { } }; -const messageVariants = { - hidden: { - opacity: 0, - y: 20 - }, - visible: { - opacity: 1, - y: 0, - transition: { - duration: 0.4 - } - } -}; -interface SessionMessagesProps extends PropsWithChildren { +interface SessionMessagesProps { /** * Content to display when there are no sessions selected or a new session is started. */ @@ -52,6 +39,11 @@ interface SessionMessagesProps extends PropsWithChildren { * Text to display for the show more button. */ showMoreText?: string; + + /** + * Render function for the session messages. + */ + children?: (conversations: Conversation[]) => ReactNode; } export const SessionMessages: React.FC = ({ @@ -83,7 +75,7 @@ export const SessionMessages: React.FC = ({ // Reverse the conversations so the last one is the first one const reversedConvos = useMemo( - () => [...activeSession?.conversations ?? []].reverse(), + () => [...(activeSession?.conversations ?? [])].reverse(), [activeSession] ); @@ -103,50 +95,30 @@ export const SessionMessages: React.FC = ({ } return ( -
-
-

- -

- -
-
- {hasMore && ( - - )} - - { - setIsAnimating(false); - }} - > - {convosToRender.map((conversation, index) => ( - - - {children} - - - ))} - - -
+
+ {hasMore && ( + + )} + + { + setIsAnimating(false); + }} + > + {children(convosToRender)} + +
); }; diff --git a/src/SessionMessages/SessionMessagesHeader.tsx b/src/SessionMessages/SessionMessagesHeader.tsx new file mode 100644 index 0000000..8dbf34c --- /dev/null +++ b/src/SessionMessages/SessionMessagesHeader.tsx @@ -0,0 +1,27 @@ +import { SessionsContext } from '@/SessionsContext'; +import { Slot } from '@radix-ui/react-slot'; +import { cn, Ellipsis, DateFormat } from 'reablocks'; +import { FC, PropsWithChildren, useContext } from 'react'; + +export const SessionMessagesHeader: FC = ({ children }) => { + const { activeSession, theme } = useContext(SessionsContext); + const Comp = children ? Slot : 'header'; + + if (!activeSession) return null; + + return ( + + {children || ( + <> +

+ +

+ + + )} +
+ ); +}; diff --git a/src/SessionMessages/index.ts b/src/SessionMessages/index.ts index 4507d40..ef4fe4c 100644 --- a/src/SessionMessages/index.ts +++ b/src/SessionMessages/index.ts @@ -1,4 +1,6 @@ export * from './SessionEmpty'; +export * from './SessionMessagesHeader'; +export * from './SessionMessagePanel'; export * from './SessionMessage'; export * from './SessionMessages'; export * from './MessageSource'; diff --git a/src/SessionsList/SessionListItem.tsx b/src/SessionsList/SessionListItem.tsx index a94ef2f..a4624cc 100644 --- a/src/SessionsList/SessionListItem.tsx +++ b/src/SessionsList/SessionListItem.tsx @@ -43,7 +43,9 @@ export const SessionListItem: FC = ({ dense disableGutters active={session.id === activeSessionId} - className={cn(theme.sessions.session.base, { [theme.sessions.session.active]: session.id === activeSessionId })} + className={cn(theme.sessions.session.base, { + [theme.sessions.session.active]: session.id === activeSessionId + })} onClick={() => selectSession?.(session.id)} end={ <> diff --git a/stories/Demos.stories.tsx b/stories/Demos.stories.tsx index b6e4714..61899e5 100644 --- a/stories/Demos.stories.tsx +++ b/stories/Demos.stories.tsx @@ -1,4 +1,11 @@ -import { useState, useCallback, useRef, useEffect, FC } from 'react'; +import { + useState, + useCallback, + useRef, + useEffect, + FC, + useContext +} from 'react'; import OpenAI from 'openai'; import { Meta } from '@storybook/react'; import { @@ -12,19 +19,40 @@ import { SessionMessages, SessionGroups, SessionInput, - SessionListItemProps + SessionListItemProps, + SessionMessagePanel, + SessionMessagesHeader, + SessionsContext, + SessionMessage } from '../src'; import { Card, + Chip, + cn, + DateFormat, Divider, IconButton, Input, List, ListItem, - Menu + Menu, + RefreshIcon } from 'reablocks'; import { subDays, subMinutes, subHours } from 'date-fns'; import MenuIcon from '@/assets/menu.svg?react'; +import { motion } from 'framer-motion'; +import { MessageActions } from '@/SessionMessages/MessageActions'; +import { MessageFiles } from '@/SessionMessages/MessageFiles'; +import { + MessageQuestion, + MessageQuestionProps +} from '@/SessionMessages/MessageQuestion'; +import { + MessageResponse, + MessageResponseProps +} from '@/SessionMessages/MessageResponse'; +import { MessageSources } from '@/SessionMessages/MessageSources'; +import { MessageFileProps } from '@/SessionMessages/MessageFile'; export default { title: 'Demos', @@ -112,10 +140,17 @@ export const Console = () => { } -
- + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+
); @@ -194,10 +229,17 @@ export const Embeds = () => { } -
- + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -238,10 +280,18 @@ export const DefaultSession = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -308,38 +358,54 @@ export const Loading = () => { } -
- - -
+ + + + + {conversations => + conversations.map((conversation, index) => ( + + )) + } + + + ); }; -export const FileUploads = () => { - const sessionsWithFiles: Session[] = [ - { - id: '1', - title: 'Session with Files', - createdAt: new Date(), - updatedAt: new Date(), - conversations: [ - { - id: '1', - question: 'Here are some files I uploaded', - response: 'Ive received your files. Let me know if you have any questions about them.', - createdAt: new Date(), - updatedAt: new Date(), - files: [ - { name: 'document.pdf', size: 1024000, type: 'application/pdf' }, - { name: 'report.docx', size: 512000, type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } - ] - } - ] - } - ]; +const sessionsWithFiles: Session[] = [ + { + id: 'session-files', + title: 'Session with Files', + createdAt: new Date(), + updatedAt: new Date(), + conversations: [ + { + id: '1', + question: 'Here are some files I uploaded', + response: + 'Ive received your files. Let me know if you have any questions about them.', + createdAt: new Date(), + updatedAt: new Date(), + files: [ + { name: 'document.pdf', size: 1024000, type: 'application/pdf' }, + { + name: 'report.docx', + size: 512000, + type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + } + ] + } + ] + } +]; +export const FileUploads = () => { return (
{ alert('delete!')} > @@ -374,10 +440,17 @@ export const FileUploads = () => { } -
- + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+
); @@ -418,10 +491,18 @@ export const DefaultInputValue = () => { } -
- - -
+ + + + + {conversations => + conversations.map(conversation => ( + + )) + } + + + ); @@ -457,24 +538,42 @@ export const UndeleteableSessions = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); }; export const SessionGrouping = () => { - const createSessionWithDate = (id: string, title: string, daysAgo: number): Session => ({ + const createSessionWithDate = ( + id: string, + title: string, + daysAgo: number + ): Session => ({ id, title, createdAt: subDays(new Date(), daysAgo), updatedAt: subDays(new Date(), daysAgo), conversations: [ - { id: `${id}-1`, question: 'Sample question', response: 'Sample response', createdAt: subDays(new Date(), daysAgo), updatedAt: subDays(new Date(), daysAgo) }, - ], + { + id: `${id}-1`, + question: 'Sample question', + response: 'Sample response', + createdAt: subDays(new Date(), daysAgo), + updatedAt: subDays(new Date(), daysAgo) + } + ] }); const sessionsWithVariousDates: Session[] = [ @@ -487,11 +586,23 @@ export const SessionGrouping = () => { createSessionWithDate('6', 'Two Months Ago Session', 65), createSessionWithDate('7', 'Six Months Ago Session', 180), createSessionWithDate('8', 'Last Year Session', 370), - createSessionWithDate('9', 'Two Years Ago Session', 740), + createSessionWithDate('9', 'Two Years Ago Session', 740) ]; return ( -
+
{ } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+
); @@ -571,10 +690,18 @@ export const HundredSessions = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+
); @@ -634,10 +761,18 @@ export const HundredConversations = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -689,10 +824,18 @@ export const LongSessionNames = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -810,10 +953,18 @@ export const MarkdownShowcase = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -889,10 +1040,18 @@ export const CVEExample = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); @@ -1037,35 +1196,88 @@ export const OpenAIIntegration = () => { } -
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+ ); }; -const CustomSessionMessage: FC = ({ - question, - response -}) => ( -
- - This is my question: {question} - -
+const CustomMessagesHeader: FC = () => { + const { activeSession } = useContext(SessionsContext); + + return ( +
+
+ +
+

{activeSession?.title}

+
+ ); +}; + +const CustomMessageQuestion: FC = ({ question }) => ( + + This is my question: {question} + +); + +const CustomMessageResponse: FC = ({ response }) => ( +
This is the response: {response} -
+ ); -const CustomSessionListItem: FC = ({ session }) => { +const CustomMessageFile: FC = ({ name, type }) => ( + + {name || type} + +); + +const CustomMessageSource: FC = ({ title, url, image }) => { + const { theme } = useContext(SessionsContext); + return ( + alert('take me to ' + url)} + start={ + image && ( + {title} + ) + } + > + {title || url} + + ); +}; + +const CustomSessionListItem: FC = ({ + session, + children, + ...rest +}) => { const [open, setOpen] = useState(false); const btnRef = useRef(null); return ( <> = ({ session }) => { > {session.title} - setOpen(false)} reference={btnRef}> + setOpen(false)} + reference={btnRef} + appendToBody={false} + > alert('rename')}>Rename @@ -1109,7 +1326,14 @@ export const CustomComponents = () => { borderRadius: 5 }} > - + @@ -1129,12 +1353,39 @@ export const CustomComponents = () => { } -
+ + + + - + {conversations => + conversations.map((conversation, index) => ( + + + + + + + + + + + + + + + + )) + } -
+
); @@ -1174,7 +1425,9 @@ export const EmptyState = () => { ))} {groups.length === 0 && (
-

No sessions yet. Start a new session!

+

+ No sessions yet. Start a new session! +

)} @@ -1185,7 +1438,9 @@ export const EmptyState = () => { -

No messages yet. Start a new conversation!

+

+ No messages yet. Start a new conversation! +

} /> @@ -1196,18 +1451,17 @@ export const EmptyState = () => { ); }; -export const ConversationSources = () => { - const sessionWithSources: Session[] = [ - { - id: 'session-sources', - title: 'Session with Sources', - createdAt: subHours(new Date(), 1), - updatedAt: new Date(), - conversations: [ - { - id: 'conversation-1', - question: 'What are the main causes of climate change?', - response: `Climate change is primarily caused by human activities that release greenhouse gases into the atmosphere. The main causes include: +const sessionWithSources: Session[] = [ + { + id: 'session-sources', + title: 'Session with Sources', + createdAt: subHours(new Date(), 1), + updatedAt: new Date(), + conversations: [ + { + id: 'conversation-1', + question: 'What are the main causes of climate change?', + response: `Climate change is primarily caused by human activities that release greenhouse gases into the atmosphere. The main causes include: 1. Burning of fossil fuels (coal, oil, and natural gas) 2. Deforestation and land-use changes @@ -1215,24 +1469,27 @@ export const ConversationSources = () => { 4. Agriculture and livestock farming These activities increase the concentration of greenhouse gases in the atmosphere, leading to the greenhouse effect and global warming.`, - createdAt: new Date(), - updatedAt: new Date(), - sources: [ - { - title: 'NASA: Causes of Climate Change', - image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/NASA_logo.svg/1224px-NASA_logo.svg.png', - url: 'https://climate.nasa.gov/causes/' - }, - { - title: 'IPCC: Climate Change 2021: The Physical Science Basis and Global Warming Is the Last War We will Fight', - url: 'https://www.ipcc.ch/report/ar6/wg1/' - } - ] - } - ] - } - ]; + createdAt: new Date(), + updatedAt: new Date(), + sources: [ + { + title: 'NASA: Causes of Climate Change', + image: + 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/NASA_logo.svg/1224px-NASA_logo.svg.png', + url: 'https://climate.nasa.gov/causes/' + }, + { + title: + 'IPCC: Climate Change 2021: The Physical Science Basis and Global Warming Is the Last War We will Fight', + url: 'https://www.ipcc.ch/report/ar6/wg1/' + } + ] + } + ] + } +]; +export const ConversationSources = () => { return (
-
- + + + + + {conversations => + conversations.map(conversation => ( + + )) + } + -
+
);