Przeglądaj źródła

✅ 完全移除了所有 emoji 选择器相关组件
✅ 移除了 emoji-picker-react 依赖,减少了包大小
✅ Avatar 组件现在专注于显示模型图标
✅ 代码更加清洁和专业
✅ 保留了聊天消息中 emoji 的显示功能(通过 markdown 样式)

Ryuiso 3 miesięcy temu
rodzic
commit
939a2f1a40

+ 1 - 0
.gitignore

@@ -11,6 +11,7 @@
 # next.js
 /.next/
 /out/
+out.zip
 
 # production
 /build

+ 3 - 41
app/components/emoji.tsx → app/components/avatar.tsx

@@ -1,9 +1,3 @@
-import EmojiPicker, {
-  Emoji,
-  EmojiStyle,
-  Theme as EmojiTheme,
-} from "emoji-picker-react";
-
 import { ModelType } from "../store";
 
 import BotIconDefault from "../icons/llm-icons/default.svg";
@@ -22,29 +16,6 @@ import BotIconHunyuan from "../icons/llm-icons/hunyuan.svg";
 import BotIconDoubao from "../icons/llm-icons/doubao.svg";
 import BotIconChatglm from "../icons/llm-icons/chatglm.svg";
 
-export function getEmojiUrl(unified: string, style: EmojiStyle) {
-  // Whoever owns this Content Delivery Network (CDN), I am using your CDN to serve emojis
-  // Old CDN broken, so I had to switch to this one
-  // Author: https://github.com/H0llyW00dzZ
-  return `https://fastly.jsdelivr.net/npm/emoji-datasource-apple/img/${style}/64/${unified}.png`;
-}
-
-export function AvatarPicker(props: {
-  onEmojiClick: (emojiId: string) => void;
-}) {
-  return (
-    <EmojiPicker
-      width={"100%"}
-      lazyLoadEmojis
-      theme={EmojiTheme.AUTO}
-      getEmojiUrl={getEmojiUrl}
-      onEmojiClick={(e) => {
-        props.onEmojiClick(e.unified);
-      }}
-    />
-  );
-}
-
 export function Avatar(props: { model?: ModelType; avatar?: string }) {
   let LlmIcon = BotIconDefault;
 
@@ -99,19 +70,10 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
     );
   }
 
+  // 使用固定的默认头像
   return (
-    <div className="user-avatar">
-      {props.avatar && <EmojiAvatar avatar={props.avatar} />}
+    <div className="no-dark">
+      <BotIconDefault className="user-avatar" width={30} height={30} />
     </div>
   );
 }
-
-export function EmojiAvatar(props: { avatar: string; size?: number }) {
-  return (
-    <Emoji
-      unified={props.avatar}
-      size={props.size ?? 18}
-      getEmojiUrl={getEmojiUrl}
-    />
-  );
-}

+ 3 - 3
app/components/chat.tsx

@@ -108,7 +108,7 @@ import {
   ServiceProvider,
   UNFINISHED_INPUT,
 } from "../constant";
-import { Avatar } from "./emoji";
+import { Avatar } from "./avatar";
 import { ContextPrompts, MaskAvatar, MaskConfig } from "./mask";
 import { useMaskStore } from "../store/mask";
 import { ChatCommandPrefix, useChatCommand, useCommand } from "../command";
