From 2fe8417900e8a51bf9ac2a881b37b7e5bae10ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=B7=A5=E7=A8=8B=E5=B8=88?= Date: Sun, 16 Aug 2026 00:27:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(pc-client):=20PC=20=E7=AB=AF=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E6=89=8B=E6=9C=BA=E7=AB=AF=E8=AE=BE=E8=AE=A1=20Token?= =?UTF-8?q?=20=E5=B9=B6=E8=A1=A5=E6=8F=90=E4=BA=A4=20src/components?= =?UTF-8?q?=EF=BC=88B-52=20=E8=A7=86=E8=A7=89=E9=98=BB=E5=A1=9E=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: multica-agent --- .gitignore | 4 +- pc-client/src/App.tsx | 2 +- .../src/components/ApplicationItem/index.tsx | 148 ++++++++++++++++++ pc-client/src/components/CKEditor/index.scss | 105 +++++++++++++ pc-client/src/components/CKEditor/index.tsx | 123 +++++++++++++++ pc-client/src/components/CKEditor/utils.ts | 46 ++++++ .../components/DraggableModalWrap/index.tsx | 47 ++++++ .../src/components/EditableContent/index.tsx | 101 ++++++++++++ .../src/components/ErrorBoundary/index.tsx | 37 +++++ .../FlexibleSider/flexible-sider.module.scss | 22 +++ .../src/components/FlexibleSider/index.tsx | 34 ++++ pc-client/src/components/OIMAvatar/index.tsx | 91 +++++++++++ pc-client/src/components/SettingRow/index.tsx | 53 +++++++ .../src/components/WindowControlBar/index.tsx | 47 ++++++ pc-client/src/layout/LeftNavBar/About.tsx | 2 +- pc-client/src/layout/LeftNavBar/BlackList.tsx | 2 +- .../layout/LeftNavBar/PersonalSettings.tsx | 2 +- pc-client/src/layout/LeftNavBar/index.tsx | 2 +- .../pages/chat/ConversationSider/index.tsx | 4 +- .../pages/chat/queryChat/ChatFooter/index.tsx | 4 +- .../MessageItem/FileMessageRender.tsx | 6 +- .../MessageItem/SoundMessageRender.tsx | 2 +- .../pages/contact/myFriends/AlphabetIndex.tsx | 2 +- .../src/pages/contact/myFriends/index.tsx | 4 +- .../pages/contact/myGroups/GroupListItem.tsx | 2 +- pc-client/src/styles/antd.scss | 4 +- pc-client/src/styles/global.scss | 16 +- 27 files changed, 884 insertions(+), 28 deletions(-) create mode 100644 pc-client/src/components/ApplicationItem/index.tsx create mode 100644 pc-client/src/components/CKEditor/index.scss create mode 100644 pc-client/src/components/CKEditor/index.tsx create mode 100644 pc-client/src/components/CKEditor/utils.ts create mode 100644 pc-client/src/components/DraggableModalWrap/index.tsx create mode 100644 pc-client/src/components/EditableContent/index.tsx create mode 100644 pc-client/src/components/ErrorBoundary/index.tsx create mode 100644 pc-client/src/components/FlexibleSider/flexible-sider.module.scss create mode 100644 pc-client/src/components/FlexibleSider/index.tsx create mode 100644 pc-client/src/components/OIMAvatar/index.tsx create mode 100644 pc-client/src/components/SettingRow/index.tsx create mode 100644 pc-client/src/components/WindowControlBar/index.tsx diff --git a/.gitignore b/.gitignore index b418b5f..8f97012 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .env .env.local .env.*.local -components/ +# 仅忽略仓库根目录的 components(如 OpenIM 样例遗留目录), +# 不匹配 pc-client/src/components 等源码子目录,保证其可入库 +/components/ .selftest/ data/ diff --git a/pc-client/src/App.tsx b/pc-client/src/App.tsx index 1d04d52..d1474e4 100644 --- a/pc-client/src/App.tsx +++ b/pc-client/src/App.tsx @@ -25,7 +25,7 @@ function App() { autoInsertSpaceInButton={false} locale={locale === "zh-CN" ? zhCN : enUS} theme={{ - token: { colorPrimary: "#0073D9" }, + token: { colorPrimary: "#3B87F5", colorError: "#F53F3F" }, }} > diff --git a/pc-client/src/components/ApplicationItem/index.tsx b/pc-client/src/components/ApplicationItem/index.tsx new file mode 100644 index 0000000..7fa4c96 --- /dev/null +++ b/pc-client/src/components/ApplicationItem/index.tsx @@ -0,0 +1,148 @@ +import { ApplicationHandleResult } from "@openim/wasm-client-sdk"; +import { + FriendApplicationItem, + GroupApplicationItem, +} from "@openim/wasm-client-sdk/lib/types/entity"; +import { Button, Spin } from "antd"; +import { t } from "i18next"; +import { memo, useCallback, useState } from "react"; + +import arrow from "@/assets/images/contact/arrowTopRight.png"; +import OIMAvatar from "@/components/OIMAvatar"; +import { IMSDK } from "@/layout/MainContentWrap"; +import { emit } from "@/utils/events"; + +type ApplicationItemSource = FriendApplicationItem & GroupApplicationItem; + +export type AccessFunction = ( + source: Partial, + isRecv: boolean, +) => Promise; + +const ApplicationItem = ({ + currentUserID, + source, + onAccept, + onReject, +}: { + source: Partial; + currentUserID: string; + onAccept: AccessFunction; + onReject: AccessFunction; +}) => { + const [loading, setLoading] = useState(false); + const isRecv = source.userID !== currentUserID && source.fromUserID !== currentUserID; + const isGroup = Boolean(source.groupID); + const showActionBtn = source.handleResult === 0 && isRecv; + + const getApplicationDesc = () => { + if (isGroup) { + return t("application.applyToJoin"); + } + return isRecv ? t("application.applyToFriend") : t("application.applyToAdd"); + }; + + const getTitle = () => { + if (isGroup) { + return isRecv ? source.nickname : source.groupName; + } + return isRecv ? source.fromNickname : source.toNickname; + }; + + const getStatusStr = () => { + if (source.handleResult === ApplicationHandleResult.Agree) { + return t("application.agreed"); + } + if (source.handleResult === ApplicationHandleResult.Reject) { + return t("application.refused"); + } + return t("application.pending"); + }; + + const getAvatarUrl = () => { + if (isGroup) { + return isRecv ? source.userFaceURL : source.groupFaceURL; + } + return isRecv ? source.fromFaceURL : source.toFaceURL; + }; + + const loadingWrap = async (isAgree: boolean) => { + setLoading(true); + await (isAgree ? onAccept(source, isRecv) : onReject(source, isRecv)); + setLoading(false); + }; + + const tryShowCard = useCallback(async () => { + if (isGroup) { + const { data } = await IMSDK.getSpecifiedGroupsInfo([source.groupID!]); + emit("OPEN_GROUP_CARD", data[0]); + return; + } + window.userClick(isRecv ? source.fromUserID : source.toUserID); + }, []); + + return ( + +
+
+ +
+

