feat: close #1762 add hover text for chat input actions

This commit is contained in:
Yidadaa 2023-06-13 02:27:39 +08:00
parent 0d4611052e
commit 88df4a2223
4 changed files with 135 additions and 41 deletions

View File

@ -17,10 +17,35 @@
transition: all ease 0.3s; transition: all ease 0.3s;
margin-bottom: 10px; margin-bottom: 10px;
align-items: center; align-items: center;
height: 16px;
&:not(:last-child) { &:not(:last-child) {
margin-right: 5px; margin-right: 5px;
} }
.text {
white-space: nowrap;
padding-left: 5px;
opacity: 0;
transform: translateX(-5px);
transition: all ease 0.3s;
transition-delay: 0.1s;
pointer-events: none;
}
&:hover {
.text {
opacity: 1;
transform: translate(0);
}
}
.text,
.icon {
display: flex;
align-items: center;
justify-content: center;
}
} }
} }

View File

@ -279,6 +279,52 @@ function ClearContextDivider() {
); );
} }
function ChatAction(props: {
text: string;
icon: JSX.Element;
onClick: () => void;
}) {
const iconRef = useRef<HTMLDivElement>(null);
const textRef = useRef<HTMLDivElement>(null);
const [hovering, setHovering] = useState(false);
const [width, setWidth] = useState(20);
const 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(hovering ? textWidth + iconWidth : iconWidth);
};
useEffect(() => {
updateWidth();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hovering]);
return (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
style={{
width,
}}
onClick={() => {
props.onClick();
setTimeout(updateWidth, 1);
}}
>
<div ref={iconRef} className={chatStyle["icon"]}>
{props.icon}
</div>
<div className={chatStyle["text"]} ref={textRef}>
{props.text}
</div>
</div>
);
}
function useScrollToBottom() { function useScrollToBottom() {
// for auto-scroll // for auto-scroll
const scrollRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<HTMLDivElement>(null);
@ -330,61 +376,60 @@ export function ChatActions(props: {
return ( return (
<div className={chatStyle["chat-input-actions"]}> <div className={chatStyle["chat-input-actions"]}>
{couldStop && ( {couldStop && (
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={stopAll} onClick={stopAll}
> text={Locale.Chat.InputActions.Stop}
<StopIcon /> icon={<StopIcon />}
</div> />
)} )}
{!props.hitBottom && ( {!props.hitBottom && (
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={props.scrollToBottom} onClick={props.scrollToBottom}
> text={Locale.Chat.InputActions.ToBottom}
<BottomIcon /> icon={<BottomIcon />}
</div> />
)} )}
{props.hitBottom && ( {props.hitBottom && (
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={props.showPromptModal} onClick={props.showPromptModal}
> text={Locale.Chat.InputActions.Settings}
<SettingsIcon /> icon={<SettingsIcon />}
</div> />
)} )}
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={nextTheme} onClick={nextTheme}
> text={Locale.Chat.InputActions.Theme[theme]}
{theme === Theme.Auto ? ( icon={
<AutoIcon /> <>
) : theme === Theme.Light ? ( {theme === Theme.Auto ? (
<LightIcon /> <AutoIcon />
) : theme === Theme.Dark ? ( ) : theme === Theme.Light ? (
<DarkIcon /> <LightIcon />
) : null} ) : theme === Theme.Dark ? (
</div> <DarkIcon />
) : null}
</>
}
/>
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={props.showPromptHints} onClick={props.showPromptHints}
> text={Locale.Chat.InputActions.Prompt}
<PromptIcon /> icon={<PromptIcon />}
</div> />
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={() => { onClick={() => {
navigate(Path.Masks); navigate(Path.Masks);
}} }}
> text={Locale.Chat.InputActions.Masks}
<MaskIcon /> icon={<MaskIcon />}
</div> />
<div <ChatAction
className={`${chatStyle["chat-input-action"]} clickable`} text={Locale.Chat.InputActions.Clear}
icon={<BreakIcon />}
onClick={() => { onClick={() => {
chatStore.updateCurrentSession((session) => { chatStore.updateCurrentSession((session) => {
if (session.clearContextIndex === session.messages.length) { if (session.clearContextIndex === session.messages.length) {
@ -395,9 +440,7 @@ export function ChatActions(props: {
} }
}); });
}} }}
> />
<BreakIcon />
</div>
</div> </div>
); );
} }

View File

@ -27,6 +27,19 @@ const cn = {
Retry: "重试", Retry: "重试",
Delete: "删除", Delete: "删除",
}, },
InputActions: {
Stop: "停止响应",
ToBottom: "滚到最新",
Theme: {
auto: "自动主题",
light: "亮色模式",
dark: "深色模式",
},
Prompt: "快捷指令",
Masks: "所有面具",
Clear: "清除聊天",
Settings: "对话设置",
},
Rename: "重命名对话", Rename: "重命名对话",
Typing: "正在输入…", Typing: "正在输入…",
Input: (submitKey: string) => { Input: (submitKey: string) => {

View File

@ -28,6 +28,19 @@ const en: RequiredLocaleType = {
Retry: "Retry", Retry: "Retry",
Delete: "Delete", Delete: "Delete",
}, },
InputActions: {
Stop: "Stop",
ToBottom: "To Latest",
Theme: {
auto: "Auto",
light: "Light Theme",
dark: "Dark Theme",
},
Prompt: "Prompts",
Masks: "Masks",
Clear: "Clear Context",
Settings: "Settings",
},
Rename: "Rename Chat", Rename: "Rename Chat",
Typing: "Typing…", Typing: "Typing…",
Input: (submitKey: string) => { Input: (submitKey: string) => {