/**
* =========================================================================
* PLATEFORME ECO-PANNEAU.FR - VERSION 1.0.0
* Socle UI (3/4) - Design System et Layout Principal
* =========================================================================
*/
// =========================================================================
// 1. DESIGN SYSTEM : COMPOSANTS UI UNIFIÉS (FACTORISÉS)
// =========================================================================
window.Button = ({ children, onClick, disabled, variant = 'primary', icon: Icon, className = '', type = 'button', title = '', ...props }) => {
const baseClass = "px-4 py-2 rounded-xl text-xs font-bold transition flex items-center justify-center gap-2 shadow-sm border border-transparent";
const variants = {
primary: "bg-emerald-600 text-white hover:bg-emerald-700 shadow-md",
success: "bg-emerald-50 text-emerald-600 hover:bg-emerald-100",
successSolid: "bg-emerald-600 text-white hover:bg-emerald-700 shadow-md",
danger: "bg-red-50 text-red-600 hover:bg-red-100",
dangerSolid: "bg-red-600 text-white hover:bg-red-700 shadow-md",
warning: "bg-orange-50 text-orange-600 hover:bg-orange-100",
warningSolid: "bg-orange-500 text-white hover:bg-orange-600 shadow-md",
info: "bg-blue-50 text-blue-700 hover:bg-blue-100",
infoSolid: "bg-blue-600 text-white hover:bg-blue-700 shadow-md",
secondary: "bg-slate-100 text-slate-700 hover:bg-slate-200 border-slate-200",
outline: "bg-white border-slate-200 text-slate-600 hover:bg-slate-50",
purple: "bg-purple-50 text-purple-700 hover:bg-purple-100",
dark: "bg-slate-900 text-white hover:bg-slate-800 shadow-md",
ghost: "bg-transparent text-slate-500 hover:text-slate-800 hover:bg-slate-100 shadow-none border-transparent"
};
const handleAction = (e) => {
if (disabled) return;
if (onClick) onClick(e);
if (type === 'submit') {
const form = e.currentTarget.closest('form');
if (form && typeof form.requestSubmit === 'function') {
form.requestSubmit();
}
}
};
return (
{
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction(e);
}
}}
title={title}
className={`${baseClass} ${variants[variant] || variants.primary} ${className} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
{...props}
>
{Icon && }
{children}
{type === 'submit' && }
);
};
window.IconBadge = ({ icon: Icon, variant = 'info', size = 'md', className = '' }) => {
const variants = {
primary: "bg-emerald-100 text-emerald-600",
success: "bg-emerald-100 text-emerald-600",
danger: "bg-red-100 text-red-600",
warning: "bg-orange-100 text-orange-600",
info: "bg-blue-100 text-blue-600",
secondary: "bg-slate-100 text-slate-500",
purple: "bg-purple-100 text-purple-600",
dark: "bg-slate-800 text-slate-300"
};
const sizes = {
sm: "w-8 h-8 rounded-lg",
md: "w-10 h-10 rounded-xl",
lg: "w-12 h-12 rounded-2xl",
xl: "w-14 h-14 rounded-2xl"
};
const iconSizes = { sm: 14, md: 18, lg: 24, xl: 28 };
return (
{Icon && }
);
};
window.Toggle = ({ checked, onChange, variant = 'success', disabled = false }) => {
const variants = {
success: 'bg-emerald-500',
info: 'bg-blue-500',
warning: 'bg-orange-500',
danger: 'bg-red-500',
purple: 'bg-purple-500'
};
const colorClass = variants[variant] || variants.success;
return (
{ if(onChange && !disabled) { e.stopPropagation(); onChange(!checked); } }}
>
);
};
window.EmptyState = ({ icon: Icon, text, subtext, className = "" }) => (
{Icon &&
}
{text}
{subtext &&
{subtext}
}
);
window.AlertBox = ({ type = 'info', icon: Icon, title, children, className = "" }) => {
const styles = {
info: 'bg-blue-50 text-blue-800 border-blue-200',
warning: 'bg-orange-50 text-orange-800 border-orange-200',
error: 'bg-red-50 text-red-800 border-red-200',
success: 'bg-emerald-50 text-emerald-800 border-emerald-200'
};
const iconColors = {
info: 'text-blue-500',
warning: 'text-orange-500',
error: 'text-red-500',
success: 'text-emerald-500'
};
return (
{Icon &&
}
{title &&
{title}
}
{children}
);
};
window.StatCard = ({ title, value, icon, variant = 'info', onClick }) => {
const variants = {
success: { bg: 'bg-emerald-100', text: 'text-emerald-600' },
info: { bg: 'bg-blue-100', text: 'text-blue-600' },
warning: { bg: 'bg-amber-100', text: 'text-amber-600' },
danger: { bg: 'bg-red-100', text: 'text-red-600' },
secondary: { bg: 'bg-slate-200', text: 'text-slate-600' },
purple: { bg: 'bg-purple-100', text: 'text-purple-600' },
indigo: { bg: 'bg-indigo-100', text: 'text-indigo-600' }
};
const v = variants[variant] || variants.info;
return (
);
};
window.PriceInput = ({ label, value, onChange, ...props }) => (
);
window.StatusBadge = ({ status, variant, className = '' }) => {
let colorClass = 'bg-slate-100 text-slate-600 border-slate-200';
if (variant) {
const variants = {
success: 'bg-emerald-100 text-emerald-700 border-emerald-200',
danger: 'bg-red-100 text-red-700 border-red-200',
warning: 'bg-amber-100 text-amber-700 border-amber-200',
info: 'bg-blue-100 text-blue-700 border-blue-200',
secondary: 'bg-slate-100 text-slate-600 border-slate-200'
};
colorClass = variants[variant] || colorClass;
} else {
const s = (status || '').toLowerCase();
if (s.includes('actif') || s.includes('livré') || s.includes('activé') || s.includes('accept')) {
colorClass = 'bg-emerald-100 text-emerald-700 border-emerald-200';
} else if (s.includes('suspendu') || s.includes('erreur') || s.includes('hors ligne') || s.includes('refus') || s.includes('désactivé')) {
colorClass = 'bg-red-100 text-red-700 border-red-200';
} else if (s.includes('brouillon') || s.includes('attente') || s.includes('validation') || s.includes('programmé')) {
colorClass = 'bg-amber-100 text-amber-700 border-amber-200';
} else if (s.includes('expédié')) {
colorClass = 'bg-blue-100 text-blue-700 border-blue-200';
}
}
return (
{status}
);
};
window.FormInput = ({ label, value, onChange, type = 'text', required = false, disabled = false, placeholder = '', className = '', hint = '', error = false, errorText = '', ...props }) => (
{hint && !errorText &&
{hint}
}
{errorText &&
{errorText}
}
);
window.FormTextarea = ({ label, value, onChange, rows = 3, required = false, disabled = false, placeholder = '', className = '', hint = '', error = false, errorText = '', ...props }) => (
{hint && !errorText &&
{hint}
}
{errorText &&
{errorText}
}
);
// =========================================================================
// 2. LAYOUT PRINCIPAL (SHELL)
// =========================================================================
window.DashboardLayout = ({ role, user, theme = 'emerald', navItems, activeTab, setActiveTab, onLogout, customLogout, children, sidebarFooter }) => {
const LogOutIcon = window.LogOutIcon || (() => null);
const XIcon = window.XIcon || (() => null);
const MenuIcon = window.MenuIcon || (() => null);
const LogoSVG = window.LogoSVG || (() => null);
const [isMobileMenuOpen, ReactSetIsMobileMenuOpen] = React.useState(false);
const themeConfig = {
emerald: { bg: 'bg-emerald-900', hover: 'hover:bg-emerald-800', active: 'bg-emerald-800 text-white border-emerald-400', text: 'text-emerald-100', border: 'border-emerald-800' },
purple: { bg: 'bg-slate-900', hover: 'hover:bg-slate-800', active: 'bg-purple-600 text-white border-purple-400', text: 'text-slate-300', border: 'border-slate-800' },
blue: { bg: 'bg-blue-900', hover: 'hover:bg-blue-800', active: 'bg-blue-800 text-white border-blue-400', text: 'text-blue-100', border: 'border-blue-800' }
}[theme];
return (
{isMobileMenuOpen && (
{sidebarFooter}
{customLogout ? (
{customLogout.icon} {customLogout.label}
) : (
Déconnexion
)}
)}
{children}
);
};
/* EOF ========== [_react/_ui_components.jsx] */