aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
348 lines (345 loc) • 11.7 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import { forwardRef, useState } from 'react';
import { GlassButton, IconButton } from '../../button/GlassButton.js';
import '../../button/GlassFab.js';
import '../../button/GlassMagneticButton.js';
import { cn } from '../../../lib/utilsComprehensive.js';
import { GlassCard } from '../../card/GlassCard.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 '../../../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 '../../data-display/GlassHeatmap.js';
import '../../data-display/GlassLoadingSkeleton.js';
import '../../data-display/GlassProgress.js';
import '../../data-display/GlassTimeline.js';
import 'lucide-react';
import '../../data-display/GlassSkeleton.js';
import '../../data-display/GlassNotificationCenter.js';
import '../../data-display/GlassAnimatedNumber.js';
import '../../layout/GlassBox.js';
import '../../layout/GlassContainer.js';
import '../../layout/GlassFlex.js';
import { GlassGrid, GlassGridItem } from '../../layout/GlassGrid.js';
import '../../layout/GlassMasonry.js';
import '../../layout/GlassScrollArea.js';
import '../../layout/GlassSplitPane.js';
import { VStack, HStack } from '../../layout/GlassStack.js';
import '../../layout/OptimizedGlassContainer.js';
import '../../layout/Box.js';
/**
* GlassDetailView component
* Comprehensive detail view with multiple layout options
*/
const GlassDetailView = /*#__PURE__*/forwardRef(({
title,
subtitle,
status,
breadcrumb,
actions = [],
sections = [],
tabs = [],
activeTab,
onTabChange,
layout = "default",
sidebar,
loading = false,
error,
onBack,
onShare,
onPrint,
className,
children,
...props
}, ref) => {
const [expandedSections, setExpandedSections] = useState(new Set(sections.filter(s => s.defaultExpanded !== false).map(s => s.id)));
const [currentTab, setCurrentTab] = useState(activeTab || tabs[0]?.id);
// Toggle section expansion
const toggleSection = sectionId => {
const newExpanded = new Set(expandedSections);
if (newExpanded.has(sectionId)) {
newExpanded.delete(sectionId);
} else {
newExpanded.add(sectionId);
}
setExpandedSections(newExpanded);
};
// Handle tab change
const handleTabChange = tabId => {
setCurrentTab(tabId);
onTabChange?.(tabId);
};
// Render field value
const renderFieldValue = field => {
if (field.render) {
return field.render(field.value);
}
switch (field.type) {
case "boolean":
return jsx(GlassBadge, {
"data-glass-component": true,
variant: field.value ? "success" : "error",
size: "xs",
children: field.value ? "Yes" : "No"
});
case "badge":
return jsx(GlassBadge, {
variant: "outline",
size: "xs",
children: field.value
});
case "link":
return jsx("a", {
href: field.value,
target: "_blank",
rel: "noopener noreferrer",
className: 'text-primary hover:underline glass-focus glass-touch-target glass-contrast-guard',
children: field.value
});
case "date":
return new Date(field.value).toLocaleDateString();
case "number":
return typeof field.value === "number" ? field.value.toLocaleString() : field.value;
default:
return field.value;
}
};
// Render field
const renderField = field => {
const widthClasses = {
auto: "w-auto",
full: "w-full",
half: "w-1/2",
third: "w-1/3",
quarter: "w-1/4"
};
return jsxs("div", {
className: cn("glass-auto-gap glass-auto-gap-xs", widthClasses[field.width || "auto"]),
children: [jsx("label", {
className: 'glass-text-sm font-medium glass-text-secondary',
children: field.label
}), jsxs(HStack, {
space: "sm",
align: "center",
children: [jsx("div", {
className: 'glass-text-sm text-primary',
children: renderFieldValue(field)
}), field.copyable && jsx(IconButton, {
icon: "\uD83D\uDCCB",
variant: "ghost",
size: "xs",
onClick: e => navigator.clipboard?.writeText(String(field.value)),
"aria-label": "Copy to clipboard",
className: "glass-focus glass-touch-target"
})]
})]
}, field.id);
};
// Render section
const renderSection = section => {
const isExpanded = expandedSections.has(section.id);
return jsx(MotionFramer, {
type: "slide",
direction: "down",
children: jsxs(GlassCard, {
variant: "default",
children: [jsxs("div", {
className: cn("flex items-center justify-between", section.collapsible && "cursor-pointer glass-focus glass-touch-target"),
onClick: section.collapsible ? () => toggleSection(section.id) : undefined,
children: [jsxs(VStack, {
space: "xs",
children: [jsx("h3", {
className: 'glass-text-lg font-semibold text-primary',
children: section.title
}), section.description && jsx("p", {
className: "glass-text-sm glass-text-secondary",
children: section.description
})]
}), section.collapsible && jsx(GlassButton, {
leftIcon: isExpanded ? "−" : "+",
variant: "ghost",
size: "sm",
"aria-label": isExpanded ? "Collapse section" : "Expand section"
})]
}), (!section.collapsible || isExpanded) && jsx(MotionFramer, {
type: "slide",
direction: "down",
className: 'mt-6',
children: section.component ? section.component : section.fields ? jsx("div", {
className: 'glass-grid glass-grid-cols-1 md:grid-cols-2 lg:grid-cols-3 glass-gap-6',
children: section.fields.map(renderField)
}) : null
})]
})
}, section.id);
};
// Render tabs
const renderTabs = () => {
if (tabs.length === 0) return null;
return jsxs(VStack, {
space: "md",
children: [jsx("div", {
className: "glass-border-b glass-border-glass-border/20",
children: jsx("nav", {
className: 'glass-flex space-x-8',
children: tabs.map(tab => jsxs(GlassButton, {
onClick: e => handleTabChange(tab.id),
className: cn("flex items-center glass-gap-2 glass-py-2 glass-px-1 border-b-2 transition-colors glass-focus glass-touch-target", currentTab === tab.id ? "border-primary text-primary font-medium" : "border-transparent glass-text-secondary hover:text-foreground"),
children: [tab.icon, jsx("span", {
children: tab.label
}), tab.badge && jsx(GlassBadge, {
variant: "outline",
size: "xs",
children: tab.badge
})]
}, tab.id))
})
}), jsx("div", {
children: tabs.find(tab => tab.id === currentTab)?.content
})]
});
};
// Render header
const renderHeader = () => jsxs(VStack, {
space: "md",
children: [breadcrumb && jsx("div", {
className: "glass-text-sm glass-text-secondary",
children: breadcrumb
}), jsxs(HStack, {
space: "md",
align: "center",
justify: "between",
children: [jsxs(HStack, {
space: "md",
align: "center",
children: [onBack && jsx(GlassButton, {
leftIcon: "\u2190",
variant: "ghost",
size: "sm",
onClick: onBack,
"aria-label": "Go back",
className: "glass-focus glass-touch-target"
}), jsxs(VStack, {
space: "xs",
children: [jsxs(HStack, {
space: "sm",
align: "center",
children: [jsx("h1", {
className: 'glass-text-2xl font-bold text-primary',
children: title
}), status && jsx(GlassBadge, {
variant: status.variant,
size: "sm",
children: status.label
})]
}), subtitle && jsx("p", {
className: "glass-text-lg glass-text-secondary",
children: subtitle
})]
})]
}), jsxs(HStack, {
space: "sm",
align: "center",
children: [onShare && jsx(GlassButton, {
leftIcon: "\uD83D\uDCE4",
variant: "ghost",
size: "sm",
onClick: onShare,
"aria-label": "Share",
className: "glass-focus glass-touch-target"
}), onPrint && jsx(GlassButton, {
leftIcon: "\uD83D\uDDA8\uFE0F",
variant: "ghost",
size: "sm",
onClick: onPrint,
"aria-label": "Print",
className: "glass-focus glass-touch-target"
}), actions.map(action => jsx(GlassButton, {
variant: action.variant,
size: "sm",
leftIcon: action.icon,
onClick: action.onClick,
disabled: action.disabled,
loading: action.loading,
className: "glass-focus glass-touch-target",
children: action.label
}, action.id))]
})]
})]
});
// Render content based on layout
const renderContent = () => {
if (loading) {
return jsx("div", {
className: 'glass-flex glass-items-center glass-justify-center h-64',
children: jsx("div", {
className: 'w-8 h-8 glass-border-2 glass-border-primary glass-border-t-transparent glass-radius-full animate-spin'
})
});
}
if (error) {
return jsxs(GlassCard, {
variant: "default",
className: 'glass-p-8 text-center',
children: [jsx("div", {
className: 'text-destructive font-medium mb-2',
children: "Error"
}), jsx("div", {
className: "glass-text-secondary",
children: error
})]
});
}
switch (layout) {
case "sidebar":
return jsxs(GlassGrid, {
cols: 12,
gap: "lg",
children: [jsx(GlassGridItem, {
colSpan: 8,
children: jsxs(VStack, {
space: "lg",
children: [tabs.length > 0 ? renderTabs() : sections.map(renderSection), children]
})
}), jsx(GlassGridItem, {
colSpan: 4,
children: sidebar
})]
});
case "tabs":
return renderTabs();
case "accordion":
return jsxs(VStack, {
space: "md",
children: [sections.map(section => ({
...section,
collapsible: true
})).map(renderSection), children]
});
default:
return jsxs(VStack, {
space: "lg",
children: [sections.map(renderSection), tabs.length > 0 && renderTabs(), children]
});
}
};
return jsxs("div", {
ref: ref,
className: cn("w-full glass-auto-gap glass-auto-gap-3xl", className),
...props,
children: [renderHeader(), renderContent()]
});
});
GlassDetailView.displayName = "GlassDetailView";
export { GlassDetailView };
//# sourceMappingURL=GlassDetailView.js.map