b60c003ec2
完善 2026 主题的移动端与桌面端交互体验,修复多项可访问性和信息展示问题。 - 允许浏览器缩放,补充焦点样式、按钮名称、表单标签和对话框键盘焦点管理\n- 支持 reduced-motion,扩大公共页、后台导航、记录列表和分页控件的触控区域\n- 优化系统设置分区导航、密码显示、字段语义和底部粘性保存栏\n- 压缩移动文件列表操作区,改善桌面表格滚动可达性和统计值截断\n- 优化仪表盘指标、趋势摘要、进度条语义及中英文文案
80 lines
2.7 KiB
Vue
80 lines
2.7 KiB
Vue
<template>
|
|
<div
|
|
class="theme-2026-card theme-2026-card-hover group rounded-[24px] p-4 shadow-md transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg sm:rounded-[30px] sm:p-6"
|
|
:class="[
|
|
isDarkMode
|
|
? 'hover:bg-gray-800 hover:shadow-black/20'
|
|
: 'hover:shadow-gray-200/80'
|
|
]"
|
|
>
|
|
<div class="flex items-center justify-between gap-3">
|
|
<div class="min-w-0">
|
|
<p class="line-clamp-2 text-xs leading-tight sm:text-sm" :title="title" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-600']">
|
|
{{ title }}
|
|
</p>
|
|
<h3 class="mt-1 break-words text-xl font-bold leading-tight tabular-nums sm:text-2xl" :title="String(value)" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
|
|
{{ value }}
|
|
</h3>
|
|
</div>
|
|
<div
|
|
class="shrink-0 rounded-full p-2.5 transition-transform duration-300 group-hover:scale-105 sm:p-3"
|
|
:class="iconBgClass"
|
|
>
|
|
<component :is="icon" class="h-5 w-5 sm:h-6 sm:w-6" :class="iconClass" aria-hidden="true" />
|
|
</div>
|
|
</div>
|
|
<p class="mt-2 line-clamp-2 text-xs sm:text-sm" :class="descriptionClass">
|
|
<slot name="description"></slot>
|
|
</p>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import type { Component } from 'vue'
|
|
import { useInjectedDarkMode } from '@/composables'
|
|
|
|
interface Props {
|
|
title: string
|
|
value: string | number
|
|
icon: Component
|
|
iconColor: 'indigo' | 'purple' | 'green' | 'blue'
|
|
descriptionType?: 'success' | 'error' | 'neutral'
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
descriptionType: 'neutral'
|
|
})
|
|
|
|
const isDarkMode = useInjectedDarkMode()
|
|
|
|
const iconBgClass = computed(() => {
|
|
const colorMap = {
|
|
indigo: isDarkMode.value ? 'bg-[#294047]' : 'bg-[#dcebed]',
|
|
purple: isDarkMode.value ? 'bg-[#443d4b]' : 'bg-[#e7e2ea]',
|
|
green: isDarkMode.value ? 'bg-[#31564f]' : 'bg-[#e1eee8]',
|
|
blue: isDarkMode.value ? 'bg-[#2d4851]' : 'bg-[#dce8eb]'
|
|
}
|
|
return colorMap[props.iconColor]
|
|
})
|
|
|
|
const iconClass = computed(() => {
|
|
const colorMap = {
|
|
indigo: isDarkMode.value ? 'text-[#b8d4dc]' : 'text-[#3f6a77]',
|
|
purple: isDarkMode.value ? 'text-[#d4c8dc]' : 'text-[#6f6379]',
|
|
green: isDarkMode.value ? 'text-[#c4dfd5]' : 'text-[#55796e]',
|
|
blue: isDarkMode.value ? 'text-[#bfd9df]' : 'text-[#4b7380]'
|
|
}
|
|
return colorMap[props.iconColor]
|
|
})
|
|
|
|
const descriptionClass = computed(() => {
|
|
const typeMap = {
|
|
success: isDarkMode.value ? 'text-[#b6d6ca]' : 'text-[#5f8377]',
|
|
error: isDarkMode.value ? 'text-[#e5c5ca]' : 'text-[#8b5962]',
|
|
neutral: isDarkMode.value ? 'text-gray-400' : 'text-gray-600'
|
|
}
|
|
return typeMap[props.descriptionType]
|
|
})
|
|
</script>
|