feat(ux-ui): update layout, providers and config for UX remediation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a3b61b8ae4
commit
6568b9bfed
@ -16,36 +16,73 @@ import {
|
|||||||
ChevronDown,
|
ChevronDown,
|
||||||
LogOut,
|
LogOut,
|
||||||
Users2,
|
Users2,
|
||||||
|
Search,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { cn } from '@utils/cn';
|
import { cn } from '@utils/cn';
|
||||||
import { useUIStore } from '@stores/useUIStore';
|
import { useUIStore } from '@stores/useUIStore';
|
||||||
import { useAuthStore } from '@stores/useAuthStore';
|
import { useAuthStore } from '@stores/useAuthStore';
|
||||||
import { useIsMobile } from '@hooks/useMediaQuery';
|
import { useIsMobile } from '@hooks/useMediaQuery';
|
||||||
|
import { useFilteredNavigation, type NavigationItem } from '@hooks/useFilteredNavigation';
|
||||||
|
import { ThemeToggle } from '@components/atoms/ThemeToggle';
|
||||||
|
import { CommandPaletteWithRouter, useCommandPalette } from '@components/organisms/CommandPalette';
|
||||||
|
|
||||||
interface DashboardLayoutProps {
|
interface DashboardLayoutProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigation = [
|
/**
|
||||||
|
* Search button component that opens the command palette
|
||||||
|
*/
|
||||||
|
function SearchButton() {
|
||||||
|
const { open } = useCommandPalette();
|
||||||
|
const isMac = typeof navigator !== 'undefined' && navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={open}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-2 rounded-lg px-3 py-1.5',
|
||||||
|
'border border-gray-200 bg-gray-50 text-gray-500',
|
||||||
|
'hover:bg-gray-100 hover:text-gray-700',
|
||||||
|
'dark:border-gray-600 dark:bg-gray-700 dark:text-gray-400',
|
||||||
|
'dark:hover:bg-gray-600 dark:hover:text-gray-300',
|
||||||
|
'transition-colors duration-150'
|
||||||
|
)}
|
||||||
|
aria-label="Buscar"
|
||||||
|
>
|
||||||
|
<Search className="h-4 w-4" />
|
||||||
|
<span className="hidden text-sm sm:inline">Buscar...</span>
|
||||||
|
<kbd className="hidden rounded border border-gray-300 bg-white px-1.5 py-0.5 text-[10px] font-medium text-gray-500 sm:inline dark:border-gray-500 dark:bg-gray-600 dark:text-gray-400">
|
||||||
|
{isMac ? '⌘' : 'Ctrl'}+K
|
||||||
|
</kbd>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigation: NavigationItem[] = [
|
||||||
{ name: 'Dashboard', href: '/dashboard', icon: Home },
|
{ name: 'Dashboard', href: '/dashboard', icon: Home },
|
||||||
{ name: 'Usuarios', href: '/users', icon: Users },
|
{ name: 'Usuarios', href: '/users', icon: Users, module: 'users' },
|
||||||
{ name: 'Empresas', href: '/companies', icon: Building2 },
|
{ name: 'Empresas', href: '/companies', icon: Building2, module: 'companies' },
|
||||||
{ name: 'Partners', href: '/partners', icon: Users2 },
|
{ name: 'Partners', href: '/partners', icon: Users2, module: 'partners' },
|
||||||
{ name: 'Inventario', href: '/inventory', icon: Package },
|
{ name: 'Inventario', href: '/inventory', icon: Package, module: 'inventory' },
|
||||||
{ name: 'Ventas', href: '/sales', icon: ShoppingCart },
|
{ name: 'Ventas', href: '/sales', icon: ShoppingCart, module: 'sales' },
|
||||||
{ name: 'Compras', href: '/purchases', icon: ShoppingCart },
|
{ name: 'Compras', href: '/purchases', icon: ShoppingCart, module: 'purchases' },
|
||||||
{ name: 'Finanzas', href: '/financial', icon: Receipt },
|
{ name: 'Finanzas', href: '/financial', icon: Receipt, module: 'finance' },
|
||||||
{ name: 'Proyectos', href: '/projects', icon: FolderKanban },
|
{ name: 'Proyectos', href: '/projects', icon: FolderKanban, module: 'projects' },
|
||||||
{ name: 'CRM', href: '/crm', icon: UserCircle },
|
{ name: 'CRM', href: '/crm', icon: UserCircle, module: 'crm' },
|
||||||
{ name: 'RRHH', href: '/hr', icon: Users },
|
{ name: 'RRHH', href: '/hr', icon: Users, module: 'hr' },
|
||||||
{ name: 'Configuración', href: '/settings', icon: Settings },
|
{ name: 'Configuración', href: '/settings', icon: Settings, roles: ['admin', 'super_admin'] },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function DashboardLayout({ children }: DashboardLayoutProps) {
|
/**
|
||||||
|
* Internal layout component (used inside CommandPaletteWithRouter)
|
||||||
|
*/
|
||||||
|
function DashboardLayoutInner({ children }: DashboardLayoutProps) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const { sidebarOpen, sidebarCollapsed, toggleSidebar, setSidebarOpen, setIsMobile } = useUIStore();
|
const { sidebarOpen, sidebarCollapsed, toggleSidebar, setSidebarOpen, setIsMobile } = useUIStore();
|
||||||
const { user, logout } = useAuthStore();
|
const { user, logout } = useAuthStore();
|
||||||
|
const { items: filteredNavigation, isLoading: isNavigationLoading } = useFilteredNavigation(navigation);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsMobile(isMobile);
|
setIsMobile(isMobile);
|
||||||
@ -59,11 +96,11 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
}, [location.pathname, isMobile, setSidebarOpen]);
|
}, [location.pathname, isMobile, setSidebarOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
||||||
{/* Mobile sidebar backdrop */}
|
{/* Mobile sidebar backdrop */}
|
||||||
{isMobile && sidebarOpen && (
|
{isMobile && sidebarOpen && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-40 bg-gray-600/75"
|
className="fixed inset-0 z-40 bg-gray-600/75 dark:bg-gray-900/80"
|
||||||
onClick={() => setSidebarOpen(false)}
|
onClick={() => setSidebarOpen(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -71,7 +108,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<aside
|
<aside
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed inset-y-0 left-0 z-50 flex flex-col bg-white shadow-lg transition-all duration-300',
|
'fixed inset-y-0 left-0 z-50 flex flex-col bg-white shadow-lg transition-all duration-300 dark:bg-gray-800 dark:shadow-gray-900/50',
|
||||||
isMobile
|
isMobile
|
||||||
? sidebarOpen
|
? sidebarOpen
|
||||||
? 'translate-x-0'
|
? 'translate-x-0'
|
||||||
@ -82,17 +119,17 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="flex h-16 items-center justify-between border-b px-4">
|
<div className="flex h-16 items-center justify-between border-b px-4 dark:border-gray-700">
|
||||||
{(!sidebarCollapsed || isMobile) && (
|
{(!sidebarCollapsed || isMobile) && (
|
||||||
<Link to="/dashboard" className="flex items-center">
|
<Link to="/dashboard" className="flex items-center">
|
||||||
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary-600">
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary-600">
|
||||||
<span className="text-lg font-bold text-white">E</span>
|
<span className="text-lg font-bold text-white">E</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-2 text-lg font-bold text-gray-900">ERP</span>
|
<span className="ml-2 text-lg font-bold text-gray-900 dark:text-white">ERP</span>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<button onClick={() => setSidebarOpen(false)} className="p-2">
|
<button onClick={() => setSidebarOpen(false)} className="p-2 dark:text-gray-400" aria-label="Cerrar menú">
|
||||||
<X className="h-5 w-5" />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -100,45 +137,53 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<nav className="flex-1 space-y-1 overflow-y-auto p-2">
|
<nav className="flex-1 space-y-1 overflow-y-auto p-2">
|
||||||
{navigation.map((item) => {
|
{isNavigationLoading ? (
|
||||||
const isActive = location.pathname.startsWith(item.href);
|
<div className="flex items-center justify-center py-4">
|
||||||
return (
|
<div className="h-5 w-5 animate-spin rounded-full border-2 border-primary-600 border-t-transparent" />
|
||||||
<Link
|
</div>
|
||||||
key={item.name}
|
) : (
|
||||||
to={item.href}
|
filteredNavigation.map((item) => {
|
||||||
className={cn(
|
const isActive = location.pathname.startsWith(item.href);
|
||||||
'flex items-center rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
const Icon = item.icon;
|
||||||
isActive
|
return (
|
||||||
? 'bg-primary-50 text-primary-700'
|
<Link
|
||||||
: 'text-gray-700 hover:bg-gray-100'
|
key={item.name}
|
||||||
)}
|
to={item.href}
|
||||||
>
|
className={cn(
|
||||||
<item.icon className={cn('h-5 w-5 flex-shrink-0', isActive ? 'text-primary-600' : 'text-gray-400')} />
|
'flex items-center rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||||
{(!sidebarCollapsed || isMobile) && (
|
isActive
|
||||||
<span className="ml-3">{item.name}</span>
|
? 'bg-primary-50 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400'
|
||||||
)}
|
: 'text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'
|
||||||
</Link>
|
)}
|
||||||
);
|
>
|
||||||
})}
|
{Icon && <Icon className={cn('h-5 w-5 flex-shrink-0', isActive ? 'text-primary-600 dark:text-primary-400' : 'text-gray-400 dark:text-gray-500')} />}
|
||||||
|
{(!sidebarCollapsed || isMobile) && (
|
||||||
|
<span className="ml-3">{item.name}</span>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* User menu */}
|
{/* User menu */}
|
||||||
<div className="border-t p-4">
|
<div className="border-t p-4 dark:border-gray-700">
|
||||||
{(!sidebarCollapsed || isMobile) ? (
|
{(!sidebarCollapsed || isMobile) ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="flex h-9 w-9 items-center justify-center rounded-full bg-primary-100 text-primary-700">
|
<div className="flex h-9 w-9 items-center justify-center rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/30 dark:text-primary-400">
|
||||||
{user?.firstName?.[0]}{user?.lastName?.[0]}
|
{user?.firstName?.[0]}{user?.lastName?.[0]}
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 flex-1 overflow-hidden">
|
<div className="ml-3 flex-1 overflow-hidden">
|
||||||
<p className="truncate text-sm font-medium text-gray-900">
|
<p className="truncate text-sm font-medium text-gray-900 dark:text-white">
|
||||||
{user?.firstName} {user?.lastName}
|
{user?.firstName} {user?.lastName}
|
||||||
</p>
|
</p>
|
||||||
<p className="truncate text-xs text-gray-500">{user?.email}</p>
|
<p className="truncate text-xs text-gray-500 dark:text-gray-400">{user?.email}</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={logout}
|
onClick={logout}
|
||||||
className="p-2 text-gray-400 hover:text-gray-600"
|
className="p-2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300"
|
||||||
title="Cerrar sesión"
|
title="Cerrar sesión"
|
||||||
|
aria-label="Cerrar sesión"
|
||||||
>
|
>
|
||||||
<LogOut className="h-4 w-4" />
|
<LogOut className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
@ -146,8 +191,9 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={logout}
|
onClick={logout}
|
||||||
className="flex w-full items-center justify-center p-2 text-gray-400 hover:text-gray-600"
|
className="flex w-full items-center justify-center p-2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300"
|
||||||
title="Cerrar sesión"
|
title="Cerrar sesión"
|
||||||
|
aria-label="Cerrar sesión"
|
||||||
>
|
>
|
||||||
<LogOut className="h-5 w-5" />
|
<LogOut className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
@ -163,23 +209,28 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Top bar */}
|
{/* Top bar */}
|
||||||
<header className="sticky top-0 z-30 flex h-16 items-center justify-between border-b bg-white px-4 shadow-sm">
|
<header className="sticky top-0 z-30 flex h-16 items-center justify-between border-b bg-white px-4 shadow-sm dark:border-gray-700 dark:bg-gray-800">
|
||||||
<button
|
<div className="flex items-center gap-4">
|
||||||
onClick={toggleSidebar}
|
<button
|
||||||
className="rounded-lg p-2 hover:bg-gray-100"
|
onClick={toggleSidebar}
|
||||||
>
|
className="rounded-lg p-2 hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||||
<Menu className="h-5 w-5" />
|
aria-label="Abrir menú"
|
||||||
</button>
|
>
|
||||||
|
<Menu className="h-5 w-5 dark:text-gray-400" />
|
||||||
|
</button>
|
||||||
|
<SearchButton />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<button className="relative rounded-lg p-2 hover:bg-gray-100">
|
<ThemeToggle />
|
||||||
<Bell className="h-5 w-5 text-gray-500" />
|
<button className="relative rounded-lg p-2 hover:bg-gray-100 dark:hover:bg-gray-700" aria-label="Notificaciones">
|
||||||
|
<Bell className="h-5 w-5 text-gray-500 dark:text-gray-400" />
|
||||||
<span className="absolute right-1 top-1 flex h-4 w-4 items-center justify-center rounded-full bg-danger-500 text-xs text-white">
|
<span className="absolute right-1 top-1 flex h-4 w-4 items-center justify-center rounded-full bg-danger-500 text-xs text-white">
|
||||||
3
|
3
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary-100 text-sm font-medium text-primary-700">
|
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary-100 text-sm font-medium text-primary-700 dark:bg-primary-900/30 dark:text-primary-400">
|
||||||
{user?.firstName?.[0]}{user?.lastName?.[0]}
|
{user?.firstName?.[0]}{user?.lastName?.[0]}
|
||||||
</div>
|
</div>
|
||||||
<ChevronDown className="h-4 w-4 text-gray-400" />
|
<ChevronDown className="h-4 w-4 text-gray-400" />
|
||||||
@ -193,3 +244,15 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dashboard Layout with Command Palette support
|
||||||
|
* Wraps the layout with CommandPaletteWithRouter for Cmd+K / Ctrl+K navigation
|
||||||
|
*/
|
||||||
|
export function DashboardLayout({ children }: DashboardLayoutProps) {
|
||||||
|
return (
|
||||||
|
<CommandPaletteWithRouter>
|
||||||
|
<DashboardLayoutInner>{children}</DashboardLayoutInner>
|
||||||
|
</CommandPaletteWithRouter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { ToastContainer } from '@components/organisms/Toast';
|
import { ToastContainer } from '@components/organisms/Toast';
|
||||||
|
import { ThemeProvider } from '@shared/providers/ThemeProvider';
|
||||||
|
|
||||||
interface AppProvidersProps {
|
interface AppProvidersProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -7,9 +8,9 @@ interface AppProvidersProps {
|
|||||||
|
|
||||||
export function AppProviders({ children }: AppProvidersProps) {
|
export function AppProviders({ children }: AppProvidersProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<ThemeProvider>
|
||||||
{children}
|
{children}
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
</>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
362
src/index.css
362
src/index.css
@ -2,39 +2,240 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
CSS VARIABLES - Design Tokens para Runtime Theming
|
||||||
|
============================================================================= */
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
|
:root {
|
||||||
|
/* =========================================================================
|
||||||
|
RGB VALUES FOR TAILWIND ALPHA SUPPORT
|
||||||
|
Format: R G B (space-separated for rgb(var(--color) / alpha) syntax)
|
||||||
|
========================================================================= */
|
||||||
|
|
||||||
|
/* Primary Palette - ISEM Blue (RGB values) */
|
||||||
|
--color-primary-50: 230 243 255;
|
||||||
|
--color-primary-100: 204 231 255;
|
||||||
|
--color-primary-200: 153 207 255;
|
||||||
|
--color-primary-300: 102 183 255;
|
||||||
|
--color-primary-400: 51 159 255;
|
||||||
|
--color-primary-500: 0 97 168;
|
||||||
|
--color-primary-600: 0 77 134;
|
||||||
|
--color-primary-700: 0 58 101;
|
||||||
|
--color-primary-800: 0 38 67;
|
||||||
|
--color-primary-900: 0 19 34;
|
||||||
|
|
||||||
|
/* Secondary Palette - ISEM Green (RGB values) */
|
||||||
|
--color-secondary-50: 230 255 245;
|
||||||
|
--color-secondary-100: 204 255 235;
|
||||||
|
--color-secondary-200: 153 255 214;
|
||||||
|
--color-secondary-300: 102 255 194;
|
||||||
|
--color-secondary-400: 51 255 173;
|
||||||
|
--color-secondary-500: 0 168 104;
|
||||||
|
--color-secondary-600: 0 134 83;
|
||||||
|
--color-secondary-700: 0 101 63;
|
||||||
|
--color-secondary-800: 0 67 42;
|
||||||
|
--color-secondary-900: 0 34 21;
|
||||||
|
|
||||||
|
/* Success Palette (RGB values) */
|
||||||
|
--color-success-50: 209 231 221;
|
||||||
|
--color-success-100: 209 231 221;
|
||||||
|
--color-success-500: 25 135 84;
|
||||||
|
--color-success-600: 21 115 71;
|
||||||
|
--color-success-700: 15 81 50;
|
||||||
|
|
||||||
|
/* Warning Palette (RGB values) */
|
||||||
|
--color-warning-50: 255 243 205;
|
||||||
|
--color-warning-100: 255 243 205;
|
||||||
|
--color-warning-500: 255 193 7;
|
||||||
|
--color-warning-600: 224 168 0;
|
||||||
|
--color-warning-700: 102 77 3;
|
||||||
|
|
||||||
|
/* Danger Palette (RGB values) */
|
||||||
|
--color-danger-50: 248 215 218;
|
||||||
|
--color-danger-100: 248 215 218;
|
||||||
|
--color-danger-500: 220 53 69;
|
||||||
|
--color-danger-600: 187 45 59;
|
||||||
|
--color-danger-700: 132 32 41;
|
||||||
|
|
||||||
|
/* Info Palette (RGB values) */
|
||||||
|
--color-info-50: 207 244 252;
|
||||||
|
--color-info-100: 207 244 252;
|
||||||
|
--color-info-500: 13 202 240;
|
||||||
|
--color-info-600: 10 162 192;
|
||||||
|
--color-info-700: 5 81 96;
|
||||||
|
|
||||||
|
/* Background Colors (RGB values) - Light Theme */
|
||||||
|
--color-background: 255 255 255;
|
||||||
|
--color-background-subtle: 248 249 251;
|
||||||
|
--color-background-muted: 241 243 245;
|
||||||
|
--color-background-emphasis: 233 236 239;
|
||||||
|
|
||||||
|
/* Foreground Colors (RGB values) - Light Theme */
|
||||||
|
--color-foreground: 33 37 41;
|
||||||
|
--color-foreground-muted: 108 117 125;
|
||||||
|
--color-foreground-subtle: 173 181 189;
|
||||||
|
|
||||||
|
/* Border Colors (RGB values) - Light Theme */
|
||||||
|
--color-border: 222 226 230;
|
||||||
|
--color-border-subtle: 233 236 239;
|
||||||
|
--color-border-emphasis: 206 212 218;
|
||||||
|
|
||||||
|
/* Surface Colors (RGB values) - Light Theme */
|
||||||
|
--color-surface: 249 250 251;
|
||||||
|
--color-surface-hover: 243 244 246;
|
||||||
|
--color-surface-card: 255 255 255;
|
||||||
|
--color-surface-popover: 255 255 255;
|
||||||
|
--color-surface-modal: 255 255 255;
|
||||||
|
--color-surface-dropdown: 255 255 255;
|
||||||
|
|
||||||
|
/* =========================================================================
|
||||||
|
LEGACY HEX VALUES (Backward Compatibility)
|
||||||
|
Keep these for direct CSS usage and gradual migration
|
||||||
|
========================================================================= */
|
||||||
|
|
||||||
|
/* Colores de Marca ISEM (HEX) */
|
||||||
|
--color-brand-primary: #0061A8;
|
||||||
|
--color-brand-secondary: #00A868;
|
||||||
|
|
||||||
|
/* Colores Semanticos (HEX) */
|
||||||
|
--color-success-hex: #198754;
|
||||||
|
--color-success-light-hex: #D1E7DD;
|
||||||
|
--color-success-dark-hex: #0F5132;
|
||||||
|
--color-warning-hex: #FFC107;
|
||||||
|
--color-warning-light-hex: #FFF3CD;
|
||||||
|
--color-warning-dark-hex: #664D03;
|
||||||
|
--color-danger-hex: #DC3545;
|
||||||
|
--color-danger-light-hex: #F8D7DA;
|
||||||
|
--color-danger-dark-hex: #842029;
|
||||||
|
--color-info-hex: #0DCAF0;
|
||||||
|
--color-info-light-hex: #CFF4FC;
|
||||||
|
--color-info-dark-hex: #055160;
|
||||||
|
|
||||||
|
/* Semantic Aliases (HEX for legacy components) */
|
||||||
|
--color-success: #198754;
|
||||||
|
--color-success-light: #D1E7DD;
|
||||||
|
--color-success-dark: #0F5132;
|
||||||
|
--color-warning: #FFC107;
|
||||||
|
--color-warning-light: #FFF3CD;
|
||||||
|
--color-warning-dark: #664D03;
|
||||||
|
--color-danger: #DC3545;
|
||||||
|
--color-danger-light: #F8D7DA;
|
||||||
|
--color-danger-dark: #842029;
|
||||||
|
--color-info: #0DCAF0;
|
||||||
|
--color-info-light: #CFF4FC;
|
||||||
|
--color-info-dark: #055160;
|
||||||
|
|
||||||
|
/* Primary/Secondary HEX aliases */
|
||||||
|
--color-primary-hex: var(--color-brand-primary);
|
||||||
|
--color-secondary-hex: var(--color-brand-secondary);
|
||||||
|
|
||||||
|
/* Sombras Tema Claro */
|
||||||
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--shadow-default: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||||
|
|
||||||
|
/* Tipografia */
|
||||||
|
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, Monaco, monospace;
|
||||||
|
|
||||||
|
/* Animaciones */
|
||||||
|
--duration-fast: 150ms;
|
||||||
|
--duration-normal: 200ms;
|
||||||
|
--duration-slow: 300ms;
|
||||||
|
--easing-default: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
|
||||||
|
/* Bordes */
|
||||||
|
--radius-sm: 0.125rem;
|
||||||
|
--radius-default: 0.25rem;
|
||||||
|
--radius-md: 0.375rem;
|
||||||
|
--radius-lg: 0.5rem;
|
||||||
|
--radius-xl: 0.75rem;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tema Oscuro */
|
||||||
|
.dark {
|
||||||
|
/* Background Colors (RGB values) - Dark Theme */
|
||||||
|
--color-background: 27 30 35;
|
||||||
|
--color-background-subtle: 33 37 41;
|
||||||
|
--color-background-muted: 45 49 57;
|
||||||
|
--color-background-emphasis: 52 58 64;
|
||||||
|
|
||||||
|
/* Foreground Colors (RGB values) - Dark Theme */
|
||||||
|
--color-foreground: 236 236 236;
|
||||||
|
--color-foreground-muted: 160 160 160;
|
||||||
|
--color-foreground-subtle: 108 117 125;
|
||||||
|
|
||||||
|
/* Border Colors (RGB values) - Dark Theme */
|
||||||
|
--color-border: 73 80 87;
|
||||||
|
--color-border-subtle: 52 58 64;
|
||||||
|
--color-border-emphasis: 108 117 125;
|
||||||
|
|
||||||
|
/* Surface Colors (RGB values) - Dark Theme */
|
||||||
|
--color-surface: 31 41 55;
|
||||||
|
--color-surface-hover: 55 65 81;
|
||||||
|
--color-surface-card: 45 49 57;
|
||||||
|
--color-surface-popover: 52 58 64;
|
||||||
|
--color-surface-modal: 45 49 57;
|
||||||
|
--color-surface-dropdown: 52 58 64;
|
||||||
|
|
||||||
|
/* Sombras Tema Oscuro */
|
||||||
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
|
||||||
|
--shadow-default: 0 1px 3px 0 rgb(0 0 0 / 0.4), 0 1px 2px -1px rgb(0 0 0 / 0.4);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.4);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.4);
|
||||||
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.4), 0 8px 10px -6px rgb(0 0 0 / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@apply antialiased;
|
@apply antialiased;
|
||||||
|
font-family: var(--font-sans);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-gray-50 text-gray-900;
|
background-color: rgb(var(--color-background));
|
||||||
|
color: rgb(var(--color-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@apply border-gray-200;
|
border-color: rgb(var(--color-border));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
COMPONENTES BASE
|
||||||
|
============================================================================= */
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
/* Botones */
|
||||||
.btn {
|
.btn {
|
||||||
@apply inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50;
|
@apply inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50;
|
||||||
|
transition-duration: var(--duration-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
@apply bg-primary-600 text-white hover:bg-primary-700 focus-visible:ring-primary-500;
|
@apply bg-primary-500 text-white hover:bg-primary-600 focus-visible:ring-primary-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
@apply bg-secondary-100 text-secondary-900 hover:bg-secondary-200 focus-visible:ring-secondary-500;
|
@apply bg-secondary-500 text-white hover:bg-secondary-600 focus-visible:ring-secondary-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-outline {
|
.btn-outline {
|
||||||
@apply border border-gray-300 bg-white hover:bg-gray-50 focus-visible:ring-gray-500;
|
@apply border border-border-emphasis bg-transparent hover:bg-background-muted focus-visible:ring-primary-500;
|
||||||
|
color: rgb(var(--color-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
@apply bg-transparent hover:bg-background-muted focus-visible:ring-primary-500;
|
||||||
|
color: rgb(var(--color-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
@apply bg-danger-600 text-white hover:bg-danger-700 focus-visible:ring-danger-500;
|
@apply bg-danger-500 text-white hover:bg-danger-600 focus-visible:ring-danger-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm {
|
.btn-sm {
|
||||||
@ -49,31 +250,125 @@
|
|||||||
@apply h-12 px-6 text-lg;
|
@apply h-12 px-6 text-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inputs */
|
||||||
.input {
|
.input {
|
||||||
@apply block w-full rounded-md border border-gray-300 px-3 py-2 text-sm placeholder-gray-400 shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500;
|
@apply block w-full rounded-md border px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50;
|
||||||
|
background-color: rgb(var(--color-background));
|
||||||
|
border-color: rgb(var(--color-border));
|
||||||
|
color: rgb(var(--color-foreground));
|
||||||
|
transition-duration: var(--duration-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input::placeholder {
|
||||||
|
color: rgb(var(--color-foreground-subtle));
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
border-color: rgb(var(--color-primary-500));
|
||||||
|
--tw-ring-color: rgb(var(--color-primary-500));
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-error {
|
.input-error {
|
||||||
@apply border-danger-500 focus:border-danger-500 focus:ring-danger-500;
|
@apply border-danger-500 focus:border-danger-500 focus:ring-danger-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Labels */
|
||||||
.label {
|
.label {
|
||||||
@apply block text-sm font-medium text-gray-700;
|
@apply block text-sm font-medium;
|
||||||
|
color: rgb(var(--color-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cards */
|
||||||
.card {
|
.card {
|
||||||
@apply rounded-lg border bg-white shadow-sm;
|
@apply rounded-lg border;
|
||||||
|
background-color: rgb(var(--color-surface-card));
|
||||||
|
border-color: rgb(var(--color-border));
|
||||||
|
box-shadow: var(--shadow-default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Links */
|
||||||
.link {
|
.link {
|
||||||
@apply text-primary-600 hover:text-primary-700 hover:underline;
|
@apply hover:underline;
|
||||||
|
color: rgb(var(--color-primary-500));
|
||||||
|
transition-duration: var(--duration-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: rgb(var(--color-primary-600));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Badges */
|
||||||
|
.badge {
|
||||||
|
@apply inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-primary {
|
||||||
|
@apply bg-primary-100 text-primary-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-secondary {
|
||||||
|
@apply bg-secondary-100 text-secondary-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-success {
|
||||||
|
background-color: var(--color-success-light);
|
||||||
|
color: var(--color-success-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-warning {
|
||||||
|
background-color: var(--color-warning-light);
|
||||||
|
color: var(--color-warning-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-danger {
|
||||||
|
background-color: var(--color-danger-light);
|
||||||
|
color: var(--color-danger-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-info {
|
||||||
|
background-color: var(--color-info-light);
|
||||||
|
color: var(--color-info-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alerts */
|
||||||
|
.alert {
|
||||||
|
@apply rounded-lg border p-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background-color: var(--color-success-light);
|
||||||
|
border-color: var(--color-success);
|
||||||
|
color: var(--color-success-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-warning {
|
||||||
|
background-color: var(--color-warning-light);
|
||||||
|
border-color: var(--color-warning);
|
||||||
|
color: var(--color-warning-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-danger {
|
||||||
|
background-color: var(--color-danger-light);
|
||||||
|
border-color: var(--color-danger);
|
||||||
|
color: var(--color-danger-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-info {
|
||||||
|
background-color: var(--color-info-light);
|
||||||
|
border-color: var(--color-info);
|
||||||
|
color: var(--color-info-dark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
UTILIDADES
|
||||||
|
============================================================================= */
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
|
/* Scrollbar personalizado */
|
||||||
.scrollbar-thin {
|
.scrollbar-thin {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: theme('colors.gray.300') transparent;
|
scrollbar-color: rgb(var(--color-border)) transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-thin::-webkit-scrollbar {
|
.scrollbar-thin::-webkit-scrollbar {
|
||||||
@ -86,7 +381,50 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
background-color: theme('colors.gray.300');
|
background-color: rgb(var(--color-border));
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Focus visible mejorado */
|
||||||
|
.focus-ring {
|
||||||
|
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2;
|
||||||
|
--tw-ring-color: rgb(var(--color-primary-500));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Texto truncado */
|
||||||
|
.truncate-2 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.truncate-3 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transiciones suaves */
|
||||||
|
.transition-theme {
|
||||||
|
transition-property: background-color, border-color, color, fill, stroke;
|
||||||
|
transition-duration: var(--duration-normal);
|
||||||
|
transition-timing-function: var(--easing-default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
MULTI-TENANT THEMING (Placeholder para override por tenant)
|
||||||
|
============================================================================= */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Los tenants pueden sobreescribir estas variables via JS:
|
||||||
|
* document.documentElement.style.setProperty('--color-brand-primary', '#FF0000');
|
||||||
|
*
|
||||||
|
* O cargar un CSS adicional con:
|
||||||
|
* [data-tenant="empresa-abc"] {
|
||||||
|
* --color-brand-primary: #123456;
|
||||||
|
* --color-brand-secondary: #654321;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|||||||
@ -1,78 +1,234 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
|
||||||
|
// Helper function to create CSS variable color with alpha support
|
||||||
|
const withAlpha = (variableName) => `rgb(var(${variableName}) / <alpha-value>)`
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
content: [
|
content: [
|
||||||
"./index.html",
|
"./index.html",
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
|
darkMode: 'class',
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
|
// =================================================================
|
||||||
|
// CSS VARIABLE COLORS (Dynamic Theming Support)
|
||||||
|
// These reference CSS variables defined in index.css
|
||||||
|
// Supports alpha via: bg-primary-500/50, text-foreground/80, etc.
|
||||||
|
// =================================================================
|
||||||
|
|
||||||
|
// Primary Palette - Uses CSS Variables
|
||||||
primary: {
|
primary: {
|
||||||
50: '#f0f9ff',
|
50: withAlpha('--color-primary-50'),
|
||||||
100: '#e0f2fe',
|
100: withAlpha('--color-primary-100'),
|
||||||
200: '#bae6fd',
|
200: withAlpha('--color-primary-200'),
|
||||||
300: '#7dd3fc',
|
300: withAlpha('--color-primary-300'),
|
||||||
400: '#38bdf8',
|
400: withAlpha('--color-primary-400'),
|
||||||
500: '#0ea5e9',
|
500: withAlpha('--color-primary-500'),
|
||||||
600: '#0284c7',
|
600: withAlpha('--color-primary-600'),
|
||||||
700: '#0369a1',
|
700: withAlpha('--color-primary-700'),
|
||||||
800: '#075985',
|
800: withAlpha('--color-primary-800'),
|
||||||
900: '#0c4a6e',
|
900: withAlpha('--color-primary-900'),
|
||||||
950: '#082f49',
|
DEFAULT: withAlpha('--color-primary-500'),
|
||||||
},
|
},
|
||||||
|
// Secondary Palette - Uses CSS Variables
|
||||||
secondary: {
|
secondary: {
|
||||||
50: '#f8fafc',
|
50: withAlpha('--color-secondary-50'),
|
||||||
100: '#f1f5f9',
|
100: withAlpha('--color-secondary-100'),
|
||||||
200: '#e2e8f0',
|
200: withAlpha('--color-secondary-200'),
|
||||||
300: '#cbd5e1',
|
300: withAlpha('--color-secondary-300'),
|
||||||
400: '#94a3b8',
|
400: withAlpha('--color-secondary-400'),
|
||||||
500: '#64748b',
|
500: withAlpha('--color-secondary-500'),
|
||||||
600: '#475569',
|
600: withAlpha('--color-secondary-600'),
|
||||||
700: '#334155',
|
700: withAlpha('--color-secondary-700'),
|
||||||
800: '#1e293b',
|
800: withAlpha('--color-secondary-800'),
|
||||||
900: '#0f172a',
|
900: withAlpha('--color-secondary-900'),
|
||||||
950: '#020617',
|
DEFAULT: withAlpha('--color-secondary-500'),
|
||||||
},
|
},
|
||||||
|
// Semantic Colors - Uses CSS Variables
|
||||||
success: {
|
success: {
|
||||||
50: '#f0fdf4',
|
50: withAlpha('--color-success-50'),
|
||||||
500: '#22c55e',
|
100: withAlpha('--color-success-100'),
|
||||||
600: '#16a34a',
|
500: withAlpha('--color-success-500'),
|
||||||
700: '#15803d',
|
600: withAlpha('--color-success-600'),
|
||||||
|
700: withAlpha('--color-success-700'),
|
||||||
|
DEFAULT: withAlpha('--color-success-500'),
|
||||||
|
light: withAlpha('--color-success-50'),
|
||||||
|
dark: withAlpha('--color-success-700'),
|
||||||
},
|
},
|
||||||
warning: {
|
warning: {
|
||||||
50: '#fffbeb',
|
50: withAlpha('--color-warning-50'),
|
||||||
500: '#f59e0b',
|
100: withAlpha('--color-warning-100'),
|
||||||
600: '#d97706',
|
500: withAlpha('--color-warning-500'),
|
||||||
700: '#b45309',
|
600: withAlpha('--color-warning-600'),
|
||||||
|
700: withAlpha('--color-warning-700'),
|
||||||
|
DEFAULT: withAlpha('--color-warning-500'),
|
||||||
|
light: withAlpha('--color-warning-50'),
|
||||||
|
dark: withAlpha('--color-warning-700'),
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
50: '#fef2f2',
|
50: withAlpha('--color-danger-50'),
|
||||||
500: '#ef4444',
|
100: withAlpha('--color-danger-100'),
|
||||||
600: '#dc2626',
|
500: withAlpha('--color-danger-500'),
|
||||||
700: '#b91c1c',
|
600: withAlpha('--color-danger-600'),
|
||||||
|
700: withAlpha('--color-danger-700'),
|
||||||
|
DEFAULT: withAlpha('--color-danger-500'),
|
||||||
|
light: withAlpha('--color-danger-50'),
|
||||||
|
dark: withAlpha('--color-danger-700'),
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
50: withAlpha('--color-info-50'),
|
||||||
|
100: withAlpha('--color-info-100'),
|
||||||
|
500: withAlpha('--color-info-500'),
|
||||||
|
600: withAlpha('--color-info-600'),
|
||||||
|
700: withAlpha('--color-info-700'),
|
||||||
|
DEFAULT: withAlpha('--color-info-500'),
|
||||||
|
light: withAlpha('--color-info-50'),
|
||||||
|
dark: withAlpha('--color-info-700'),
|
||||||
|
},
|
||||||
|
// Neutral Colors - Uses CSS Variables (auto dark/light)
|
||||||
|
background: {
|
||||||
|
DEFAULT: withAlpha('--color-background'),
|
||||||
|
subtle: withAlpha('--color-background-subtle'),
|
||||||
|
muted: withAlpha('--color-background-muted'),
|
||||||
|
emphasis: withAlpha('--color-background-emphasis'),
|
||||||
|
},
|
||||||
|
foreground: {
|
||||||
|
DEFAULT: withAlpha('--color-foreground'),
|
||||||
|
muted: withAlpha('--color-foreground-muted'),
|
||||||
|
subtle: withAlpha('--color-foreground-subtle'),
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
DEFAULT: withAlpha('--color-border'),
|
||||||
|
subtle: withAlpha('--color-border-subtle'),
|
||||||
|
emphasis: withAlpha('--color-border-emphasis'),
|
||||||
|
},
|
||||||
|
surface: {
|
||||||
|
DEFAULT: withAlpha('--color-surface'),
|
||||||
|
hover: withAlpha('--color-surface-hover'),
|
||||||
|
card: withAlpha('--color-surface-card'),
|
||||||
|
popover: withAlpha('--color-surface-popover'),
|
||||||
|
modal: withAlpha('--color-surface-modal'),
|
||||||
|
dropdown: withAlpha('--color-surface-dropdown'),
|
||||||
|
},
|
||||||
|
|
||||||
|
// =================================================================
|
||||||
|
// STATIC HEX COLORS (Backward Compatibility)
|
||||||
|
// Keep these for legacy code - prefix with 'static-'
|
||||||
|
// =================================================================
|
||||||
|
'static-primary': {
|
||||||
|
50: '#E6F3FF',
|
||||||
|
100: '#CCE7FF',
|
||||||
|
200: '#99CFFF',
|
||||||
|
300: '#66B7FF',
|
||||||
|
400: '#339FFF',
|
||||||
|
500: '#0061A8',
|
||||||
|
600: '#004D86',
|
||||||
|
700: '#003A65',
|
||||||
|
800: '#002643',
|
||||||
|
900: '#001322',
|
||||||
|
},
|
||||||
|
'static-secondary': {
|
||||||
|
50: '#E6FFF5',
|
||||||
|
100: '#CCFFEB',
|
||||||
|
200: '#99FFD6',
|
||||||
|
300: '#66FFC2',
|
||||||
|
400: '#33FFAD',
|
||||||
|
500: '#00A868',
|
||||||
|
600: '#008653',
|
||||||
|
700: '#00653F',
|
||||||
|
800: '#00432A',
|
||||||
|
900: '#002215',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],
|
sans: ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
|
||||||
|
mono: ['JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', 'monospace'],
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
xs: ['0.75rem', { lineHeight: '1rem' }],
|
||||||
|
sm: ['0.875rem', { lineHeight: '1.25rem' }],
|
||||||
|
base: ['1rem', { lineHeight: '1.5rem' }],
|
||||||
|
lg: ['1.125rem', { lineHeight: '1.75rem' }],
|
||||||
|
xl: ['1.25rem', { lineHeight: '1.75rem' }],
|
||||||
|
'2xl': ['1.5rem', { lineHeight: '2rem' }],
|
||||||
|
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
|
||||||
|
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
|
||||||
},
|
},
|
||||||
spacing: {
|
spacing: {
|
||||||
'18': '4.5rem',
|
'18': '4.5rem',
|
||||||
'88': '22rem',
|
'88': '22rem',
|
||||||
},
|
},
|
||||||
|
borderRadius: {
|
||||||
|
sm: '0.125rem',
|
||||||
|
DEFAULT: '0.25rem',
|
||||||
|
md: '0.375rem',
|
||||||
|
lg: '0.5rem',
|
||||||
|
xl: '0.75rem',
|
||||||
|
'2xl': '1rem',
|
||||||
|
'3xl': '1.5rem',
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
|
||||||
|
DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
|
||||||
|
md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
|
||||||
|
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
|
||||||
|
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
|
||||||
|
'2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
|
||||||
|
inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
dropdown: '1000',
|
||||||
|
sticky: '1020',
|
||||||
|
fixed: '1030',
|
||||||
|
modalBackdrop: '1040',
|
||||||
|
modal: '1050',
|
||||||
|
popover: '1060',
|
||||||
|
tooltip: '1070',
|
||||||
|
toast: '1080',
|
||||||
|
},
|
||||||
animation: {
|
animation: {
|
||||||
'fade-in': 'fadeIn 0.2s ease-out',
|
'fade-in': 'fadeIn 0.2s ease-out',
|
||||||
|
'fade-out': 'fadeOut 0.2s ease-in',
|
||||||
'slide-in': 'slideIn 0.2s ease-out',
|
'slide-in': 'slideIn 0.2s ease-out',
|
||||||
|
'slide-out': 'slideOut 0.2s ease-in',
|
||||||
'spin-slow': 'spin 2s linear infinite',
|
'spin-slow': 'spin 2s linear infinite',
|
||||||
|
'pulse-slow': 'pulse 3s ease-in-out infinite',
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
fadeIn: {
|
fadeIn: {
|
||||||
'0%': { opacity: '0' },
|
'0%': { opacity: '0' },
|
||||||
'100%': { opacity: '1' },
|
'100%': { opacity: '1' },
|
||||||
},
|
},
|
||||||
|
fadeOut: {
|
||||||
|
'0%': { opacity: '1' },
|
||||||
|
'100%': { opacity: '0' },
|
||||||
|
},
|
||||||
slideIn: {
|
slideIn: {
|
||||||
'0%': { transform: 'translateY(-10px)', opacity: '0' },
|
'0%': { transform: 'translateY(-10px)', opacity: '0' },
|
||||||
'100%': { transform: 'translateY(0)', opacity: '1' },
|
'100%': { transform: 'translateY(0)', opacity: '1' },
|
||||||
},
|
},
|
||||||
|
slideOut: {
|
||||||
|
'0%': { transform: 'translateY(0)', opacity: '1' },
|
||||||
|
'100%': { transform: 'translateY(-10px)', opacity: '0' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
transitionDuration: {
|
||||||
|
'0': '0ms',
|
||||||
|
'75': '75ms',
|
||||||
|
'100': '100ms',
|
||||||
|
'150': '150ms',
|
||||||
|
'200': '200ms',
|
||||||
|
'300': '300ms',
|
||||||
|
'500': '500ms',
|
||||||
|
'700': '700ms',
|
||||||
|
'1000': '1000ms',
|
||||||
|
},
|
||||||
|
transitionTimingFunction: {
|
||||||
|
'ease-in': 'cubic-bezier(0.4, 0, 1, 1)',
|
||||||
|
'ease-out': 'cubic-bezier(0, 0, 0.2, 1)',
|
||||||
|
'ease-in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user