{getTitle()}

+

+ {getApplicationDesc()} + {(isGroup || (!isGroup && !isRecv)) && ( + + {source.groupName || source.toNickname} + + )} +

+

+ {t("application.information")}: +

+

{source.reqMsg}

+
+
+ + {showActionBtn && ( +
+
+ +
+
+ +
+
+ )} + + {!showActionBtn && ( +
+ {!isRecv && } +

{getStatusStr()}

+
+ )} +
+
+ ); +}; + +export default memo(ApplicationItem); diff --git a/pc-client/src/components/CKEditor/index.scss b/pc-client/src/components/CKEditor/index.scss new file mode 100644 index 0000000..66a4031 --- /dev/null +++ b/pc-client/src/components/CKEditor/index.scss @@ -0,0 +1,105 @@ +.image-inline { + margin: 2px; + img { + aspect-ratio: auto !important; + max-width: 30vw !important; + max-height: 15vh !important; + width: auto !important; + object-fit: contain; + cursor: pointer; + } +} + +.ck-content { + padding: 0 18px !important; + border: none !important; + word-break: break-all; +} + +.ck-content [draggable="true"] { + pointer-events: none; +} + +.ck-content > p { + margin: 10px 0 !important; +} + +.ck.ck-toolbar { + border: none !important; +} + +.ck-editor__editable { + --ck-inner-shadow: none !important; + --ck-drop-shadow: none !important; + --ck-drop-shadow-active: none !important; + outline: none !important; +} + +.ck-editor__editable:focus { + box-shadow: none !important; +} + +.ck.ck-editor__editable[role="textbox"]:focus { + border: none; + box-shadow: none !important; +} + +.ck-powered-by { + display: none !important; +} + +.ck-widget__type-around__button, +.ck-widget__type-around__button_after { + display: none !important; +} + +.ck-editor { + flex: 1; + overflow-y: auto; +} + +.ck-editor__main, +.ck-content { + height: 100% !important; +} + +.ck-image-upload-complete-icon { + display: none !important; +} + +.ck-image-upload-complete-icon:after { + display: none !important; +} + +.ck-balloon-panel_visible { + border-radius: 10px !important; + border: none !important; + box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) !important; + overflow: hidden !important; +} + +.ck-list__item .ck-on { + background-color: #f0f0f0 !important; +} + +.ck .ck-widget { + --ck-widget-outline-thickness: 2px !important; + --ck-color-widget-hover-border: transparent !important; +} + +.ck .ck-widget.ck-widget_selected { + --ck-widget-outline-thickness: 2px !important; +} + +.ck.ck-clipboard-drop-target-line { + --ck-clipboard-drop-target-color: transparent !important; +} + +.ck-powered-by-balloon { + z-index: -99; +} + +.ck-editor__top { + display: none; +} diff --git a/pc-client/src/components/CKEditor/index.tsx b/pc-client/src/components/CKEditor/index.tsx new file mode 100644 index 0000000..d4ce9ba --- /dev/null +++ b/pc-client/src/components/CKEditor/index.tsx @@ -0,0 +1,123 @@ +import "./index.scss"; +import "ckeditor5/ckeditor5.css"; + +import { ClassicEditor } from "@ckeditor/ckeditor5-editor-classic"; +import { Essentials } from "@ckeditor/ckeditor5-essentials"; +import { Paragraph } from "@ckeditor/ckeditor5-paragraph"; +import { CKEditor } from "@ckeditor/ckeditor5-react"; +import { + forwardRef, + ForwardRefRenderFunction, + memo, + useImperativeHandle, + useRef, +} from "react"; + +export type CKEditorRef = { + focus: (moveToEnd?: boolean) => void; +}; + +interface CKEditorProps { + value: string; + placeholder?: string; + onChange?: (value: string) => void; + onEnter?: () => void; +} + +export interface EmojiData { + src: string; + alt: string; +} + +const keyCodes = { + delete: 46, + backspace: 8, +}; + +const Index: ForwardRefRenderFunction = ( + { value, placeholder, onChange, onEnter }, + ref, +) => { + const ckEditor = useRef(null); + + const focus = (moveToEnd = false) => { + const editor = ckEditor.current; + + if (editor) { + const model = editor.model; + const view = editor.editing.view; + const root = model.document.getRoot(); + if (moveToEnd && root) { + const range = model.createRange(model.createPositionAt(root, "end")); + + model.change((writer) => { + writer.setSelection(range); + }); + } + view.focus(); + } + }; + + const listenKeydown = (editor: ClassicEditor) => { + editor.editing.view.document.on( + "keydown", + (evt, data) => { + if (data.keyCode === 13 && !data.shiftKey) { + data.preventDefault(); + evt.stop(); + onEnter?.(); + return; + } + if (data.keyCode === keyCodes.backspace || data.keyCode === keyCodes.delete) { + const selection = editor.model.document.selection; + const hasSelectContent = !editor.model.getSelectedContent(selection).isEmpty; + const hasEditorContent = Boolean(editor.getData()); + + if (!hasEditorContent) { + return; + } + + if (hasSelectContent) return; + } + }, + { priority: "high" }, + ); + }; + + useImperativeHandle( + ref, + () => ({ + focus, + }), + [], + ); + + return ( + { + ckEditor.current = editor; + listenKeydown(editor); + focus(true); + }} + onChange={(event, editor) => { + const data = editor.getData(); + onChange?.(data); + }} + /> + ); +}; + +export default memo(forwardRef(Index)); diff --git a/pc-client/src/components/CKEditor/utils.ts b/pc-client/src/components/CKEditor/utils.ts new file mode 100644 index 0000000..308de8b --- /dev/null +++ b/pc-client/src/components/CKEditor/utils.ts @@ -0,0 +1,46 @@ +export const replaceEmoji2Str = (text: string) => { + const parser = new DOMParser(); + const doc = parser.parseFromString(text, "text/html"); + + const emojiEls: HTMLImageElement[] = Array.from(doc.querySelectorAll(".emojione")); + emojiEls.map((face) => { + // @ts-ignore + const escapedOut = face.outerHTML.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); + text = text.replace(new RegExp(escapedOut, "g"), face.alt); + }); + return text; +}; + +export const getCleanText = (html: string) => { + let text = replaceEmoji2Str(html); + text = text.replace(/<\/p>

/g, "\n"); + text = text.replace(//gi, "\n"); + text = text.replace(/<[^>]+>/g, ""); + text = convertChar(text); + text = decodeHtmlEntities(text); + return text.trim(); +}; + +let textAreaDom: HTMLTextAreaElement | null = null; +const decodeHtmlEntities = (text: string) => { + if (!textAreaDom) { + textAreaDom = document.createElement("textarea"); + } + textAreaDom.innerHTML = text; + return textAreaDom.value; +}; + +export const convertChar = (text: string) => text.replace(/ /gi, " "); + +export const getCleanTextExceptImg = (html: string) => { + html = replaceEmoji2Str(html); + + const regP = /<\/p>

/g; + html = html.replace(regP, "


"); + + const regBr = //gi; + html = html.replace(regBr, "\n"); + + const regWithoutHtmlExceptImg = /<(?!img\s*\/?)[^>]+>/gi; + return html.replace(regWithoutHtmlExceptImg, ""); +}; diff --git a/pc-client/src/components/DraggableModalWrap/index.tsx b/pc-client/src/components/DraggableModalWrap/index.tsx new file mode 100644 index 0000000..740c35f --- /dev/null +++ b/pc-client/src/components/DraggableModalWrap/index.tsx @@ -0,0 +1,47 @@ +import { Modal, ModalProps } from "antd"; +import { FC, memo, useRef, useState } from "react"; +import type { DraggableData, DraggableEvent } from "react-draggable"; +import Draggable from "react-draggable"; + +interface IDraggableModalWrapProps extends ModalProps { + ignoreClasses?: string; +} + +const DraggableModalWrap: FC = (props) => { + const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 }); + const draggleRef = useRef(null); + + const onStart = (_event: DraggableEvent, uiData: DraggableData) => { + const { clientWidth, clientHeight } = window.document.documentElement; + const targetRect = draggleRef.current?.getBoundingClientRect(); + if (!targetRect) { + return; + } + setBounds({ + left: -targetRect.left + uiData.x, + right: clientWidth - (targetRect.right - uiData.x), + top: -targetRect.top + uiData.y, + bottom: clientHeight - (targetRect.bottom - uiData.y), + }); + }; + + return ( + ( + onStart(event, uiData)} + > +

{modal}
+ + )} + > + {props.children} + + ); +}; + +export default memo(DraggableModalWrap); diff --git a/pc-client/src/components/EditableContent/index.tsx b/pc-client/src/components/EditableContent/index.tsx new file mode 100644 index 0000000..c643daf --- /dev/null +++ b/pc-client/src/components/EditableContent/index.tsx @@ -0,0 +1,101 @@ +import { EnterOutlined } from "@ant-design/icons"; +import { useClickAway } from "ahooks"; +import { Input, InputRef } from "antd"; +import clsx from "clsx"; +import { FC, useRef, useState } from "react"; + +import edit_name from "@/assets/images/chatSetting/edit_name.png"; + +interface IEditableContentProps { + editable?: boolean; + value?: string; + placeholder?: string; + className?: string; + textClassName?: string; + onChange?: (value: string) => Promise; +} + +const EditableContent: FC = ({ + editable, + value, + placeholder, + className, + textClassName, + onChange, +}) => { + const wrapRef = useRef(null); + const inputRef = useRef(null); + const [editState, setEditState] = useState({ + isEdit: false, + loading: false, + innerValue: value, + }); + + useClickAway(() => { + if (editState.isEdit) { + setEditState({ + isEdit: false, + loading: false, + innerValue: value, + }); + } + }, [wrapRef]); + + const toggleEdit = (e: React.MouseEvent) => { + e.stopPropagation(); + setEditState({ + isEdit: true, + loading: false, + innerValue: value === "-" ? "" : value, + }); + setTimeout(() => inputRef.current?.focus()); + }; + + const onPressEnter = async ( + e: React.KeyboardEvent & { target: { value: string } }, + ) => { + setEditState((state) => ({ ...state, loading: true })); + await onChange?.(e.target.value); + setEditState({ + isEdit: false, + loading: false, + innerValue: e.target.value, + }); + }; + + return ( +
+ {editState.isEdit ? ( + + setEditState((state) => ({ ...state, innerValue: e.target.value })) + } + ref={inputRef} + onPressEnter={onPressEnter} + suffix={} + /> + ) : ( + <> +
+ {value} +
+ {editable && ( + edit name + )} + + )} +
+ ); +}; + +export default EditableContent; diff --git a/pc-client/src/components/ErrorBoundary/index.tsx b/pc-client/src/components/ErrorBoundary/index.tsx new file mode 100644 index 0000000..1be5e9d --- /dev/null +++ b/pc-client/src/components/ErrorBoundary/index.tsx @@ -0,0 +1,37 @@ +import { Component, ErrorInfo, ReactNode } from "react"; + +type ErrorBoundaryProps = { + logTips?: string; + placeholder: ReactNode; + children: ReactNode; +}; + +type ErrorBoundaryState = { + hasError: boolean; + logTips?: string; +}; + +class ErrorBoundary extends Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false, logTips: props.logTips }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error(this.state.logTips ?? "ErrorBoundary"); + console.error(errorInfo); + console.error(error); + + this.setState({ hasError: true }); + } + + render() { + if (this.state.hasError) { + return this.props.placeholder; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/pc-client/src/components/FlexibleSider/flexible-sider.module.scss b/pc-client/src/components/FlexibleSider/flexible-sider.module.scss new file mode 100644 index 0000000..aeaa272 --- /dev/null +++ b/pc-client/src/components/FlexibleSider/flexible-sider.module.scss @@ -0,0 +1,22 @@ +.sider_resize { + width: 300px; + min-width: 240px; + max-width: 45vw; + resize: horizontal; + overflow: scroll; + height: 100%; + opacity: 0; + + &::-webkit-scrollbar { + height: calc(100vh - 40px); + } +} + +.sider_bar { + position: absolute; + right: 0; + top: 0; + bottom: 0; + border-left: 1px solid var(--gap-text); + pointer-events: none; +} diff --git a/pc-client/src/components/FlexibleSider/index.tsx b/pc-client/src/components/FlexibleSider/index.tsx new file mode 100644 index 0000000..19f2dab --- /dev/null +++ b/pc-client/src/components/FlexibleSider/index.tsx @@ -0,0 +1,34 @@ +import clsx from "clsx"; +import * as React from "react"; + +import styles from "./flexible-sider.module.scss"; + +const FlexibleSider = ({ + needHidden, + children, + wrapClassName, +}: { + needHidden: boolean; + wrapClassName?: string; + children: React.ReactNode; +}) => ( + +); + +export default FlexibleSider; diff --git a/pc-client/src/components/OIMAvatar/index.tsx b/pc-client/src/components/OIMAvatar/index.tsx new file mode 100644 index 0000000..9614b5d --- /dev/null +++ b/pc-client/src/components/OIMAvatar/index.tsx @@ -0,0 +1,91 @@ +import { Avatar as AntdAvatar, AvatarProps } from "antd"; +import clsx from "clsx"; +import * as React from "react"; +import { useMemo } from "react"; + +import default_group from "@/assets/images/contact/group.png"; +import { avatarList, getDefaultAvatar } from "@/utils/avatar"; + +const default_avatars = avatarList.map((item) => item.name); + +// 头像文字:两个字以内原样显示;中文名取最后一个字,其他取首字母 +const getDisplayText = (text?: string) => { + if (!text) return text; + const trimmed = text.trim(); + if (trimmed.length <= 2) return trimmed; + if (/^[一-龥]/.test(trimmed)) return trimmed.slice(-1); + return trimmed[0].toUpperCase(); +}; + +interface IOIMAvatarProps extends AvatarProps { + text?: string; + color?: string; + bgColor?: string; + isgroup?: boolean; + isnotification?: boolean; + size?: number; +} + +const OIMAvatar: React.FC = (props) => { + const { + src, + text, + size = 42, + color = "#fff", + bgColor = "#3B87F5", + isgroup = false, + isnotification, + } = props; + const [errorHolder, setErrorHolder] = React.useState(); + + const getAvatarUrl = useMemo(() => { + if (src) { + if (default_avatars.includes(src as string)) + return getDefaultAvatar(src as string); + + return src; + } + return isgroup ? default_group : undefined; + }, [src, isgroup, isnotification]); + + const avatarProps = { ...props, isgroup: undefined, isnotification: undefined }; + + React.useEffect(() => { + if (!isgroup) { + setErrorHolder(undefined); + } + }, [isgroup]); + + const errorHandler = () => { + if (isgroup) { + setErrorHolder(default_group); + } + }; + + return ( + + {getDisplayText(text)} + + ); +}; + +export default OIMAvatar; diff --git a/pc-client/src/components/SettingRow/index.tsx b/pc-client/src/components/SettingRow/index.tsx new file mode 100644 index 0000000..31cb1a3 --- /dev/null +++ b/pc-client/src/components/SettingRow/index.tsx @@ -0,0 +1,53 @@ +import { Switch } from "antd"; +import clsx from "clsx"; +import { FC, ReactNode, useState } from "react"; + +interface ISettingRowProps { + title: string; + value?: boolean; + hidden?: boolean; + className?: string; + children?: ReactNode; + tryChange?: (checked: boolean) => Promise; + rowClick?: () => void; +} + +const SettingRow: FC = ({ + title, + value, + hidden, + className, + children, + tryChange, + rowClick, +}) => { + const [loading, setLoading] = useState(false); + const onClick = async (checked: boolean) => { + setLoading(true); + await tryChange?.(checked); + setLoading(false); + }; + + if (hidden) { + return null; + } + + return ( +
+
{title}
+ {children ?? ( + + )} +
+ ); +}; + +export default SettingRow; diff --git a/pc-client/src/components/WindowControlBar/index.tsx b/pc-client/src/components/WindowControlBar/index.tsx new file mode 100644 index 0000000..cbab449 --- /dev/null +++ b/pc-client/src/components/WindowControlBar/index.tsx @@ -0,0 +1,47 @@ +import { Platform } from "@openim/wasm-client-sdk"; +import { useKeyPress } from "ahooks"; + +import win_close from "@/assets/images/topSearchBar/win_close.png"; +import win_max from "@/assets/images/topSearchBar/win_max.png"; +import win_min from "@/assets/images/topSearchBar/win_min.png"; + +const WindowControlBar = () => { + useKeyPress("esc", () => { + window.electronAPI?.ipcInvoke("minimizeWindow"); + }); + + if (!window.electronAPI || window.electronAPI?.getPlatform() === Platform.MacOSX) { + return null; + } + return ( +
+
window.electronAPI?.ipcInvoke("minimizeWindow")} + > + win_min +
+ win_max window.electronAPI?.ipcInvoke("maxmizeWindow")} + /> + win_close window.electronAPI?.ipcInvoke("closeWindow")} + /> +
+ ); +}; + +export default WindowControlBar; diff --git a/pc-client/src/layout/LeftNavBar/About.tsx b/pc-client/src/layout/LeftNavBar/About.tsx index ccb01f2..3cd4d47 100644 --- a/pc-client/src/layout/LeftNavBar/About.tsx +++ b/pc-client/src/layout/LeftNavBar/About.tsx @@ -136,7 +136,7 @@ export const AboutContent = ({ closeOverlay }: { closeOverlay?: () => void }) =>
{t("placeholder.about")} diff --git a/pc-client/src/layout/LeftNavBar/BlackList.tsx b/pc-client/src/layout/LeftNavBar/BlackList.tsx index f2b8427..92431c8 100644 --- a/pc-client/src/layout/LeftNavBar/BlackList.tsx +++ b/pc-client/src/layout/LeftNavBar/BlackList.tsx @@ -84,7 +84,7 @@ export const BlackListContent = ({ closeOverlay }: { closeOverlay?: () => void }
{t("placeholder.blackList")} diff --git a/pc-client/src/layout/LeftNavBar/PersonalSettings.tsx b/pc-client/src/layout/LeftNavBar/PersonalSettings.tsx index 40a7fb7..59e651f 100644 --- a/pc-client/src/layout/LeftNavBar/PersonalSettings.tsx +++ b/pc-client/src/layout/LeftNavBar/PersonalSettings.tsx @@ -64,7 +64,7 @@ export const PersonalSettingsContent = ({
{t("placeholder.accountSetting")} diff --git a/pc-client/src/layout/LeftNavBar/index.tsx b/pc-client/src/layout/LeftNavBar/index.tsx index 3ce30ea..93d9488 100644 --- a/pc-client/src/layout/LeftNavBar/index.tsx +++ b/pc-client/src/layout/LeftNavBar/index.tsx @@ -128,7 +128,7 @@ const NavItem = ({ nav: { icon: Icon, icon_active: ActiveIcon, title, path } }: diff --git a/pc-client/src/pages/chat/ConversationSider/index.tsx b/pc-client/src/pages/chat/ConversationSider/index.tsx index f7ff480..f4fe416 100644 --- a/pc-client/src/pages/chat/ConversationSider/index.tsx +++ b/pc-client/src/pages/chat/ConversationSider/index.tsx @@ -13,7 +13,7 @@ import ConversationItemComp from "./ConversationItem"; // 断网时顶部的深色提示横条 const OfflineBar = () => (
-
+
{
{t("placeholder.chat")}
} + prefix={} placeholder={t("placeholder.search")} allowClear value={keyword} diff --git a/pc-client/src/pages/chat/queryChat/ChatFooter/index.tsx b/pc-client/src/pages/chat/queryChat/ChatFooter/index.tsx index ab5a0e8..e46c276 100644 --- a/pc-client/src/pages/chat/queryChat/ChatFooter/index.tsx +++ b/pc-client/src/pages/chat/queryChat/ChatFooter/index.tsx @@ -141,7 +141,7 @@ const ChatFooter: ForwardRefRenderFunction = (_, ref) => { }; const toolIconClass = - "cursor-pointer text-xl text-[#8e9ab0] hover:text-[#515E70]"; + "cursor-pointer text-xl text-[var(--sub-text)] hover:text-[#515E70]"; return (
@@ -186,7 +186,7 @@ const ChatFooter: ForwardRefRenderFunction = (_, ref) => { {/* 录音条 */} {recording && (
- + {t("placeholder.microphone")} {seconds}″ diff --git a/pc-client/src/pages/chat/queryChat/MessageItem/FileMessageRender.tsx b/pc-client/src/pages/chat/queryChat/MessageItem/FileMessageRender.tsx index a2f1ce1..2e23a99 100644 --- a/pc-client/src/pages/chat/queryChat/MessageItem/FileMessageRender.tsx +++ b/pc-client/src/pages/chat/queryChat/MessageItem/FileMessageRender.tsx @@ -17,14 +17,14 @@ const FileIcon = () => ( - + diff --git a/pc-client/src/pages/chat/queryChat/MessageItem/SoundMessageRender.tsx b/pc-client/src/pages/chat/queryChat/MessageItem/SoundMessageRender.tsx index 0b58f5d..1585570 100644 --- a/pc-client/src/pages/chat/queryChat/MessageItem/SoundMessageRender.tsx +++ b/pc-client/src/pages/chat/queryChat/MessageItem/SoundMessageRender.tsx @@ -88,7 +88,7 @@ const SoundMessageRender: FC = ({ message, isSender }) => { {duration}″
{!isSender && !played && ( - + )}
); diff --git a/pc-client/src/pages/contact/myFriends/AlphabetIndex.tsx b/pc-client/src/pages/contact/myFriends/AlphabetIndex.tsx index 5019bca..c8c23ab 100644 --- a/pc-client/src/pages/contact/myFriends/AlphabetIndex.tsx +++ b/pc-client/src/pages/contact/myFriends/AlphabetIndex.tsx @@ -36,7 +36,7 @@ const AlphabetIndex: ForwardRefRenderFunction< {indexList.map((letter, idx) => ( jumpToLetter(idx, letter)} diff --git a/pc-client/src/pages/contact/myFriends/index.tsx b/pc-client/src/pages/contact/myFriends/index.tsx index fe9a9e4..134422c 100644 --- a/pc-client/src/pages/contact/myFriends/index.tsx +++ b/pc-client/src/pages/contact/myFriends/index.tsx @@ -90,10 +90,10 @@ export const MyFriends = () => { groupCounts={sectionData.groupCounts} groupContent={(index) => (
-
+
{sectionData.indexList[index]}
-
+
)} itemContent={(index) => { diff --git a/pc-client/src/pages/contact/myGroups/GroupListItem.tsx b/pc-client/src/pages/contact/myGroups/GroupListItem.tsx index 3881292..315fa5c 100644 --- a/pc-client/src/pages/contact/myGroups/GroupListItem.tsx +++ b/pc-client/src/pages/contact/myGroups/GroupListItem.tsx @@ -17,7 +17,7 @@ const GroupListItem = ({

{source.groupName}

-

{source.memberCount}

+

{source.memberCount}

); diff --git a/pc-client/src/styles/antd.scss b/pc-client/src/styles/antd.scss index a4c400b..6003c52 100644 --- a/pc-client/src/styles/antd.scss +++ b/pc-client/src/styles/antd.scss @@ -79,7 +79,7 @@ .ant-drawer-header { padding: 0 24px; - background-color: #e8eaef; + background-color: var(--gap-text); border: none; .ant-drawer-header-title { @@ -101,7 +101,7 @@ .anticon-close, .anticon-right { - color: #8e9ab0; + color: var(--sub-text); } } diff --git a/pc-client/src/styles/global.scss b/pc-client/src/styles/global.scss index 345dfe5..d07749a 100644 --- a/pc-client/src/styles/global.scss +++ b/pc-client/src/styles/global.scss @@ -1,14 +1,14 @@ :root { --full-height: 100%; --chat-bubble: #ffffff; - --chat-bubble-sender: #cde6ff; - --base-black: #0c1c33; - --primary: #0073d9; - --primary-active: #eaf4ff; - --top-search-bar: #0073d9; - --sub-text: #8e9ab0; - --gap-text: #e8eaef; - --warn-text: #ff381f; + --chat-bubble-sender: #d6e7fc; + --base-black: #1d2129; + --primary: #3b87f5; + --primary-active: #ebf3fe; + --top-search-bar: #3b87f5; + --sub-text: #86909c; + --gap-text: #eeeeee; + --warn-text: #f53f3f; --moment-text: #6085b1; --searchbar-height: 2.5rem; }