diff --git a/page-share.md b/page-share.md
new file mode 100644
index 0000000..34be44d
--- /dev/null
+++ b/page-share.md
@@ -0,0 +1,2 @@
+# Page Share
+
diff --git a/src/components/Common/ShareBtn.tsx b/src/components/Common/ShareBtn.tsx
new file mode 100644
index 0000000..395b216
--- /dev/null
+++ b/src/components/Common/ShareBtn.tsx
@@ -0,0 +1,193 @@
+import { Form, Image, Input, Modal, Tooltip, message } from "antd"
+import { Share } from "lucide-react"
+import { useState } from "react"
+import type { Message } from "~store/option"
+import Markdown from "./Markdown"
+import React from "react"
+import { useMutation } from "@tanstack/react-query"
+import { getPageShareUrl } from "~services/ollama"
+import { cleanUrl } from "~libs/clean-url"
+import { getUserId, saveWebshare } from "~libs/db"
+
+type Props = {
+ messages: Message[]
+}
+
+const reformatMessages = (messages: Message[], username: string) => {
+ return messages.map((message, idx) => {
+ return {
+ id: idx,
+ name: message.isBot ? message.name : username,
+ isBot: message.isBot,
+ message: message.message,
+ images: message.images
+ }
+ })
+}
+
+export const PlaygroundMessage = (
+ props: Message & {
+ username: string
+ }
+) => {
+ return (
+
+
+
+
+
+ {props.isBot ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {props.isBot ? props.name : props.username}
+
+
+
+
+
+ {/* source if aviable */}
+ {props.images && props.images.length > 0 && (
+
+ {props.images
+ .filter((image) => image.length > 0)
+ .map((image, index) => (
+
+ ))}
+
+ )}
+
+
+
+
+ )
+}
+
+export const ShareBtn: React.FC = ({ messages }) => {
+ const [open, setOpen] = useState(false)
+ const [form] = Form.useForm()
+ const name = Form.useWatch("name", form)
+
+ React.useEffect(() => {
+ if (messages.length > 0) {
+ form.setFieldsValue({
+ title: messages[0].message
+ })
+ }
+ }, [messages])
+
+ const onSubmit = async (values: { title: string; name: string }) => {
+ const owner_id = await getUserId()
+ const chat = reformatMessages(messages, values.name)
+ const title = values.title
+ const url = await getPageShareUrl()
+ const res = await fetch(`${cleanUrl(url)}/api/v1/share/create`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({
+ owner_id,
+ messages: chat,
+ title
+ })
+ })
+
+ if (!res.ok) throw new Error("Failed to create share link")
+
+ const data = await res.json()
+
+ return {
+ ...data,
+ url: `${cleanUrl(url)}/share/${data.chat_id}`,
+ api_url: cleanUrl(url),
+ share_id: data.chat_id
+ }
+ }
+
+ const { mutate: createShareLink, isPending } = useMutation({
+ mutationFn: onSubmit,
+ onSuccess: async (data) => {
+ const url = data.url
+ navigator.clipboard.writeText(url)
+ message.success("Link copied to clipboard")
+ await saveWebshare({ title: data.title, url, api_url: data.api_url, share_id: data.share_id })
+ setOpen(false)
+ },
+ onError: (error) => {
+ message.error(error?.message || "Failed to create share link")
+ }
+ })
+
+ return (
+ <>
+
+
+
+
+ setOpen(false)}>
+
+
+
+
+
+
+
+
+
+
+ {messages.map((message, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx
index 4c08354..f50f2d4 100644
--- a/src/components/Layouts/Layout.tsx
+++ b/src/components/Layouts/Layout.tsx
@@ -16,6 +16,7 @@ import {
ZapIcon
} from "lucide-react"
import { getAllPrompts } from "~libs/db"
+import { ShareBtn } from "~components/Common/ShareBtn"
export default function OptionLayout({
children
@@ -29,7 +30,9 @@ export default function OptionLayout({
clearChat,
selectedSystemPrompt,
setSelectedQuickPrompt,
- setSelectedSystemPrompt
+ setSelectedSystemPrompt,
+ messages,
+ streaming
} = useMessageOption()
const {
@@ -155,6 +158,9 @@ export default function OptionLayout({
+ {pathname === "/" && messages.length > 0 && !streaming && (
+
+ )}
{/*
{
return (
<>