Refined UI,code logic for improved user experience

This commit is contained in:
2023-06-23 20:07:43 +08:00
parent 8420085fb1
commit 6711506acd
16 changed files with 170 additions and 320 deletions
+11
View File
@@ -1,4 +1,6 @@
import DeleteIcon from "../icons/delete.svg";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPen } from '@fortawesome/free-solid-svg-icons'
import BotIcon from "../icons/bot.svg";
import styles from "./home.module.scss";
@@ -20,6 +22,7 @@ import { useRef, useEffect } from "react";
export function ChatItem(props: {
onClick?: () => void;
onRename?: () => void;
onDelete?: () => void;
title: string;
count: number;
@@ -77,6 +80,14 @@ export function ChatItem(props: {
</>
)}
<div
className={styles["chat-item-rename"]}
onClickCapture={props.onRename}
>
{/* <RenameIcon /> */}
<FontAwesomeIcon icon={faPen} />
</div>
<div
className={styles["chat-item-delete"]}
onClickCapture={props.onDelete}
+31 -15
View File
@@ -22,12 +22,18 @@ import ResetIcon from "../icons/reload.svg";
import ClearIcon from "../icons/clear.svg";
import SettingsIcon from "../icons/chat-settings.svg";
import Image from 'next/image'
import AvatarIcon from "../icons/star/happy.png";
import LightIcon from "../icons/light.svg";
import DarkIcon from "../icons/dark.svg";
import AutoIcon from "../icons/auto.svg";
import BottomIcon from "../icons/bottom.svg";
import StopIcon from "../icons/pause.svg";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPaintbrush, faTrashCan, faCircleHalfStroke } from '@fortawesome/free-solid-svg-icons'
import {
ChatMessage,
SubmitKey,
@@ -174,11 +180,11 @@ function useSubmitHandler() {
if (e.key !== "Enter") return false;
if (e.key === "Enter" && e.nativeEvent.isComposing) return false;
return (
(config.submitKey === SubmitKey.AltEnter && e.altKey) ||
(config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
(config.submitKey === SubmitKey.ShiftEnter && e.shiftKey) ||
(config.submitKey === SubmitKey.MetaEnter && e.metaKey) ||
(config.submitKey === SubmitKey.Enter &&
(submitKey === SubmitKey.AltEnter && e.altKey) ||
(submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
(submitKey === SubmitKey.ShiftEnter && e.shiftKey) ||
(submitKey === SubmitKey.MetaEnter && e.metaKey) ||
(submitKey === SubmitKey.Enter &&
!e.altKey &&
!e.ctrlKey &&
!e.shiftKey &&
@@ -401,13 +407,19 @@ export function ChatActions(props: {
icon={<BottomIcon />}
/>
)}
{props.hitBottom && (
{/* {props.hitBottom && (
<ChatAction
onClick={props.showPromptModal}
text={Locale.Chat.InputActions.Settings}
icon={<SettingsIcon />}
/>
)}
)} */}
<ChatAction
onClick={() => {}} // todo: add ai painting action
text={Locale.Chat.InputActions.AIPaint}
icon={<FontAwesomeIcon icon={faPaintbrush} />}
/>
<ChatAction
onClick={nextTheme}
@@ -415,7 +427,8 @@ export function ChatActions(props: {
icon={
<>
{theme === Theme.Auto ? (
<AutoIcon />
// <FontAwesomeIcon icon="fa-solid fa-circle-half-stroke" />
<FontAwesomeIcon icon={faCircleHalfStroke} />
) : theme === Theme.Light ? (
<LightIcon />
) : theme === Theme.Dark ? (
@@ -431,17 +444,18 @@ export function ChatActions(props: {
icon={<PromptIcon />}
/>
<ChatAction
{/* <ChatAction
onClick={() => {
navigate(Path.Masks);
}}
text={Locale.Chat.InputActions.Masks}
icon={<MaskIcon />}
/>
/> */}
<ChatAction
text={Locale.Chat.InputActions.Clear}
icon={<ClearIcon />}
// icon={<FontAwesomeIcon icon="fa-regular fa-trash-can" />}
icon={<FontAwesomeIcon icon={faTrashCan} />}
onClick={() => {
chatStore.updateCurrentSession((session) => {
if (session.clearContextIndex === session.messages.length) {
@@ -820,7 +834,8 @@ export function Chat() {
<div className={styles["chat-message-container"]}>
<div className={styles["chat-message-avatar"]}>
{message.role === "user" ? (
<Avatar avatar={config.avatar} />
// <Avatar avatar={config.avatar} />
<Image src={AvatarIcon} alt="Avatar" width={32} height={32} />
) : (
<MaskAvatar mask={session.mask} />
)}
@@ -848,12 +863,12 @@ export function Chat() {
>
{Locale.Chat.Actions.Delete}
</div>
<div
{/* <div
className={styles["chat-message-top-action"]}
onClick={() => onResend(message.id ?? i)}
>
{Locale.Chat.Actions.Retry}
</div>
</div> */}
</>
)}
@@ -930,7 +945,8 @@ export function Chat() {
/>
<IconButton
icon={<SendWhiteIcon />}
text={Locale.Chat.Send}
// text={Locale.Chat.Send}
text=''
className={styles["chat-input-send"]}
type="primary"
onClick={() => doSubmit(userInput)}
+30
View File
@@ -183,6 +183,24 @@
animation: slide-in ease 0.3s;
}
.chat-item-rename {
position: absolute;
top: 10px;
right: 30px;
transition: all ease 0.3s;
opacity: 0;
cursor: pointer;
}
.chat-item:hover > .chat-item-rename {
opacity: 0.5;
transform: translateX(-10px);
}
.chat-item:hover > .chat-item-rename:hover {
opacity: 1;
}
.chat-item-delete {
position: absolute;
top: 10px;
@@ -283,8 +301,20 @@
}
}
.chat-item-rename {
top: 15px;
right: 35px;
opacity: 1;
}
.chat-item:hover > .chat-item-rename {
opacity: 0.5;
right: 30px;
}
.chat-item-delete {
top: 15px;
opacity: 1; // 手机模式下始终显示
}
.chat-item:hover > .chat-item-delete {
+2 -2
View File
@@ -158,14 +158,14 @@ export function SideBar(props: { className?: string }) {
<div className={styles["sidebar-tail"]}>
<div className={styles["sidebar-actions"]}>
<div className={styles["sidebar-action"] + " " + styles.mobile}>
<IconButton
{/* <IconButton
icon={<CloseIcon />}
onClick={() => {
if (confirm(Locale.Home.DeleteChat)) {
chatStore.deleteSession(chatStore.currentSessionIndex);
}
}}
/>
/> */}
</div>
<div className={styles["sidebar-action"]}>
{/* <Link to={Path.Settings}>
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

+3 -1
View File
@@ -39,6 +39,7 @@ const cn = {
Masks: "所有面具",
Clear: "清除聊天",
Settings: "对话设置",
AIPaint: "AI绘画",
},
Rename: "重命名对话",
Typing: "正在输入…",
@@ -47,7 +48,8 @@ const cn = {
if (submitKey === String(SubmitKey.Enter)) {
inputHints += "Shift + Enter 换行";
}
return inputHints + "/ 触发补全";
// return inputHints + "/ 触发补全";
return inputHints;
},
Send: "发送",
Config: {
+3 -1
View File
@@ -40,6 +40,7 @@ const en: RequiredLocaleType = {
Masks: "Masks",
Clear: "Clear Context",
Settings: "Settings",
AIPaint: "AI Paint",
},
Rename: "Rename Chat",
Typing: "Typing…",
@@ -48,7 +49,8 @@ const en: RequiredLocaleType = {
if (submitKey === String(SubmitKey.Enter)) {
inputHints += ", Shift + Enter to wrap";
}
return inputHints + ", / to search prompts";
// return inputHints + ", / to search prompts";
return inputHints;
},
Send: "Send",
Config: {
+44 -29
View File
@@ -19,7 +19,7 @@ export enum Theme {
export const DEFAULT_CONFIG = {
// submitKey: SubmitKey.CtrlEnter as SubmitKey,
submitKey: SubmitKey.Enter as SubmitKey,
submitKey: SubmitKey.Enter,
avatar: "1f603",
fontSize: 14,
theme: Theme.Auto as Theme,
@@ -156,35 +156,50 @@ export const ModalConfigValidator = {
},
};
export const useAppConfig = create<ChatConfigStore>()(
persist(
(set, get) => ({
...DEFAULT_CONFIG,
// export const useAppConfig = create<ChatConfigStore>()(
// persist(
// (set, get) => ({
// ...DEFAULT_CONFIG,
reset() {
set(() => ({ ...DEFAULT_CONFIG }));
},
// reset() {
// set(() => ({ ...DEFAULT_CONFIG }));
// },
update(updater) {
const config = { ...get() };
updater(config);
set(() => config);
},
}),
{
name: StoreKey.Config,
version: 2,
migrate(persistedState, version) {
if (version === 2) return persistedState as any;
// update(updater) {
// const config = { ...get() };
// updater(config);
// set(() => config);
// },
// }),
// {
// name: StoreKey.Config,
// version: 2,
// migrate(persistedState, version) {
// if (version === 2) return persistedState as any;
const state = persistedState as ChatConfig;
state.modelConfig.sendMemory = true;
state.modelConfig.historyMessageCount = 4;
state.modelConfig.compressMessageLengthThreshold = 1000;
state.dontShowMaskSplashScreen = false;
// const state = persistedState as ChatConfig;
// state.modelConfig.sendMemory = true;
// state.modelConfig.historyMessageCount = 4;
// state.modelConfig.compressMessageLengthThreshold = 1000;
// state.dontShowMaskSplashScreen = false;
return state;
},
},
),
);
// return state;
// },
// },
// ),
// );
// 取消 AppConfig 的持久化
export const useAppConfig = create<ChatConfigStore>((set, get) => ({
...DEFAULT_CONFIG,
reset() {
set(() => ({ ...DEFAULT_CONFIG }));
},
update(updater) {
const config = { ...get() };
updater(config);
set(() => config);
},
}));