aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
303 lines (300 loc) • 11.7 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { TrendingUp, TrendingDown, Minus, Target, Activity, Users, DollarSign } from 'lucide-react';
import { forwardRef } from 'react';
import '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import { MotionFramer } from '../../primitives/motion/MotionFramer.js';
import { CardHeader, CardTitle, CardContent } from '../card/index.js';
import { GlassCard } from '../card/GlassCard.js';
/**
* GlassMetricCard component
* A glassmorphism metric card for displaying various dashboard metrics
*/
const GlassMetricCard = /*#__PURE__*/forwardRef(({
// TODO: Integrate ContrastGuard for table cells, list items, badges, card titles, and other text content for WCAG AA compliance
title,
value,
unit = "",
description,
icon,
type = "custom",
variant = "default",
size = "md",
layout = "vertical",
showProgress = false,
progress = 0,
progressLabel,
trend,
comparison,
children,
loading = false,
onClick,
className,
...props
}, ref) => {
// Size configurations
const sizeConfigs = {
sm: {
cardClass: "glass-p-4",
titleClass: "glass-text-sm font-medium",
valueClass: "glass-text-xl font-bold",
iconSize: "w-6 h-6",
progressHeight: "h-1"
},
md: {
cardClass: "glass-p-6",
titleClass: "glass-text-base font-medium",
valueClass: "glass-text-2xl font-bold",
iconSize: "w-8 h-8",
progressHeight: "h-2"
},
lg: {
cardClass: "p-8",
titleClass: "glass-text-lg font-semibold",
valueClass: "text-3xl font-bold",
iconSize: "w-10 h-10",
progressHeight: "h-3"
},
xl: {
cardClass: "glass-p-10",
titleClass: "glass-text-xl font-semibold",
valueClass: "text-4xl font-bold",
iconSize: "w-12 h-12",
progressHeight: "h-4"
}
};
// Get automatic icon based on type
const getTypeIcon = () => {
switch (type) {
case "revenue":
return jsx(DollarSign, {
className: sizeConfigs[size].iconSize
});
case "users":
return jsx(Users, {
className: sizeConfigs[size].iconSize
});
case "conversion":
return jsx(Target, {
className: sizeConfigs[size].iconSize
});
case "performance":
return jsx(Activity, {
className: sizeConfigs[size].iconSize
});
case "growth":
return jsx(TrendingUp, {
className: sizeConfigs[size].iconSize
});
case "target":
return jsx(Target, {
className: sizeConfigs[size].iconSize
});
default:
return null;
}
};
// Variant color configurations
const variantConfigs = {
default: {
iconColor: "glass-text-primary/70",
valueColor: "glass-text-primary",
trendUpColor: "text-green-400",
trendDownColor: "text-red-400",
trendNeutralColor: "text-yellow-400",
progressBg: "bg-white/20",
progressFill: "bg-white/60"
},
success: {
iconColor: "text-green-400",
valueColor: "text-green-200",
trendUpColor: "text-green-300",
trendDownColor: "text-red-400",
trendNeutralColor: "text-yellow-400",
progressBg: "bg-green-500/20",
progressFill: "bg-green-500"
},
warning: {
iconColor: "text-yellow-400",
valueColor: "text-yellow-200",
trendUpColor: "text-green-400",
trendDownColor: "text-red-400",
trendNeutralColor: "text-yellow-300",
progressBg: "bg-yellow-500/20",
progressFill: "bg-yellow-500"
},
error: {
iconColor: "text-red-400",
valueColor: "text-red-200",
trendUpColor: "text-red-400",
trendDownColor: "text-red-300",
trendNeutralColor: "text-yellow-400",
progressBg: "bg-red-500/20",
progressFill: "bg-red-500"
},
info: {
iconColor: "text-blue-400",
valueColor: "text-blue-200",
trendUpColor: "text-green-400",
trendDownColor: "text-red-400",
trendNeutralColor: "text-yellow-400",
progressBg: "bg-blue-500/20",
progressFill: "bg-blue-500"
},
primary: {
iconColor: "text-primary",
valueColor: "text-primary-foreground",
trendUpColor: "text-green-400",
trendDownColor: "text-red-400",
trendNeutralColor: "text-yellow-400",
progressBg: "bg-primary/20",
progressFill: "bg-primary"
}
};
const config = sizeConfigs?.[size];
const variantConfig = variantConfigs?.[variant];
const displayIcon = icon || getTypeIcon();
// Loading skeleton
if (loading) {
return jsx(GlassCard, {
"data-glass-component": true,
className: cn("animate-pulse", config.cardClass, className),
children: jsxs("div", {
className: "glass-gap-4",
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsx("div", {
className: 'h-4 glass-surface-subtle/20 glass-radius-md w-24'
}), jsx("div", {
className: 'w-8 h-8 glass-surface-subtle/20 glass-radius-md'
})]
}), jsxs("div", {
className: "glass-gap-2",
children: [jsx("div", {
className: 'h-8 glass-surface-subtle/20 glass-radius-md w-32'
}), jsx("div", {
className: 'h-4 glass-surface-subtle/20 glass-radius-md w-20'
})]
}), showProgress && jsx("div", {
className: 'h-2 glass-surface-subtle/10 glass-radius-md'
})]
})
});
}
return jsx(MotionFramer, {
preset: "fadeIn",
className: "glass-w-full glass-metric-card",
children: jsxs(GlassCard, {
ref: ref,
elevation: "level2",
intensity: "medium",
depth: 2,
tint: "neutral",
border: "subtle",
animation: "none",
performanceMode: "medium",
hoverable: !!onClick,
clickable: !!onClick,
onClick: onClick,
className: cn(config.cardClass, "group relative overflow-hidden", onClick && ["cursor-pointer", "hover:shadow-2xl hover:shadow-blue-500/20", "transition-all duration-500 ease-out"], className),
...props,
children: [jsx(CardHeader, {
className: 'pb-2',
children: jsxs("div", {
className: cn("flex items-start justify-between", layout === "horizontal" ? "flex-row items-center" : "flex-col"),
children: [jsxs("div", {
className: "glass-flex-1",
children: [jsxs(CardTitle, {
className: cn(config.titleClass, "glass-text-primary/90 flex items-center glass-gap-2"),
children: [displayIcon && jsxs("div", {
className: cn("inline-flex items-center justify-center glass-radius-lg", "bg-gradient-to-br from-white/10 to-white/5", "border border-white/20 glass-p-2 mr-3", "group-hover:from-white/15 group-hover:to-white/8", "group-hover:border-white/30 group-hover:shadow-lg", "group-hover:scale-110 group-hover:-rotate-2", "transition-all duration-300 ease-out", variantConfig.iconColor),
children: [jsx("div", {
className: 'absolute inset-0 glass-gradient-primary glass-gradient-primary glass-gradient-primary glass-radius-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300'
}), jsx("span", {
className: cn(config.iconSize, "relative z-10 transition-transform duration-300 group-hover:scale-110"),
children: displayIcon
})]
}), title]
}), description && jsx("p", {
className: 'glass-text-sm text-primary/60 glass-mt-1',
children: description
})]
}), trend && jsxs("div", {
className: "glass-flex glass-items-center glass-gap-1 glass-mt-2",
children: [trend.direction === "up" && jsx(TrendingUp, {
className: cn("w-4 h-4", variantConfig.trendUpColor)
}), trend.direction === "down" && jsx(TrendingDown, {
className: cn("w-4 h-4", variantConfig.trendDownColor)
}), trend.direction === "neutral" && jsx(Minus, {
className: cn("w-4 h-4", variantConfig.trendNeutralColor)
}), jsxs("span", {
className: cn("glass-text-sm font-medium", trend.direction === "up" ? variantConfig.trendUpColor : trend.direction === "down" ? variantConfig.trendDownColor : variantConfig.trendNeutralColor),
children: [trend.value > 0 ? "+" : "", trend.value, "% ", trend.label]
})]
})]
})
}), jsxs(CardContent, {
className: 'pt-0',
children: [jsxs("div", {
className: cn("flex items-baseline glass-gap-2 glass-mb-4 relative", layout === "horizontal" ? "justify-start" : "justify-center"),
children: [jsxs("div", {
className: 'relative',
children: [jsx("div", {
className: 'absolute inset-0 glass-gradient-primary glass-gradient-primary via-purple-400/30 glass-gradient-primary glass-blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500 -z-10 scale-150'
}), jsx("span", {
className: cn(config.valueClass, variantConfig.valueColor, "relative z-10 font-bold tracking-tight", "group-hover:scale-105 group-hover:glass-text-primary", "transition-all duration-300 ease-out", "drop-shadow-sm group-hover:drop-shadow-lg"),
children: value
})]
}), unit && jsx("span", {
className: cn("glass-text-lg glass-text-primary/70 font-medium relative", "group-hover:glass-text-primary/90 transition-colors duration-300"),
children: unit
})]
}), showProgress && jsxs("div", {
className: 'mb-4',
children: [jsx("div", {
className: cn("w-full glass-radius-full overflow-hidden", config.progressHeight, variantConfig.progressBg),
children: jsx(MotionFramer, {
preset: "slideRight",
className: cn("h-full", variantConfig.progressFill),
style: {
width: `${Math.min(progress, 100)}%`
}
})
}), progressLabel && jsxs("div", {
className: "glass-flex glass-justify-between glass-items-center glass-mt-2",
children: [jsx("span", {
className: 'glass-text-xs text-primary/60',
children: progressLabel
}), jsxs("span", {
className: 'glass-text-xs text-primary/60',
children: [Math.round(progress), "%"]
})]
})]
}), comparison && jsx("div", {
className: 'mb-4 glass-p-3 glass-surface-subtle/5 glass-radius-lg',
children: jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsx("span", {
className: 'glass-text-sm text-primary/70',
children: comparison.label
}), jsx("span", {
className: 'glass-text-sm font-medium text-primary',
children: comparison.value
})]
})
}), children && jsx("div", {
className: "glass-mt-4",
children: children
})]
})]
})
});
});
GlassMetricCard.displayName = "GlassMetricCard";
export { GlassMetricCard, GlassMetricCard as default };
//# sourceMappingURL=GlassMetricCard.js.map