UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

1,128 lines (1,125 loc) 35.9 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { useReducedMotion } from '../../hooks/useReducedMotion.js'; import { useRef, useState, useEffect, useCallback, useContext, forwardRef, createContext } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { cn } from '../../lib/utilsComprehensive.js'; import '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import '../../primitives/motion/MotionFramer.js'; import { useA11yId, announceToScreenReader } from '../../utils/a11y.js'; // Predefined achievements const GLASS_ACHIEVEMENTS = [ // Interaction achievements { id: "first_click", title: "Glass Toucher", description: "Made your first interaction with a glass component", icon: "🫳", category: "interaction", rarity: "common", xp: 10, requirements: [{ type: "action_count", action: "click", count: 1 }], unlocked: false, progress: 0, hidden: false }, { id: "hundred_clicks", title: "Glass Enthusiast", description: "Clicked glass components 100 times", icon: "💎", category: "interaction", rarity: "rare", xp: 50, requirements: [{ type: "action_count", action: "click", count: 100 }], unlocked: false, progress: 0, hidden: false }, { id: "hover_master", title: "Ethereal Navigator", description: "Hovered over glass elements with perfect precision", icon: "👻", category: "mastery", rarity: "epic", xp: 100, requirements: [{ type: "action_count", action: "hover", count: 500 }], unlocked: false, progress: 0, hidden: false }, // Exploration achievements { id: "component_explorer", title: "Glass Archaeologist", description: "Discovered and interacted with 10 different glass components", icon: "🔍", category: "exploration", rarity: "rare", xp: 75, requirements: [{ type: "items_collected", items: [] }], // Dynamically populated unlocked: false, progress: 0, hidden: false }, { id: "hidden_features", title: "Secret Keeper", description: "Unlocked 5 hidden glass features", icon: "🗝️", category: "exploration", rarity: "legendary", xp: 200, requirements: [{ type: "items_collected", items: [] }], unlocked: false, progress: 0, hidden: true }, // Performance achievements { id: "speed_demon", title: "Glass Lightning", description: "Completed 10 interactions in under 5 seconds", icon: "⚡", category: "performance", rarity: "epic", xp: 150, requirements: [{ type: "challenge", challenge: "speed_interactions" }], unlocked: false, progress: 0, hidden: false }, { id: "combo_master", title: "Glass Virtuoso", description: "Performed a perfect 20-action combo", icon: "🎭", category: "performance", rarity: "legendary", xp: 300, requirements: [{ type: "combo", combo: ["click", "hover", "scroll", "focus"] }], unlocked: false, progress: 0, hidden: false }, // Time-based achievements { id: "night_owl", title: "Midnight Glass Shaper", description: "Used glass components between midnight and 6 AM", icon: "🦉", category: "creative", rarity: "rare", xp: 80, requirements: [{ type: "challenge", challenge: "night_usage" }], unlocked: false, progress: 0, hidden: false }, { id: "marathon_user", title: "Glass Endurance Master", description: "Spent 2 hours continuously using glass components", icon: "🏃‍♂️", category: "mastery", rarity: "epic", xp: 200, requirements: [{ type: "time_spent", duration: 7200000 }], // 2 hours unlocked: false, progress: 0, hidden: false }, // Social achievements { id: "collaborator", title: "Glass Harmonizer", description: "Collaborated with others using glass components", icon: "🤝", category: "social", rarity: "rare", xp: 100, requirements: [{ type: "action_count", action: "collaborate", count: 10 }], unlocked: false, progress: 0, hidden: false }, // Creative achievements { id: "customizer", title: "Glass Artisan", description: "Customized glass components with unique styles", icon: "🎨", category: "creative", rarity: "epic", xp: 150, requirements: [{ type: "action_count", action: "customize", count: 25 }], unlocked: false, progress: 0, hidden: false }, // Mastery achievements { id: "streak_master", title: "Consistency Crystal", description: "Maintained a 30-day streak of glass interactions", icon: "💠", category: "mastery", rarity: "legendary", xp: 500, requirements: [{ type: "streak", count: 30 }], unlocked: false, progress: 0, hidden: false }]; // Achievement engine class GlassAchievementEngine { constructor(userId = "default") { this.actionHistory = []; this.sessionStart = Date.now(); this.notifications = []; this.listeners = []; this.checkInterval = null; this.achievements = [...GLASS_ACHIEVEMENTS]; this.progress = { userId, level: 1, totalXP: 0, currentXP: 0, xpToNextLevel: 100, achievements: this.achievements, stats: { totalInteractions: 0, sessionsCompleted: 0, timeSpent: 0, componentsExplored: [], highestStreak: 0, perfectSessions: 0, customizationsUnlocked: 0, socialInteractions: 0 }, streak: 0, lastActiveDate: new Date().toDateString() }; this.loadProgress(); this.updateStreak(); this.startPeriodicChecks(); } loadProgress() { // CRITICAL SSR FIX: Skip localStorage access on server if (typeof localStorage === 'undefined') { return; } try { const stored = localStorage.getItem(`auraglass-achievements-${this.progress.userId}`); if (stored) { const data = JSON.parse(stored); this.progress = { ...this.progress, ...data }; // Merge achievements with any new ones this.progress.achievements = this.mergeAchievements(data.achievements || []); } } catch (error) { console.warn("Failed to load achievement progress:", error); } } mergeAchievements(storedAchievements) { const merged = [...this.achievements]; storedAchievements.forEach(stored => { const index = merged.findIndex(a => a.id === stored.id); if (index >= 0) { merged[index] = { ...merged[index], ...stored }; } }); return merged; } saveProgress() { // CRITICAL SSR FIX: Skip localStorage access on server if (typeof localStorage === 'undefined') { return; } try { localStorage.setItem(`auraglass-achievements-${this.progress.userId}`, JSON.stringify(this.progress)); } catch (error) { console.warn("Failed to save achievement progress:", error); } } updateStreak() { const today = new Date().toDateString(); const yesterday = new Date(Date.now() - 86400000).toDateString(); if (this.progress.lastActiveDate === yesterday) { this.progress.streak++; } else if (this.progress.lastActiveDate !== today) { this.progress.streak = 1; } this.progress.lastActiveDate = today; this.progress.stats.highestStreak = Math.max(this.progress.stats.highestStreak, this.progress.streak); } startPeriodicChecks() { this.checkInterval = setInterval(() => { this.checkTimeBasedAchievements(); }, 10000); // Check every 10 seconds } recordAction(action, context = {}) { const timestamp = Date.now(); this.actionHistory.push({ action, timestamp, context }); this.progress.stats.totalInteractions++; // Keep history manageable if (this.actionHistory.length > 1000) { this.actionHistory = this.actionHistory.slice(-500); } // Update specific stats if (action === "component_interaction" && context.component) { if (!this.progress.stats.componentsExplored.includes(context.component)) { this.progress.stats.componentsExplored.push(context.component); } } if (action === "customize") { this.progress.stats.customizationsUnlocked++; } if (action === "collaborate") { this.progress.stats.socialInteractions++; } // Check achievements this.checkAchievements(); } checkAchievements() { this.progress.achievements.forEach(achievement => { if (achievement.unlocked) return; const newProgress = this.calculateAchievementProgress(achievement); achievement.progress = newProgress; if (newProgress >= 1) { this.unlockAchievement(achievement); } }); } calculateAchievementProgress(achievement) { let totalProgress = 0; const requirements = achievement.requirements; requirements.forEach(req => { let reqProgress = 0; switch (req.type) { case "action_count": if (req.action && req.count) { const actionCount = this.actionHistory.filter(a => a.action === req.action).length; reqProgress = Math.min(1, actionCount / req.count); } break; case "streak": if (req.count) { reqProgress = Math.min(1, this.progress.streak / req.count); } break; case "time_spent": if (req.duration) { const sessionTime = Date.now() - this.sessionStart; reqProgress = Math.min(1, sessionTime / req.duration); } break; case "items_collected": if (achievement.id === "component_explorer") { reqProgress = Math.min(1, this.progress.stats.componentsExplored.length / 10); } break; case "challenge": reqProgress = this.checkChallenge(req.challenge || ""); break; case "combo": reqProgress = this.checkCombo(req.combo || []); break; } totalProgress += reqProgress; }); return totalProgress / requirements.length; } checkChallenge(challenge) { switch (challenge) { case "speed_interactions": // Check for 10 interactions in 5 seconds const recent = this.actionHistory.filter(a => Date.now() - a.timestamp < 5000); return Math.min(1, recent.length / 10); case "night_usage": const hour = new Date().getHours(); return hour >= 0 && hour < 6 ? 1 : 0; default: return 0; } } checkCombo(comboActions) { if (comboActions.length === 0) return 0; // Check for sequence of actions in recent history const recentActions = this.actionHistory.slice(-20).map(a => a.action); let bestCombo = 0; let currentCombo = 0; recentActions.forEach(action => { if (comboActions.includes(action)) { currentCombo++; } else { bestCombo = Math.max(bestCombo, currentCombo); currentCombo = 0; } }); bestCombo = Math.max(bestCombo, currentCombo); return Math.min(1, bestCombo / 20); } checkTimeBasedAchievements() { const sessionTime = Date.now() - this.sessionStart; this.progress.stats.timeSpent = sessionTime; // Check time-based achievements this.checkAchievements(); } unlockAchievement(achievement) { achievement.unlocked = true; achievement.unlockedAt = Date.now(); achievement.progress = 1; // Award XP this.addXP(achievement.xp); // Create notification const notification = { achievement: { ...achievement }, timestamp: Date.now(), shown: false }; this.notifications.push(notification); // Notify listeners this.listeners.forEach(listener => listener(notification)); // Apply rewards this.applyAchievementRewards(achievement); this.saveProgress(); } addXP(xp) { this.progress.totalXP += xp; this.progress.currentXP += xp; // Level up check while (this.progress.currentXP >= this.progress.xpToNextLevel) { this.progress.currentXP -= this.progress.xpToNextLevel; this.progress.level++; this.progress.xpToNextLevel = this.calculateXPForNextLevel(); // Level up achievement this.recordAction("level_up", { level: this.progress.level }); } } calculateXPForNextLevel() { // Exponential XP curve return Math.floor(100 * Math.pow(1.5, this.progress.level - 1)); } applyAchievementRewards(achievement) { if (!achievement.rewards) return; achievement.rewards.forEach(reward => { switch (reward.type) { case "theme": // Unlock theme this.recordAction("theme_unlocked", { theme: reward.value }); break; case "effect": // Unlock visual effect this.recordAction("effect_unlocked", { effect: reward.value }); break; case "sound": // Unlock sound this.recordAction("sound_unlocked", { sound: reward.value }); break; } }); } getProgress() { return { ...this.progress }; } getUnlockedAchievements() { return this.progress.achievements.filter(a => a.unlocked); } getAvailableAchievements() { return this.progress.achievements.filter(a => !a.unlocked && !a.hidden); } getNotifications() { return [...this.notifications]; } markNotificationShown(notificationIndex) { if (this.notifications[notificationIndex]) { this.notifications[notificationIndex].shown = true; } } addListener(listener) { this.listeners.push(listener); return () => { const index = this.listeners.indexOf(listener); if (index > -1) { this.listeners.splice(index, 1); } }; } cleanup() { if (this.checkInterval) { clearInterval(this.checkInterval); } this.saveProgress(); } } // React context const AchievementContext = /*#__PURE__*/createContext({ engine: null, progress: null, recordAction: () => {}, notifications: [] }); // Provider component function GlassAchievementProvider({ children, userId }) { useReducedMotion(); const engineRef = useRef(); const [progress, setProgress] = useState(null); const [notifications, setNotifications] = useState([]); useEffect(() => { engineRef.current = new GlassAchievementEngine(userId); setProgress(engineRef.current.getProgress()); const removeListener = engineRef.current.addListener(notification => { setNotifications(prev => [...prev, notification]); }); // Update progress periodically const interval = setInterval(() => { if (engineRef.current) { setProgress(engineRef.current.getProgress()); } }, 5000); return () => { clearInterval(interval); removeListener(); if (engineRef.current) { engineRef.current.cleanup(); } }; }, [userId]); const recordAction = useCallback((action, context = {}) => { if (engineRef.current) { engineRef.current.recordAction(action, context); } }, []); const value = { engine: engineRef.current || null, progress, recordAction, notifications }; return jsx(AchievementContext.Provider, { value: value, children: children }); } // Hook to use achievements function useAchievements() { const context = useContext(AchievementContext); if (!context) { throw new Error("useAchievements must be used within GlassAchievementProvider"); } return context; } // Achievement notification component function GlassAchievementNotifications({ className, position = "top-right" }) { const { notifications, engine } = useAchievements(); const [visibleNotifications, setVisibleNotifications] = useState([]); useEffect(() => { const newNotifications = notifications.filter(n => !n.shown); if (newNotifications.length > 0) { setVisibleNotifications(prev => [...prev, ...newNotifications]); // Mark as shown newNotifications.forEach((_, index) => { const actualIndex = notifications.indexOf(newNotifications[index]); engine?.markNotificationShown(actualIndex); }); } }, [notifications, engine]); const removeNotification = notification => { setVisibleNotifications(prev => prev.filter(n => n !== notification)); }; const positionClasses = { "top-right": "top-4 right-4", "top-left": "top-4 left-4", "bottom-right": "bottom-4 right-4", "bottom-left": "bottom-4 left-4" }; return jsx("div", { className: cn("fixed z-50 glass-gap-2", positionClasses[position], className), children: jsx(AnimatePresence, { children: visibleNotifications.map((notification, index) => jsx(AchievementNotificationCard, { notification: notification, onClose: () => removeNotification(notification), delay: index * 200 }, `${notification.achievement.id}-${notification.timestamp}`)) }) }); } // Individual notification card const AchievementNotificationCard = /*#__PURE__*/forwardRef(({ notification, onClose, delay = 0 }, ref) => { const prefersReducedMotion = useReducedMotion(); const { achievement } = notification; const componentId = useA11yId("achievement-notification"); // Announce achievement unlock to screen readers useEffect(() => { announceToScreenReader(`Achievement unlocked: ${achievement.title}. ${achievement.description}. You earned ${achievement.xp} XP.`, "polite"); }, [achievement]); useEffect(() => { const timer = setTimeout(() => { onClose(); }, 5000 + delay); return () => clearTimeout(timer); }, [onClose, delay]); const handleKeyDown = useCallback(event => { if (event.key === "Escape") { onClose(); } }, [onClose]); const rarityColors = { common: "from-gray-600 to-gray-700", rare: "from-blue-600 to-blue-700", epic: "from-purple-600 to-purple-700", legendary: "from-amber-500 to-orange-600" }; return jsxs(motion.div, { ref: ref, id: componentId, role: "alert", "aria-live": "polite", "aria-atomic": "true", tabIndex: 0, onKeyDown: handleKeyDown, className: 'relative', initial: { x: 300, opacity: 0, scale: 0.8 }, animate: prefersReducedMotion ? {} : { x: 0, opacity: 1, scale: 1 }, exit: { x: 300, opacity: 0, scale: 0.8 }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.3 }, children: [jsxs(OptimizedGlassCore, { intent: "neutral", elevation: "level4", intensity: "strong", depth: 3, tint: "neutral", border: "glow", animation: "none", performanceMode: "medium", className: 'w-80 glass-p-4 relative overflow-hidden glass-radius-lg', children: [jsx("div", { className: cn("absolute inset-0 opacity-20 bg-gradient-to-br", rarityColors[achievement.rarity]) }), jsxs("div", { className: 'relative z-10', children: [jsxs("div", { className: 'glass-flex glass-items-start glass-justify-between mb-3', children: [jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsx("div", { className: "glass-text-2xl", children: achievement.icon }), jsx("div", { children: jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("h3", { className: 'glass-text-sm font-medium text-primary/90', children: "Achievement Unlocked!" }), jsx("span", { className: cn("glass-px-2 glass-py-1 glass-text-xs glass-radius-full capitalize", achievement.rarity === "common" && "bg-gray-600 glass-text-secondary", achievement.rarity === "rare" && "bg-blue-600 text-blue-200", achievement.rarity === "epic" && "bg-purple-600 text-purple-200", achievement.rarity === "legendary" && "bg-amber-500 text-amber-100"), children: achievement.rarity })] }) })] }), jsx("button", { onClick: onClose, className: 'glass-text-xs text-primary/60 hover:text-primary/90 glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', "aria-label": "Close achievement notification", children: "\u2715" })] }), jsxs("div", { className: 'mb-3', children: [jsx("h4", { className: 'font-medium text-primary/90 mb-1', children: achievement.title }), jsx("p", { className: 'glass-text-sm text-primary/70', children: achievement.description })] }), jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("div", { className: 'glass-text-xs text-primary/60', children: "Reward:" }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-1", children: [jsx("span", { className: 'text-amber-400', children: "\u2728" }), jsxs("span", { className: 'glass-text-sm font-medium text-primary/90', children: ["+", achievement.xp, " XP"] })] })] }), jsx("div", { className: 'glass-text-xs text-primary/50', children: achievement.category })] })] })] }), jsx(motion.div, { className: 'absolute inset-0 pointer-events-none', initial: { opacity: 0 }, animate: prefersReducedMotion ? {} : { opacity: [0, 1, 0] }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 2, delay: delay / 1000 + 0.5 }, children: Array.from({ length: 12 }, (_, i) => jsx(motion.div, { className: 'absolute w-1 h-1 bg-amber-400 glass-radius-full', style: { left: "50%", top: "50%" }, animate: prefersReducedMotion ? {} : { x: [0, Math.cos(i * 30 * Math.PI / 180) * 100], y: [0, Math.sin(i * 30 * Math.PI / 180) * 100], opacity: [1, 0], scale: [1, 0] }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 1.5, delay: delay / 1000 + 0.5 + i * 0.1, ease: "easeOut" } }, i)) })] }); }); // Achievement dashboard function GlassAchievementDashboard({ className, show = true }) { const prefersReducedMotion = useReducedMotion(); const { progress, engine } = useAchievements(); const [activeTab, setActiveTab] = useState("progress"); if (!show || !progress) return null; const unlockedAchievements = engine?.getUnlockedAchievements() || []; const availableAchievements = engine?.getAvailableAchievements() || []; return jsx("section", { children: jsxs(OptimizedGlassCore, { intent: "neutral", elevation: "level3", intensity: "medium", depth: 3, tint: "neutral", border: "subtle", animation: "none", performanceMode: "medium", className: cn("fixed bottom-4 left-4 w-96 max-h-96 overflow-hidden glass-radius-lg", className), role: "complementary", "aria-label": "Achievement dashboard", children: [jsxs("div", { className: "glass-p-4 glass-border-b glass-border-white/10", children: [jsxs("div", { className: 'glass-flex glass-items-center glass-justify-between mb-2', children: [jsx("h3", { className: 'glass-text-lg font-medium text-primary/90', children: "Glass Achievements" }), jsxs("div", { className: 'glass-text-sm text-primary/70', children: ["Level ", progress.level] })] }), jsx("div", { className: 'glass-w-full glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-sm h-2 overflow-hidden glass-contrast-guard', children: jsx(motion.div, { className: "glass-h-full glass-gradient-primary glass-gradient-primary glass-gradient-primary", animate: { width: `${progress.currentXP / progress.xpToNextLevel * 100}%` }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.5 } }) }), jsxs("div", { className: 'glass-flex glass-justify-between glass-text-xs text-primary/50 glass-mt-1', children: [jsxs("span", { children: [progress.currentXP, " XP"] }), jsxs("span", { children: [progress.xpToNextLevel, " XP to next level"] })] })] }), jsx("div", { className: "glass-flex glass-border-b glass-border-white/10", children: [{ id: "progress", label: "Progress", count: progress.totalXP }, { id: "achievements", label: "Achievements", count: unlockedAchievements.length }, { id: "stats", label: "Stats", count: progress.stats.totalInteractions }].map(tab => jsxs("button", { onClick: () => setActiveTab(tab.id), className: cn("flex-1 glass-px-3 glass-py-2 glass-text-sm transition-colors glass-focus glass-touch-target glass-contrast-guard", activeTab === tab.id ? "glass-text-primary/90 bg-white/10" : "glass-text-primary/60 hover:glass-text-primary/90"), children: [jsx("div", { children: tab.label }), jsx("div", { className: "glass-text-xs", children: tab.count })] }, tab.id)) }), jsxs("div", { className: 'glass-p-4 glass-max-h-64 overflow-y-auto', children: [activeTab === "progress" && jsxs("div", { className: "glass-gap-3", children: [jsxs("div", { className: 'glass-grid glass-grid-cols-2 glass-gap-2 text-center', children: [jsxs("div", { className: "glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-md glass-p-2 glass-contrast-guard", children: [jsx("div", { className: 'glass-text-lg font-medium text-primary/90', children: progress.level }), jsx("div", { className: 'glass-text-xs text-primary/60', children: "Level" })] }), jsxs("div", { className: "glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-md glass-p-2 glass-contrast-guard", children: [jsx("div", { className: 'glass-text-lg font-medium text-primary/90', children: progress.totalXP }), jsx("div", { className: 'glass-text-xs text-primary/60', children: "Total XP" })] })] }), jsxs("div", { children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/90 mb-2', children: "In Progress" }), jsx("div", { className: "glass-gap-2", children: availableAchievements.slice(0, 3).map(achievement => jsxs("div", { className: "glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-sm glass-p-2 glass-contrast-guard", children: [jsxs("div", { className: 'glass-flex glass-items-center glass-justify-between mb-1', children: [jsx("span", { className: 'glass-text-sm text-primary/90', children: achievement.title }), jsxs("span", { className: 'glass-text-xs text-primary/60', children: [(achievement.progress * 100).toFixed(0), "%"] })] }), jsx("div", { className: 'glass-w-full glass-surface-subtle glass-radius-full h-1', children: jsx("div", { className: 'glass-surface-blue h-1 glass-radius-full', style: { width: `${achievement.progress * 100}%` } }) })] }, achievement.id)) })] })] }), activeTab === "achievements" && jsx("div", { className: "glass-gap-2", children: unlockedAchievements.map(achievement => jsx("div", { className: "glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-sm glass-p-3 glass-contrast-guard", children: jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsx("div", { className: "glass-text-xl", children: achievement.icon }), jsxs("div", { className: "glass-flex-1", children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/90', children: achievement.title }), jsxs("span", { className: 'glass-text-xs text-primary/60', children: ["+", achievement.xp, " XP"] })] }), jsx("p", { className: 'glass-text-xs text-primary/60', children: achievement.description }), achievement.unlockedAt && jsxs("div", { className: 'glass-text-xs text-primary/50 glass-mt-1', children: ["Unlocked", " ", new Date(achievement.unlockedAt).toLocaleDateString()] })] })] }) }, achievement.id)) }), activeTab === "stats" && jsx("div", { className: "glass-gap-3", children: jsx("div", { className: "glass-grid glass-grid-cols-2 glass-gap-2", children: [{ label: "Interactions", value: progress.stats.totalInteractions }, { label: "Components", value: progress.stats.componentsExplored.length }, { label: "Streak", value: progress.streak }, { label: "Sessions", value: progress.stats.sessionsCompleted }, { label: "Time Spent", value: `${Math.floor(progress.stats.timeSpent / 60000)}m` }, { label: "Social", value: progress.stats.socialInteractions }].map(stat => jsxs("div", { className: 'glass-surface-subtle/5 glass-glass-glass-backdrop-blur-sm glass-contrast-guard glass-radius-md glass-p-2 text-center glass-contrast-guard', children: [jsx("div", { className: 'glass-text-lg font-medium text-primary/90', children: stat.value }), jsx("div", { className: 'glass-text-xs text-primary/60', children: stat.label })] }, stat.label)) }) })] })] }) }); } // Hook for easy achievement integration function useAchievementTracker() { const { recordAction } = useAchievements(); const trackClick = useCallback(component => { recordAction("click", { component }); if (component) { recordAction("component_interaction", { component }); } }, [recordAction]); const trackHover = useCallback(component => { recordAction("hover", { component }); if (component) { recordAction("component_interaction", { component }); } }, [recordAction]); const trackCustomization = useCallback((type, value) => { recordAction("customize", { type, value }); }, [recordAction]); const trackCollaboration = useCallback((action, users) => { recordAction("collaborate", { action, users }); }, [recordAction]); return { trackClick, trackHover, trackCustomization, trackCollaboration, recordAction }; } // Achievement presets const achievementPresets = { casual: { xpMultiplier: 1, notificationDuration: 3000, showProgress: true }, hardcore: { xpMultiplier: 0.5, notificationDuration: 5000, showProgress: true, hiddenAchievements: true }, minimal: { xpMultiplier: 1, notificationDuration: 2000, showProgress: false, quietMode: true } }; function AchievementSummaryCard() { const { progress } = useAchievements(); const statBlocks = [{ label: "Current level", value: progress?.level ?? "—" }, { label: "Unlocked", value: progress?.achievements.filter(a => a.unlocked).length ?? 0 }, { label: "Streak", value: progress?.streak ?? 0 }]; return jsxs("div", { className: cn("glass-surface-primary glass-radius-2xl glass-p-6 glass-space-y-4", "glass-border glass-border-white/10 glass-shadow-soft-lg"), "data-testid": "glass-achievement-summary", children: [jsxs("div", { children: [jsx("p", { className: "glass-text-xs glass-text-tertiary uppercase tracking-wide", children: "Achievement System" }), jsx("h2", { className: "glass-text-2xl glass-text-primary font-semibold", children: progress ? progress.stats.totalInteractions : "Calibrating" }), jsx("p", { className: "glass-text-sm glass-text-secondary", children: "Total interactions tracked" })] }), jsx("div", { className: "glass-grid glass-grid-cols-3 glass-gap-3", children: statBlocks.map(stat => jsxs("div", { className: "glass-surface-subtle glass-radius-xl glass-p-3", children: [jsx("p", { className: "glass-text-xs glass-text-tertiary uppercase tracking-wide", children: stat.label }), jsx("p", { className: "glass-text-lg glass-text-primary font-semibold", children: stat.value })] }, stat.label)) }), jsxs("div", { className: "glass-text-xs glass-text-secondary", children: ["XP to next level: ", progress ? progress.xpToNextLevel : "—"] })] }); } const GlassAchievementSystem = ({ userId, className, children, showDashboard = true, showNotifications = true, ...rest }) => jsx(GlassAchievementProvider, { userId: userId, children: jsxs("div", { className: cn("glass-achievement-system glass-relative glass-space-y-4", className), ...rest, children: [children ?? jsx(AchievementSummaryCard, {}), showDashboard && jsx(GlassAchievementDashboard, {}), showNotifications && jsx(GlassAchievementNotifications, {})] }) }); export { GlassAchievementDashboard, GlassAchievementNotifications, GlassAchievementProvider, GlassAchievementSystem, achievementPresets, GlassAchievementSystem as default, useAchievementTracker, useAchievements }; //# sourceMappingURL=GlassAchievementSystem.js.map