Files
X-Financial/web/src/components/shared/WorkbenchListIcon.vue
caoxiaozhu 2dcc72102d style: 全局 UI 主题皮肤重构与样式模块化
引入 Element Plus 主题定制和主题皮肤 composable,将全局
样式拆分为组件级独立 CSS 文件(侧边栏、顶栏、工作台等),
统一色彩变量和间距规范,重构所有视图和组件样式以适配新
主题系统,优化图表和知识图谱组件视觉表现,提取审计和差
旅报销相关子组件。
2026-05-27 09:17:57 +08:00

108 lines
2.9 KiB
Vue

<template>
<div
class="workbench-list-icon"
:class="[`workbench-list-icon--${iconKey}`, `workbench-list-icon--${iconStyle}`]"
:style="{ '--icon-color': color, '--icon-accent': accent || color }"
>
<span class="workbench-list-icon__halo" aria-hidden="true"></span>
<span class="workbench-list-icon__panel" aria-hidden="true">
<span class="workbench-list-icon__shine" aria-hidden="true"></span>
<span class="workbench-list-icon__art" aria-hidden="true" v-html="iconMarkup"></span>
</span>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { workbenchIconMap } from '../../utils/workbenchIconAssets.js'
const props = defineProps({
iconKey: { type: String, required: true },
color: { type: String, default: 'var(--theme-primary)' },
accent: { type: String, default: '' }
})
const iconMeta = computed(() => workbenchIconMap[props.iconKey] || workbenchIconMap.hospitality)
const iconMarkup = computed(() => iconMeta.value.markup)
const iconStyle = computed(() => iconMeta.value.style)
</script>
<style scoped>
.workbench-list-icon {
position: relative;
width: 56px;
height: 56px;
flex-shrink: 0;
color: var(--icon-color);
}
.workbench-list-icon__halo {
position: absolute;
inset: -3px;
border-radius: 20px;
background: radial-gradient(
circle at 50% 40%,
color-mix(in srgb, var(--icon-accent, var(--icon-color)) 42%, transparent) 0%,
transparent 72%
);
opacity: 0.9;
}
.workbench-list-icon__panel {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
display: grid;
place-items: center;
overflow: hidden;
border-radius: 18px;
border: 1px solid color-mix(in srgb, var(--icon-color) 20%, #e2e8f0);
background:
radial-gradient(circle at 24% 16%, rgba(255, 255, 255, 0.98), transparent 46%),
linear-gradient(
160deg,
color-mix(in srgb, var(--icon-accent, var(--icon-color)) 24%, #fff) 0%,
#fff 42%,
color-mix(in srgb, var(--icon-color) 6%, #f8fafc) 100%
);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.98),
0 1px 2px rgba(15, 23, 42, 0.04),
0 12px 24px color-mix(in srgb, var(--icon-color) 14%, transparent);
}
.workbench-list-icon__shine {
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.55), transparent 38%);
pointer-events: none;
}
.workbench-list-icon__art {
position: relative;
z-index: 1;
display: grid;
place-items: center;
width: 30px;
height: 30px;
}
.workbench-list-icon__art :deep(.workbench-heroicon) {
width: 30px;
height: 30px;
display: block;
color: var(--icon-color);
filter: drop-shadow(0 2px 6px color-mix(in srgb, var(--icon-color) 22%, transparent));
}
.workbench-list-icon--outline .workbench-list-icon__art :deep(.workbench-heroicon) {
stroke-width: 1.65;
}
.workbench-list-icon--solid .workbench-list-icon__art :deep(.workbench-heroicon path) {
opacity: 0.96;
}
</style>