Add ShareBtn component and update SettingsOptionLayout

This commit is contained in:
n4ze3m
2024-03-09 18:43:39 +05:30
parent 3eabe10bde
commit 7ce79bb134
10 changed files with 526 additions and 3 deletions

View File

@@ -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 (
<div className="group w-full text-gray-800 dark:text-gray-100">
<div className="text-base gap-4 md:gap-6 md:max-w-2xl lg:max-w-xl xl:max-w-3xl flex lg:px-0 m-auto w-full">
<div className="flex flex-row gap-4 md:gap-6 md:max-w-2xl lg:max-w-xl xl:max-w-3xl m-auto w-full">
<div className="w-8 flex flex-col relative items-end">
<div className="relative h-7 w-7 p-1 rounded-sm text-white flex items-center justify-center text-opacity-100r">
{props.isBot ? (
<div className="absolute h-8 w-8 rounded-full bg-gradient-to-r from-green-300 to-purple-400"></div>
) : (
<div className="absolute h-8 w-8 rounded-full from-blue-400 to-blue-600 bg-gradient-to-r"></div>
)}
</div>
</div>
<div className="flex w-[calc(100%-50px)] flex-col gap-3 lg:w-[calc(100%-115px)]">
<span className="text-xs font-bold text-gray-800 dark:text-white">
{props.isBot ? props.name : props.username}
</span>
<div className="flex flex-grow flex-col">
<Markdown message={props.message} />
</div>
{/* source if aviable */}
{props.images && props.images.length > 0 && (
<div className="flex md:max-w-2xl lg:max-w-xl xl:max-w-3xl mt-4 m-auto w-full">
{props.images
.filter((image) => image.length > 0)
.map((image, index) => (
<Image
key={index}
src={image}
alt="Uploaded Image"
width={180}
className="rounded-md relative"
/>
))}
</div>
)}
</div>
</div>
</div>
</div>
)
}
export const ShareBtn: React.FC<Props> = ({ 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 (
<>
<Tooltip title="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="Share link to Chat"
open={open}
footer={null}
width={600}
onCancel={() => setOpen(false)}>
<Form
form={form}
layout="vertical"
onFinish={createShareLink}
initialValues={{
title: "Untitled Chat",
name: "Anonymous"
}}>
<Form.Item
name="title"
label="Chat Title"
rules={[{ required: true, message: "Please enter chat title" }]}>
<Input size="large" placeholder="Enter chat title" />
</Form.Item>
<Form.Item
name="name"
label="Your Name"
rules={[{ required: true, message: "Please enter your name" }]}>
<Input size="large" placeholder="Enter your name" />
</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>
</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 ? "Generating link..." : "Generate Link"}
</button>
</div>
</Form.Item>
</Form>
</Modal>
</>
)
}