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
JavaScript
'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