feat: Add more options for chat messages to copy, download chat entirely

This commit is contained in:
n4ze3m 2024-12-14 18:30:27 +05:30
parent ccca2eafd3
commit 43b4f076e9
20 changed files with 509 additions and 111 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Venligst vælg en model for at forsæætte", "validationSelectModel": "Venligst vælg en model for at forsæætte",
"deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historik?", "deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historik?",
"editHistoryTitle": "Indtast en ny titel", "editHistoryTitle": "Indtast en ny titel",
"temporaryChat": "Midlertidig Chat" "temporaryChat": "Midlertidig Chat",
"more": {
"copy": {
"group": "Kopier",
"asText": "Kopier som tekst",
"asMarkdown": "Kopier som Markdown",
"success": "Kopieret til udklipsholder!"
},
"download": {
"group": "Download",
"text": "Tekstfil (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON-fil (.json)"
},
"share": "Del"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Bitte wähle ein Modell aus, um fortzufahren", "validationSelectModel": "Bitte wähle ein Modell aus, um fortzufahren",
"deleteHistoryConfirmation": "Bist du sicher, dass du diesen Verlauf löschen möchtest?", "deleteHistoryConfirmation": "Bist du sicher, dass du diesen Verlauf löschen möchtest?",
"editHistoryTitle": "Gib einen neuen Titel ein", "editHistoryTitle": "Gib einen neuen Titel ein",
"temporaryChat": "Temporärer Chat" "temporaryChat": "Temporärer Chat",
"more": {
"copy": {
"group": "Kopieren",
"asText": "Als Text kopieren",
"asMarkdown": "Als Markdown kopieren",
"success": "In die Zwischenablage kopiert!"
},
"download": {
"group": "Herunterladen",
"text": "Textdatei (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON-Datei (.json)"
},
"share": "Teilen"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Please select a model to continue", "validationSelectModel": "Please select a model to continue",
"deleteHistoryConfirmation": "Are you sure you want to delete this history?", "deleteHistoryConfirmation": "Are you sure you want to delete this history?",
"editHistoryTitle": "Enter a new title", "editHistoryTitle": "Enter a new title",
"temporaryChat": "Temporary Chat" "temporaryChat": "Temporary Chat",
"more": {
"copy": {
"group": "Copy",
"asText": "Copy as Text",
"asMarkdown": "Copy as Markdown",
"success": "Copied to clipboard!"
},
"download": {
"group": "Download",
"text": "Text File (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON File (.json)"
},
"share": "Share"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Selecione un modelo para continuar", "validationSelectModel": "Selecione un modelo para continuar",
"deleteHistoryConfirmation": "¿Esta seguro que quiere borrar éste histórico?", "deleteHistoryConfirmation": "¿Esta seguro que quiere borrar éste histórico?",
"editHistoryTitle": "Ingrese un nuevo título", "editHistoryTitle": "Ingrese un nuevo título",
"temporaryChat": "Chat Temporal" "temporaryChat": "Chat Temporal",
"more": {
"copy": {
"group": "Copiar",
"asText": "Copiar como Texto",
"asMarkdown": "Copiar como Markdown",
"success": "¡Copiado al portapapeles!"
},
"download": {
"group": "Descargar",
"text": "Archivo de Texto (.txt)",
"markdown": "Markdown (.md)",
"json": "Archivo JSON (.json)"
},
"share": "Compartir"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "لطفا یک مدل را برای ادامه انتخاب کنید", "validationSelectModel": "لطفا یک مدل را برای ادامه انتخاب کنید",
"deleteHistoryConfirmation": "آیا مطمئن هستید که می خواهید این تاریخچه را حذف کنید؟", "deleteHistoryConfirmation": "آیا مطمئن هستید که می خواهید این تاریخچه را حذف کنید؟",
"editHistoryTitle": "یک عنوان جدید وارد کنید", "editHistoryTitle": "یک عنوان جدید وارد کنید",
"temporaryChat": "گپ موقت" "temporaryChat": "گپ موقت",
"more": {
"copy": {
"group": "کپی",
"asText": "کپی به صورت متن",
"asMarkdown": "کپی به صورت مارک‌داون",
"success": "در کلیپ‌بورد کپی شد!"
},
"download": {
"group": "دانلود",
"text": "فایل متنی (.txt)",
"markdown": "مارک‌داون (.md)",
"json": "فایل JSON (.json)"
},
"share": "اشتراک‌گذاری"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Veuillez sélectionner un modèle pour continuer", "validationSelectModel": "Veuillez sélectionner un modèle pour continuer",
"deleteHistoryConfirmation": "Êtes-vous sûr de vouloir supprimer cette historique ?", "deleteHistoryConfirmation": "Êtes-vous sûr de vouloir supprimer cette historique ?",
"editHistoryTitle": "Entrez un nouveau titre", "editHistoryTitle": "Entrez un nouveau titre",
"temporaryChat": "Chat temporaire" "temporaryChat": "Chat temporaire",
"more": {
"copy": {
"group": "Copier",
"asText": "Copier en texte",
"asMarkdown": "Copier en Markdown",
"success": "Copié dans le presse-papiers !"
},
"download": {
"group": "Télécharger",
"text": "Fichier texte (.txt)",
"markdown": "Markdown (.md)",
"json": "Fichier JSON (.json)"
},
"share": "Partager"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Scegliere un modello per continuare", "validationSelectModel": "Scegliere un modello per continuare",
"deleteHistoryConfirmation": "Sei sicuro che vuoi eliminare la cronologia?", "deleteHistoryConfirmation": "Sei sicuro che vuoi eliminare la cronologia?",
"editHistoryTitle": "Inserisci un nuovo titolo", "editHistoryTitle": "Inserisci un nuovo titolo",
"temporaryChat": "Chat Temporanea" "temporaryChat": "Chat Temporanea",
"more": {
"copy": {
"group": "Copia",
"asText": "Copia come Testo",
"asMarkdown": "Copia come Markdown",
"success": "Copiato negli appunti!"
},
"download": {
"group": "Scarica",
"text": "File di Testo (.txt)",
"markdown": "Markdown (.md)",
"json": "File JSON (.json)"
},
"share": "Condividi"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "続行するにはモデルを選択してください", "validationSelectModel": "続行するにはモデルを選択してください",
"deleteHistoryConfirmation": "この履歴を削除しますか?", "deleteHistoryConfirmation": "この履歴を削除しますか?",
"editHistoryTitle": "新しいタイトルを入力", "editHistoryTitle": "新しいタイトルを入力",
"temporaryChat": "一時的なチャット" "temporaryChat": "一時的なチャット",
"more": {
"copy": {
"group": "コピー",
"asText": "テキストとしてコピー",
"asMarkdown": "Markdownとしてコピー",
"success": "クリップボードにコピーしました!"
},
"download": {
"group": "ダウンロード",
"text": "テキストファイル (.txt)",
"markdown": "Markdownファイル (.md)",
"json": "JSONファイル (.json)"
},
"share": "共有"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "계속하려면 모델을 선택하세요", "validationSelectModel": "계속하려면 모델을 선택하세요",
"deleteHistoryConfirmation": "이 기록을 삭제하시겠습니까?", "deleteHistoryConfirmation": "이 기록을 삭제하시겠습니까?",
"editHistoryTitle": "새 제목 입력", "editHistoryTitle": "새 제목 입력",
"temporaryChat": "임시 채팅" "temporaryChat": "임시 채팅",
"more": {
"copy": {
"group": "복사",
"asText": "텍스트로 복사",
"asMarkdown": "마크다운으로 복사",
"success": "클립보드에 복사되었습니다!"
},
"download": {
"group": "다운로드",
"text": "텍스트 파일 (.txt)",
"markdown": "마크다운 (.md)",
"json": "JSON 파일 (.json)"
},
"share": "공유"
}
} }

View File

@ -9,5 +9,20 @@
"deleteHistoryConfirmation": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ?", "deleteHistoryConfirmation": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ?",
"editHistoryTitle": "ചാറ്റ് title എഡിറ്റുചെയ്യുക", "editHistoryTitle": "ചാറ്റ് title എഡിറ്റുചെയ്യുക",
"validationSelectModel": "തുടരുന്നതിന് ഒരു മോഡല്‍ തിരഞ്ഞെടുക്കുക", "validationSelectModel": "തുടരുന്നതിന് ഒരു മോഡല്‍ തിരഞ്ഞെടുക്കുക",
"temporaryChat": "താൽക്കാലിക ചാറ്റ്" "temporaryChat": "താൽക്കാലിക ചാറ്റ്",
"more": {
"copy": {
"group": "പകർത്തുക",
"asText": "ടെക്സ്റ്റായി പകർത്തുക",
"asMarkdown": "മാർക്ക്ഡൗൺ ആയി പകർത്തുക",
"success": "ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തി!"
},
"download": {
"group": "ഡൗൺലോഡ്",
"text": "ടെക്സ്റ്റ് ഫയൽ (.txt)",
"markdown": "മാർക്ക്ഡൗൺ (.md)",
"json": "JSON ഫയൽ (.json)"
},
"share": "പങ്കുവയ്ക്കുക"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Vennligst velg en modell for å fortsette", "validationSelectModel": "Vennligst velg en modell for å fortsette",
"deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historikken?", "deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historikken?",
"editHistoryTitle": "Skriv inn en ny tittel", "editHistoryTitle": "Skriv inn en ny tittel",
"temporaryChat": "Midlertidig Chat" "temporaryChat": "Midlertidig Chat",
"more": {
"copy": {
"group": "Kopier",
"asText": "Kopier som tekst",
"asMarkdown": "Kopier som Markdown",
"success": "Kopiert til utklippstavlen!"
},
"download": {
"group": "Last ned",
"text": "Tekstfil (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON-fil (.json)"
},
"share": "Del"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Por favor, selecione um modelo para continuar", "validationSelectModel": "Por favor, selecione um modelo para continuar",
"deleteHistoryConfirmation": "Tem certeza de que deseja excluir este histórico?", "deleteHistoryConfirmation": "Tem certeza de que deseja excluir este histórico?",
"editHistoryTitle": "Digite um novo título", "editHistoryTitle": "Digite um novo título",
"temporaryChat": "Chat Temporário" "temporaryChat": "Chat Temporário",
"more": {
"copy": {
"group": "Copiar",
"asText": "Copiar como Texto",
"asMarkdown": "Copiar como Markdown",
"success": "Copiado para área de transferência!"
},
"download": {
"group": "Baixar",
"text": "Arquivo de Texto (.txt)",
"markdown": "Markdown (.md)",
"json": "Arquivo JSON (.json)"
},
"share": "Compartilhar"
}
} }

View File

@ -9,5 +9,19 @@
"validationSelectModel": "Пожалуйста, выберите модель, чтобы продолжить", "validationSelectModel": "Пожалуйста, выберите модель, чтобы продолжить",
"deleteHistoryConfirmation": "Вы уверены, что хотите удалить эту историю?", "deleteHistoryConfirmation": "Вы уверены, что хотите удалить эту историю?",
"editHistoryTitle": "Введите новое название", "editHistoryTitle": "Введите новое название",
"temporaryChat": "Временный чат" "temporaryChat": "Временный чат",
} "more": {
"copy": {
"group": "Копировать",
"asText": "Копировать как текст",
"asMarkdown": "Копировать как Markdown",
"success": "Скопировано в буфер обмена!"
},
"download": {
"group": "Скачать",
"text": "Текстовый файл (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON файл (.json)"
},
"share": "Поделиться"
}}

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Vänligen välj en modell för att fortsätta", "validationSelectModel": "Vänligen välj en modell för att fortsätta",
"deleteHistoryConfirmation": "Är du säker på att du vill radera denna historik?", "deleteHistoryConfirmation": "Är du säker på att du vill radera denna historik?",
"editHistoryTitle": "Ange en ny titel", "editHistoryTitle": "Ange en ny titel",
"temporaryChat": "Tillfällig chatt" "temporaryChat": "Tillfällig chatt",
"more": {
"copy": {
"group": "Kopiera",
"asText": "Kopiera som text",
"asMarkdown": "Kopiera som Markdown",
"success": "Kopierat till urklipp!"
},
"download": {
"group": "Ladda ner",
"text": "Textfil (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON-fil (.json)"
},
"share": "Dela"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "Будь ласка, виберіть модель для продовження", "validationSelectModel": "Будь ласка, виберіть модель для продовження",
"deleteHistoryConfirmation": "Ви впевнені, що хочете видалити цю історію?", "deleteHistoryConfirmation": "Ви впевнені, що хочете видалити цю історію?",
"editHistoryTitle": "Введіть нову назву", "editHistoryTitle": "Введіть нову назву",
"temporaryChat": "Тимчасовий чат" "temporaryChat": "Тимчасовий чат",
"more": {
"copy": {
"group": "Копіювати",
"asText": "Копіювати як текст",
"asMarkdown": "Копіювати як Markdown",
"success": "Скопійовано в буфер обміну!"
},
"download": {
"group": "Завантажити",
"text": "Текстовий файл (.txt)",
"markdown": "Markdown (.md)",
"json": "JSON файл (.json)"
},
"share": "Поділитися"
}
} }

View File

@ -9,5 +9,20 @@
"validationSelectModel": "请选择一个模型以继续", "validationSelectModel": "请选择一个模型以继续",
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?", "deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
"editHistoryTitle": "输入一个新的标题", "editHistoryTitle": "输入一个新的标题",
"temporaryChat": "临时聊天" "temporaryChat": "临时聊天",
"more": {
"copy": {
"group": "复制",
"asText": "复制为文本",
"asMarkdown": "复制为 Markdown",
"success": "已复制到剪贴板!"
},
"download": {
"group": "下载",
"text": "文本文件 (.txt)",
"markdown": "Markdown 文件 (.md)",
"json": "JSON 文件 (.json)"
},
"share": "分享"
}
} }

View File

@ -14,6 +14,8 @@ import fetcher from "@/libs/fetcher"
type Props = { type Props = {
messages: Message[] messages: Message[]
historyId: string historyId: string
open: boolean
setOpen: (state: boolean) => void
} }
const reformatMessages = (messages: Message[], username: string) => { const reformatMessages = (messages: Message[], username: string) => {
@ -77,9 +79,13 @@ export const PlaygroundMessage = (
) )
} }
export const ShareBtn: React.FC<Props> = ({ messages, historyId }) => { export const ShareModal: React.FC<Props> = ({
messages,
historyId,
open,
setOpen
}) => {
const { t } = useTranslation("common") const { t } = useTranslation("common")
const [open, setOpen] = useState(false)
const [form] = Form.useForm() const [form] = Form.useForm()
const name = Form.useWatch("name", form) const name = Form.useWatch("name", form)
@ -142,15 +148,6 @@ export const ShareBtn: React.FC<Props> = ({ messages, historyId }) => {
}) })
return ( return (
<>
<Tooltip title={t("share.tooltip.share")}>
<button
onClick={() => setOpen(true)}
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<Share className="w-6 h-6" />
</button>
</Tooltip>
<Modal <Modal
title={t("share.modal.title")} title={t("share.modal.title")}
open={open} open={open}
@ -168,24 +165,14 @@ export const ShareBtn: React.FC<Props> = ({ messages, historyId }) => {
<Form.Item <Form.Item
name="title" name="title"
label={t("share.form.title.label")} label={t("share.form.title.label")}
rules={[ rules={[{ required: true, message: t("share.form.title.required") }]}>
{ required: true, message: t("share.form.title.required") } <Input size="large" placeholder={t("share.form.title.placeholder")} />
]}>
<Input
size="large"
placeholder={t("share.form.title.placeholder")}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="name" name="name"
label={t("share.form.name.label")} label={t("share.form.name.label")}
rules={[ rules={[{ required: true, message: t("share.form.name.required") }]}>
{ required: true, message: t("share.form.name.required") } <Input size="large" placeholder={t("share.form.name.placeholder")} />
]}>
<Input
size="large"
placeholder={t("share.form.name.placeholder")}
/>
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
@ -211,6 +198,5 @@ export const ShareBtn: React.FC<Props> = ({ messages, historyId }) => {
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>
</>
) )
} }