@@ -1849,11 +1849,11 @@ function _Chat() {
                                 ></IconButton>
                               </div>
                               {isUser ? (
-                                <Avatar avatar={config.avatar} />
+                                <Avatar />
                               ) : (
                                 <>
                                   {["system"].includes(message.role) ? (
-                                    <Avatar avatar="2699-fe0f" />
+                                    <Avatar />
                                   ) : (
                                     <MaskAvatar
                                       avatar={session.mask.avatar}

+ 3 - 3
app/components/exporter.tsx

@@ -27,7 +27,7 @@ import ShareIcon from "../icons/share.svg";
 import DownloadIcon from "../icons/download.svg";
 import { useEffect, useMemo, useRef, useState } from "react";
 import { MessageSelector, useMessageSelector } from "./message-selector";
-import { Avatar } from "./emoji";
+import { Avatar } from "./avatar";
 import dynamic from "next/dynamic";
 import NextImage from "next/image";
 
@@ -529,7 +529,7 @@ export function ImagePreviewer(props: {
               github.com/ChatGPTNextWeb/ChatGPT-Next-Web
             </div>
             <div className={styles["icons"]}>
-              <MaskAvatar avatar={config.avatar} />
+              <Avatar />
               <span className={styles["icon-space"]}>&</span>
               <MaskAvatar
                 avatar={mask.avatar}
@@ -563,7 +563,7 @@ export function ImagePreviewer(props: {
             >
               <div className={styles["avatar"]}>
                 {m.role === "user" ? (
-                  <Avatar avatar={config.avatar}></Avatar>
+                  <Avatar></Avatar>
                 ) : (
                   <MaskAvatar
                     avatar={session.mask.avatar}

+ 6 - 35
app/components/mask.tsx

@@ -13,7 +13,7 @@ import EyeIcon from "../icons/eye.svg";
 import CopyIcon from "../icons/copy.svg";
 import DragIcon from "../icons/drag.svg";
 
-import { DEFAULT_MASK_AVATAR, Mask, useMaskStore } from "../store/mask";
+import { Mask, useMaskStore } from "../store/mask";
 import {
   ChatMessage,
   createMessage,
@@ -32,7 +32,7 @@ import {
   Select,
   showConfirm,
 } from "./ui-lib";
-import { Avatar, AvatarPicker } from "./emoji";
+import { Avatar } from "./avatar";
 import Locale, { AllLangs, ALL_LANG_OPTIONS, Lang } from "../locales";
 import { useNavigate } from "react-router-dom";
 
@@ -65,12 +65,8 @@ function reorder<T>(list: T[], startIndex: number, endIndex: number): T[] {
   return result;
 }
 
-export function MaskAvatar(props: { avatar: string; model?: ModelType }) {
-  return props.avatar !== DEFAULT_MASK_AVATAR ? (
-    <Avatar avatar={props.avatar} />
-  ) : (
-    <Avatar model={props.model} />
-  );
+export function MaskAvatar(props: { avatar?: string; model?: ModelType }) {
+  return <Avatar model={props.model} />;
 }
 
 export function MaskConfig(props: {
@@ -80,7 +76,7 @@ export function MaskConfig(props: {
   readonly?: boolean;
   shouldSyncFromGlobal?: boolean;
 }) {
-  const [showPicker, setShowPicker] = useState(false);
+
 
   const updateConfig = (updater: (config: ModelConfig) => void) => {
     if (props.readonly) return;
@@ -113,32 +109,7 @@ export function MaskConfig(props: {
       />
 
       <List>
-        <ListItem title={Locale.Mask.Config.Avatar}>
-          <Popover
-            content={
-              <AvatarPicker
-                onEmojiClick={(emoji) => {
-                  props.updateMask((mask) => (mask.avatar = emoji));
-                  setShowPicker(false);
-                }}
-              ></AvatarPicker>
-            }
-            open={showPicker}
-            onClose={() => setShowPicker(false)}
-          >
-            <div
-              tabIndex={0}
-              aria-label={Locale.Mask.Config.Avatar}
-              onClick={() => setShowPicker(true)}
-              style={{ cursor: "pointer" }}
-            >
-              <MaskAvatar
-                avatar={props.mask.avatar}
-                model={props.mask.modelConfig.model}
-              />
-            </div>
-          </Popover>
-        </ListItem>
+
         <ListItem title={Locale.Mask.Config.Name}>
           <input
             aria-label={Locale.Mask.Config.Name}

+ 2 - 2
app/components/message-selector.tsx

@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
 import { ChatMessage, useAppConfig, useChatStore } from "../store";
 import { Updater } from "../typing";
 import { IconButton } from "./button";
-import { Avatar } from "./emoji";
+import { Avatar } from "./avatar";
 import { MaskAvatar } from "./mask";
 import Locale from "../locales";
 
@@ -209,7 +209,7 @@ export function MessageSelector(props: {
             >
               <div className={styles["avatar"]}>
                 {m.role === "user" ? (
-                  <Avatar avatar={config.avatar}></Avatar>
+                  <Avatar></Avatar>
                 ) : (
                   <MaskAvatar
                     avatar={session.mask.avatar}

+ 4 - 4
app/components/new-chat.tsx

@@ -1,7 +1,7 @@
 import { useEffect, useRef, useState } from "react";
 import { Path, SlotID } from "../constant";
 import { IconButton } from "./button";
-import { EmojiAvatar } from "./emoji";
+import { Avatar } from "./avatar";
 import styles from "./new-chat.module.scss";
 
 import LeftIcon from "../icons/left.svg";
@@ -137,13 +137,13 @@ export function NewChat() {
       </div>
       <div className={styles["mask-cards"]}>
         <div className={styles["mask-card"]}>
-          <EmojiAvatar avatar="1f606" size={24} />
+          <Avatar />
         </div>
         <div className={styles["mask-card"]}>
-          <EmojiAvatar avatar="1f916" size={24} />
+          <Avatar />
         </div>
         <div className={styles["mask-card"]}>
-          <EmojiAvatar avatar="1f479" size={24} />
+          <Avatar />
         </div>
       </div>
 

+ 2 - 27
app/components/settings.tsx

@@ -78,7 +78,7 @@ import { Prompt, SearchService, usePromptStore } from "../store/prompt";
 import { ErrorBoundary } from "./error";
 import { InputRange } from "./input-range";
 import { useNavigate } from "react-router-dom";
-import { Avatar, AvatarPicker } from "./emoji";
+
 import { getClientConfig } from "../config/client";
 import { useSyncStore } from "../store/sync";
 import { nanoid } from "nanoid";
@@ -580,7 +580,6 @@ function SyncItems() {
 
 export function Settings() {
   const navigate = useNavigate();
-  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
   const config = useAppConfig();
   const updateConfig = config.update;
 
@@ -1475,31 +1474,7 @@ export function Settings() {
       </div>
       <div className={styles["settings"]}>
         <List>
-          <ListItem title={Locale.Settings.Avatar}>
-            <Popover
-              onClose={() => setShowEmojiPicker(false)}
-              content={
-                <AvatarPicker
-                  onEmojiClick={(avatar: string) => {
-                    updateConfig((config) => (config.avatar = avatar));
-                    setShowEmojiPicker(false);
-                  }}
-                />
-              }
-              open={showEmojiPicker}
-            >
-              <div
-                aria-label={Locale.Settings.Avatar}
-                tabIndex={0}
-                className={styles.avatar}
-                onClick={() => {
-                  setShowEmojiPicker(!showEmojiPicker);
-                }}
-              >
-                <Avatar avatar={config.avatar} />
-              </div>
-            </Popover>
-          </ListItem>
+
 
 
 

+ 1 - 1
app/components/ui-lib.tsx

@@ -23,7 +23,7 @@ import React, {
   useRef,
 } from "react";
 import { IconButton } from "./button";
-import { Avatar } from "./emoji";
+import { Avatar } from "./avatar";
 import clsx from "clsx";
 
 export function Popover(props: {

+ 0 - 1
app/store/config.ts

@@ -42,7 +42,6 @@ export const DEFAULT_CONFIG = {
   lastUpdate: Date.now(), // timestamp, to merge state
 
   submitKey: SubmitKey.Enter,
-  avatar: "1f603",
   fontSize: 14,
   fontFamily: "",
   theme: Theme.Auto as Theme,

+ 1 - 2
app/store/mask.ts

@@ -31,11 +31,10 @@ export type MaskState = typeof DEFAULT_MASK_STATE & {
   language?: Lang | undefined;
 };
 
-export const DEFAULT_MASK_AVATAR = "gpt-bot";
 export const createEmptyMask = () =>
   ({
     id: nanoid(),
-    avatar: DEFAULT_MASK_AVATAR,
+    avatar: "",
     name: DEFAULT_TOPIC,
     context: [],
     syncGlobalConfig: true, // use global config as default

+ 3 - 25
package-lock.json

@@ -19,7 +19,6 @@
         "bufferutil": "^4.0.9",
         "clsx": "^2.1.1",
         "csstype": "^3.1.3",
-        "emoji-picker-react": "^4.9.2",
         "fuse.js": "^7.0.0",
         "heic2any": "^0.0.4",
         "html-to-image": "^1.11.11",
@@ -5075,9 +5074,9 @@
       "license": "MIT"
     },
     "node_modules/@types/node": {
-      "version": "20.19.9",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz",
-      "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==",
+      "version": "20.19.10",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.10.tgz",
+      "integrity": "sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ==",
       "license": "MIT",
       "dependencies": {
         "undici-types": "~6.21.0"
@@ -8125,21 +8124,6 @@
         "url": "https://github.com/sindresorhus/emittery?sponsor=1"
       }
     },
-    "node_modules/emoji-picker-react": {
-      "version": "4.13.2",
-      "resolved": "https://registry.npmjs.org/emoji-picker-react/-/emoji-picker-react-4.13.2.tgz",
-      "integrity": "sha512-azaJQLTshEOZVhksgU136izJWJyZ4Clx6xQ6Vctzk1gOdPPAUbTa/JYDwZJ8rh97QxnjpyeftXl99eRlYr3vNA==",
-      "license": "MIT",
-      "dependencies": {
-        "flairup": "1.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "peerDependencies": {
-        "react": ">=16"
-      }
-    },
     "node_modules/emoji-regex": {
       "version": "9.2.2",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -9279,12 +9263,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/flairup": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/flairup/-/flairup-1.0.0.tgz",
-      "integrity": "sha512-IKlE+pNvL2R+kVL1kEhUYqRxVqeFnjiIvHWDMLFXNaqyUdFXQM2wte44EfMYJNHkW16X991t2Zg8apKkhv7OBA==",
-      "license": "MIT"
-    },
     "node_modules/flat-cache": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",

+ 1 - 1
package.json

@@ -27,7 +27,7 @@
     "bufferutil": "^4.0.9",
     "clsx": "^2.1.1",
     "csstype": "^3.1.3",
-    "emoji-picker-react": "^4.9.2",
+
     "fuse.js": "^7.0.0",
     "heic2any": "^0.0.4",
     "html-to-image": "^1.11.11",