Merge branch 'main' b0c6f6d 20230616 into pro
This commit is contained in:
+102
-43
@@ -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 />}
|
||||
|
||||
Reference in New Issue
Block a user