From 04d9ea9ebaf36709dc7ec8724a0c9fd15edd3025 Mon Sep 17 00:00:00 2001 From: mesalogo Date: Thu, 17 Sep 2026 13:01:39 +0800 Subject: [PATCH] fix: use monochrome brand icons for messaging channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show distinct WeChat, WeCom, and DingTalk marks in channel settings and the project dropdown. Bundle the SVGs locally and inherit the interface foreground color. Release note: 远程通道设置和项目下拉列表统一使用微信、企业微信、钉钉各自的黑白品牌图标。 --- src/renderer/src/ChannelIcon.tsx | 92 +++++++++++++++++++++ src/renderer/src/ChannelSettingsSection.tsx | 7 +- src/renderer/src/ProjectSwitcher.tsx | 7 +- 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/renderer/src/ChannelIcon.tsx diff --git a/src/renderer/src/ChannelIcon.tsx b/src/renderer/src/ChannelIcon.tsx new file mode 100644 index 00000000..3a718c2d --- /dev/null +++ b/src/renderer/src/ChannelIcon.tsx @@ -0,0 +1,92 @@ +import type { ProjectChannel } from '../../shared/assistant-contracts' + +/*! + * WeChat: Simple Icons (CC0), https://github.com/simple-icons/simple-icons + * WeCom: icon extracted from Tencent's official SVG (wordmark excluded): + * https://wwcdn.weixin.qq.com/node/wwnl/wwnl/style/images/independent/index/HeaderLogoMobile$9b6c3fb4.svg + * DingTalk: Ant Design Icons, https://github.com/ant-design/ant-design-icons + * Copyright (c) 2018-present Ant UED, https://xtech.antfin.com/ + * + * MIT License (DingTalk): + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +const channelMarks = { + weixin: { + viewBox: '0 0 24 24', + path: 'M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-6.656-6.088V8.89c-.135-.01-.27-.027-.407-.03zm-2.53 3.274c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.969-.982z' + }, + dingtalk: { + viewBox: '0 0 1024 1024', + path: 'M573.7 252.5C422.5 197.4 201.3 96.7 201.3 96.7c-15.7-4.1-17.9 11.1-17.9 11.1c-5 61.1 33.6 160.5 53.6 182.8c19.9 22.3 319.1 113.7 319.1 113.7S326 357.9 270.5 341.9c-55.6-16-37.9 17.8-37.9 17.8c11.4 61.7 64.9 131.8 107.2 138.4c42.2 6.6 220.1 4 220.1 4s-35.5 4.1-93.2 11.9c-42.7 5.8-97 12.5-111.1 17.8c-33.1 12.5 24 62.6 24 62.6c84.7 76.8 129.7 50.5 129.7 50.5c33.3-10.7 61.4-18.5 85.2-24.2L565 743.1h84.6L603 928l205.3-271.9H700.8l22.3-38.7c.3.5.4.8.4.8S799.8 496.1 829 433.8l.6-1h-.1c5-10.8 8.6-19.7 10-25.8c17-71.3-114.5-99.4-265.8-154.5' + } +} satisfies Record, { viewBox: string; path: string }> + +export function ChannelIcon({ + channel, + size = 16 +}: { + channel: ProjectChannel + size?: number +}): React.JSX.Element { + if (channel === 'wecom') { + return ( + + ) + } + + const mark = channelMarks[channel] + return ( + + ) +} diff --git a/src/renderer/src/ChannelSettingsSection.tsx b/src/renderer/src/ChannelSettingsSection.tsx index a84f0822..6ba76760 100644 --- a/src/renderer/src/ChannelSettingsSection.tsx +++ b/src/renderer/src/ChannelSettingsSection.tsx @@ -28,6 +28,7 @@ import type { WeixinBindingSnapshot } from '../../shared/weixin-channel-contract import type { AppNotificationInput } from './notifications' import { trapTabFocus } from './dialog-focus' import { PageTabs } from './WorkspacePrimitives' +import { ChannelIcon } from './ChannelIcon' import { SettingsCategoryHeader, SettingsWarningList @@ -799,9 +800,9 @@ export function ChannelSettingsSection({ tRef.current = t }, [t]) const channelTabs = [ - { id: 'weixin', label: t('channels.tabs.weixin') }, - { id: 'wecom', label: t('channels.tabs.wecom') }, - { id: 'dingtalk', label: t('channels.tabs.dingtalk') } + { id: 'weixin', label: t('channels.tabs.weixin'), icon: }, + { id: 'wecom', label: t('channels.tabs.wecom'), icon: }, + { id: 'dingtalk', label: t('channels.tabs.dingtalk'), icon: } ] as const const [snapshot, setSnapshot] = useState() const [runtimeSettings, setRuntimeSettings] = diff --git a/src/renderer/src/ProjectSwitcher.tsx b/src/renderer/src/ProjectSwitcher.tsx index c482dc3f..e12624e5 100644 --- a/src/renderer/src/ProjectSwitcher.tsx +++ b/src/renderer/src/ProjectSwitcher.tsx @@ -54,6 +54,7 @@ import { ProjectRuntimeSelector } from './ProjectRuntimeSelector' import { ProjectActivityCounts } from './ProjectActivity' import type { ProjectActivityCountsProps } from './ProjectActivity' import { ProjectWorkModeFields } from './ProjectWorkModeFields' +import { ChannelIcon } from './ChannelIcon' import { SegmentedControl } from './WorkspacePrimitives' import { displayErrorMessage } from './error-message' @@ -1108,7 +1109,11 @@ export function ProjectSwitcher({ tabIndex={selected ? 0 : -1} type="button" > -