settings.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { useState, useRef, useEffect } from "react";
  2. import EmojiPicker, { 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. import Locale, { changeLang, getLang } from '../locales'
  12. export function Settings(props: { closeSettings: () => void }) {
  13. const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  14. const [config, updateConfig, resetConfig, clearAllData] = useChatStore((state) => [
  15. state.config,
  16. state.updateConfig,
  17. state.resetConfig,
  18. state.clearAllData,
  19. ]);
  20. return (
  21. <>
  22. <div className={styles["window-header"]}>
  23. <div className={styles["window-header-title"]}>
  24. <div className={styles["window-header-main-title"]}>{Locale.Settings.Title}</div>
  25. <div className={styles["window-header-sub-title"]}>{Locale.Settings.SubTitle}</div>
  26. </div>
  27. <div className={styles["window-actions"]}>
  28. <div className={styles["window-action-button"]}>
  29. <IconButton
  30. icon={<ClearIcon />}
  31. onClick={clearAllData}
  32. bordered
  33. title={Locale.Settings.Actions.ClearAll}
  34. />
  35. </div>
  36. <div className={styles["window-action-button"]}>
  37. <IconButton
  38. icon={<ResetIcon />}
  39. onClick={resetConfig}
  40. bordered
  41. title={Locale.Settings.Actions.ResetAll}
  42. />
  43. </div>
  44. <div className={styles["window-action-button"]}>
  45. <IconButton
  46. icon={<CloseIcon />}
  47. onClick={props.closeSettings}
  48. bordered
  49. title={Locale.Settings.Actions.Close}
  50. />
  51. </div>
  52. </div>
  53. </div>
  54. <div className={styles["settings"]}>
  55. <List>
  56. <ListItem>
  57. <div className={styles["settings-title"]}>{Locale.Settings.Avatar}</div>
  58. <Popover
  59. onClose={() => setShowEmojiPicker(false)}
  60. content={
  61. <EmojiPicker
  62. lazyLoadEmojis
  63. theme={EmojiTheme.AUTO}
  64. onEmojiClick={(e) => {
  65. updateConfig((config) => (config.avatar = e.unified));
  66. setShowEmojiPicker(false);
  67. }}
  68. />
  69. }
  70. open={showEmojiPicker}
  71. >
  72. <div
  73. className={styles.avatar}
  74. onClick={() => setShowEmojiPicker(true)}
  75. >
  76. <Avatar role="user" />
  77. </div>
  78. </Popover>
  79. </ListItem>
  80. <ListItem>
  81. <div className={styles["settings-title"]}>{Locale.Settings.SendKey}</div>
  82. <div className="">
  83. <select
  84. value={config.submitKey}
  85. onChange={(e) => {
  86. updateConfig(
  87. (config) =>
  88. (config.submitKey = e.target.value as any as SubmitKey)
  89. );
  90. }}
  91. >
  92. {Object.values(SubmitKey).map((v) => (
  93. <option value={v} key={v}>
  94. {v}
  95. </option>
  96. ))}
  97. </select>
  98. </div>
  99. </ListItem>
  100. <ListItem>
  101. <div className={styles["settings-title"]}>{Locale.Settings.Theme}</div>
  102. <div className="">
  103. <select
  104. value={config.theme}
  105. onChange={(e) => {
  106. updateConfig(
  107. (config) => (config.theme = e.target.value as any as Theme)
  108. );
  109. }}
  110. >
  111. {Object.values(Theme).map((v) => (
  112. <option value={v} key={v}>
  113. {v}
  114. </option>
  115. ))}
  116. </select>
  117. </div>
  118. </ListItem>
  119. <ListItem>
  120. <div className={styles["settings-title"]}>{Locale.Settings.TightBorder}</div>
  121. <input
  122. type="checkbox"
  123. checked={config.tightBorder}
  124. onChange={(e) =>
  125. updateConfig(
  126. (config) => (config.tightBorder = e.currentTarget.checked)
  127. )
  128. }
  129. ></input>
  130. </ListItem>
  131. <ListItem>
  132. <div className={styles["settings-title"]}>{Locale.Settings.Lang.Name}</div>
  133. <div className="">
  134. <select
  135. value={getLang()}
  136. onChange={(e) => {
  137. changeLang(e.target.value as any)
  138. }}
  139. >
  140. <option value='en' key='en'>
  141. {Locale.Settings.Lang.Options.en}
  142. </option>
  143. <option value='cn' key='cn'>
  144. {Locale.Settings.Lang.Options.cn}
  145. </option>
  146. </select>
  147. </div>
  148. </ListItem>
  149. </List>
  150. <List>
  151. <ListItem>
  152. <div className={styles["settings-title"]}>{Locale.Settings.HistoryCount}</div>
  153. <input
  154. type="range"
  155. title={config.historyMessageCount.toString()}
  156. value={config.historyMessageCount}
  157. min="2"
  158. max="25"
  159. step="2"
  160. onChange={(e) =>
  161. updateConfig(
  162. (config) =>
  163. (config.historyMessageCount = e.target.valueAsNumber)
  164. )
  165. }
  166. ></input>
  167. </ListItem>
  168. <ListItem>
  169. <div className={styles["settings-title"]}>
  170. {Locale.Settings.CompressThreshold}
  171. </div>
  172. <input
  173. type="number"
  174. min={500}
  175. max={4000}
  176. value={config.compressMessageLengthThreshold}
  177. onChange={(e) =>
  178. updateConfig(
  179. (config) => (config.compressMessageLengthThreshold = e.currentTarget.valueAsNumber)
  180. )
  181. }
  182. ></input>
  183. </ListItem>
  184. </List>
  185. </div>
  186. </>
  187. );
  188. }