reform the message box with bubble style
This commit is contained in:
@@ -722,7 +722,7 @@ export default function ChatBOX(props: {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{showGenerating && (
|
{showGenerating && (
|
||||||
<p className="p-2 my-2 animate-pulse dark:text-white message-content">
|
<p className="p-2 my-2 animate-pulse message-content">
|
||||||
{generatingMessage || Tr("Generating...")}
|
{generatingMessage || Tr("Generating...")}
|
||||||
...
|
...
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const logprobToColor = (logprob: number) => {
|
|||||||
// 绿色的RGB值为(0, 255, 0),红色的RGB值为(255, 0, 0)
|
// 绿色的RGB值为(0, 255, 0),红色的RGB值为(255, 0, 0)
|
||||||
const red = Math.round(255 * (1 - percent / 100));
|
const red = Math.round(255 * (1 - percent / 100));
|
||||||
const green = Math.round(255 * (percent / 100));
|
const green = Math.round(255 * (percent / 100));
|
||||||
const color = `rgb(${red}, ${green}, 0)`;
|
const color = `rgba(${red}, ${green}, 0, 0.5)`;
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|||||||
122
src/message.tsx
122
src/message.tsx
@@ -51,17 +51,26 @@ export default function Message(props: Props) {
|
|||||||
setChatStore({ ...chatStore });
|
setChatStore({ ...chatStore });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
🗑️
|
Delete
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
const CopiedHint = () => (
|
const CopiedHint = () => (
|
||||||
<span
|
<div role="alert" class="alert">
|
||||||
className={
|
<svg
|
||||||
"bg-purple-400 p-1 rounded shadow-md absolute z-20 left-1/2 top-3/4 transform -translate-x-1/2 -translate-y-1/2"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
}
|
fill="none"
|
||||||
>
|
viewBox="0 0 24 24"
|
||||||
{Tr("Message copied to clipboard!")}
|
class="stroke-info h-6 w-6 shrink-0"
|
||||||
</span>
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<span>{Tr("Message copied to clipboard!")}</span>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
@@ -78,7 +87,7 @@ export default function Message(props: Props) {
|
|||||||
copyToClipboard(textToCopy);
|
copyToClipboard(textToCopy);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
📋
|
Copy
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -105,51 +114,62 @@ export default function Message(props: Props) {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
className={`w-fit p-2 rounded my-2 ${
|
className={`chat min-w-16 w-fit p-2 my-2 ${
|
||||||
chat.role === "assistant"
|
chat.role === "assistant" ? "chat-start" : "chat-end"
|
||||||
? "bg-white dark:bg-gray-700 dark:text-white"
|
|
||||||
: "bg-green-400"
|
|
||||||
} ${chat.hide ? "opacity-50" : ""}`}
|
} ${chat.hide ? "opacity-50" : ""}`}
|
||||||
>
|
>
|
||||||
{chat.hide ? (
|
<div
|
||||||
<MessageHide chat={chat} />
|
className={`chat-bubble ${
|
||||||
) : typeof chat.content !== "string" ? (
|
chat.role === "assistant"
|
||||||
<MessageDetail chat={chat} renderMarkdown={renderMarkdown} />
|
? "chat-bubble-secondary"
|
||||||
) : chat.tool_calls ? (
|
: "chat-bubble-primary"
|
||||||
<MessageToolCall chat={chat} copyToClipboard={copyToClipboard} />
|
}`}
|
||||||
) : chat.role === "tool" ? (
|
>
|
||||||
<MessageToolResp chat={chat} copyToClipboard={copyToClipboard} />
|
{chat.hide ? (
|
||||||
) : renderMarkdown ? (
|
<MessageHide chat={chat} />
|
||||||
// @ts-ignore
|
) : typeof chat.content !== "string" ? (
|
||||||
<Markdown markdown={getMessageText(chat)} />
|
<MessageDetail chat={chat} renderMarkdown={renderMarkdown} />
|
||||||
) : (
|
) : chat.tool_calls ? (
|
||||||
<div className="message-content">
|
<MessageToolCall
|
||||||
{
|
chat={chat}
|
||||||
// only show when content is string or list of message
|
copyToClipboard={copyToClipboard}
|
||||||
// this check is used to avoid rendering tool call
|
/>
|
||||||
chat.content &&
|
) : chat.role === "tool" ? (
|
||||||
(chat.logprobs && renderColor
|
<MessageToolResp
|
||||||
? chat.logprobs.content
|
chat={chat}
|
||||||
.filter((c) => c.token)
|
copyToClipboard={copyToClipboard}
|
||||||
.map((c) => (
|
/>
|
||||||
<div
|
) : renderMarkdown ? (
|
||||||
style={{
|
// @ts-ignore
|
||||||
color: logprobToColor(c.logprob),
|
<Markdown markdown={getMessageText(chat)} />
|
||||||
display: "inline",
|
) : (
|
||||||
}}
|
<div className="message-content">
|
||||||
>
|
{
|
||||||
{c.token}
|
// only show when content is string or list of message
|
||||||
</div>
|
// this check is used to avoid rendering tool call
|
||||||
))
|
chat.content &&
|
||||||
: getMessageText(chat))
|
(chat.logprobs && renderColor
|
||||||
}
|
? chat.logprobs.content
|
||||||
</div>
|
.filter((c) => c.token)
|
||||||
)}
|
.map((c) => (
|
||||||
<hr className="mt-2" />
|
<div
|
||||||
<TTSPlay chat={chat} />
|
style={{
|
||||||
<div className="w-full flex justify-between">
|
backgroundColor: logprobToColor(c.logprob),
|
||||||
|
display: "inline",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{c.token}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
: getMessageText(chat))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="chat-footer opacity-50 flex gap-x-2">
|
||||||
|
<TTSPlay chat={chat} />
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
<button onClick={() => setShowEdit(true)}>🖋</button>
|
<button onClick={() => setShowEdit(true)}>Edit</button>
|
||||||
{chatStore.tts_api && chatStore.tts_key && (
|
{chatStore.tts_api && chatStore.tts_key && (
|
||||||
<TTSButton
|
<TTSButton
|
||||||
chatStore={chatStore}
|
chatStore={chatStore}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function MessageDetail({ chat, renderMarkdown }: Props) {
|
|||||||
{chat.content.map((mdt) =>
|
{chat.content.map((mdt) =>
|
||||||
mdt.type === "text" ? (
|
mdt.type === "text" ? (
|
||||||
chat.hide ? (
|
chat.hide ? (
|
||||||
mdt.text?.split("\n")[0].slice(0, 16) + "... (deleted)"
|
mdt.text?.split("\n")[0].slice(0, 16) + " ..."
|
||||||
) : renderMarkdown ? (
|
) : renderMarkdown ? (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
<Markdown markdown={mdt.text} />
|
<Markdown markdown={mdt.text} />
|
||||||
|
|||||||
@@ -6,7 +6,5 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function MessageHide({ chat }: Props) {
|
export function MessageHide({ chat }: Props) {
|
||||||
return (
|
return <div>{getMessageText(chat).split("\n")[0].slice(0, 18)} ...</div>;
|
||||||
<div>{getMessageText(chat).split("\n")[0].slice(0, 18)} ... (deleted)</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,6 +491,12 @@ export default (props: {
|
|||||||
<select data-choose-theme class="select select-bordered">
|
<select data-choose-theme class="select select-bordered">
|
||||||
<option value="light">Light</option>
|
<option value="light">Light</option>
|
||||||
<option value="dark">Dark</option>
|
<option value="dark">Dark</option>
|
||||||
|
<option value="cupcake">Cupcake</option>
|
||||||
|
<option value="halloween">Halloween</option>
|
||||||
|
<option value="wireframe">Wireframe</option>
|
||||||
|
<option value="sunset">Sunset</option>
|
||||||
|
<option value="lemonade">Lemonade</option>
|
||||||
|
<option value="luxury">Luxury</option>
|
||||||
<option value="cyberpunk">Cyberpunk</option>
|
<option value="cyberpunk">Cyberpunk</option>
|
||||||
<option value="black">Black</option>
|
<option value="black">Black</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Reference in New Issue
Block a user