View File

@ -19,10 +19,10 @@ import { fetchChatModels } from "~/services/ollama"
import { useMessageOption } from "~/hooks/useMessageOption" import { useMessageOption } from "~/hooks/useMessageOption"
import { Select, Tooltip } from "antd" import { Select, Tooltip } from "antd"
import { getAllPrompts } from "@/db" import { getAllPrompts } from "@/db"
import { ShareBtn } from "~/components/Common/ShareBtn"
import { ProviderIcons } from "../Common/ProviderIcon" import { ProviderIcons } from "../Common/ProviderIcon"
import { NewChat } from "./NewChat" import { NewChat } from "./NewChat"
import { PageAssistSelect } from "../Select" import { PageAssistSelect } from "../Select"
import { MoreOptions } from "./MoreOptions"
type Props = { type Props = {
setSidebarOpen: (open: boolean) => void setSidebarOpen: (open: boolean) => void
setOpenModelSettings: (open: boolean) => void setOpenModelSettings: (open: boolean) => void
@ -50,7 +50,11 @@ export const Header: React.FC<Props> = ({
historyId, historyId,
temporaryChat temporaryChat
} = useMessageOption() } = useMessageOption()
const { data: models, isLoading: isModelsLoading, refetch } = useQuery({ const {
data: models,
isLoading: isModelsLoading,
refetch
} = useQuery({
queryKey: ["fetchModel"], queryKey: ["fetchModel"],
queryFn: () => fetchChatModels({ returnEmpty: true }), queryFn: () => fetchChatModels({ returnEmpty: true }),
refetchIntervalInBackground: false, refetchIntervalInBackground: false,
@ -134,7 +138,6 @@ export const Header: React.FC<Props> = ({
), ),
value: model.model value: model.model
}))} }))}
onRefresh={() => { onRefresh={() => {
refetch() refetch()
}} }}
@ -189,6 +192,19 @@ export const Header: React.FC<Props> = ({
<div className="flex flex-1 justify-end px-4"> <div className="flex flex-1 justify-end px-4">
<div className="ml-4 flex items-center md:ml-6"> <div className="ml-4 flex items-center md:ml-6">
<div className="flex gap-4 items-center"> <div className="flex gap-4 items-center">
{/* {pathname === "/" &&
messages.length > 0 &&
!streaming &&
shareModeEnabled && (
<ShareBtn historyId={historyId} messages={messages} />
)} */}
{messages.length > 0 && !streaming && (
<MoreOptions
shareModeEnabled={shareModeEnabled}
historyId={historyId}
messages={messages}
/>
)}
{!hideCurrentChatModelSettings && ( {!hideCurrentChatModelSettings && (
<Tooltip title={t("common:currentChatModelSettings")}> <Tooltip title={t("common:currentChatModelSettings")}>
<button <button
@ -198,12 +214,6 @@ export const Header: React.FC<Props> = ({
</button> </button>
</Tooltip> </Tooltip>
)} )}
{pathname === "/" &&
messages.length > 0 &&
!streaming &&
shareModeEnabled && (
<ShareBtn historyId={historyId} messages={messages} />
)}
<Tooltip title={t("githubRepository")}> <Tooltip title={t("githubRepository")}>
<a <a
href="https://github.com/n4ze3m/page-assist" href="https://github.com/n4ze3m/page-assist"

View File

@ -0,0 +1,163 @@
import {
MoreHorizontal,
FileText,
Share2,
FileJson,
FileCode
} from "lucide-react"
import { Dropdown, MenuProps, message } from "antd"
import { Message } from "@/types/message"
import { useState } from "react"
import { ShareModal } from "../Common/ShareModal"
import { useTranslation } from "react-i18next"
interface MoreOptionsProps {
messages: Message[]
historyId: string
shareModeEnabled: boolean
}
const formatAsText = (messages: Message[]) => {
return messages
.map((msg) => {
const text = `${msg.isBot ? msg.name : "You"}: ${msg.message}`
return text
})
.join("\n\n")
}
const formatAsMarkdown = (messages: Message[]) => {
return messages
.map((msg) => {
let content = `**${msg.isBot ? msg.name : "You"}**:\n${msg.message}`
if (msg.images && msg.images.length > 0) {
const imageMarkdown = msg.images
.filter((img) => img.length > 0)
.map((img) => `\n\n![Image](${img})`)
.join("\n")
content += imageMarkdown
}
return content
})
.join("\n\n")
}
const downloadFile = (content: string, filename: string) => {
const blob = new Blob([content], { type: "text/plain;charset=utf-8" })
const url = URL.createObjectURL(blob)
const link = document.createElement("a")
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
}
export const MoreOptions = ({
shareModeEnabled = false,
historyId,
messages
}: MoreOptionsProps) => {
const { t } = useTranslation("option")
const [onShareOpen, setOnShareOpen] = useState(false)
const baseItems: MenuProps["items"] = [
{
type: "group",
label: t("more.copy.group"),
children: [
{
key: "copy-text",
label: t("more.copy.asText"),
icon: <FileText className="w-4 h-4" />,
onClick: () => {
navigator.clipboard.writeText(formatAsText(messages))
message.success(t("more.copy.success"))
}
},
{
key: "copy-markdown",
label: t("more.copy.asMarkdown"),
icon: <FileCode className="w-4 h-4" />,
onClick: () => {
navigator.clipboard.writeText(formatAsMarkdown(messages))
message.success(t("more.copy.success"))
}
}
]
},
{
type: "divider"
},
{
type: "group",
label: t("more.download.group"),
children: [
{
key: "download-txt",
label: t("more.download.text"),
icon: <FileText className="w-4 h-4" />,
onClick: () => {
downloadFile(formatAsText(messages), "chat.txt")
}
},
{
key: "download-md",
label: t("more.download.markdown"),
icon: <FileCode className="w-4 h-4" />,
onClick: () => {
downloadFile(formatAsMarkdown(messages), "chat.md")
}
},
{
key: "download-json",
label: t("more.download.json"),
icon: <FileJson className="w-4 h-4" />,
onClick: () => {
const jsonContent = JSON.stringify(messages, null, 2)
downloadFile(jsonContent, "chat.json")
}
}
]
}
]
const shareItem = {
type: "divider"
} as const
const shareOption = {
key: "share",
label: t("more.share"),
icon: <Share2 className="w-4 h-4" />,
onClick: () => {
setOnShareOpen(true)
}
}
const items = shareModeEnabled
? [...baseItems, shareItem, shareOption]
: baseItems
return (
<>
<Dropdown
menu={{
items
}}
trigger={["click"]}
placement="bottomRight">
<button className="!text-gray-500 dark:text-gray-300 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<MoreHorizontal className="w-6 h-6" />
</button>
</Dropdown>
<ShareModal
open={onShareOpen}
historyId={historyId}
messages={messages}
setOpen={setOnShareOpen}
/>
</>
)
}