Skip to content

Commit e509749

Browse files
committed
perf: improve prompt list performance
1 parent a69cec8 commit e509749

File tree

12 files changed

+235
-75
lines changed

12 files changed

+235
-75
lines changed

app/components/settings.module.scss

+37-28
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77
cursor: pointer;
88
}
99

10+
.edit-prompt-modal {
11+
display: flex;
12+
flex-direction: column;
13+
14+
.edit-prompt-title {
15+
max-width: unset;
16+
margin-bottom: 20px;
17+
text-align: left;
18+
}
19+
.edit-prompt-content {
20+
max-width: unset;
21+
}
22+
}
23+
1024
.user-prompt-modal {
1125
min-height: 40vh;
1226

@@ -18,48 +32,43 @@
1832
}
1933

2034
.user-prompt-list {
21-
padding: 10px 0;
35+
border: var(--border-in-light);
36+
border-radius: 10px;
2237

2338
.user-prompt-item {
24-
margin-bottom: 10px;
25-
widows: 100%;
39+
display: flex;
40+
justify-content: space-between;
41+
padding: 10px;
42+
43+
&:not(:last-child) {
44+
border-bottom: var(--border-in-light);
45+
}
2646

2747
.user-prompt-header {
28-
display: flex;
29-
widows: 100%;
30-
margin-bottom: 5px;
48+
max-width: calc(100% - 100px);
3149

3250
.user-prompt-title {
33-
flex-grow: 1;
34-
max-width: 100%;
35-
margin-right: 5px;
36-
padding: 5px;
51+
font-size: 14px;
52+
line-height: 2;
53+
font-weight: bold;
54+
}
55+
.user-prompt-content {
3756
font-size: 12px;
38-
text-align: left;
3957
}
58+
}
4059

41-
.user-prompt-buttons {
42-
display: flex;
43-
align-items: center;
60+
.user-prompt-buttons {
61+
display: flex;
62+
align-items: center;
4463

45-
.user-prompt-button {
46-
height: 100%;
64+
.user-prompt-button {
65+
height: 100%;
4766

48-
&:not(:last-child) {
49-
margin-right: 5px;
50-
}
67+
&:not(:last-child) {
68+
margin-right: 5px;
5169
}
5270
}
5371
}
54-
55-
.user-prompt-content {
56-
width: 100%;
57-
box-sizing: border-box;
58-
padding: 5px;
59-
margin-right: 10px;
60-
font-size: 12px;
61-
flex-grow: 1;
62-
}
6372
}
6473
}
6574

app/components/settings.tsx

+96-44
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { useState, useEffect, useMemo, HTMLProps, useRef } from "react";
33
import styles from "./settings.module.scss";
44

55
import ResetIcon from "../icons/reload.svg";
6+
import AddIcon from "../icons/add.svg";
67
import CloseIcon from "../icons/close.svg";
78
import CopyIcon from "../icons/copy.svg";
89
import ClearIcon from "../icons/clear.svg";
910
import EditIcon from "../icons/edit.svg";
11+
import EyeIcon from "../icons/eye.svg";
1012
import { Input, List, ListItem, Modal, PasswordInput, Popover } from "./ui-lib";
1113
import { ModelConfigList } from "./model-config";
1214

@@ -30,6 +32,55 @@ import { InputRange } from "./input-range";
3032
import { useNavigate } from "react-router-dom";
3133
import { Avatar, AvatarPicker } from "./emoji";
3234

35+
function EditPromptModal(props: { id: number; onClose: () => void }) {
36+
const promptStore = usePromptStore();
37+
const prompt = promptStore.get(props.id);
38+
39+
return prompt ? (
40+
<div className="modal-mask">
41+
<Modal
42+
title={Locale.Settings.Prompt.EditModal.Title}
43+
onClose={props.onClose}
44+
actions={[
45+
<IconButton
46+
key=""
47+
onClick={props.onClose}
48+
text={Locale.UI.Confirm}
49+
bordered
50+
/>,
51+
]}
52+
>
53+
<div className={styles["edit-prompt-modal"]}>
54+
<input
55+
type="text"
56+
value={prompt.title}
57+
readOnly={!prompt.isUser}
58+
className={styles["edit-prompt-title"]}
59+
onInput={(e) =>
60+
promptStore.update(
61+
props.id,
62+
(prompt) => (prompt.title = e.currentTarget.value),
63+
)
64+
}
65+
></input>
66+
<Input
67+
value={prompt.content}
68+
readOnly={!prompt.isUser}
69+
className={styles["edit-prompt-content"]}
70+
rows={10}
71+
onInput={(e) =>
72+
promptStore.update(
73+
props.id,
74+
(prompt) => (prompt.content = e.currentTarget.value),
75+
)
76+
}
77+
></Input>
78+
</div>
79+
</Modal>
80+
</div>
81+
) : null;
82+
}
83+
3384
function UserPromptModal(props: { onClose?: () => void }) {
3485
const promptStore = usePromptStore();
3586
const userPrompts = promptStore.getUserPrompts();
@@ -39,6 +90,8 @@ function UserPromptModal(props: { onClose?: () => void }) {
3990
const [searchPrompts, setSearchPrompts] = useState<Prompt[]>([]);
4091
const prompts = searchInput.length > 0 ? searchPrompts : allPrompts;
4192

93+
const [editingPromptId, setEditingPromptId] = useState<number>();
94+
4295
useEffect(() => {
4396
if (searchInput.length > 0) {
4497
const searchResult = SearchService.search(searchInput);
@@ -56,8 +109,13 @@ function UserPromptModal(props: { onClose?: () => void }) {
56109
actions={[
57110
<IconButton
58111
key="add"
59-
onClick={() => promptStore.add({ title: "", content: "" })}
60-
icon={<ClearIcon />}
112+
onClick={() =>
113+
promptStore.add({
114+
title: "Empty Prompt",
115+
content: "Empty Prompt Content",
116+
})
117+
}
118+
icon={<AddIcon />}
61119
bordered
62120
text={Locale.Settings.Prompt.Modal.Add}
63121
/>,
@@ -76,57 +134,51 @@ function UserPromptModal(props: { onClose?: () => void }) {
76134
{prompts.map((v, _) => (
77135
<div className={styles["user-prompt-item"]} key={v.id ?? v.title}>
78136
<div className={styles["user-prompt-header"]}>
79-
<input
80-
type="text"
81-
className={styles["user-prompt-title"]}
82-
value={v.title}
83-
readOnly={!v.isUser}
84-
onChange={(e) => {
85-
if (v.isUser) {
86-
promptStore.updateUserPrompts(
87-
v.id!,
88-
(prompt) => (prompt.title = e.currentTarget.value),
89-
);
90-
}
91-
}}
92-
></input>
93-
94-
<div className={styles["user-prompt-buttons"]}>
95-
{v.isUser && (
96-
<IconButton
97-
icon={<ClearIcon />}
98-
bordered
99-
className={styles["user-prompt-button"]}
100-
onClick={() => promptStore.remove(v.id!)}
101-
/>
102-
)}
137+
<div className={styles["user-prompt-title"]}>{v.title}</div>
138+
<div className={styles["user-prompt-content"] + " one-line"}>
139+
{v.content}
140+
</div>
141+
</div>
142+
143+
<div className={styles["user-prompt-buttons"]}>
144+
{v.isUser && (
103145
<IconButton
104-
icon={<CopyIcon />}
105-
bordered
146+
icon={<ClearIcon />}
106147
className={styles["user-prompt-button"]}
107-
onClick={() => copyToClipboard(v.content)}
148+
onClick={() => promptStore.remove(v.id!)}
108149
/>
109-
</div>
150+
)}
151+
{v.isUser ? (
152+
<IconButton
153+
icon={<EditIcon />}
154+
className={styles["user-prompt-button"]}
155+
onClick={() => setEditingPromptId(v.id)}
156+
/>
157+
) : (
158+
<IconButton
159+
icon={<EyeIcon />}
160+
className={styles["user-prompt-button"]}
161+
onClick={() => setEditingPromptId(v.id)}
162+
/>
163+
)}
164+
<IconButton
165+
icon={<CopyIcon />}
166+
className={styles["user-prompt-button"]}
167+
onClick={() => copyToClipboard(v.content)}
168+
/>
110169
</div>
111-
<Input
112-
rows={2}
113-
value={v.content}
114-
className={styles["user-prompt-content"]}
115-
readOnly={!v.isUser}
116-
onChange={(e) => {
117-
if (v.isUser) {
118-
promptStore.updateUserPrompts(
119-
v.id!,
120-
(prompt) => (prompt.content = e.currentTarget.value),
121-
);
122-
}
123-
}}
124-
/>
125170
</div>
126171
))}
127172
</div>
128173
</div>
129174
</Modal>
175+
176+
{editingPromptId !== undefined && (
177+
<EditPromptModal
178+
id={editingPromptId!}
179+
onClose={() => setEditingPromptId(undefined)}
180+
/>
181+
)}
130182
</div>
131183
);
132184
}

app/locales/cn.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,12 @@ const cn = {
116116
Edit: "编辑",
117117
Modal: {
118118
Title: "提示词列表",
119-
Add: "增加一条",
119+
Add: "新建",
120120
Search: "搜索提示词",
121121
},
122+
EditModal: {
123+
Title: "编辑提示词",
124+
},
122125
},
123126
HistoryCount: {
124127
Title: "附带历史消息数",
@@ -223,6 +226,14 @@ const cn = {
223226
SubTitle: "现在开始,与面具背后的灵魂思维碰撞",
224227
More: "搜索更多",
225228
},
229+
230+
UI: {
231+
Confirm: "确认",
232+
Cancel: "取消",
233+
Close: "关闭",
234+
Create: "新建",
235+
Edit: "编辑",
236+
},
226237
};
227238

228239
export type LocaleType = typeof cn;

app/locales/de.ts

+11
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ const de: LocaleType = {
121121
Add: "Add One",
122122
Search: "Search Prompts",
123123
},
124+
EditModal: {
125+
Title: "Edit Prompt",
126+
},
124127
},
125128
HistoryCount: {
126129
Title: "Anzahl der angehängten Nachrichten",
@@ -230,6 +233,14 @@ const de: LocaleType = {
230233
NotShow: "Not Show Again",
231234
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
232235
},
236+
237+
UI: {
238+
Confirm: "Confirm",
239+
Cancel: "Cancel",
240+
Close: "Close",
241+
Create: "Create",
242+
Edit: "Edit",
243+
},
233244
};
234245

235246
export default de;

app/locales/en.ts

+11
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ const en: LocaleType = {
120120
Add: "Add One",
121121
Search: "Search Prompts",
122122
},
123+
EditModal: {
124+
Title: "Edit Prompt",
125+
},
123126
},
124127
HistoryCount: {
125128
Title: "Attached Messages Count",
@@ -226,6 +229,14 @@ const en: LocaleType = {
226229
NotShow: "Not Show Again",
227230
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
228231
},
232+
233+
UI: {
234+
Confirm: "Confirm",
235+
Cancel: "Cancel",
236+
Close: "Close",
237+
Create: "Create",
238+
Edit: "Edit",
239+
},
229240
};
230241

231242
export default en;

app/locales/es.ts

+11
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ const es: LocaleType = {
120120
Add: "Add One",
121121
Search: "Search Prompts",
122122
},
123+
EditModal: {
124+
Title: "Edit Prompt",
125+
},
123126
},
124127
HistoryCount: {
125128
Title: "Cantidad de mensajes adjuntos",
@@ -227,6 +230,14 @@ const es: LocaleType = {
227230
NotShow: "Not Show Again",
228231
ConfirmNoShow: "Confirm to disable?You can enable it in settings later.",
229232
},
233+
234+
UI: {
235+
Confirm: "Confirm",
236+
Cancel: "Cancel",
237+
Close: "Close",
238+
Create: "Create",
239+
Edit: "Edit",
240+
},
230241
};
231242

232243
export default es;

0 commit comments

Comments
 (0)