Merge branch 'main' b0c6f6d 20230616 into pro

This commit is contained in:
2023-06-22 13:20:21 +08:00
31 changed files with 794 additions and 735 deletions
+102 -43
View File
@@ -1,5 +1,11 @@
import { useDebouncedCallback } from "use-debounce";
import { useState, useRef, useEffect, useLayoutEffect } from "react";
import React, {
useState,
useRef,
useEffect,
useLayoutEffect,
useMemo,
} from "react";
import SendWhiteIcon from "../icons/send-white.svg";
import BrainIcon from "../icons/brain.svg";
@@ -61,6 +67,7 @@ import { useMaskStore } from "../store/mask";
import { useCommand } from "../command";
import { prettyObject } from "../utils/format";
import { ExportMessageModal } from "./exporter";
import { getClientConfig } from "../config/client";
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
loading: () => <LoadingIcon />,
@@ -279,6 +286,57 @@ function ClearContextDivider() {
);
}
function ChatAction(props: {
text: string;
icon: JSX.Element;
onClick: () => void;
}) {
const iconRef = useRef<HTMLDivElement>(null);
const textRef = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState({
full: 20,
icon: 20,
});
function updateWidth() {
if (!iconRef.current || !textRef.current) return;
const getWidth = (dom: HTMLDivElement) => dom.getBoundingClientRect().width;
const textWidth = getWidth(textRef.current);
const iconWidth = getWidth(iconRef.current);
setWidth({
full: textWidth + iconWidth,
icon: iconWidth,
});
}
useEffect(() => {
updateWidth();
}, []);
return (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={() => {
props.onClick();
setTimeout(updateWidth, 1);
}}
style={
{
"--icon-width": `${width.icon}px`,
"--full-width": `${width.full}px`,
} as React.CSSProperties
}
>
<div ref={iconRef} className={chatStyle["icon"]}>
{props.icon}
</div>
<div className={chatStyle["text"]} ref={textRef}>
{props.text}
</div>
</div>
);
}
function useScrollToBottom() {
// for auto-scroll
const scrollRef = useRef<HTMLDivElement>(null);
@@ -330,61 +388,60 @@ export function ChatActions(props: {
return (
<div className={chatStyle["chat-input-actions"]}>
{couldStop && (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={stopAll}
>
<StopIcon />
</div>
text={Locale.Chat.InputActions.Stop}
icon={<StopIcon />}
/>
)}
{!props.hitBottom && (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={props.scrollToBottom}
>
<BottomIcon />
</div>
text={Locale.Chat.InputActions.ToBottom}
icon={<BottomIcon />}
/>
)}
{props.hitBottom && (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={props.showPromptModal}
>
<SettingsIcon />
</div>
text={Locale.Chat.InputActions.Settings}
icon={<SettingsIcon />}
/>
)}
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={nextTheme}
>
{theme === Theme.Auto ? (
<AutoIcon />
) : theme === Theme.Light ? (
<LightIcon />
) : theme === Theme.Dark ? (
<DarkIcon />
) : null}
</div>
text={Locale.Chat.InputActions.Theme[theme]}
icon={
<>
{theme === Theme.Auto ? (
<AutoIcon />
) : theme === Theme.Light ? (
<LightIcon />
) : theme === Theme.Dark ? (
<DarkIcon />
) : null}
</>
}
/>
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={props.showPromptHints}
>
<PromptIcon />
</div>
text={Locale.Chat.InputActions.Prompt}
icon={<PromptIcon />}
/>
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
onClick={() => {
navigate(Path.Masks);
}}
>
<MaskIcon />
</div>
text={Locale.Chat.InputActions.Masks}
icon={<MaskIcon />}
/>
<div
className={`${chatStyle["chat-input-action"]} clickable`}
<ChatAction
text={Locale.Chat.InputActions.Clear}
icon={<BreakIcon />}
onClick={() => {
chatStore.updateCurrentSession((session) => {
if (session.clearContextIndex === session.messages.length) {
@@ -395,9 +452,7 @@ export function ChatActions(props: {
}
});
}}
>
<ClearIcon />
</div>
/>
</div>
);
}
@@ -656,9 +711,13 @@ export function Chat() {
}
};
const clientConfig = useMemo(() => getClientConfig(), []);
const location = useLocation();
const isChat = location.pathname === Path.Chat;
const autoFocus = !isMobileScreen || isChat; // only focus in chat page
const showMaxIcon = !isMobileScreen && !clientConfig?.isApp;
useCommand({
fill: setUserInput,
@@ -707,7 +766,7 @@ export function Chat() {
}}
/>
</div>
{!isMobileScreen && (
{showMaxIcon && (
<div className="window-action-button">
<IconButton
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}