From f9c1be851746ba79e33c9bf787e7689e69a111c0 Mon Sep 17 00:00:00 2001 From: BiggerRain <15911122312@163.COM> Date: Mon, 19 May 2025 17:24:51 +0800 Subject: [PATCH] fix: app icon & category icon (#529) --- docs/content.en/docs/release-notes/_index.md | 13 +-- src/components/Common/Icons/CommonIcon.tsx | 70 ++++++------- src/components/Common/Icons/UniversalIcon.tsx | 98 +++++++++++++------ src/components/Common/UI/Footer.tsx | 7 +- src/components/Search/DocumentDetail.tsx | 4 +- src/components/Search/DropdownList.tsx | 9 +- src/components/Search/ListRight.tsx | 4 +- src/components/Search/MCPPopover.tsx | 2 +- src/components/Search/SearchListItem.tsx | 2 +- src/components/Search/SearchPopover.tsx | 2 +- src/hooks/useFindConnectorIcon.ts | 4 +- 11 files changed, 129 insertions(+), 86 deletions(-) diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index 22c422f5..b28c1aba 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -7,17 +7,7 @@ title: "Release Notes" Information about release notes of Coco Server is provided here. -## Latest (In development) - -### ❌ Breaking changes - -### 🚀 Features - -### 🐛 Bug fix - -### ✈️ Improvements - -## 0.5.0 (2025-05-17) +## 0.5.0 (In development) ### ❌ Breaking changes @@ -62,6 +52,7 @@ Information about release notes of Coco Server is provided here. - refactor: optimizing list styles in markdown content #520 - feat: add a component for text reading aloud #522 - style: history component styles #528 +- fix: app icon & category icon #529 ## 0.4.0 (2025-04-27) diff --git a/src/components/Common/Icons/CommonIcon.tsx b/src/components/Common/Icons/CommonIcon.tsx index 5d51bdb7..d9b44f32 100644 --- a/src/components/Common/Icons/CommonIcon.tsx +++ b/src/components/Common/Icons/CommonIcon.tsx @@ -1,16 +1,17 @@ import { useState } from "react"; import { isEmpty } from "lodash-es"; import { useAsyncEffect } from "ahooks"; +import { Box } from "lucide-react"; import platformAdapter from "@/utils/platformAdapter"; -import UniversalIcon from "./UniversalIcon"; +import UniversalIcon, { getIconType } from "./UniversalIcon"; import { useFindConnectorIcon } from "@/hooks/useFindConnectorIcon"; interface CommonIconProps { renderOrder: string[]; item: any; itemIcon?: string; - defaultIcon?: React.FC; + defaultIcon?: React.FC | string; className?: string; onClick?: (e: React.MouseEvent) => void; } @@ -26,6 +27,9 @@ function CommonIcon({ const connectorSource = useFindConnectorIcon(item); const [isAbsolute, setIsAbsolute] = useState(); + const [defaultIconState, setDefaultIconState] = useState< + React.FC | string | undefined + >(defaultIcon); useAsyncEffect(async () => { if (isEmpty(item)) return; @@ -35,40 +39,40 @@ function CommonIcon({ omitSize: true, }); setIsAbsolute(Boolean(isAbsolute)); + setDefaultIconState(defaultIcon || Box); } catch (error) { setIsAbsolute(false); } }, [item]); - // Handle special icon types - const renderSpecialIcon = () => { - if (item.id === "Calculator") { - return ( - - ); - } - - if (isAbsolute) { - return ( - - ); - } - - return null; - }; - // Handle regular icon types const renderIconByType = (renderType: string) => { switch (renderType) { + case "special_icon": { + if (item.id === "Calculator") { + return ( + + ); + } + + if (isAbsolute) { + return ( + + ); + } + return null; + } case "item_icon": + if (getIconType(itemIcon) === "default") return null; return ( @@ -100,13 +105,10 @@ function CommonIcon({ } }; - // Render logic - const specialIcon = renderSpecialIcon(); - if (specialIcon) return specialIcon; - for (const renderType of renderOrder) { const icon = renderIconByType(renderType); - if (icon) return icon; + if (!icon) continue; + return icon; } return null; diff --git a/src/components/Common/Icons/UniversalIcon.tsx b/src/components/Common/Icons/UniversalIcon.tsx index 1dbc20e2..3b591c3f 100644 --- a/src/components/Common/Icons/UniversalIcon.tsx +++ b/src/components/Common/Icons/UniversalIcon.tsx @@ -1,41 +1,52 @@ import React from "react"; -import { Box } from "lucide-react"; +import { File } from "lucide-react"; import IconWrapper from "./IconWrapper"; import ThemedIcon from "./ThemedIcon"; import FontIcon from "./FontIcon"; import { useAppStore } from "@/stores/appStore"; +import platformAdapter from "@/utils/platformAdapter"; interface UniversalIconProps { - icon?: string; // Icon source - defaultIcon?: React.FC; // Default icon component - className?: string; // Style class name + icon?: string; // Icon source + defaultIcon?: React.FC | string; // Default icon component + appIcon?: boolean; // Whether the icon is local + className?: string; // Style class name onClick?: React.MouseEventHandler; wrapWithIconWrapper?: boolean; // Whether to wrap with IconWrapper } -type IconType = 'url' | 'base64' | 'font' | 'local' | 'splice' | 'default'; +type IconType = + | "url" + | "base64" + | "font" + | "local" + | "app" + | "splice" + | "default"; + +// Determine icon type +export const getIconType = (icon?: string, appIcon?: boolean): IconType => { + if (!icon) return "default"; + if (appIcon) return "app"; + if (icon.startsWith("http://") || icon.startsWith("https://")) return "url"; + if (icon.startsWith("data:image/")) return "base64"; + if (icon.startsWith("font_")) return "font"; + if (icon.startsWith("/assets")) return "local"; + if (icon.startsWith("/")) return "splice"; + return "default"; +}; function UniversalIcon({ icon, - defaultIcon = Box, + defaultIcon = File, + appIcon = false, className = "w-5 h-5 flex-shrink-0", onClick = () => {}, wrapWithIconWrapper = true, }: UniversalIconProps) { const endpoint_http = useAppStore((state) => state.endpoint_http); - // Determine icon type - const getIconType = (icon?: string): IconType => { - if (!icon) return 'default'; - if (icon.startsWith('http://') || icon.startsWith('https://')) return 'url'; - if (icon.startsWith('data:image/')) return 'base64'; - if (icon.startsWith('font_')) return 'font'; - if (icon.startsWith('/assets')) return 'local'; - if (icon.startsWith('/')) return 'splice'; - return 'default'; - }; - // Render image type icon const renderImageIcon = (src: string) => { const img = icon; @@ -43,34 +54,63 @@ function UniversalIcon({ {img} - ) : img; + ) : ( + img + ); + }; + + // Render app type icon + const renderAppIcon = (src: string) => { + const img = ( + icon + ); + return wrapWithIconWrapper ? ( + + {img} + + ) : ( + img + ); }; // Render default icon const renderDefaultIcon = () => { - const defaultComponent = ; + if (typeof defaultIcon === "string") { + return renderImageIcon(defaultIcon); + } + const defaultComponent = ( + + ); return wrapWithIconWrapper ? ( {defaultComponent} - ) : defaultComponent; + ) : ( + defaultComponent + ); }; // Render component based on icon type - const iconType = getIconType(icon); + const iconType = getIconType(icon, appIcon); switch (iconType) { - case 'url': - case 'base64': - case 'local': - return renderImageIcon(icon!); - case 'splice': - const url = `${endpoint_http}${icon!}` + case "url": + case "base64": + case "local": + return renderImageIcon(icon!); + case "app": + return renderAppIcon(icon!); + case "splice": + const url = `${endpoint_http}${icon!}`; return renderImageIcon(url); - case 'font': + case "font": return ; default: return renderDefaultIcon(); } } -export default UniversalIcon; \ No newline at end of file +export default UniversalIcon; diff --git a/src/components/Common/UI/Footer.tsx b/src/components/Common/UI/Footer.tsx index 3e922fc3..934eb87f 100644 --- a/src/components/Common/UI/Footer.tsx +++ b/src/components/Common/UI/Footer.tsx @@ -13,6 +13,9 @@ import { useUpdateStore } from "@/stores/updateStore"; import VisibleKey from "../VisibleKey"; import { useShortcutsStore } from "@/stores/shortcutsStore"; import { formatKey } from "@/utils/keyboardUtils"; +import source_default_img from "@/assets/images/source_default.png"; +import source_default_dark_img from "@/assets/images/source_default_dark.png"; +import { useThemeStore } from "@/stores/themeStore"; interface FooterProps { isTauri: boolean; @@ -27,6 +30,7 @@ export default function Footer({ }: FooterProps) { const { t } = useTranslation(); const sourceData = useSearchStore((state) => state.sourceData); + const isDark = useThemeStore((state) => state.isDark); const isPinned = useAppStore((state) => state.isPinned); const setIsPinned = useAppStore((state) => state.setIsPinned); @@ -59,8 +63,9 @@ export default function Footer({ {sourceData?.source?.name ? ( ) : ( diff --git a/src/components/Search/DocumentDetail.tsx b/src/components/Search/DocumentDetail.tsx index 8dcc9db8..770eba49 100644 --- a/src/components/Search/DocumentDetail.tsx +++ b/src/components/Search/DocumentDetail.tsx @@ -66,7 +66,7 @@ export const DocumentDetail: React.FC = ({ document }) => { /> ) : ( = ({ document }) => { icon={ diff --git a/src/components/Search/DropdownList.tsx b/src/components/Search/DropdownList.tsx index 374a6360..78a4894f 100644 --- a/src/components/Search/DropdownList.tsx +++ b/src/components/Search/DropdownList.tsx @@ -10,6 +10,7 @@ import { ArrowBigRight } from "lucide-react"; import { isNil } from "lodash-es"; import { useDebounceFn, useUnmount } from "ahooks"; import { useTranslation } from "react-i18next"; +import clsx from "clsx"; import { useSearchStore } from "@/stores/searchStore"; import ThemedIcon from "@/components/Common/Icons/ThemedIcon"; @@ -23,7 +24,9 @@ import Calculator from "./Calculator"; import { useShortcutsStore } from "@/stores/shortcutsStore"; import ErrorSearch from "@/components/Common/ErrorNotification/ErrorSearch"; // import AiSummary from "./AiSummary"; -import clsx from "clsx"; +import source_default_img from "@/assets/images/source_default.png"; +import source_default_dark_img from "@/assets/images/source_default_dark.png"; +import { useThemeStore } from "@/stores/themeStore"; type ISearchData = Record; @@ -47,6 +50,7 @@ function DropdownList({ const globalItemIndexMap: any[] = []; const setSourceData = useSearchStore((state) => state.setSourceData); + const isDark = useThemeStore((state) => state.isDark); const [selectedItem, setSelectedItem] = useState(null); const [selectedName, setSelectedName] = useState(""); @@ -235,8 +239,9 @@ function DropdownList({
{sourceName} - {items[0]?.source.name} diff --git a/src/components/Search/ListRight.tsx b/src/components/Search/ListRight.tsx index d88d4d39..4bfa3f56 100644 --- a/src/components/Search/ListRight.tsx +++ b/src/components/Search/ListRight.tsx @@ -28,7 +28,7 @@ export function RichCategories({
{ @@ -72,7 +72,7 @@ export function RichCategories({ > { diff --git a/src/components/Search/MCPPopover.tsx b/src/components/Search/MCPPopover.tsx index 782edbd0..6ec46161 100644 --- a/src/components/Search/MCPPopover.tsx +++ b/src/components/Search/MCPPopover.tsx @@ -287,7 +287,7 @@ export default function MCPPopover({ ) : ( diff --git a/src/components/Search/SearchListItem.tsx b/src/components/Search/SearchListItem.tsx index e1b7ab67..def681cb 100644 --- a/src/components/Search/SearchListItem.tsx +++ b/src/components/Search/SearchListItem.tsx @@ -59,7 +59,7 @@ const SearchListItem: React.FC = React.memo( } min-w-0 flex gap-2 items-center justify-start `} > diff --git a/src/hooks/useFindConnectorIcon.ts b/src/hooks/useFindConnectorIcon.ts index eee38391..34eaef61 100644 --- a/src/hooks/useFindConnectorIcon.ts +++ b/src/hooks/useFindConnectorIcon.ts @@ -4,10 +4,10 @@ import { useAppStore } from "@/stores/appStore"; export function useFindConnectorIcon(item: any) { const connector_data = useConnectStore((state) => state.connector_data); const datasourceData = useConnectStore((state) => state.datasourceData); - const currentService = useConnectStore((state) => state.currentService); const isTauri = useAppStore((state) => state.isTauri); - let currentServiceId = currentService?.id; + + let currentServiceId = item?.querySource?.id; if (!isTauri) { currentServiceId = "web" }