feat: redesign sessions dashboard with multi-view layout and sortable table
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m17s

- Redesign session cards with colored left border (Figma-style), improved
  visual hierarchy, hover states, and stats in footer
- Add 4 switchable view modes: grid, list, sortable table, and timeline
- Table view: unified flat table with clickable column headers for sorting
  (Type, Titre, Créateur, Participant, Stats, Date)
- Add Créateur column showing the workshop owner with Gravatar avatar
- Widen Type column to 160px for better readability
- Improve tabs navigation with pill-shaped active state and shadow
- Fix TypeFilterDropdown to exclude 'Équipe' from type list
- Make filter tabs visually distinct with bg-card + border + shadow-sm
- Split WorkshopTabs.tsx into 4 focused modules:
  workshop-session-types.ts, workshop-session-helpers.ts,
  SessionCard.tsx, WorkshopTabs.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 13:54:23 +01:00
parent 7be296231c
commit 66ac190c15
6 changed files with 887 additions and 894 deletions

View File

@@ -33,15 +33,15 @@ function WorkshopTabsSkeleton() {
return (
<div className="space-y-6">
{/* Tabs skeleton */}
<div className="flex gap-2 border-b border-border pb-4">
<div className="flex gap-2 pb-2">
{[...Array(4)].map((_, i) => (
<div key={i} className="h-10 w-32 bg-card animate-pulse rounded-lg" />
<div key={i} className="h-9 w-28 bg-card animate-pulse rounded-full" />
))}
</div>
{/* Cards skeleton */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{[...Array(6)].map((_, i) => (
<div key={i} className="h-40 bg-card animate-pulse rounded-xl" />
<div key={i} className="h-44 bg-card animate-pulse rounded-xl" />
))}
</div>
</div>
@@ -110,14 +110,22 @@ export default async function SessionsPage() {
].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
const hasNoSessions = allSessions.length === 0;
const totalCount = allSessions.length;
return (
<main className="mx-auto max-w-7xl px-4 py-8">
<main className="mx-auto max-w-7xl px-4 py-8 sm:py-12">
{/* Header */}
<div className="mb-8 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div className="mb-10 flex flex-col sm:flex-row sm:items-end justify-between gap-6">
<div>
<h1 className="text-3xl font-bold text-foreground">Mes Ateliers</h1>
<p className="mt-1 text-muted">Tous vos ateliers en un seul endroit</p>
<div className="flex items-center gap-3 mb-1.5">
<h1 className="text-3xl font-bold tracking-tight text-foreground">Mes Ateliers</h1>
{totalCount > 0 && (
<span className="inline-flex items-center justify-center px-2.5 h-6 rounded-full bg-primary/10 text-primary text-sm font-semibold">
{totalCount}
</span>
)}
</div>
<p className="text-sm text-muted">Tous vos ateliers en un seul endroit</p>
</div>
<NewWorkshopDropdown />
</div>