style(ui): replace dark hover bg from neutral-950 to neutral-900 and use RelativeDate component in UsersPage

This commit is contained in:
2026-04-22 17:30:48 -04:00
parent 52443591b2
commit e5df0e102b
7 changed files with 46 additions and 25 deletions
+2 -21
View File
@@ -1,7 +1,7 @@
'use client'; 'use client';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Card, Table, Badge, StatusBadge, Button, UserAvatar } from '@zen/core/shared/components'; import { Card, Table, Badge, StatusBadge, Button, UserAvatar, RelativeDate } from '@zen/core/shared/components';
import { PencilEdit01Icon } from '@zen/core/shared/icons'; import { PencilEdit01Icon } from '@zen/core/shared/icons';
import { useToast } from '@zen/core/toast'; import { useToast } from '@zen/core/toast';
import AdminHeader from '../components/AdminHeader.js'; import AdminHeader from '../components/AdminHeader.js';
@@ -65,11 +65,7 @@ const UsersPageClient = () => {
key: 'created_at', key: 'created_at',
label: 'Créé le', label: 'Créé le',
sortable: true, sortable: true,
render: (user) => ( render: (user) => <RelativeDate date={user.created_at} />,
<span className="text-sm text-neutral-600 dark:text-gray-300">
{formatDate(user.created_at)}
</span>
),
skeleton: { height: 'h-4', width: '70%' }, skeleton: { height: 'h-4', width: '70%' },
}, },
{ {
@@ -144,21 +140,6 @@ const UsersPageClient = () => {
setSortOrder(newSortOrder); setSortOrder(newSortOrder);
}; };
const formatDate = (dateString) => {
if (!dateString) return 'N/A';
try {
return new Date(dateString).toLocaleDateString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
});
} catch {
return 'Date invalide';
}
};
return ( return (
<> <>
<Card variant="default" padding="none"> <Card variant="default" padding="none">
+1 -1
View File
@@ -25,7 +25,7 @@ const Breadcrumb = ({ items = [], className = '' }) => {
item.active item.active
? 'text-black dark:text-white cursor-default' ? 'text-black dark:text-white cursor-default'
: item.onClick : item.onClick
? 'text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-950 cursor-pointer' ? 'text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-900 cursor-pointer'
: 'text-neutral-400 cursor-default', : 'text-neutral-400 cursor-default',
].filter(Boolean).join(' ')} ].filter(Boolean).join(' ')}
> >
+1 -1
View File
@@ -14,7 +14,7 @@ const FilterTabs = ({ tabs = [], value, onChange, className = ''}) => {
index !== 0 ? 'border-l border-neutral-200 dark:border-[#1B1B1B]' : '', index !== 0 ? 'border-l border-neutral-200 dark:border-[#1B1B1B]' : '',
value === tab.key value === tab.key
? 'bg-neutral-100 dark:bg-neutral-700/40 text-neutral-900 dark:text-white' ? 'bg-neutral-100 dark:bg-neutral-700/40 text-neutral-900 dark:text-white'
: 'bg-white dark:bg-[#0B0B0B] text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-950', : 'bg-white dark:bg-[#0B0B0B] text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-900',
].filter(Boolean).join(' ')} ].filter(Boolean).join(' ')}
> >
{tab.label} {tab.label}
+1 -1
View File
@@ -67,7 +67,7 @@ export const TableSkeleton = ({ rows = 5, columns = 4 }) => (
</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">
{Array.from({ length: rows }).map((_, rowIndex) => ( {Array.from({ length: rows }).map((_, rowIndex) => (
<tr key={rowIndex} className="hover:bg-neutral-50 dark:hover:bg-neutral-950 transition-colors"> <tr key={rowIndex} className="hover:bg-neutral-50 dark:hover:bg-neutral-900 transition-colors">
{Array.from({ length: columns }).map((_, colIndex) => ( {Array.from({ length: columns }).map((_, colIndex) => (
<td key={colIndex} className="px-6 py-4 whitespace-nowrap"> <td key={colIndex} className="px-6 py-4 whitespace-nowrap">
<Skeleton height="h-4" width={`${60 + Math.random() * 30}%`} /> <Skeleton height="h-4" width={`${60 + Math.random() * 30}%`} />
@@ -0,0 +1,39 @@
'use client';
const DEFAULT_CLASS = 'text-xs text-neutral-400 dark:text-gray-500 font-ibm-plex-mono';
function getRelativeTime(date) {
if (!date) return null;
const d = date instanceof Date ? date : new Date(date);
if (isNaN(d.getTime())) return null;
const rtf = new Intl.RelativeTimeFormat('fr', { numeric: 'auto' });
const diffMs = d.getTime() - Date.now();
const diffSec = Math.round(diffMs / 1000);
const absMin = Math.abs(Math.round(diffSec / 60));
const absH = Math.abs(Math.round(diffSec / 3600));
const absDays = Math.abs(Math.round(diffSec / 86400));
if (Math.abs(diffSec) < 60) return rtf.format(diffSec, 'second');
if (absMin < 60) return rtf.format(Math.round(diffSec / 60), 'minute');
if (absH < 24) return rtf.format(Math.round(diffSec / 3600), 'hour');
if (absDays < 7) return rtf.format(Math.round(diffSec / 86400), 'day');
if (absDays < 30) return rtf.format(Math.round(diffSec / 604800), 'week');
if (absDays < 365) return rtf.format(Math.round(diffSec / 2592000), 'month');
return rtf.format(Math.round(diffSec / 31536000), 'year');
}
const RelativeDate = ({ date, className = DEFAULT_CLASS, ...props }) => {
const text = getRelativeTime(date);
if (!text) return null;
const d = date instanceof Date ? date : new Date(date);
return (
<time dateTime={d.toISOString()} className={className} title={d.toLocaleString('fr-FR')} {...props}>
{text}
</time>
);
};
export default RelativeDate;
+1 -1
View File
@@ -60,7 +60,7 @@ const Table = ({
); );
const SkeletonRow = () => ( const SkeletonRow = () => (
<tr className="hover:bg-neutral-100 dark:hover:bg-neutral-950 transition-colors"> <tr className="hover:bg-neutral-100 dark:hover:bg-neutral-900 transition-colors">
{columns.map((column, index) => ( {columns.map((column, index) => (
<td key={index} className={`${sizeClasses.cell} ${column.noWrap !== false ? '' : 'whitespace-nowrap'}`}> <td key={index} className={`${sizeClasses.cell} ${column.noWrap !== false ? '' : 'whitespace-nowrap'}`}>
{column.skeleton ? ( {column.skeleton ? (
+1
View File
@@ -28,3 +28,4 @@ export { default as Switch } from './Switch';
export { default as TagInput } from './TagInput'; export { default as TagInput } from './TagInput';
export { default as UserAvatar } from './UserAvatar'; export { default as UserAvatar } from './UserAvatar';
export { default as ColorPicker } from './ColorPicker.client'; export { default as ColorPicker } from './ColorPicker.client';
export { default as RelativeDate } from './RelativeDate.client';