// Shared icons (Lucide-style SVG) and helper components
const Icon = ({ name, size = 18, stroke = 2, className = '', style = {} }) => {
const paths = {
home: <>>,
file: <>>,
files: <>>,
users: <>>,
user: <>>,
chart: <>>,
sparkles: <>>,
settings: <>>,
search: <>>,
bell: <>>,
plus: <>>,
check: ,
checkCircle: <>>,
x: <>>,
chevronRight: ,
chevronLeft: ,
chevronDown: ,
arrowRight: <>>,
arrowLeft: <>>,
clock: <>>,
calendar: <>>,
lock: <>>,
mail: <>>,
eye: <>>,
brain: <>>,
wand: <>>,
upload: <>>,
download: <>>,
filter: ,
trash: <>>,
edit: <>>,
copy: <>>,
grip: <>>,
logout: <>>,
flag: <>>,
bookmark: ,
warn: <>>,
play: ,
send: <>>,
book: <>>,
trophy: <>>,
building: <>>,
mapPin: <>>,
layers: <>>,
shield: ,
maximize: <>>,
save: <>>,
refresh: <>>,
moreH: <>>,
palette: <>>,
zap: ,
globe: <>>,
trending: <>>,
};
return (
);
};
const Logo = ({ size = 'md', variant = 'prof' }) => {
const grad = variant === 'stud' ? 'linear-gradient(135deg, #8B7CF6, #7C3AED)'
: variant === 'admin' ? 'linear-gradient(135deg, #6366F1, #8B5CF6)'
: 'linear-gradient(135deg, #6ECFB5, #4DB8A0)';
const sizes = { sm: { box: 26, font: 12, text: 15 }, md: { box: 32, font: 15, text: 18 }, lg: { box: 40, font: 18, text: 22 } };
const sz = sizes[size];
return (
);
};
// Avatar — colored circle with initials
const Avatar = ({ name, size = 36, variant = 'prof' }) => {
const initials = name.split(' ').map(n => n[0]).slice(0, 2).join('').toUpperCase();
const bgs = {
prof: ['#6ECFB5', '#A78BFA', '#F5C842', '#E879A0', '#60A5FA'],
stud: ['#8B7CF6', '#E879A0', '#F5C842'],
admin: ['#6366F1', '#8B5CF6', '#F59E0B'],
};
const palette = bgs[variant];
const colorIdx = name.charCodeAt(0) % palette.length;
return (
{initials}
);
};
// Sparkline SVG
const Sparkline = ({ data, color = '#6ECFB5', width = 80, height = 24 }) => {
const max = Math.max(...data); const min = Math.min(...data);
const range = max - min || 1;
const pts = data.map((v, i) => `${(i / (data.length - 1)) * width},${height - ((v - min) / range) * height}`).join(' ');
return (
);
};
// Toast host
const Toast = ({ message, visible, variant = 'prof' }) => {
const colors = { prof: '#6ECFB5', stud: '#8B7CF6', admin: '#6366F1' };
if (!visible) return null;
return (
{message}
);
};
// Confetti
const Confetti = () => {
const colors = ['#8B7CF6', '#E879A0', '#F5C842', '#6ECFB5', '#60A5FA'];
const pieces = Array.from({ length: 80 }, (_, i) => ({
left: Math.random() * 100, delay: Math.random() * 1.2, dur: 2 + Math.random() * 2,
color: colors[i % colors.length], size: 6 + Math.random() * 8,
}));
return (
{pieces.map((p, i) => (
))}
);
};
Object.assign(window, { Icon, Logo, Avatar, Sparkline, Toast, Confetti });