From f4c4d7495f55b43a6e48a4855de7f678b1ca15d5 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 18 May 2026 11:25:00 +0800 Subject: [PATCH] refactor: optimize storage card accent colors and clean up unused directory UI logic --- src/components/cards/DirectoryCard.vue | 117 ++++--------------------- src/styles/common.scss | 5 +- src/styles/themes/transparent.scss | 2 +- 3 files changed, 18 insertions(+), 106 deletions(-) diff --git a/src/components/cards/DirectoryCard.vue b/src/components/cards/DirectoryCard.vue index 93681132..e17dffa8 100644 --- a/src/components/cards/DirectoryCard.vue +++ b/src/components/cards/DirectoryCard.vue @@ -4,25 +4,9 @@ import api from '@/api' import { nextTick } from 'vue' import { useI18n } from 'vue-i18n' import { storageRemoteDict } from '@/api/constants' -import { getCardAccentRgbFromImage } from '@/composables/useCardAccentColor' -import storage_png from '@images/misc/storage.png' -import alipan_png from '@images/misc/alipan.webp' -import u115_png from '@images/misc/u115.png' -import rclone_png from '@images/misc/rclone.png' -import alist_png from '@images/misc/openlist.svg' -import smb_png from '@images/misc/smb.png' const DEFAULT_DIRECTORY_ACCENT_RGB = '145, 85, 253' -const STORAGE_ICON_MAP = { - local: storage_png, - alipan: alipan_png, - u115: u115_png, - rclone: rclone_png, - alist: alist_png, - smb: smb_png, -} - -const STORAGE_FALLBACK_COLOR_MAP = { +const STORAGE_ACCENT_COLOR_MAP = { local: '#FFB400', alipan: '#00A7F2', u115: '#17B26A', @@ -35,7 +19,6 @@ const STORAGE_FALLBACK_COLOR_MAP = { const { t } = useI18n() const downloadAccentRgb = ref(DEFAULT_DIRECTORY_ACCENT_RGB) const libraryAccentRgb = ref(DEFAULT_DIRECTORY_ACCENT_RGB) -let accentUpdateToken = 0 // 输入参数 const props = defineProps({ @@ -92,12 +75,8 @@ const transferSourceItems = computed(() => [ { title: t('directory.manualTransfer'), value: 'manual' }, ]) -function hasKnownStorageType(storageType?: string): storageType is keyof typeof STORAGE_ICON_MAP { - return !!storageType && Object.prototype.hasOwnProperty.call(STORAGE_ICON_MAP, storageType) -} - -function getStorageIcon(storageType?: string) { - return hasKnownStorageType(storageType) ? STORAGE_ICON_MAP[storageType] : storage_png +function hasKnownStorageType(storageType?: string): storageType is keyof typeof STORAGE_ACCENT_COLOR_MAP { + return !!storageType && Object.prototype.hasOwnProperty.call(STORAGE_ACCENT_COLOR_MAP, storageType) } function hexToRgbString(hexColor: string) { @@ -109,46 +88,18 @@ function hexToRgbString(hexColor: string) { return `${(colorValue >> 16) & 255}, ${(colorValue >> 8) & 255}, ${colorValue & 255}` } -function rgbToHex(value: number) { - return Math.round(value).toString(16).padStart(2, '0') +function getCustomStoragePaletteColor(storageType?: string) { + const customStorageIndex = Math.max(Number(storageType?.match(/\d+$/)?.[0] ?? 1) - 1, 0) + const customStorageColors = ['#F97316', '#8B5CF6', '#06B6D4', '#84CC16', '#EC4899', '#14B8A6'] + + return customStorageColors[customStorageIndex % customStorageColors.length] } -function hslToHex(hue: number, saturation: number, lightness: number) { - const normalizedSaturation = saturation / 100 - const normalizedLightness = lightness / 100 - const chroma = (1 - Math.abs(2 * normalizedLightness - 1)) * normalizedSaturation - const secondComponent = chroma * (1 - Math.abs(((hue / 60) % 2) - 1)) - const lightnessMatch = normalizedLightness - chroma / 2 - let red = 0 - let green = 0 - let blue = 0 +function getStorageAccentColor(storageType?: string) { + if (hasKnownStorageType(storageType)) return STORAGE_ACCENT_COLOR_MAP[storageType] - if (hue < 60) [red, green, blue] = [chroma, secondComponent, 0] - else if (hue < 120) [red, green, blue] = [secondComponent, chroma, 0] - else if (hue < 180) [red, green, blue] = [0, chroma, secondComponent] - else if (hue < 240) [red, green, blue] = [0, secondComponent, chroma] - else if (hue < 300) [red, green, blue] = [secondComponent, 0, chroma] - else [red, green, blue] = [chroma, 0, secondComponent] - - return `#${rgbToHex((red + lightnessMatch) * 255)}${rgbToHex((green + lightnessMatch) * 255)}${rgbToHex((blue + lightnessMatch) * 255)}` -} - -function getStableStorageColor(storageType?: string) { - const source = storageType || 'custom' - let hash = 0 - - for (let index = 0; index < source.length; index += 1) { - hash = Math.imul(31, hash) + source.charCodeAt(index) - } - - return hslToHex(Math.abs(hash) % 360, 66, 54) -} - -function getStorageFallbackColor(storageType?: string) { - if (hasKnownStorageType(storageType)) return STORAGE_FALLBACK_COLOR_MAP[storageType] - - // 自定义存储没有固定品牌图标,按类型生成稳定颜色,保证切换 custom1/custom2 时也有变化。 - return getStableStorageColor(storageType) + // 自定义存储没有固定品牌图标,使用离散调色板,保证连续 custom1/custom2 也能明显区分。 + return getCustomStoragePaletteColor(storageType) } // 目录卡片用下载存储和媒体库存储两端的图标主色生成轻渐变,体现整理链路的两个存储端点。 @@ -157,50 +108,12 @@ const directoryAccentStyle = computed(() => ({ '--app-card-accent-end-rgb': libraryAccentRgb.value, })) -function loadStorageIconImage(storageType?: string) { - return new Promise(resolve => { - if (typeof Image === 'undefined') { - resolve(null) - return - } - - const image = new Image() - - image.onload = () => resolve(image) - image.onerror = () => resolve(null) - image.src = getStorageIcon(storageType) - - if (image.complete) resolve(image) - }) -} - -async function getStorageAccentRgb(storageType?: string) { - const fallbackColor = getStorageFallbackColor(storageType) - - if (!hasKnownStorageType(storageType)) return hexToRgbString(fallbackColor) - - const image = await loadStorageIconImage(storageType) - - return getCardAccentRgbFromImage(image, fallbackColor) -} - -async function updateDirectoryAccentColors() { - const currentToken = ++accentUpdateToken +function updateDirectoryAccentColors() { const downloadStorage = props.directory.storage const libraryStorage = props.directory.library_storage || props.directory.storage - downloadAccentRgb.value = hexToRgbString(getStorageFallbackColor(downloadStorage)) - libraryAccentRgb.value = hexToRgbString(getStorageFallbackColor(libraryStorage)) - - const [downloadRgb, libraryRgb] = await Promise.all([ - getStorageAccentRgb(downloadStorage), - getStorageAccentRgb(libraryStorage), - ]) - - if (currentToken !== accentUpdateToken) return - - downloadAccentRgb.value = downloadRgb - libraryAccentRgb.value = libraryRgb + downloadAccentRgb.value = hexToRgbString(getStorageAccentColor(downloadStorage)) + libraryAccentRgb.value = hexToRgbString(getStorageAccentColor(libraryStorage)) } // 监控模式下拉字典 diff --git a/src/styles/common.scss b/src/styles/common.scss index adee6c91..224b050d 100644 --- a/src/styles/common.scss +++ b/src/styles/common.scss @@ -92,7 +92,7 @@ html { --app-card-accent-rgb: var(--v-theme-primary); --app-card-accent-end-rgb: var(--app-card-accent-rgb); --app-card-accent-start-opacity: 0.09; - --app-card-accent-end-opacity: 0.02; + --app-card-accent-end-opacity: 0.06; --app-card-border-opacity: 0.2; --app-card-hover-border-opacity: 0.34; --app-card-stripe-opacity: 0.78; @@ -115,7 +115,6 @@ html { .app-card-colorful:hover { border-color: rgba(var(--app-card-accent-rgb), var(--app-card-hover-border-opacity)) !important; box-shadow: var(--app-card-hover-shadow) !important; - transform: translateY(-2px); } .app-card-colorful:focus-visible { @@ -138,7 +137,7 @@ html[data-theme="transparent"] .app-card-colorful, backdrop-filter: blur(var(--transparent-blur, 10px)); border: 0 !important; --app-card-accent-start-opacity: 0.04; - --app-card-accent-end-opacity: 0.012; + --app-card-accent-end-opacity: 0.03; --app-card-border-opacity: 0; --app-card-hover-border-opacity: 0; --app-card-stripe-opacity: 0.42; diff --git a/src/styles/themes/transparent.scss b/src/styles/themes/transparent.scss index f3b310b8..cd803b3c 100644 --- a/src/styles/themes/transparent.scss +++ b/src/styles/themes/transparent.scss @@ -43,7 +43,7 @@ html[data-theme="transparent"] { linear-gradient( 135deg, rgba(var(--app-card-accent-rgb), var(--app-card-accent-start-opacity, 0.04)), - rgba(var(--app-card-accent-end-rgb, var(--app-card-accent-rgb)), var(--app-card-accent-end-opacity, 0.012)) 46%, + rgba(var(--app-card-accent-end-rgb, var(--app-card-accent-rgb)), var(--app-card-accent-end-opacity, 0.03)) 46%, rgba(var(--v-theme-surface), 0) 76% ), rgba(var(--v-theme-surface), var(--transparent-opacity-light)) !important;