aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
356 lines (353 loc) • 14 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { useState } from 'react';
import { GlassCore } from '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import '../../primitives/motion/MotionFramer.js';
import { useCollaboration } from './GlassCollaborationProvider.js';
import { cn } from '../../lib/utilsComprehensive.js';
const UserAvatar = ({
user,
size = "md",
showStatus = true
}) => {
const sizeClasses = {
sm: "w-6 h-6 text-xs",
md: "w-8 h-8 text-sm",
lg: "w-10 h-10 text-base"
};
const isActive = Date.now() - user.lastActive < 60000; // Active within last minute
return jsxs("div", {
"data-glass-component": true,
className: 'relative',
children: [user.avatar ? jsx("img", {
src: user.avatar,
alt: user.name,
className: cn("rounded-full object-cover border-2", sizeClasses[size], isActive ? "border-green-400" : "border-gray-300")
}) : jsx("div", {
className: cn("rounded-full flex items-center justify-center text-white font-medium border-2", sizeClasses[size], isActive ? "border-green-400" : "border-gray-300"),
style: {
backgroundColor: user.color
},
children: user.name[0]?.toUpperCase()
}), showStatus && jsx("div", {
className: cn("absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full border-2 border-white", isActive ? "bg-green-400" : "bg-gray-400")
})]
});
};
const ActivityItem = ({
activity,
user
}) => {
const formatTime = timestamp => {
const now = Date.now();
const diff = now - timestamp;
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
if (minutes < 1) return "now";
if (minutes < 60) return `${minutes}m`;
if (hours < 24) return `${hours}h`;
return new Date(timestamp).toLocaleDateString();
};
const getActivityIcon = () => {
switch (activity.type) {
case "join":
return "🟢";
case "leave":
return "🔴";
case "edit":
return "✏️";
case "comment":
return "💬";
case "cursor_move":
return "👆";
default:
return "•";
}
};
const getActivityColor = () => {
switch (activity.type) {
case "join":
return "text-green-600";
case "leave":
return "text-red-600";
case "edit":
return "text-blue-600";
case "comment":
return "text-purple-600";
default:
return "text-gray-600";
}
};
return jsxs("div", {
className: 'glass-flex glass-items-center glass-gap-3 glass-p-2 glass-radius hover:glass-surface-subtle transition-colors',
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-gap-2",
children: [user && jsx(UserAvatar, {
user: user,
size: "sm",
showStatus: false
}), jsx("span", {
className: "glass-text-lg",
children: getActivityIcon()
})]
}), jsx("div", {
className: 'glass-flex-1 min-glass-w-0',
children: jsx("p", {
className: cn("text-sm", getActivityColor()),
children: activity.description
})
}), jsx("span", {
className: 'glass-text-xs glass-text-secondary whitespace-nowrap',
children: formatTime(activity.timestamp)
})]
});
};
const ConnectionStatus = () => {
const {
connectionStatus,
isConnected
} = useCollaboration();
const getStatusColor = () => {
switch (connectionStatus) {
case "connected":
return "text-green-600";
case "connecting":
case "reconnecting":
return "text-yellow-600";
case "disconnected":
return "text-red-600";
default:
return "text-gray-600";
}
};
const getStatusIcon = () => {
switch (connectionStatus) {
case "connected":
return "🟢";
case "connecting":
case "reconnecting":
return "🟡";
case "disconnected":
return "🔴";
default:
return "⚫";
}
};
const getStatusText = () => {
switch (connectionStatus) {
case "connected":
return "Connected";
case "connecting":
return "Connecting...";
case "reconnecting":
return "Reconnecting...";
case "disconnected":
return "Disconnected";
default:
return "Unknown";
}
};
return jsxs("div", {
className: cn("flex items-center gap-2 text-sm", getStatusColor()),
children: [jsx("span", {
children: getStatusIcon()
}), jsx("span", {
children: getStatusText()
})]
});
};
const GlassCollaborationDashboard = ({
className,
position = "top-right",
showUserList = true,
showActivityFeed = true,
showControls = true
}) => {
const {
users,
currentUser,
activities,
comments,
showCursors,
showComments,
showActivity,
toggleCursors,
toggleComments,
toggleActivity
} = useCollaboration();
const [isExpanded, setIsExpanded] = useState(false);
const [activeTab, setActiveTab] = useState("users");
const positionClasses = {
"top-left": "top-4 left-4",
"top-right": "top-4 right-4",
"bottom-left": "bottom-4 left-4",
"bottom-right": "bottom-4 right-4"
};
const activeUsers = users.filter(user => Date.now() - user.lastActive < 300000); // Active within 5 minutes
const recentActivities = activities.slice(0, 20);
const unresolvedComments = comments.filter(c => !c.resolved);
return jsx("div", {
className: cn("fixed z-40", positionClasses[position], className),
children: !isExpanded ?
// Collapsed state
jsx(GlassCore, {
className: "glass-p-3 glass-contrast-guard",
children: jsxs("button", {
onClick: () => setIsExpanded(true),
className: 'glass-flex glass-items-center glass-gap-3 hover:glass-surface-subtle glass-radius glass-p-2 transition-colors glass-focus glass-touch-target glass-contrast-guard',
children: [jsxs("div", {
className: 'glass-flex -space-x-2',
children: [activeUsers.slice(0, 3).map(user => jsx(UserAvatar, {
user: user,
size: "sm"
}, user.id)), activeUsers.length > 3 && jsxs("div", {
className: 'w-6 h-6 glass-surface-subtle glass-text-secondary glass-radius-full glass-flex glass-items-center glass-justify-center glass-text-xs glass-border-2 glass-border-white',
children: ["+", activeUsers.length - 3]
})]
}), jsxs("div", {
className: 'text-left',
children: [jsxs("div", {
className: 'glass-text-sm font-medium glass-text-secondary',
children: [activeUsers.length, " online"]
}), jsx(ConnectionStatus, {})]
}), unresolvedComments.length > 0 && jsx("div", {
className: 'w-5 h-5 glass-surface-red text-primary glass-radius-full glass-flex glass-items-center glass-justify-center glass-text-xs',
children: unresolvedComments.length
})]
})
}) :
// Expanded state
jsxs(GlassCore, {
className: 'w-80 max-h-96 overflow-hidden glass-contrast-guard',
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between glass-p-4 glass-border-b glass-border-subtle",
children: [jsx("h3", {
className: 'font-semibold glass-text-secondary',
children: "Collaboration"
}), jsx("button", {
onClick: () => setIsExpanded(false),
className: 'glass-text-secondary hover:glass-text-secondary glass-p-1 glass-focus glass-touch-target glass-contrast-guard',
children: "\u2715"
})]
}), jsx("div", {
className: "glass-px-4 glass-py-2 glass-surface-subtle glass-border-b glass-border-subtle",
children: jsx(ConnectionStatus, {})
}), showControls && jsx("div", {
className: "glass-p-4 glass-border-b glass-border-subtle",
children: jsxs("div", {
className: "glass-grid glass-grid-cols-3 glass-gap-2",
children: [jsxs("button", {
onClick: toggleCursors,
className: cn("flex flex-col items-center gap-1 p-2 rounded text-xs transition-colors glass-focus glass-touch-target glass-contrast-guard", showCursors ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-600 hover:bg-gray-200"),
children: [jsx("span", {
children: "\uD83D\uDC46"
}), "Cursors"]
}), jsxs("button", {
onClick: toggleComments,
className: cn("flex flex-col items-center gap-1 p-2 rounded text-xs transition-colors relative glass-focus glass-touch-target glass-contrast-guard", showComments ? "bg-purple-100 text-purple-700" : "bg-gray-100 text-gray-600 hover:bg-gray-200"),
children: [jsx("span", {
children: "\uD83D\uDCAC"
}), "Comments", unresolvedComments.length > 0 && jsx("div", {
className: 'absolute glass-top-1 -right-1 w-4 h-4 glass-surface-red text-primary glass-radius-full glass-flex glass-items-center glass-justify-center glass-text-xs',
children: unresolvedComments.length
})]
}), jsxs("button", {
onClick: toggleActivity,
className: cn("flex flex-col items-center gap-1 p-2 rounded text-xs transition-colors glass-focus glass-touch-target glass-contrast-guard", showActivity ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-600 hover:bg-gray-200"),
children: [jsx("span", {
children: "\uD83D\uDCCA"
}), "Activity"]
})]
})
}), jsxs("div", {
className: "glass-flex glass-border-b glass-border-subtle",
children: [jsxs("button", {
onClick: () => setActiveTab("users"),
className: cn("flex-1 px-4 py-2 text-sm font-medium transition-colors glass-focus glass-touch-target glass-contrast-guard", activeTab === "users" ? "text-blue-600 border-b-2 border-blue-600 bg-blue-50" : "text-gray-600 hover:text-gray-900"),
children: ["Users (", activeUsers.length, ")"]
}), jsx("button", {
onClick: () => setActiveTab("activity"),
className: cn("flex-1 px-4 py-2 text-sm font-medium transition-colors glass-focus glass-touch-target glass-contrast-guard", activeTab === "activity" ? "text-blue-600 border-b-2 border-blue-600 bg-blue-50" : "text-gray-600 hover:text-gray-900"),
children: "Activity"
})]
}), jsxs("div", {
className: 'glass-max-h-64 overflow-y-auto',
children: [activeTab === "users" && showUserList && jsxs("div", {
className: 'glass-p-4 space-y-3',
children: [activeUsers.map(user => {
const isCurrentUser = user.id === currentUser?.id;
const isActive = Date.now() - user.lastActive < 60000;
return jsxs("div", {
className: cn("flex items-center gap-3 p-2 rounded", isCurrentUser ? "bg-blue-50" : "hover:bg-gray-50"),
children: [jsx(UserAvatar, {
user: user,
size: "md"
}), jsxs("div", {
className: 'glass-flex-1 min-glass-w-0',
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-gap-2",
children: [jsxs("span", {
className: 'glass-text-sm font-medium glass-text-secondary truncate',
children: [user.name, isCurrentUser && " (You)"]
}), !isActive && jsx("span", {
className: "glass-text-xs glass-text-secondary",
children: "Away"
})]
}), jsx("span", {
className: 'glass-text-xs glass-text-secondary truncate',
children: user.email
})]
}), user.cursor && jsx("span", {
className: 'glass-text-xs text-primary',
children: "\uD83D\uDCCD"
})]
}, user.id);
}), activeUsers.length === 0 && jsxs("div", {
className: 'text-center glass-py-6 glass-text-secondary',
children: [jsx("div", {
className: 'glass-text-2xl mb-2',
children: "\uD83D\uDC65"
}), jsx("p", {
className: "glass-text-sm",
children: "No users online"
})]
})]
}), activeTab === "activity" && showActivityFeed && jsxs("div", {
className: 'glass-p-4 space-y-1',
children: [recentActivities.map(activity => {
const user = users.find(u => u.id === activity.userId);
return jsx(ActivityItem, {
activity: activity,
user: user
}, activity.id);
}), recentActivities.length === 0 && jsxs("div", {
className: 'text-center glass-py-6 glass-text-secondary',
children: [jsx("div", {
className: 'glass-text-2xl mb-2',
children: "\uD83D\uDCCA"
}), jsx("p", {
className: "glass-text-sm",
children: "No recent activity"
})]
})]
})]
}), jsx("div", {
className: "glass-px-4 glass-py-2 glass-surface-subtle glass-border-t glass-border-subtle glass-text-xs glass-text-secondary",
children: jsxs("div", {
className: "glass-flex glass-justify-between",
children: [jsxs("span", {
children: [comments.length, " comments"]
}), jsxs("span", {
children: [activities.length, " activities"]
})]
})
})]
})
});
};
export { GlassCollaborationDashboard };
//# sourceMappingURL=GlassCollaborationDashboard.js.map