refactor(style): apply new design
This commit is contained in:
@@ -3,11 +3,12 @@
|
|||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react';
|
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react';
|
||||||
import { ChevronDownIcon } from '@zen/core/shared/icons';
|
import { ChevronDownIcon } from '@zen/core/shared/icons';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter, usePathname } from 'next/navigation';
|
||||||
import { useTheme, getThemeIcon } from '@zen/core/themes';
|
import { useTheme, getThemeIcon } from '@zen/core/themes';
|
||||||
|
|
||||||
const AdminHeader = ({ isMobileMenuOpen, setIsMobileMenuOpen, user, onLogout, appName = 'ZEN' }) => {
|
const AdminHeader = ({ isMobileMenuOpen, setIsMobileMenuOpen, user, onLogout, appName = 'ZEN', navigationSections = [] }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
const getImageUrl = (imageKey) => {
|
const getImageUrl = (imageKey) => {
|
||||||
if (!imageKey) return null;
|
if (!imageKey) return null;
|
||||||
@@ -47,14 +48,28 @@ const AdminHeader = ({ isMobileMenuOpen, setIsMobileMenuOpen, user, onLogout, ap
|
|||||||
const ThemeIcon = getThemeIcon(theme, systemIsDark);
|
const ThemeIcon = getThemeIcon(theme, systemIsDark);
|
||||||
const themeLabel = theme === 'light' ? 'Mode clair' : theme === 'dark' ? 'Mode sombre' : 'Thème système';
|
const themeLabel = theme === 'light' ? 'Mode clair' : theme === 'dark' ? 'Mode sombre' : 'Thème système';
|
||||||
|
|
||||||
|
const currentPageName = (() => {
|
||||||
|
for (const section of navigationSections) {
|
||||||
|
for (const item of section.items) {
|
||||||
|
if (pathname === item.href || pathname.startsWith(item.href + '/')) {
|
||||||
|
return item.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (section.items.length === 1 && (pathname === section.items[0].href || pathname.startsWith(section.items[0].href + '/'))) {
|
||||||
|
return section.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})();
|
||||||
|
|
||||||
const quickLinks = [];
|
const quickLinks = [];
|
||||||
const imageUrl = getImageUrl(user?.image);
|
const imageUrl = getImageUrl(user?.image);
|
||||||
const userInitials = getUserInitials(user?.name);
|
const userInitials = getUserInitials(user?.name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-white dark:bg-black border-b border-neutral-200 dark:border-neutral-800/70 sticky top-0 z-30 h-12 flex items-center w-full">
|
<header className="bg-white dark:bg-black border-b border-neutral-200 dark:border-neutral-800/70 sticky top-0 z-30 h-12 flex items-center w-full">
|
||||||
<div className="flex items-center justify-between lg:justify-end px-4 lg:px-6 py-2 w-full">
|
<div className="flex items-center justify-between px-4 lg:px-6 py-2 w-full">
|
||||||
{/* Left section — Mobile menu button + Logo */}
|
{/* Left section — Mobile menu button + Logo / Desktop breadcrumb */}
|
||||||
<div className="flex items-center space-x-3 lg:hidden">
|
<div className="flex items-center space-x-3 lg:hidden">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||||
@@ -68,6 +83,17 @@ const AdminHeader = ({ isMobileMenuOpen, setIsMobileMenuOpen, user, onLogout, ap
|
|||||||
<h1 className="text-neutral-900 dark:text-white font-semibold text-lg">{appName}</h1>
|
<h1 className="text-neutral-900 dark:text-white font-semibold text-lg">{appName}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Desktop breadcrumb */}
|
||||||
|
{currentPageName && (
|
||||||
|
<div className="hidden lg:flex items-center gap-1.5 text-[13px]">
|
||||||
|
<span className="text-neutral-500 dark:text-neutral-400">{appName}</span>
|
||||||
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-neutral-400 dark:text-neutral-600 flex-shrink-0">
|
||||||
|
<polyline points="9 18 15 12 9 6" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-neutral-900 dark:text-white font-medium">{currentPageName}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Right section — Quick links + Profile */}
|
{/* Right section — Quick links + Profile */}
|
||||||
<div className="flex items-center gap-3 sm:gap-4">
|
<div className="flex items-center gap-3 sm:gap-4">
|
||||||
<nav className="hidden sm:flex items-center gap-4 lg:gap-6">
|
<nav className="hidden sm:flex items-center gap-4 lg:gap-6">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function AdminPagesLayout({ children, user, onLogout, appName, en
|
|||||||
navigationSections={navigationSections}
|
navigationSections={navigationSections}
|
||||||
/>
|
/>
|
||||||
<div className="flex-1 flex flex-col min-w-0">
|
<div className="flex-1 flex flex-col min-w-0">
|
||||||
<AdminHeader isMobileMenuOpen={isMobileMenuOpen} setIsMobileMenuOpen={setIsMobileMenuOpen} user={user} onLogout={onLogout} appName={appName} />
|
<AdminHeader isMobileMenuOpen={isMobileMenuOpen} setIsMobileMenuOpen={setIsMobileMenuOpen} user={user} onLogout={onLogout} appName={appName} navigationSections={navigationSections} />
|
||||||
<main className="flex-1 overflow-y-auto bg-neutral-50 dark:bg-black">
|
<main className="flex-1 overflow-y-auto bg-neutral-50 dark:bg-black">
|
||||||
<div className="px-8 py-7 pb-32 max-w-[1400px] mx-auto">
|
<div className="px-8 py-7 pb-32 max-w-[1400px] mx-auto">
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ const AdminSidebar = ({ isMobileMenuOpen, setIsMobileMenuOpen, appName, enabledM
|
|||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<Link href="/admin" className="px-4 h-12 flex items-center justify-start gap-2 border-b border-neutral-200 dark:border-neutral-800/70">
|
<Link href="/admin" className="px-4 h-12 flex items-center justify-start gap-2 border-b border-neutral-200 dark:border-neutral-800/70">
|
||||||
<h1 className="text-neutral-900 dark:text-white font-semibold">{appName}</h1>
|
<h1 className="text-neutral-900 dark:text-white font-semibold">{appName}</h1>
|
||||||
<span className="bg-red-700/10 border border-red-600/20 text-red-600 uppercase text-[10px] leading-none px-2 py-1 rounded-lg font-semibold">
|
<span className="bg-red-700/10 border border-red-600/20 text-red-600 uppercase text-[10px] leading-none px-2 py-1 rounded font-semibold">
|
||||||
Admin
|
Admin
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -85,10 +85,10 @@ export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, re
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputClasses = 'w-full px-3 py-2.5 rounded-xl text-sm focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20';
|
const inputClasses = 'w-full px-[10px] py-[7px] rounded text-[13px] focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-neutral-900/40 border border-neutral-200 dark:border-neutral-800/50 rounded-xl px-4 py-6 md:px-6 md:py-8 w-full max-w-md">
|
<div className="bg-white dark:bg-neutral-900/40 border border-neutral-200 dark:border-neutral-800/50 rounded-md px-4 py-6 md:px-6 md:py-8 w-full max-w-md">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-6">
|
<div className="text-center mb-6">
|
||||||
<h1 className="text-2xl font-bold text-neutral-900 dark:text-white mb-2">
|
<h1 className="text-2xl font-bold text-neutral-900 dark:text-white mb-2">
|
||||||
@@ -190,7 +190,7 @@ export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, re
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={isLoading || success || currentUser}
|
disabled={isLoading || success || currentUser}
|
||||||
className="cursor-pointer w-full bg-neutral-900 text-white mt-2 py-2.5 px-4 rounded-xl text-sm font-medium hover:bg-neutral-800 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-[120ms] ease-out focus:outline-none focus:ring-1 focus:ring-neutral-900/20 dark:bg-white dark:text-black dark:hover:bg-neutral-100 dark:focus:ring-white/20"
|
className="cursor-pointer w-full bg-neutral-900 text-white mt-2 py-[7px] px-4 rounded text-[13px] font-medium hover:bg-neutral-800 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-[120ms] ease-out focus:outline-none focus:ring-1 focus:ring-neutral-900/20 dark:bg-white dark:text-black dark:hover:bg-neutral-100 dark:focus:ring-white/20"
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center space-x-2">
|
<div className="flex items-center justify-center space-x-2">
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ const Badge = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sizes = {
|
const sizes = {
|
||||||
sm: 'px-2 py-0.5 rounded-lg text-[11px]',
|
sm: 'px-2 py-0.5 rounded text-[12px]',
|
||||||
md: 'px-2.5 py-0.5 rounded-lg text-[11px]',
|
md: 'px-2.5 py-0.5 rounded text-[12px]',
|
||||||
lg: 'px-3 py-1 rounded-lg text-xs'
|
lg: 'px-3 py-1 rounded text-xs'
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,20 +15,20 @@ const Button = ({
|
|||||||
className = '',
|
className = '',
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const baseClassName = 'cursor-pointer inline-flex items-center justify-center font-medium rounded-xl transition-all duration-[120ms] ease-out focus:outline-none focus:ring-1 disabled:opacity-50 disabled:cursor-not-allowed';
|
const baseClassName = 'cursor-pointer inline-flex items-center justify-center font-medium rounded transition-all duration-[120ms] ease-out focus:outline-none focus:ring-1 disabled:opacity-50 disabled:cursor-not-allowed';
|
||||||
|
|
||||||
const variants = {
|
const variants = {
|
||||||
primary: 'bg-neutral-900 text-white hover:bg-neutral-800 focus:ring-neutral-900/20 dark:bg-white dark:text-black dark:hover:bg-neutral-100 dark:focus:ring-white/20',
|
primary: 'bg-neutral-900 text-white hover:bg-neutral-800 focus:ring-neutral-900/20 dark:bg-white dark:text-black dark:hover:bg-neutral-100 dark:focus:ring-white/20',
|
||||||
secondary: 'bg-transparent border border-neutral-300 text-neutral-700 hover:bg-neutral-100 focus:ring-neutral-500/20 dark:bg-neutral-800/60 dark:border-neutral-700/50 dark:text-white dark:hover:bg-neutral-800/80 dark:focus:ring-neutral-600/20 dark:backdrop-blur-sm',
|
secondary: 'bg-transparent border border-neutral-300 text-neutral-700 hover:bg-neutral-100 focus:ring-neutral-500/20 dark:bg-neutral-800/60 dark:border-neutral-700/50 dark:text-white dark:hover:bg-neutral-800/80 dark:focus:ring-neutral-600/20',
|
||||||
danger: 'bg-red-50 border border-red-200 text-red-700 hover:bg-red-100 focus:ring-red-500/20 dark:bg-red-500/20 dark:border-red-500/30 dark:text-red-400 dark:hover:bg-red-500/30 dark:focus:ring-red-500/20',
|
danger: 'bg-red-50 border border-red-200 text-red-700 hover:bg-red-100 focus:ring-red-500/20 dark:bg-red-500/20 dark:border-red-500/30 dark:text-red-400 dark:hover:bg-red-500/30 dark:focus:ring-red-500/20',
|
||||||
ghost: 'text-neutral-600 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20 dark:text-neutral-400 dark:hover:text-white dark:hover:bg-neutral-700/30 dark:focus:ring-neutral-600/20',
|
ghost: 'text-neutral-600 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20 dark:text-neutral-400 dark:hover:text-white dark:hover:bg-neutral-700/30 dark:focus:ring-neutral-600/20',
|
||||||
success: 'bg-green-50 border border-green-200 text-green-700 hover:bg-green-100 focus:ring-green-500/20 dark:bg-green-500/20 dark:border-green-500/30 dark:text-green-400 dark:hover:bg-green-500/30 dark:focus:ring-green-500/20',
|
success: 'bg-green-50 border border-green-200 text-green-700 hover:bg-green-100 focus:ring-green-500/20 dark:bg-green-500/20 dark:border-green-500/30 dark:text-green-400 dark:hover:bg-green-500/30 dark:focus:ring-green-500/20',
|
||||||
warning: 'bg-yellow-50 border border-yellow-200 text-yellow-700 hover:bg-yellow-100 focus:ring-yellow-500/20 dark:bg-yellow-500/20 dark:border-yellow-500/30 dark:text-yellow-400 dark:hover:bg-yellow-500/30 dark:focus:ring-yellow-500/20'
|
warning: 'bg-yellow-50 border border-yellow-200 text-yellow-700 hover:bg-yellow-100 focus:ring-yellow-500/20 dark:bg-yellow-500/20 dark:border-yellow-500/30 dark:text-yellow-400 dark:hover:bg-yellow-500/30 dark:focus:ring-yellow-500/20'
|
||||||
};
|
};
|
||||||
|
|
||||||
const sizes = {
|
const sizes = {
|
||||||
sm: 'px-3 py-1.5 text-xs gap-1.5',
|
sm: 'px-[10px] py-[4px] text-[12px] gap-1.5',
|
||||||
md: 'px-4 py-2.5 text-sm gap-2',
|
md: 'px-[14px] py-[7px] text-[13px] gap-2',
|
||||||
lg: 'px-6 py-3 text-base gap-2.5'
|
lg: 'px-6 py-3 text-base gap-2.5'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,15 @@ const Card = ({
|
|||||||
const isLightDark = variant === 'lightDark';
|
const isLightDark = variant === 'lightDark';
|
||||||
|
|
||||||
const variants = {
|
const variants = {
|
||||||
default: 'rounded-xl bg-white dark:bg-neutral-800/30 border-neutral-200 dark:border-neutral-700/30',
|
default: 'rounded-md bg-white dark:bg-neutral-800/30 border-neutral-200 dark:border-neutral-700/30',
|
||||||
elevated: 'rounded-xl bg-neutral-50/80 dark:bg-neutral-900/40 border-neutral-200 dark:border-neutral-800/50',
|
elevated: 'rounded-md bg-neutral-50/80 dark:bg-neutral-900/40 border-neutral-200 dark:border-neutral-800/50',
|
||||||
outline: 'rounded-xl bg-transparent border-neutral-300 dark:border-neutral-700/50',
|
outline: 'rounded-md bg-transparent border-neutral-300 dark:border-neutral-700/50',
|
||||||
solid: 'rounded-xl bg-neutral-100 dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700',
|
solid: 'rounded-md bg-neutral-100 dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700',
|
||||||
lightDark: 'rounded-xl bg-white dark:bg-neutral-900/40 border-neutral-200 dark:border-neutral-800/50',
|
lightDark: 'rounded-md bg-white dark:bg-neutral-900/40 border-neutral-200 dark:border-neutral-800/50',
|
||||||
success: 'rounded-xl bg-green-50 dark:bg-green-900/30 border-green-200 dark:border-green-900/50',
|
success: 'rounded-md bg-green-50 dark:bg-green-900/30 border-green-200 dark:border-green-900/50',
|
||||||
info: 'rounded-xl bg-blue-50 dark:bg-blue-900/30 border-blue-200 dark:border-blue-900/50',
|
info: 'rounded-md bg-blue-50 dark:bg-blue-900/30 border-blue-200 dark:border-blue-900/50',
|
||||||
warning: 'rounded-xl bg-yellow-50 dark:bg-yellow-900/30 border-yellow-200 dark:border-yellow-900/50',
|
warning: 'rounded-md bg-yellow-50 dark:bg-yellow-900/30 border-yellow-200 dark:border-yellow-900/50',
|
||||||
danger: 'rounded-xl bg-red-50 dark:bg-red-900/30 border-red-200 dark:border-red-900/50'
|
danger: 'rounded-md bg-red-50 dark:bg-red-900/30 border-red-200 dark:border-red-900/50'
|
||||||
};
|
};
|
||||||
|
|
||||||
const variantsHover = {
|
const variantsHover = {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const Input = ({
|
|||||||
step,
|
step,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const baseInputClassName = `w-full px-3 py-2.5 rounded-xl text-sm focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900/60 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20 dark:hover:bg-neutral-900/80 ${
|
const baseInputClassName = `w-full px-[10px] py-[7px] rounded text-[13px] focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900/60 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20 ${
|
||||||
error ? 'border-red-500/50 dark:border-red-500/50' : ''
|
error ? 'border-red-500/50 dark:border-red-500/50' : ''
|
||||||
} ${className}`;
|
} ${className}`;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ const Input = ({
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`w-12 h-10 border rounded-xl cursor-pointer transition-all duration-200 ${
|
className={`w-12 h-10 border rounded cursor-pointer transition-all duration-[120ms] ease-out ${
|
||||||
error ? 'border-red-500/50' : 'border-neutral-300 dark:border-neutral-700/50 dark:hover:border-neutral-600'
|
error ? 'border-red-500/50' : 'border-neutral-300 dark:border-neutral-700/50 dark:hover:border-neutral-600'
|
||||||
} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
|
} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||||
style={{ backgroundColor: value || '#000000' }}
|
style={{ backgroundColor: value || '#000000' }}
|
||||||
|
|||||||
@@ -27,16 +27,16 @@ const Modal = ({
|
|||||||
className="relative z-50"
|
className="relative z-50"
|
||||||
>
|
>
|
||||||
{/* Backdrop */}
|
{/* Backdrop */}
|
||||||
<div className="fixed inset-0 bg-black/40" aria-hidden="true" />
|
<div className="fixed inset-0 bg-black/35 backdrop-blur-[2px]" aria-hidden="true" />
|
||||||
|
|
||||||
{/* Container */}
|
{/* Container */}
|
||||||
<div className="fixed inset-0 flex items-center justify-center p-4">
|
<div className="fixed inset-0 flex items-center justify-center p-4">
|
||||||
<Dialog.Panel
|
<Dialog.Panel
|
||||||
className={`
|
className={`
|
||||||
w-full ${sizeClasses[size]}
|
w-full ${sizeClasses[size]}
|
||||||
bg-white dark:bg-neutral-900
|
bg-white dark:bg-neutral-900
|
||||||
border border-neutral-200 dark:border-neutral-800
|
border border-neutral-200 dark:border-neutral-800
|
||||||
rounded-xl
|
rounded-lg
|
||||||
shadow-xl
|
shadow-xl
|
||||||
max-h-[90vh]
|
max-h-[90vh]
|
||||||
overflow-hidden
|
overflow-hidden
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ const Pagination = ({
|
|||||||
<button
|
<button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
className={`px-2 py-1 text-xs font-medium rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${
|
className={`px-2 py-1 text-xs font-medium rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${
|
||||||
isActive
|
isActive
|
||||||
? 'bg-green-500/20 text-green-600 dark:text-green-400 border border-green-500/30 dark:border-green-500/20'
|
? 'bg-neutral-900 text-white border border-neutral-900 dark:bg-white dark:text-black dark:border-white'
|
||||||
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-700/30 hover:text-neutral-900 dark:hover:text-white'
|
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-700/30 hover:text-neutral-900 dark:hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const Select = ({
|
|||||||
description,
|
description,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const baseSelectClassName = `w-full cursor-pointer px-3 py-2.5 rounded-xl text-sm focus:outline-none transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900/60 dark:border-neutral-700/50 dark:text-white dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20 dark:hover:bg-neutral-900/80 dark:backdrop-blur-sm ${
|
const baseSelectClassName = `w-full cursor-pointer px-[10px] py-[7px] rounded text-[13px] focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900/60 dark:border-neutral-700/50 dark:text-white dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20 ${
|
||||||
error ? 'border-red-500/50 dark:border-red-500/50' : ''
|
error ? 'border-red-500/50 dark:border-red-500/50' : ''
|
||||||
} ${className}`;
|
} ${className}`;
|
||||||
|
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ const StatCard = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`bg-white dark:bg-neutral-900/40 border border-neutral-200 dark:border-neutral-800/50 rounded-xl p-4 sm:p-6 transition-all duration-[120ms] ease-out ${className}`}
|
className={`bg-white dark:bg-neutral-900/40 border border-neutral-200 dark:border-neutral-800/50 rounded-md px-5 py-4 transition-all duration-[120ms] ease-out ${className}`}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<p className="text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider mb-2 sm:mb-3 truncate">
|
<p className="text-[11px] font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-[0.04em] mb-2 truncate">
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="text-xl sm:text-2xl font-bold text-neutral-900 dark:text-white mb-1 sm:mb-2 truncate">
|
<div className="text-[22px] font-semibold tracking-tight text-neutral-900 dark:text-white mb-1 truncate">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Skeleton height="h-6" width="60%" />
|
<Skeleton height="h-6" width="60%" />
|
||||||
) : (
|
) : (
|
||||||
@@ -65,11 +65,11 @@ const StatCard = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`${bgColor} ${color} p-2.5 sm:p-3 rounded-xl flex-shrink-0 ml-3`}>
|
<div className={`${bgColor} ${color} w-8 h-8 p-2 rounded flex-shrink-0 ml-3 flex items-center justify-center`}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Skeleton height="h-5 sm:h-6" width="w-5 sm:w-6" />
|
<Skeleton height="h-4" width="w-4" />
|
||||||
) : (
|
) : (
|
||||||
Icon && <Icon className="h-5 w-5 sm:h-6 sm:w-6" />
|
Icon && <Icon className="h-4 w-4" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import Badge from './Badge';
|
|||||||
import { TorriGateIcon } from '../Icons';
|
import { TorriGateIcon } from '../Icons';
|
||||||
|
|
||||||
const ROW_SIZE = {
|
const ROW_SIZE = {
|
||||||
sm: { cell: 'px-4 py-3', header: 'px-6 py-4', mobile: 'p-4' },
|
sm: { cell: 'px-4 py-[11px]', header: 'px-4 py-[9px]', mobile: 'p-4' },
|
||||||
md: { cell: 'px-6 py-4', header: 'px-6 py-4', mobile: 'p-6' },
|
md: { cell: 'px-4 py-[14px]', header: 'px-4 py-[12px]', mobile: 'p-5' },
|
||||||
lg: { cell: 'px-6 py-5', header: 'px-6 py-5', mobile: 'p-8' },
|
lg: { cell: 'px-4 py-[18px]', header: 'px-4 py-[14px]', mobile: 'p-6' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const Table = ({
|
const Table = ({
|
||||||
@@ -21,7 +21,7 @@ const Table = ({
|
|||||||
getRowProps,
|
getRowProps,
|
||||||
emptyMessage = 'Aucune donnée',
|
emptyMessage = 'Aucune donnée',
|
||||||
emptyDescription = 'Aucun élément à afficher',
|
emptyDescription = 'Aucun élément à afficher',
|
||||||
size = 'md',
|
size = 'sm',
|
||||||
className = '',
|
className = '',
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
@@ -172,7 +172,7 @@ const Table = ({
|
|||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<th
|
<th
|
||||||
key={column.key}
|
key={column.key}
|
||||||
className={`${sizeClasses.header} ${column.headerAlign === 'right' ? 'text-right' : 'text-left'} text-xs font-medium text-neutral-600 dark:text-neutral-300 uppercase tracking-wider ${
|
className={`${sizeClasses.header} ${column.headerAlign === 'right' ? 'text-right' : 'text-left'} text-[11px] font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-[0.04em] ${
|
||||||
column.sortable ? 'cursor-pointer hover:text-neutral-900 dark:hover:text-white transition-colors' : ''
|
column.sortable ? 'cursor-pointer hover:text-neutral-900 dark:hover:text-white transition-colors' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={column.sortable && onSort ? () => onSort(column.key) : undefined}
|
onClick={column.sortable && onSort ? () => onSort(column.key) : undefined}
|
||||||
@@ -185,7 +185,7 @@ const Table = ({
|
|||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-neutral-200 dark:divide-neutral-700/30">
|
<tbody className="divide-y divide-neutral-200 dark:divide-neutral-700/30 text-[13px]">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
Array.from({ length: 5 }).map((_, index) => (
|
Array.from({ length: 5 }).map((_, index) => (
|
||||||
<SkeletonRow key={index} />
|
<SkeletonRow key={index} />
|
||||||
|
|||||||
Reference in New Issue
Block a user