218 lines
4.2 KiB
Plaintext
218 lines
4.2 KiB
Plaintext
---
|
|
export interface Props {
|
|
title: string;
|
|
value: string | number;
|
|
change?: string;
|
|
changeType?: 'positive' | 'negative' | 'neutral';
|
|
icon?: string;
|
|
color?: 'primary' | 'success' | 'warning' | 'info';
|
|
}
|
|
|
|
const {
|
|
title,
|
|
value,
|
|
change,
|
|
changeType = 'neutral',
|
|
icon,
|
|
color = 'primary'
|
|
} = Astro.props;
|
|
|
|
const colorClasses = {
|
|
primary: 'metric-primary',
|
|
success: 'metric-success',
|
|
warning: 'metric-warning',
|
|
info: 'metric-info'
|
|
};
|
|
|
|
const changeClasses = {
|
|
positive: 'change-positive',
|
|
negative: 'change-negative',
|
|
neutral: 'change-neutral'
|
|
};
|
|
---
|
|
|
|
<div class={`metric-card ${colorClasses[color]}`}>
|
|
<div class="metric-header">
|
|
{icon && (
|
|
<div class="metric-icon">
|
|
<i class={icon}></i>
|
|
</div>
|
|
)}
|
|
<h3 class="metric-title">{title}</h3>
|
|
</div>
|
|
|
|
<div class="metric-body">
|
|
<div class="metric-value">{value}</div>
|
|
|
|
{change && (
|
|
<div class={`metric-change ${changeClasses[changeType]}`}>
|
|
<i class={changeType === 'positive' ? 'fas fa-arrow-up' : changeType === 'negative' ? 'fas fa-arrow-down' : 'fas fa-minus'}></i>
|
|
<span>{change}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div class="metric-bg"></div>
|
|
</div>
|
|
|
|
<style>
|
|
.metric-card {
|
|
position: relative;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
backdrop-filter: blur(15px);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
border-radius: 1.25rem;
|
|
padding: 1.5rem;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
overflow: hidden;
|
|
animation: scaleIn 0.5s ease-out;
|
|
}
|
|
|
|
.metric-card:hover {
|
|
transform: translateY(-4px) scale(1.02);
|
|
background: rgba(255, 255, 255, 0.15);
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.metric-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.metric-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 0.75rem;
|
|
background: rgba(91, 119, 142, 0.2);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.25rem;
|
|
color: #5b778e;
|
|
}
|
|
|
|
.metric-title {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: #011a2d;
|
|
margin: 0;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.metric-body {
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.metric-value {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: #011a2d;
|
|
margin-bottom: 0.5rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.metric-change {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.change-positive {
|
|
color: #064630;
|
|
}
|
|
|
|
.change-negative {
|
|
color: #720808;
|
|
}
|
|
|
|
.change-neutral {
|
|
color: #0a2c48;
|
|
}
|
|
|
|
.metric-bg {
|
|
position: absolute;
|
|
top: -50%;
|
|
right: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
opacity: 0.03;
|
|
border-radius: 50%;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.metric-card:hover .metric-bg {
|
|
opacity: 0.06;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
/* 颜色变体 */
|
|
.metric-primary .metric-bg {
|
|
background: linear-gradient(135deg, #5b778e, #b2c5d5);
|
|
}
|
|
|
|
.metric-primary .metric-icon {
|
|
background: rgba(91, 119, 142, 0.2);
|
|
color: #5b778e;
|
|
}
|
|
|
|
.metric-success .metric-bg {
|
|
background: linear-gradient(135deg, #b1d9d4, #aecedd);
|
|
}
|
|
|
|
.metric-success .metric-icon {
|
|
background: rgba(177, 217, 212, 0.2);
|
|
color: #10B981;
|
|
}
|
|
|
|
.metric-warning .metric-bg {
|
|
background: linear-gradient(135deg, #b2c5d5, #aecedd);
|
|
}
|
|
|
|
.metric-warning .metric-icon {
|
|
background: rgba(178, 197, 213, 0.2);
|
|
color: #F59E0B;
|
|
}
|
|
|
|
.metric-info .metric-bg {
|
|
background: linear-gradient(135deg, #aecedd, #b1d9d4);
|
|
}
|
|
|
|
.metric-info .metric-icon {
|
|
background: rgba(174, 206, 221, 0.2);
|
|
color: #5b778e;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.metric-card {
|
|
padding: 1.25rem;
|
|
}
|
|
|
|
.metric-value {
|
|
font-size: 1.75rem;
|
|
}
|
|
|
|
.metric-icon {
|
|
width: 36px;
|
|
height: 36px;
|
|
font-size: 1.1rem;
|
|
}
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.9);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
</style> |