settings.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { useState, useRef, useEffect } from "react";
  2. import EmojiPicker, { Emoji, Theme as EmojiTheme } from "emoji-picker-react";
  3. import styles from "./settings.module.scss";
  4. import ResetIcon from "../icons/reload.svg";
  5. import CloseIcon from "../icons/close.svg";
  6. import ClearIcon from "../icons/clear.svg";
  7. import { List, ListItem, Popover } from "./ui-lib";
  8. import { IconButton } from "./button";
  9. import { SubmitKey, useChatStore, Theme } from "../store";
  10. import { Avatar } from "./home";
  11. export function Settings(props: { closeSettings: () => void }) {
  12. const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  13. const [config, updateConfig, resetConfig, clearAllData] = useChatStore((state) => [
  14. state.config,
  15. state.updateConfig,
  16. state.resetConfig,
  17. state.clearAllData,
  18. ]);
  19. return (
  20. <>
  21. <div className={styles["window-header"]}>
  22. <div className={styles["window-header-title"]}>
  23. <div className={styles["window-header-main-title"]}>设置</div>
  24. <div className={styles["window-header-sub-title"]}>设置选项</div>
  25. </div>
  26. <div className={styles["window-actions"]}>
  27. <div className={styles["window-action-button"]}>
  28. <IconButton
  29. icon={<ClearIcon />}
  30. onClick={clearAllData}
  31. bordered
  32. title="清除所有数据"
  33. />
  34. </div>
  35. <div className={styles["window-action-button"]}>
  36. <IconButton
  37. icon={<ResetIcon />}
  38. onClick={resetConfig}
  39. bordered
  40. title="重置所有选项"
  41. />
  42. </div>
  43. <div className={styles["window-action-button"]}>
  44. <IconButton
  45. icon={<CloseIcon />}
  46. onClick={props.closeSettings}
  47. bordered
  48. title="关闭"
  49. />
  50. </div>
  51. </div>
  52. </div>
  53. <div className={styles["settings"]}>
  54. <List>
  55. <ListItem>
  56. <div className={styles["settings-title"]}>头像</div>
  57. <Popover
  58. onClose={() => setShowEmojiPicker(false)}
  59. content={
  60. <EmojiPicker
  61. lazyLoadEmojis
  62. theme={EmojiTheme.AUTO}
  63. onEmojiClick={(e) => {
  64. updateConfig((config) => (config.avatar = e.unified));
  65. setShowEmojiPicker(false);
  66. }}
  67. />
  68. }
  69. open={showEmojiPicker}
  70. >
  71. <div
  72. className={styles.avatar}
  73. onClick={() => setShowEmojiPicker(true)}
  74. >
  75. <Avatar role="user" />
  76. </div>
  77. </Popover>
  78. </ListItem>
  79. <ListItem>
  80. <div className={styles["settings-title"]}>发送键</div>
  81. <div className="">
  82. <select
  83. value={config.submitKey}
  84. onChange={(e) => {
  85. updateConfig(
  86. (config) =>
  87. (config.submitKey = e.target.value as any as SubmitKey)
  88. );
  89. }}
  90. >
  91. {Object.values(SubmitKey).map((v) => (
  92. <option value={v} key={v}>
  93. {v}
  94. </option>
  95. ))}
  96. </select>
  97. </div>
  98. </ListItem>
  99. <ListItem>
  100. <div className={styles["settings-title"]}>主题</div>
  101. <div className="">
  102. <select
  103. value={config.theme}
  104. onChange={(e) => {
  105. updateConfig(
  106. (config) => (config.theme = e.target.value as any as Theme)
  107. );
  108. }}
  109. >
  110. {Object.values(Theme).map((v) => (
  111. <option value={v} key={v}>
  112. {v}
  113. </option>
  114. ))}
  115. </select>
  116. </div>
  117. </ListItem>
  118. <ListItem>
  119. <div className={styles["settings-title"]}>紧凑边框</div>
  120. <input
  121. type="checkbox"
  122. checked={config.tightBorder}
  123. onChange={(e) =>
  124. updateConfig(
  125. (config) => (config.tightBorder = e.currentTarget.checked)
  126. )
  127. }
  128. ></input>
  129. </ListItem>
  130. </List>
  131. <List>
  132. <ListItem>
  133. <div className={styles["settings-title"]}>附带历史消息数</div>
  134. <input
  135. type="range"
  136. title={config.historyMessageCount.toString()}
  137. value={config.historyMessageCount}
  138. min="2"
  139. max="25"
  140. step="2"
  141. onChange={(e) =>
  142. updateConfig(
  143. (config) =>
  144. (config.historyMessageCount = e.target.valueAsNumber)
  145. )
  146. }
  147. ></input>
  148. </ListItem>
  149. <ListItem>
  150. <div className={styles["settings-title"]}>
  151. 历史消息压缩长度阈值
  152. </div>
  153. <input
  154. type="number"
  155. min={500}
  156. max={4000}
  157. value={config.compressMessageLengthThreshold}
  158. onChange={(e) =>
  159. updateConfig(
  160. (config) => (config.compressMessageLengthThreshold = e.currentTarget.valueAsNumber)
  161. )
  162. }
  163. ></input>
  164. </ListItem>
  165. <ListItem>
  166. <div className={styles["settings-title"]}>
  167. 上下文中包含机器人消息
  168. </div>
  169. <input
  170. type="checkbox"
  171. checked={config.sendBotMessages}
  172. onChange={(e) =>
  173. updateConfig(
  174. (config) => (config.sendBotMessages = e.currentTarget.checked)
  175. )
  176. }
  177. ></input>
  178. </ListItem>
  179. </List>
  180. </div>
  181. </>
  182. );
  183. }