initial commit
This commit is contained in:
218
src/components/report/MetricCard.astro
Normal file
218
src/components/report/MetricCard.astro
Normal file
@@ -0,0 +1,218 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user