feat: Add more options for chat messages to copy, download chat entirely
This commit is contained in:
parent
ccca2eafd3
commit
43b4f076e9
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Venligst vælg en model for at forsæætte",
|
||||
"deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historik?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Bitte wähle ein Modell aus, um fortzufahren",
|
||||
"deleteHistoryConfirmation": "Bist du sicher, dass du diesen Verlauf löschen möchtest?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Please select a model to continue",
|
||||
"deleteHistoryConfirmation": "Are you sure you want to delete this history?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Selecione un modelo para continuar",
|
||||
"deleteHistoryConfirmation": "¿Esta seguro que quiere borrar éste histórico?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "لطفا یک مدل را برای ادامه انتخاب کنید",
|
||||
"deleteHistoryConfirmation": "آیا مطمئن هستید که می خواهید این تاریخچه را حذف کنید؟",
|
||||
"editHistoryTitle": "یک عنوان جدید وارد کنید",
|
||||
"temporaryChat": "گپ موقت"
|
||||
}
|
||||
"temporaryChat": "گپ موقت",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "کپی",
|
||||
"asText": "کپی به صورت متن",
|
||||
"asMarkdown": "کپی به صورت مارکداون",
|
||||
"success": "در کلیپبورد کپی شد!"
|
||||
},
|
||||
"download": {
|
||||
"group": "دانلود",
|
||||
"text": "فایل متنی (.txt)",
|
||||
"markdown": "مارکداون (.md)",
|
||||
"json": "فایل JSON (.json)"
|
||||
},
|
||||
"share": "اشتراکگذاری"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Veuillez sélectionner un modèle pour continuer",
|
||||
"deleteHistoryConfirmation": "Êtes-vous sûr de vouloir supprimer cette historique ?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Scegliere un modello per continuare",
|
||||
"deleteHistoryConfirmation": "Sei sicuro che vuoi eliminare la cronologia?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -1,13 +1,28 @@
|
||||
{
|
||||
"newChat": "新しいチャット",
|
||||
"selectAPrompt": "プロンプトを選択",
|
||||
"githubRepository": "GitHubリポジトリ",
|
||||
"settings": "設定",
|
||||
"sidebarTitle": "チャット履歴",
|
||||
"error": "エラー",
|
||||
"somethingWentWrong": "何かが間違っています",
|
||||
"validationSelectModel": "続行するにはモデルを選択してください",
|
||||
"deleteHistoryConfirmation": "この履歴を削除しますか?",
|
||||
"editHistoryTitle": "新しいタイトルを入力",
|
||||
"temporaryChat": "一時的なチャット"
|
||||
}
|
||||
"newChat": "新しいチャット",
|
||||
"selectAPrompt": "プロンプトを選択",
|
||||
"githubRepository": "GitHubリポジトリ",
|
||||
"settings": "設定",
|
||||
"sidebarTitle": "チャット履歴",
|
||||
"error": "エラー",
|
||||
"somethingWentWrong": "何かが間違っています",
|
||||
"validationSelectModel": "続行するにはモデルを選択してください",
|
||||
"deleteHistoryConfirmation": "この履歴を削除しますか?",
|
||||
"editHistoryTitle": "新しいタイトルを入力",
|
||||
"temporaryChat": "一時的なチャット",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "コピー",
|
||||
"asText": "テキストとしてコピー",
|
||||
"asMarkdown": "Markdownとしてコピー",
|
||||
"success": "クリップボードにコピーしました!"
|
||||
},
|
||||
"download": {
|
||||
"group": "ダウンロード",
|
||||
"text": "テキストファイル (.txt)",
|
||||
"markdown": "Markdownファイル (.md)",
|
||||
"json": "JSONファイル (.json)"
|
||||
},
|
||||
"share": "共有"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "계속하려면 모델을 선택하세요",
|
||||
"deleteHistoryConfirmation": "이 기록을 삭제하시겠습니까?",
|
||||
"editHistoryTitle": "새 제목 입력",
|
||||
"temporaryChat": "임시 채팅"
|
||||
}
|
||||
"temporaryChat": "임시 채팅",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "복사",
|
||||
"asText": "텍스트로 복사",
|
||||
"asMarkdown": "마크다운으로 복사",
|
||||
"success": "클립보드에 복사되었습니다!"
|
||||
},
|
||||
"download": {
|
||||
"group": "다운로드",
|
||||
"text": "텍스트 파일 (.txt)",
|
||||
"markdown": "마크다운 (.md)",
|
||||
"json": "JSON 파일 (.json)"
|
||||
},
|
||||
"share": "공유"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"deleteHistoryConfirmation": "നിങ്ങളുടെ ചാറ്റ് ചരിത്രം ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ?",
|
||||
"editHistoryTitle": "ചാറ്റ് title എഡിറ്റുചെയ്യുക",
|
||||
"validationSelectModel": "തുടരുന്നതിന് ഒരു മോഡല് തിരഞ്ഞെടുക്കുക",
|
||||
"temporaryChat": "താൽക്കാലിക ചാറ്റ്"
|
||||
"temporaryChat": "താൽക്കാലിക ചാറ്റ്",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "പകർത്തുക",
|
||||
"asText": "ടെക്സ്റ്റായി പകർത്തുക",
|
||||
"asMarkdown": "മാർക്ക്ഡൗൺ ആയി പകർത്തുക",
|
||||
"success": "ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തി!"
|
||||
},
|
||||
"download": {
|
||||
"group": "ഡൗൺലോഡ്",
|
||||
"text": "ടെക്സ്റ്റ് ഫയൽ (.txt)",
|
||||
"markdown": "മാർക്ക്ഡൗൺ (.md)",
|
||||
"json": "JSON ഫയൽ (.json)"
|
||||
},
|
||||
"share": "പങ്കുവയ്ക്കുക"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Vennligst velg en modell for å fortsette",
|
||||
"deleteHistoryConfirmation": "Er du sikker på at du vil slette denne historikken?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Por favor, selecione um modelo para continuar",
|
||||
"deleteHistoryConfirmation": "Tem certeza de que deseja excluir este histórico?",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -9,5 +9,19 @@
|
||||
"validationSelectModel": "Пожалуйста, выберите модель, чтобы продолжить",
|
||||
"deleteHistoryConfirmation": "Вы уверены, что хотите удалить эту историю?",
|
||||
"editHistoryTitle": "Введите новое название",
|
||||
"temporaryChat": "Временный чат"
|
||||
}
|
||||
"temporaryChat": "Временный чат",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "Копировать",
|
||||
"asText": "Копировать как текст",
|
||||
"asMarkdown": "Копировать как Markdown",
|
||||
"success": "Скопировано в буфер обмена!"
|
||||
},
|
||||
"download": {
|
||||
"group": "Скачать",
|
||||
"text": "Текстовый файл (.txt)",
|
||||
"markdown": "Markdown (.md)",
|
||||
"json": "JSON файл (.json)"
|
||||
},
|
||||
"share": "Поделиться"
|
||||
}}
|
||||
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Vänligen välj en modell för att fortsätta",
|
||||
"deleteHistoryConfirmation": "Är du säker på att du vill radera denna historik?",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "Будь ласка, виберіть модель для продовження",
|
||||
"deleteHistoryConfirmation": "Ви впевнені, що хочете видалити цю історію?",
|
||||
"editHistoryTitle": "Введіть нову назву",
|
||||
"temporaryChat": "Тимчасовий чат"
|
||||
}
|
||||
"temporaryChat": "Тимчасовий чат",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "Копіювати",
|
||||
"asText": "Копіювати як текст",
|
||||
"asMarkdown": "Копіювати як Markdown",
|
||||
"success": "Скопійовано в буфер обміну!"
|
||||
},
|
||||
"download": {
|
||||
"group": "Завантажити",
|
||||
"text": "Текстовий файл (.txt)",
|
||||
"markdown": "Markdown (.md)",
|
||||
"json": "JSON файл (.json)"
|
||||
},
|
||||
"share": "Поділитися"
|
||||
}
|
||||
}
|
@ -9,5 +9,20 @@
|
||||
"validationSelectModel": "请选择一个模型以继续",
|
||||
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
|
||||
"editHistoryTitle": "输入一个新的标题",
|
||||
"temporaryChat": "临时聊天"
|
||||
"temporaryChat": "临时聊天",
|
||||
"more": {
|
||||
"copy": {
|
||||
"group": "复制",
|
||||
"asText": "复制为文本",
|
||||
"asMarkdown": "复制为 Markdown",
|
||||
"success": "已复制到剪贴板!"
|
||||
},
|
||||
"download": {
|
||||
"group": "下载",
|
||||
"text": "文本文件 (.txt)",
|
||||
"markdown": "Markdown 文件 (.md)",
|
||||
"json": "JSON 文件 (.json)"
|
||||
},
|
||||
"share": "分享"
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ import fetcher from "@/libs/fetcher"
|
||||
type Props = {
|
||||
messages: Message[]
|
||||
historyId: string
|
||||
open: boolean
|
||||
setOpen: (state: boolean) => void
|
||||
}
|
||||
|
||||
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 [open, setOpen] = useState(false)
|
||||
const [form] = Form.useForm()
|
||||
const name = Form.useWatch("name", form)
|
||||
|
||||
@ -142,75 +148,55 @@ export const ShareBtn: React.FC<Props> = ({ messages, historyId }) => {
|
||||
})
|
||||
|
||||
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
|
||||
title={t("share.modal.title")}
|
||||
open={open}
|
||||
footer={null}
|
||||
width={600}
|
||||
onCancel={() => setOpen(false)}>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={createShareLink}
|
||||
initialValues={{
|
||||
title: t("share.form.defaultValue.title"),
|
||||
name: t("share.form.defaultValue.name")
|
||||
}}>
|
||||
<Form.Item
|
||||
name="title"
|
||||
label={t("share.form.title.label")}
|
||||
rules={[{ required: true, message: t("share.form.title.required") }]}>
|
||||
<Input size="large" placeholder={t("share.form.title.placeholder")} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label={t("share.form.name.label")}
|
||||
rules={[{ required: true, message: t("share.form.name.required") }]}>
|
||||
<Input size="large" placeholder={t("share.form.name.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Modal
|
||||
title={t("share.modal.title")}
|
||||
open={open}
|
||||
footer={null}
|
||||
width={600}
|
||||
onCancel={() => setOpen(false)}>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={createShareLink}
|
||||
initialValues={{
|
||||
title: t("share.form.defaultValue.title"),
|
||||
name: t("share.form.defaultValue.name")
|
||||
}}>
|
||||
<Form.Item
|
||||
name="title"
|
||||
label={t("share.form.title.label")}
|
||||
rules={[
|
||||
{ required: true, message: t("share.form.title.required") }
|
||||
]}>
|
||||
<Input
|
||||
size="large"
|
||||
placeholder={t("share.form.title.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label={t("share.form.name.label")}
|
||||
rules={[
|
||||
{ required: true, message: t("share.form.name.required") }
|
||||
]}>
|
||||
<Input
|
||||
size="large"
|
||||
placeholder={t("share.form.name.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<div className="max-h-[180px] overflow-x-auto border dark:border-gray-700 rounded-md p-2">
|
||||
<div className="flex flex-col p-3">
|
||||
{messages.map((message, index) => (
|
||||
<PlaygroundMessage key={index} {...message} username={name} />
|
||||
))}
|
||||
</div>
|
||||
<Form.Item>
|
||||
<div className="max-h-[180px] overflow-x-auto border dark:border-gray-700 rounded-md p-2">
|
||||
<div className="flex flex-col p-3">
|
||||
{messages.map((message, index) => (
|
||||
<PlaygroundMessage key={index} {...message} username={name} />
|
||||
))}
|
||||
</div>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex items-center rounded-md border border-transparent bg-black px-2 py-2.5 text-md font-medium leading-4 text-white shadow-sm dark:bg-white dark:text-gray-800 disabled:opacity-50 ">
|
||||
{isPending
|
||||
? t("share.form.btn.saving")
|
||||
: t("share.form.btn.save")}
|
||||
</button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</>
|
||||
<Form.Item>
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex items-center rounded-md border border-transparent bg-black px-2 py-2.5 text-md font-medium leading-4 text-white shadow-sm dark:bg-white dark:text-gray-800 disabled:opacity-50 ">
|
||||
{isPending
|
||||
? t("share.form.btn.saving")
|
||||
: t("share.form.btn.save")}
|
||||
</button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -19,10 +19,10 @@ import { fetchChatModels } from "~/services/ollama"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { Select, Tooltip } from "antd"
|
||||
import { getAllPrompts } from "@/db"
|
||||
import { ShareBtn } from "~/components/Common/ShareBtn"
|
||||
import { ProviderIcons } from "../Common/ProviderIcon"
|
||||
import { NewChat } from "./NewChat"
|
||||
import { PageAssistSelect } from "../Select"
|
||||
import { MoreOptions } from "./MoreOptions"
|
||||
type Props = {
|
||||
setSidebarOpen: (open: boolean) => void
|
||||
setOpenModelSettings: (open: boolean) => void
|
||||
@ -50,7 +50,11 @@ export const Header: React.FC<Props> = ({
|
||||
historyId,
|
||||
temporaryChat
|
||||
} = useMessageOption()
|
||||
const { data: models, isLoading: isModelsLoading, refetch } = useQuery({
|
||||
const {
|
||||
data: models,
|
||||
isLoading: isModelsLoading,
|
||||
refetch
|
||||
} = useQuery({
|
||||
queryKey: ["fetchModel"],
|
||||
queryFn: () => fetchChatModels({ returnEmpty: true }),
|
||||
refetchIntervalInBackground: false,
|
||||
@ -134,7 +138,6 @@ export const Header: React.FC<Props> = ({
|
||||
),
|
||||
value: model.model
|
||||
}))}
|
||||
|
||||
onRefresh={() => {
|
||||
refetch()
|
||||
}}
|
||||
@ -189,6 +192,19 @@ export const Header: React.FC<Props> = ({
|
||||
<div className="flex flex-1 justify-end px-4">
|
||||
<div className="ml-4 flex items-center md:ml-6">
|
||||
<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 && (
|
||||
<Tooltip title={t("common:currentChatModelSettings")}>
|
||||
<button
|
||||
@ -198,12 +214,6 @@ export const Header: React.FC<Props> = ({
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{pathname === "/" &&
|
||||
messages.length > 0 &&
|
||||
!streaming &&
|
||||
shareModeEnabled && (
|
||||
<ShareBtn historyId={historyId} messages={messages} />
|
||||
)}
|
||||
<Tooltip title={t("githubRepository")}>
|
||||
<a
|
||||
href="https://github.com/n4ze3m/page-assist"
|
||||
|
163
src/components/Layouts/MoreOptions.tsx
Normal file
163
src/components/Layouts/MoreOptions.tsx
Normal 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`)
|
||||
.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}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user