aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
402 lines (399 loc) • 17.9 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { useState, useEffect, useCallback } from 'react';
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 { MotionFramer } from '../../primitives/motion/MotionFramer.js';
import { usePredictiveEngine, useInteractionRecorder } from '../advanced/GlassPredictiveEngine.js';
import { useAchievements } from '../advanced/GlassAchievementSystem.js';
import { useBiometricAdaptation } from '../advanced/GlassBiometricAdaptation.js';
import { useEyeTracking } from '../advanced/GlassEyeTracking.js';
import { useSpatialAudio } from '../advanced/GlassSpatialAudio.js';
import { GlassButton } from '../button/GlassButton.js';
import '../button/GlassFab.js';
import '../button/GlassMagneticButton.js';
import { Target, Brain, Eye, Plus, MoreHorizontal } from 'lucide-react';
/**
* GlassKanban component
* A comprehensive Kanban board with consciousness interface features
*/
function GlassKanban({
// TODO: Integrate ContrastGuard for table cells, list items, badges, card titles, and other text content for WCAG AA compliance
columns,
className,
enableDragDrop = true,
showLimits = true,
showMetrics = false,
onCardClick,
onColumnClick,
onCardMove,
// Consciousness features
consciousness = false,
predictive = false,
adaptive = false,
eyeTracking = false,
spatialAudio = false,
trackAchievements = false
}) {
// Consciousness state
const [cardInteractionCounts, setCardInteractionCounts] = useState({});
const [columnInteractionCounts, setColumnInteractionCounts] = useState({});
const [focusedCard, setFocusedCard] = useState(null);
const [focusedColumn, setFocusedColumn] = useState(null);
const [workflowSuggestions, setWorkflowSuggestions] = useState([]);
const [boardMetrics, setBoardMetrics] = useState(null);
// Consciousness hooks
const predictiveEngine = predictive ? usePredictiveEngine() : null;
const eyeTracker = eyeTracking ? useEyeTracking() : null;
adaptive ? useBiometricAdaptation() : null;
const spatialAudioEngine = spatialAudio ? useSpatialAudio() : null;
const interactionRecorder = consciousness ? useInteractionRecorder() : null;
const achievementTracker = trackAchievements ? useAchievements() : null;
// Consciousness effects
// Eye tracking for card and column focus
useEffect(() => {
if (!eyeTracking || !eyeTracker) return;
// Eye tracking functionality temporarily disabled
// eyeTracker.startTracking(handleGazeData);
// return () => eyeTracker.stopTracking();
}, [eyeTracking, eyeTracker, achievementTracker, trackAchievements]);
// Predictive workflow suggestions
useEffect(() => {
if (!predictive || !predictiveEngine) return;
const generateWorkflowSuggestions = async () => {
try {
const boardContext = {
columns: columns.map(col => ({
id: col.id,
title: col.title,
cardCount: col.cards.length,
limit: col.limit,
cards: col.cards.map(card => ({
id: card.id,
title: card.title,
priority: card.priority,
interactionCount: cardInteractionCounts[card.id] || 0
}))
})),
interactions: cardInteractionCounts
};
const suggestions = (await predictiveEngine.engine?.generateWorkflowSuggestions(boardContext)) || [];
setWorkflowSuggestions(suggestions.slice(0, 3));
// Generate board metrics
const metrics = (await predictiveEngine.engine?.analyzeBoardPerformance(boardContext)) || {};
setBoardMetrics(metrics);
} catch (error) {
console.warn("Predictive workflow generation failed:", error);
}
};
if (columns.length > 0) {
const timeoutId = setTimeout(generateWorkflowSuggestions, 1000);
return () => clearTimeout(timeoutId);
}
}, [columns, predictive, predictiveEngine, cardInteractionCounts]);
// Spatial audio for card interactions
useEffect(() => {
if (!spatialAudio || !spatialAudioEngine) return;
const playInteractionSound = type => {
const soundMap = {
"card-click": {
sound: "card-select",
volume: 0.4,
position: {
x: 0,
y: 0,
z: 0
}
},
"column-click": {
sound: "column-focus",
volume: 0.3,
position: {
x: -0.5,
y: 0,
z: 0
}
},
"card-move": {
sound: "card-move",
volume: 0.5,
position: {
x: 0.5,
y: 0,
z: 0
}
}
};
const config = soundMap[type];
spatialAudioEngine.playGlassSound(config.sound, config.position, {
volume: config.volume,
reverb: 0.2
});
};
// Store sound function for use in handlers
window._kanbanSpatialAudio = playInteractionSound;
return () => {
delete window._kanbanSpatialAudio;
};
}, [spatialAudio, spatialAudioEngine]);
// Enhanced card click handler
const handleCardClick = useCallback((cardId, columnId) => {
// Update interaction counts
setCardInteractionCounts(prev => ({
...prev,
[cardId]: (prev[cardId] || 0) + 1
}));
// Record interaction for consciousness tracking
if (consciousness && interactionRecorder) {
const mockEvent = {
currentTarget: {
id: `card-${cardId}`
},
clientX: 0,
clientY: 0,
button: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
preventDefault: () => {},
stopPropagation: () => {}
};
interactionRecorder.recordClick(mockEvent);
}
// Track achievement
if (trackAchievements && achievementTracker) {
achievementTracker.recordAction("kanban_card_interaction", {
cardId,
columnId,
timestamp: Date.now()
});
}
// Play spatial audio
if (spatialAudio && window._kanbanSpatialAudio) {
window._kanbanSpatialAudio("card-click");
}
onCardClick?.(cardId, columnId);
}, [consciousness, interactionRecorder, trackAchievements, achievementTracker, spatialAudio, onCardClick, cardInteractionCounts]);
// Enhanced column click handler
const handleColumnClick = useCallback(columnId => {
// Update interaction counts
setColumnInteractionCounts(prev => ({
...prev,
[columnId]: (prev[columnId] || 0) + 1
}));
// Record interaction for consciousness tracking
if (consciousness && interactionRecorder) {
const mockEvent = {
currentTarget: {
id: `column-${columnId}`
},
clientX: 0,
clientY: 0,
button: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
preventDefault: () => {},
stopPropagation: () => {}
};
interactionRecorder.recordClick(mockEvent);
}
// Play spatial audio
if (spatialAudio && window._kanbanSpatialAudio) {
window._kanbanSpatialAudio("column-click");
}
onColumnClick?.(columnId);
}, [consciousness, interactionRecorder, spatialAudio, onColumnClick, columnInteractionCounts]);
return jsx(MotionFramer, {
"data-glass-component": true,
preset: "fadeIn",
className: "glass-w-full glass-h-full",
children: jsxs("div", {
className: cn("grid glass-gap-4 glass-p-4", consciousness && "consciousness-kanban-board", predictive && workflowSuggestions.length > 0 && "consciousness-predictive-board", adaptive && "consciousness-adaptive-board", eyeTracking && "consciousness-eye-trackable", className),
style: {
gridTemplateColumns: `repeat(${columns.length}, minmax(280px, 1fr))`
},
"data-consciousness-kanban": "true",
"data-consciousness-active": String(!!consciousness),
"data-predictive": String(!!predictive),
"data-adaptive": String(!!adaptive),
"data-eye-tracking": String(!!eyeTracking),
"data-spatial-audio": String(!!spatialAudio),
children: [showMetrics && boardMetrics && jsx("div", {
className: 'col-span-full mb-4 glass-p-3 glass-surface-subtle/5 glass-radius-lg glass-border glass-border-white/10',
children: jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between glass-text-sm",
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-gap-4",
children: [jsxs("span", {
className: 'text-primary/80',
children: ["Total Cards: ", boardMetrics.totalCards]
}), jsxs("span", {
className: 'text-primary/80',
children: ["Productivity: ", Math.round(boardMetrics.productivity * 100), "%"]
}), jsxs("span", {
className: 'text-primary/80',
children: ["Completion Rate:", " ", Math.round(boardMetrics.completionRate * 100), "%"]
})]
}), boardMetrics.bottlenecks.length > 0 && jsxs("div", {
className: "glass-flex glass-items-center glass-gap-2",
children: [jsx(Target, {
className: 'w-4 h-4 text-primary'
}), jsxs("span", {
className: 'text-primary glass-text-xs',
children: ["Bottlenecks: ", boardMetrics.bottlenecks.join(", ")]
})]
})]
})
}), predictive && workflowSuggestions.length > 0 && jsxs("div", {
className: 'col-span-full mb-4 glass-p-3 glass-surface-primary/10 glass-radius-lg glass-border glass-border-primary/20',
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-gap-2 mb-2',
children: [jsx(Brain, {
className: 'w-4 h-4 text-primary'
}), jsx("span", {
className: 'text-primary glass-text-sm font-medium',
children: "Workflow Suggestions"
})]
}), jsx("div", {
className: "glass-gap-2",
children: workflowSuggestions.map((suggestion, index) => jsxs("div", {
className: 'glass-text-xs text-primary/70 glass-flex glass-items-center glass-justify-between',
children: [jsxs("span", {
children: ["Move \"", suggestion.cardId, "\" to \"", suggestion.suggestedColumn, "\""]
}), jsx("span", {
className: 'text-primary/80',
children: suggestion.reason
})]
}, index))
})]
}), columns.map(column => {
const isOverLimit = column.limit && column.cards.length > column.limit;
const isFocused = eyeTracking && focusedColumn === column.id;
const interactionCount = columnInteractionCounts[column.id] || 0;
return jsxs("div", {
className: cn("glass-gap-3 min-h-[200px] glass-p-3 glass-radius-xl", "bg-white/5 border border-white/10", isFocused && "consciousness-column-focused", isOverLimit && "consciousness-column-overlimit", interactionCount > 0 && "consciousness-column-interacted", consciousness && "consciousness-enhanced-column"),
"data-consciousness-column": "true",
"data-column-id": column.id,
"data-interaction-count": interactionCount,
"data-gaze-focused": isFocused,
"data-over-limit": isOverLimit,
onClick: () => handleColumnClick(column.id),
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsxs("div", {
className: 'glass-text-sm text-primary font-medium glass-flex glass-items-center glass-gap-2',
style: {
color: column.color || "white"
},
children: [column.title, jsxs("span", {
className: 'glass-text-xs text-primary/60',
children: ["(", column.cards.length, ")"]
}), isFocused && jsx(Eye, {
className: 'w-3 h-3 text-primary'
})]
}), jsxs("div", {
className: "glass-flex glass-items-center glass-gap-2",
children: [showLimits && column.limit && jsxs("span", {
className: cn("glass-text-xs glass-px-2 glass-py-1 glass-radius-md", isOverLimit ? "bg-red-500/20 text-red-300" : "bg-white/10 glass-text-primary/60"),
children: [column.cards.length, "/", column.limit]
}), jsx(GlassButton, {
variant: "ghost",
size: "sm",
className: "glass-p-1",
consciousness: consciousness,
adaptive: adaptive,
spatialAudio: spatialAudio,
trackAchievements: trackAchievements,
children: jsx(Plus, {
className: 'w-3 h-3'
})
}), jsx(GlassButton, {
variant: "ghost",
size: "sm",
className: "glass-p-1",
consciousness: consciousness,
adaptive: adaptive,
spatialAudio: spatialAudio,
trackAchievements: trackAchievements,
children: jsx(MoreHorizontal, {
className: 'w-3 h-3'
})
})]
})]
}), jsx("div", {
className: "glass-gap-2",
children: column.cards.map((card, cardIndex) => {
const isCardFocused = eyeTracking && focusedCard === card.id;
const cardInteractionCount = cardInteractionCounts[card.id] || 0;
const hasSuggestion = workflowSuggestions.some(s => s.cardId === card.id);
return jsxs(OptimizedGlassCore, {
elevation: "level1",
className: cn("glass-radius-lg glass-p-3 border cursor-pointer transition-all duration-200", "hover:border-white/30 hover:bg-white/10", isCardFocused && "consciousness-card-focused border-primary", cardInteractionCount > 0 && "consciousness-card-interacted", hasSuggestion && "consciousness-card-suggested border-yellow-400/50", card.priority === "high" && "border-red-400/50", card.priority === "medium" && "border-yellow-400/50", card.priority === "low" && "border-green-400/50", consciousness && "consciousness-enhanced-card"),
style: {
animationDelay: `${cardIndex * 50}ms`,
animationFillMode: "both"
},
"data-consciousness-card": "true",
"data-card-id": card.id,
"data-column-id": column.id,
"data-interaction-count": cardInteractionCount,
"data-gaze-focused": isCardFocused,
"data-priority": card.priority,
"data-has-suggestion": hasSuggestion,
onClick: () => handleCardClick(card.id, column.id),
children: [jsxs("div", {
className: 'glass-flex glass-items-start glass-justify-between mb-2',
children: [jsxs("div", {
className: 'glass-text-sm text-primary font-medium glass-flex-1',
children: [card.title, isCardFocused && jsx(Eye, {
className: 'inline-block w-3 h-3 text-primary glass-ml-2'
})]
}), hasSuggestion && jsx("div", {
className: 'glass-text-xs text-primary glass-surface-yellow/20 glass-px-2 glass-py-1 glass-radius-md',
children: "Suggested"
})]
}), card.description && jsx("div", {
className: 'glass-text-xs text-primary/70 mb-2',
children: card.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: [card.priority && jsx("span", {
className: cn("glass-text-xs glass-px-2 glass-py-1 glass-radius-md", card.priority === "high" && "bg-red-500/20 text-red-300", card.priority === "medium" && "bg-yellow-500/20 text-yellow-300", card.priority === "low" && "bg-green-500/20 text-green-300"),
children: card.priority
}), card.tags && card.tags.length > 0 && jsx("div", {
className: "glass-flex glass-gap-1",
children: card.tags.slice(0, 2).map((tag, index) => jsx("span", {
className: 'glass-text-xs text-primary glass-surface-primary/20 glass-px-1 glass-radius-md',
children: tag
}, index))
})]
}), cardInteractionCount > 0 && jsxs("span", {
className: 'glass-text-xs text-primary/50',
children: [cardInteractionCount, " interactions"]
})]
}), card.assignee && jsxs("div", {
className: 'glass-text-xs text-primary/60 glass-mt-2',
children: ["Assigned: ", card.assignee]
}), card.dueDate && jsxs("div", {
className: 'glass-text-xs text-primary/60 glass-mt-1',
children: ["Due: ", card.dueDate.toLocaleDateString()]
})]
}, card.id);
})
})]
}, column.id);
})]
})
});
}
export { GlassKanban, GlassKanban as default };
//# sourceMappingURL=GlassKanban.js.map