aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
318 lines (315 loc) • 12.2 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { RefreshCw, Download, Minimize2, Maximize2, MoreVertical, Settings, BarChart3, PieChart, TrendingUp, LineChart } from 'lucide-react';
import { useState } 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 { GlassButton } from '../button/GlassButton.js';
import '../button/GlassFab.js';
import '../button/GlassMagneticButton.js';
import { CardHeader, CardTitle, CardContent } from '../card/index.js';
import '../data-display/GlassAccordion.js';
import '../data-display/GlassAlert.js';
import '../data-display/GlassAvatar.js';
import { GlassBadge } from '../data-display/GlassBadge.js';
import '../data-display/GlassBadgeLine.js';
import '../data-display/GlassDataGrid.js';
import '../data-display/GlassDataTable.js';
import '../data-display/GlassHeatmap.js';
import '../data-display/GlassLoadingSkeleton.js';
import '../data-display/GlassProgress.js';
import '../data-display/GlassTimeline.js';
import '../data-display/GlassSkeleton.js';
import '../data-display/GlassNotificationCenter.js';
import '../data-display/GlassAnimatedNumber.js';
import { GlassCard } from '../card/GlassCard.js';
/**
* GlassChartWidget component
* A glassmorphism chart container widget with header, actions, and fullscreen support
*/
const GlassChartWidget = ({
// TODO: Integrate ContrastGuard in chart labels, tooltips, and legends for WCAG AA compliance
title = "Analytics Overview",
subtitle,
children,
size = "md",
loading = false,
error,
emptyMessage,
showHeader = true,
showActions = true,
actions = [],
chartType,
showChartType = true,
timeRange,
lastUpdated,
showRefresh = true,
showDownload = true,
showFullscreen = true,
fullscreen = false,
onFullscreenChange,
onRefresh,
onDownload,
headerContent,
footerContent,
className,
...props
}) => {
const [isFullscreen, setIsFullscreen] = useState(fullscreen);
const [showActionMenu, setShowActionMenu] = useState(false);
// Size configurations
const sizeConfigs = {
sm: {
cardClass: "glass-p-4",
titleClass: "glass-text-lg font-semibold",
contentClass: "min-h-[200px]"
},
md: {
cardClass: "glass-p-6",
titleClass: "glass-text-xl font-semibold",
contentClass: "min-h-[300px]"
},
lg: {
cardClass: "p-8",
titleClass: "glass-text-2xl font-semibold",
contentClass: "min-h-[400px]"
},
xl: {
cardClass: "glass-p-10",
titleClass: "text-3xl font-semibold",
contentClass: "min-h-[500px]"
}
};
const config = sizeConfigs[size];
// Get chart type icon
const getChartTypeIcon = () => {
switch (chartType) {
case "line":
return jsx(LineChart, {
className: 'w-5 h-5'
});
case "bar":
return jsx(BarChart3, {
className: 'w-5 h-5'
});
case "area":
return jsx(TrendingUp, {
className: 'w-5 h-5'
});
case "pie":
return jsx(PieChart, {
className: 'w-5 h-5'
});
case "donut":
return jsx(PieChart, {
className: 'w-5 h-5'
});
default:
return jsx(BarChart3, {
className: 'w-5 h-5'
});
}
};
// Handle fullscreen toggle
const handleFullscreenToggle = () => {
const newFullscreen = !isFullscreen;
setIsFullscreen(newFullscreen);
onFullscreenChange?.(newFullscreen);
};
// Handle refresh
const handleRefresh = () => {
onRefresh?.();
};
// Handle download
const handleDownload = () => {
onDownload?.();
};
// Format last updated time
const formatLastUpdated = date => {
const now = new Date();
const diff = now.getTime() - date.getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) return "Just now";
if (minutes < 60) return `${minutes}m ago`;
if (hours < 24) return `${hours}h ago`;
return `${days}d ago`;
};
return jsx(MotionFramer, {
"data-glass-component": true,
preset: "fadeIn",
className: "glass-w-full",
children: jsxs(GlassCard, {
variant: "elevated",
elevation: "level3",
className: cn(config.cardClass, isFullscreen && "fixed inset-4 z-50", className),
...props,
children: [showHeader && jsx(CardHeader, {
className: 'pb-4',
children: jsxs("div", {
className: "glass-flex glass-items-start glass-justify-between",
children: [jsxs("div", {
className: "glass-flex-1 glass-min-w-0",
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-gap-3 mb-2',
children: [jsxs(CardTitle, {
className: cn(config.titleClass, "glass-text-primary flex items-center glass-gap-2"),
children: [showChartType && chartType && jsx("span", {
className: 'text-primary/60',
children: getChartTypeIcon()
}), title]
}), timeRange && jsx(GlassBadge, {
variant: "secondary",
size: "sm",
children: timeRange
})]
}), subtitle && jsx("p", {
className: 'glass-text-sm text-primary/60 mb-2',
children: subtitle
}), lastUpdated && jsxs("p", {
className: 'glass-text-xs text-primary/50',
children: ["Last updated: ", formatLastUpdated(lastUpdated)]
})]
}), jsxs("div", {
className: "glass-flex glass-items-center glass-gap-2",
children: [headerContent, jsxs("div", {
className: "glass-flex glass-items-center glass-gap-1",
children: [showRefresh && jsx(GlassButton, {
variant: "ghost",
size: "sm",
onClick: handleRefresh,
disabled: loading,
className: "glass-p-2",
"aria-label": "Refresh data",
children: jsx(RefreshCw, {
className: cn("w-4 h-4", loading && "animate-spin")
})
}), showDownload && jsx(GlassButton, {
variant: "ghost",
size: "sm",
onClick: handleDownload,
className: "glass-p-2",
"aria-label": "Download data",
children: jsx(Download, {
className: 'w-4 h-4'
})
}), showFullscreen && jsx(GlassButton, {
variant: "ghost",
size: "sm",
onClick: handleFullscreenToggle,
className: "glass-p-2",
"aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
children: isFullscreen ? jsx(Minimize2, {
className: 'w-4 h-4'
}) : jsx(Maximize2, {
className: 'w-4 h-4'
})
})]
}), showActions && actions.length > 0 && jsxs("div", {
className: 'relative',
children: [jsx(GlassButton, {
variant: "ghost",
size: "sm",
onClick: e => setShowActionMenu(!showActionMenu),
className: "glass-p-2",
"aria-label": "Open widget actions",
"aria-expanded": showActionMenu,
"aria-haspopup": "menu",
children: jsx(MoreVertical, {
className: 'w-4 h-4'
})
}), showActionMenu && jsx(MotionFramer, {
preset: "fadeIn",
className: 'absolute right-0 top-full glass-mt-2 z-10',
children: jsxs("div", {
className: "glass-surface-dark/80 glass-glass-backdrop-blur-md glass-border glass-border-white/20 glass-radius-lg glass-shadow-xl glass-min-w-48 glass-contrast-guard",
children: [actions.map((action, index) => jsxs("button", {
onClick: e => {
action.onClick();
setShowActionMenu(false);
},
disabled: action.disabled,
className: cn("w-full text-left glass-px-4 glass-py-2 glass-text-sm glass-text-primary/80 hover:bg-white/10", "first:rounded-t-lg last:rounded-b-lg", "disabled:opacity-50 disabled:cursor-not-allowed", "flex items-center glass-gap-2"),
children: [action.icon && jsx("span", {
className: 'w-4 h-4',
children: action.icon
}), action.label]
}, index)), jsxs("div", {
className: "glass-border-t glass-border-white/10",
children: [jsxs("button", {
onClick: e => {
onRefresh?.();
setShowActionMenu(false);
},
className: 'glass-w-full text-left glass-px-4 glass-py-2 glass-text-sm text-primary/80 hover:glass-surface-subtle/10 glass-flex glass-items-center glass-gap-2 glass-focus glass-touch-target glass-contrast-guard',
children: [jsx(RefreshCw, {
className: 'w-4 h-4'
}), "Refresh Data"]
}), jsxs("button", {
onClick: e => {
onDownload?.();
setShowActionMenu(false);
},
className: 'glass-w-full text-left glass-px-4 glass-py-2 glass-text-sm text-primary/80 hover:glass-surface-subtle/10 glass-flex glass-items-center glass-gap-2 glass-radius-b-lg glass-focus glass-touch-target glass-contrast-guard',
children: [jsx(Download, {
className: 'w-4 h-4'
}), "Export Data"]
})]
})]
})
})]
})]
})]
})
}), jsx(CardContent, {
className: 'pt-0',
children: error ? jsxs("div", {
className: cn("flex flex-col items-center justify-center", config.contentClass),
children: [jsx("div", {
className: 'text-primary mb-2',
children: jsx(Settings, {
className: 'w-8 h-8'
})
}), jsx("p", {
className: 'text-primary/80 text-center mb-4',
children: error
}), jsx(GlassButton, {
variant: "outline",
onClick: handleRefresh,
children: "Try Again"
})]
}) : !children && emptyMessage ? jsxs("div", {
className: cn("flex flex-col items-center justify-center", config.contentClass),
children: [jsx("div", {
className: 'text-primary/40 mb-2',
children: jsx(BarChart3, {
className: 'w-8 h-8'
})
}), jsx("p", {
className: 'text-primary/60 text-center',
children: emptyMessage
})]
}) : jsx("div", {
className: config.contentClass,
children: loading ? jsx("div", {
className: "glass-flex glass-items-center glass-justify-center glass-h-full",
children: jsx("div", {
className: 'animate-spin glass-radius-full h-8 w-8 glass-border-2 glass-border-white/20 glass-border-t-white/60'
})
}) : children
})
}), footerContent && jsx("div", {
className: 'glass-mt-4 pt-4 glass-border-t glass-border-white/10',
children: footerContent
})]
})
});
};
export { GlassChartWidget, GlassChartWidget as default };
//# sourceMappingURL=GlassChartWidget.js.map