perf: improve prompt list performance
This commit is contained in:
parent
a69cec89fb
commit
e509749421
@ -7,6 +7,20 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edit-prompt-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.edit-prompt-title {
|
||||
max-width: unset;
|
||||
margin-bottom: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
.edit-prompt-content {
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.user-prompt-modal {
|
||||
min-height: 40vh;
|
||||
|
||||
@ -18,47 +32,42 @@
|
||||
}
|
||||
|
||||
.user-prompt-list {
|
||||
padding: 10px 0;
|
||||
border: var(--border-in-light);
|
||||
border-radius: 10px;
|
||||
|
||||
.user-prompt-item {
|
||||
margin-bottom: 10px;
|
||||
widows: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: var(--border-in-light);
|
||||
}
|
||||
|
||||
.user-prompt-header {
|
||||
display: flex;
|
||||
widows: 100%;
|
||||
margin-bottom: 5px;
|
||||
max-width: calc(100% - 100px);
|
||||
|
||||
.user-prompt-title {
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
margin-right: 5px;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.user-prompt-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.user-prompt-button {
|
||||
height: 100%;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.user-prompt-content {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-prompt-content {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
margin-right: 10px;
|
||||
font-size: 12px;
|
||||
flex-grow: 1;
|
||||
.user-prompt-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.user-prompt-button {
|
||||
height: 100%;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,12 @@ import { useState, useEffect, useMemo, HTMLProps, useRef } from "react";
|
||||
import styles from "./settings.module.scss";
|
||||
|
||||
import ResetIcon from "../icons/reload.svg";
|
||||
import AddIcon from "../icons/add.svg";
|
||||
import CloseIcon from "../icons/close.svg";
|
||||
import CopyIcon from "../icons/copy.svg";
|
||||
import ClearIcon from "../icons/clear.svg";
|
||||
import EditIcon from "../icons/edit.svg";
|
||||
import EyeIcon from "../icons/eye.svg";
|
||||
import { Input, List, ListItem, Modal, PasswordInput, Popover } from "./ui-lib";
|
||||
import { ModelConfigList } from "./model-config";
|
||||
|
||||
@ -30,6 +32,55 @@ import { InputRange } from "./input-range";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Avatar, AvatarPicker } from "./emoji";
|
||||
|
||||
function EditPromptModal(props: { id: number; onClose: () => void }) {
|
||||
const promptStore = usePromptStore();
|
||||
const prompt = promptStore.get(props.id);
|
||||
|
||||
return prompt ? (
|
||||
<div className="modal-mask">
|
||||
<Modal
|
||||
title={Locale.Settings.Prompt.EditModal.Title}
|
||||
onClose={props.onClose}
|
||||
actions={[
|
||||
<IconButton
|
||||
key=""
|
||||
onClick={props.onClose}
|
||||
text={Locale.UI.Confirm}
|
||||
bordered
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
<div className={styles["edit-prompt-modal"]}>
|
||||
<input
|
||||
type="text"
|
||||
value={prompt.title}
|
||||
readOnly={!prompt.isUser}
|
||||
className={styles["edit-prompt-title"]}
|
||||
onInput={(e) =>
|
||||
promptStore.update(
|
||||
props.id,
|
||||
(prompt) => (prompt.title = e.currentTarget.value),
|
||||
)
|
||||
}
|
||||
></input>
|
||||
<Input
|
||||
value={prompt.content}
|
||||
readOnly={!prompt.isUser}
|
||||
className={styles["edit-prompt-content"]}
|
||||
rows={10}
|
||||
onInput={(e) =>
|
||||
promptStore.update(
|
||||
props.id,
|
||||
(prompt) => (prompt.content = e.currentTarget.value),
|
||||
)
|
||||
}
|
||||
></Input>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
function UserPromptModal(props: { onClose?: () => void }) {
|
||||
const promptStore = usePromptStore();
|
||||
const userPrompts = promptStore.getUserPrompts();
|
||||
@ -39,6 +90,8 @@ function UserPromptModal(props: { onClose?: () => void }) {
|
||||
const [searchPrompts, setSearchPrompts] = useState<Prompt[]>([]);
|
||||
const prompts = searchInput.length > 0 ? searchPrompts : allPrompts;
|
||||
|
||||
const [editingPromptId, setEditingPromptId] = useState<number>();
|
||||
|
||||
useEffect(() => {
|
||||
if (searchInput.length > 0) {
|
||||
const searchResult = SearchService.search(searchInput);
|
||||
@ -56,8 +109,13 @@ function UserPromptModal(props: { onClose?: () => void }) {
|
||||
actions={[
|
||||
<IconButton
|
||||
key="add"
|
||||
onClick={() => promptStore.add({ title: "", content: "" })}
|
||||
icon={<ClearIcon />}
|
||||
onClick={() =>
|
||||
promptStore.add({
|
||||
title: "Empty Prompt",
|
||||
content: "Empty Prompt Content",
|
||||
})
|
||||
}
|
||||
icon={<AddIcon />}
|
||||
bordered
|
||||
text={Locale.Settings.Prompt.Modal.Add}
|
||||
/>,
|
||||
@ -76,57 +134,51 @@ function UserPromptModal(props: { onClose?: () => void }) {
|
||||
{prompts.map((v, _) => (
|
||||
<div className={styles["user-prompt-item"]} key={v.id ?? v.title}>
|
||||
<div className={styles["user-prompt-header"]}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles["user-prompt-title"]}
|
||||
value={v.title}
|
||||
readOnly={!v.isUser}
|
||||
onChange={(e) => {
|
||||
if (v.isUser) {
|
||||
promptStore.updateUserPrompts(
|
||||
v.id!,
|
||||
(prompt) => (prompt.title = e.currentTarget.value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
></input>
|
||||
|
||||
<div className={styles["user-prompt-buttons"]}>
|
||||
{v.isUser && (
|
||||
<IconButton
|
||||
icon={<ClearIcon />}
|
||||
bordered
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => promptStore.remove(v.id!)}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
icon={<CopyIcon />}
|
||||
bordered
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => copyToClipboard(v.content)}
|
||||
/>
|
||||
<div className={styles["user-prompt-title"]}>{v.title}</div>
|
||||
<div className={styles["user-prompt-content"] + " one-line"}>
|
||||
{v.content}
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
rows={2}
|
||||
value={v.content}
|
||||
className={styles["user-prompt-content"]}
|
||||
readOnly={!v.isUser}
|
||||
onChange={(e) => {
|
||||
if (v.isUser) {
|
||||
promptStore.updateUserPrompts(
|
||||
v.id!,
|
||||
(prompt) => (prompt.content = e.currentTarget.value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className={styles["user-prompt-buttons"]}>
|
||||
{v.isUser && (
|
||||
<IconButton
|
||||
icon={<ClearIcon />}
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => promptStore.remove(v.id!)}
|
||||
/>
|
||||
)}
|
||||
{v.isUser ? (
|
||||
<IconButton
|
||||
icon={<EditIcon />}
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => setEditingPromptId(v.id)}
|
||||
/>
|
||||
) : (
|
||||
<IconButton
|
||||
icon={<EyeIcon />}
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => setEditingPromptId(v.id)}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
icon={<CopyIcon />}
|
||||
className={styles["user-prompt-button"]}
|
||||
onClick={() => copyToClipboard(v.content)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{editingPromptId !== undefined && (
|
||||
<EditPromptModal
|
||||
id={editingPromptId!}
|
||||
onClose={() => setEditingPromptId(undefined)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -116,9 +116,12 @@ const cn = {
|
||||
Edit: "编辑",
|
||||
Modal: {
|
||||
Title: "提示词列表",
|
||||
Add: "增加一条",
|
||||
Add: "新建",
|
||||
Search: "搜索提示词",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "编辑提示词",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "附带历史消息数",
|
||||
@ -223,6 +226,14 @@ const cn = {
|
||||
SubTitle: "现在开始,与面具背后的灵魂思维碰撞",
|
||||
More: "搜索更多",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "确认",
|
||||
Cancel: "取消",
|
||||
Close: "关闭",
|
||||
Create: "新建",
|
||||
Edit: "编辑",
|
||||
},
|
||||
};
|
||||
|
||||
export type LocaleType = typeof cn;
|
||||
|
@ -121,6 +121,9 @@ const de: LocaleType = {
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Edit Prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Anzahl der angehängten Nachrichten",
|
||||
@ -230,6 +233,14 @@ const de: LocaleType = {
|
||||
NotShow: "Not Show Again",
|
||||
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "Confirm",
|
||||
Cancel: "Cancel",
|
||||
Close: "Close",
|
||||
Create: "Create",
|
||||
Edit: "Edit",
|
||||
},
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
@ -120,6 +120,9 @@ const en: LocaleType = {
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Edit Prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Attached Messages Count",
|
||||
@ -226,6 +229,14 @@ const en: LocaleType = {
|
||||
NotShow: "Not Show Again",
|
||||
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "Confirm",
|
||||
Cancel: "Cancel",
|
||||
Close: "Close",
|
||||
Create: "Create",
|
||||
Edit: "Edit",
|
||||
},
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
@ -120,6 +120,9 @@ const es: LocaleType = {
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Edit Prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Cantidad de mensajes adjuntos",
|
||||
@ -227,6 +230,14 @@ const es: LocaleType = {
|
||||
NotShow: "Not Show Again",
|
||||
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "Confirm",
|
||||
Cancel: "Cancel",
|
||||
Close: "Close",
|
||||
Create: "Create",
|
||||
Edit: "Edit",
|
||||
},
|
||||
};
|
||||
|
||||
export default es;
|
||||
|
@ -120,6 +120,9 @@ const it: LocaleType = {
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Edit Prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Conteggio dei messaggi allegati",
|
||||
@ -228,6 +231,14 @@ const it: LocaleType = {
|
||||
NotShow: "Not Show Again",
|
||||
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "Confirm",
|
||||
Cancel: "Cancel",
|
||||
Close: "Close",
|
||||
Create: "Create",
|
||||
Edit: "Edit",
|
||||
},
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
@ -122,6 +122,9 @@ const jp: LocaleType = {
|
||||
Add: "新規追加",
|
||||
Search: "プロンプトワード検索",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "编辑提示词",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "履歴メッセージ数を添付",
|
||||
@ -226,6 +229,14 @@ const jp: LocaleType = {
|
||||
NotShow: "不再展示",
|
||||
ConfirmNoShow: "确认禁用?禁用后可以随时在设置中重新启用。",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "确认",
|
||||
Cancel: "取消",
|
||||
Close: "关闭",
|
||||
Create: "新建",
|
||||
Edit: "编辑",
|
||||
},
|
||||
};
|
||||
|
||||
export default jp;
|
||||
|
@ -120,6 +120,9 @@ const tr: LocaleType = {
|
||||
Add: "Add One",
|
||||
Search: "Search Prompts",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "Edit Prompt",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Ekli Mesaj Sayısı",
|
||||
@ -228,6 +231,14 @@ const tr: LocaleType = {
|
||||
NotShow: "Not Show Again",
|
||||
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
|
||||
},
|
||||
|
||||
UI: {
|
||||
Confirm: "Confirm",
|
||||
Cancel: "Cancel",
|
||||
Close: "Close",
|
||||
Create: "Create",
|
||||
Edit: "Edit",
|
||||
},
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
@ -118,6 +118,9 @@ const tw: LocaleType = {
|
||||
Add: "新增一條",
|
||||
Search: "搜尋提示詞",
|
||||
},
|
||||
EditModal: {
|
||||
Title: "编辑提示词",
|
||||
},
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "附帶歷史訊息數",
|
||||
@ -219,6 +222,13 @@ const tw: LocaleType = {
|
||||
NotShow: "不再展示",
|
||||
ConfirmNoShow: "确认禁用?禁用后可以随时在设置中重新启用。",
|
||||
},
|
||||
UI: {
|
||||
Confirm: "确认",
|
||||
Cancel: "取消",
|
||||
Close: "关闭",
|
||||
Create: "新建",
|
||||
Edit: "编辑",
|
||||
},
|
||||
};
|
||||
|
||||
export default tw;
|
||||
|
@ -17,11 +17,12 @@ export interface PromptStore {
|
||||
prompts: Record<number, Prompt>;
|
||||
|
||||
add: (prompt: Prompt) => number;
|
||||
get: (id: number) => Prompt | undefined;
|
||||
remove: (id: number) => void;
|
||||
search: (text: string) => Prompt[];
|
||||
update: (id: number, updater: (prompt: Prompt) => void) => void;
|
||||
|
||||
getUserPrompts: () => Prompt[];
|
||||
updateUserPrompts: (id: number, updater: (prompt: Prompt) => void) => void;
|
||||
}
|
||||
|
||||
export const SearchService = {
|
||||
@ -81,6 +82,16 @@ export const usePromptStore = create<PromptStore>()(
|
||||
return prompt.id!;
|
||||
},
|
||||
|
||||
get(id) {
|
||||
const targetPrompt = get().prompts[id];
|
||||
|
||||
if (!targetPrompt) {
|
||||
return SearchService.builtinPrompts.find((v) => v.id === id);
|
||||
}
|
||||
|
||||
return targetPrompt;
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
const prompts = get().prompts;
|
||||
delete prompts[id];
|
||||
@ -98,7 +109,7 @@ export const usePromptStore = create<PromptStore>()(
|
||||
return userPrompts;
|
||||
},
|
||||
|
||||
updateUserPrompts(id: number, updater) {
|
||||
update(id: number, updater) {
|
||||
const prompt = get().prompts[id] ?? {
|
||||
title: "",
|
||||
content: "",
|
||||
|
@ -1,5 +1,6 @@
|
||||
dir="$(dirname "$0")"
|
||||
config=$dir/proxychains.conf
|
||||
host_ip=$(grep nameserver /etc/resolv.conf | sed 's/nameserver //')
|
||||
echo "proxying to $host_ip"
|
||||
cp $dir/proxychains.template.conf $config
|
||||
sed -i "\$s/.*/http $host_ip 7890/" $config
|
||||
|
Loading…
x
Reference in New Issue
Block a user