Files
FileCodeBoxFronted2026/src/components/common/StatCard.vue
T

80 lines
2.6 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="truncate text-xs sm:text-sm" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-600']">
{{ title }}
</p>
<h3 class="mt-1 truncate text-xl font-bold tabular-nums sm:text-2xl" :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" />
</div>
</div>
<p class="mt-2 line-clamp-1 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>