fix: improve mobile responsiveness for tablo/project management pages

- Make project card grids responsive (single column on mobile, 2 cols on sm)
- Remove fixed w-56 card width so cards fill available space on mobile
- Convert modals to bottom-sheet style on mobile (items-end, rounded-t-2xl)
- Add max-h-[90vh] + overflow-y-auto to modals for small screens
- Increase touch targets to min 44px on action buttons and interactive elements
- Refactor DashboardTaskList rows from rigid grid to flexible layout
- Remove min-w-[600px] wrapper that forced horizontal scroll on task list
- Make tab navigation horizontally scrollable instead of wrapping on mobile
- Reduce left padding on etape child tasks for narrow screens
- Stack modal action buttons vertically on mobile (flex-col-reverse)
- Add responsive text sizing for headings and dates
- Fix share dialog invite input to stack on mobile

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arthur Belleville 2026-04-02 21:21:38 +02:00
parent 3daf720447
commit 6aea504667
No known key found for this signature in database
10 changed files with 140 additions and 139 deletions

View file

@ -32,7 +32,7 @@ export function ActionCard({
onClick={disabled ? undefined : onClick}
disabled={disabled}
className={cn(
"h-fit p-3 rounded-2xl text-left transition-all",
"h-fit p-3 rounded-2xl text-left transition-all min-h-[56px]",
disabled
? "bg-white dark:bg-gray-800 border border-[#EAECF0] dark:border-gray-700 opacity-50 cursor-not-allowed"
: isSelected

View file

@ -49,9 +49,9 @@ export const CreateTabloModal = ({ onClose, onCreate }: CreateTabloModalProps) =
};
return (
<div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50">
<div className="fixed inset-0 bg-black/80 flex items-end sm:items-center justify-center z-50">
<ClickOutside onClickOutside={handleClose}>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-4xl min-w-96 mx-4">
<div className="bg-white dark:bg-gray-800 rounded-t-2xl sm:rounded-lg shadow-xl p-4 sm:p-6 w-full sm:max-w-4xl sm:mx-4 max-h-[90vh] overflow-y-auto">
<h2 className="text-xl font-bold text-gray-900 dark:text-white mb-4">
{t("modals:createTablo.title")}
</h2>
@ -81,17 +81,17 @@ export const CreateTabloModal = ({ onClose, onCreate }: CreateTabloModalProps) =
</div>
{/* Modal Actions */}
<div className="flex justify-end space-x-3 mt-6">
<div className="flex flex-col-reverse sm:flex-row justify-end gap-2 sm:gap-3 mt-6">
<button
type="button"
className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-md"
className="px-4 py-3 sm:py-2.5 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg min-h-[44px]"
onClick={handleClose}
>
{t("common:buttons.cancel")}
</button>
<button
type="button"
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
className="px-4 py-3 sm:py-2.5 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px]"
onClick={handleCreate}
disabled={!newTabloName.trim() || creationMode === "image"}
>

View file

@ -18,7 +18,7 @@ export function DashboardActionCards({
const { t } = useTranslation("pages");
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-5">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-5">
<ActionCard
icon={<FolderPlus className="w-6 h-6" />}
label={t("dashboard.actionCards.createProject.label")}

View file

@ -56,7 +56,7 @@ function TaskRow({
return (
<div
className="grid grid-cols-[auto_1fr_1fr_auto_auto] items-center gap-4 px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors border-b border-gray-200 dark:border-gray-700 cursor-pointer"
className="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors border-b border-gray-200 dark:border-gray-700 cursor-pointer"
onClick={() => {
if (task.tablos) {
navigate(`/tablos/${task.tablos.id}?section=tasks`);
@ -66,7 +66,7 @@ function TaskRow({
{/* Checkbox */}
<button
className={cn(
"w-6 h-6 rounded-full border-2 flex items-center justify-center shrink-0",
"w-8 h-8 min-w-[32px] rounded-full border-2 flex items-center justify-center shrink-0",
isDone
? "bg-purple-600 border-purple-600"
: "border-gray-300 hover:border-purple-400 dark:border-gray-600 dark:hover:border-purple-500"
@ -79,48 +79,48 @@ function TaskRow({
{isDone && <CheckCircle2 className="w-4 h-4 text-white" />}
</button>
{/* Title */}
<p
className={cn(
"text-sm font-medium truncate",
isDone
? "line-through text-gray-400 dark:text-gray-500"
: "text-gray-900 dark:text-gray-100"
)}
>
{task.title}
</p>
{/* Tablo */}
<div className="flex items-center gap-2 min-w-0">
{task.tablos && (
<>
<div
className={cn(
"w-6 h-6 rounded-lg flex items-center justify-center text-xs shrink-0",
task.tablos.color || "bg-gray-400"
)}
>
<span className="text-white font-bold text-[10px]">
{task.tablos.name.charAt(0).toUpperCase()}
{/* Title + Tablo (stacked on mobile) */}
<div className="flex-1 min-w-0">
<p
className={cn(
"text-sm font-medium truncate",
isDone
? "line-through text-gray-400 dark:text-gray-500"
: "text-gray-900 dark:text-gray-100"
)}
>
{task.title}
</p>
<div className="flex items-center gap-2 mt-1">
{task.tablos && (
<>
<div
className={cn(
"w-4 h-4 rounded flex items-center justify-center text-xs shrink-0",
task.tablos.color || "bg-gray-400"
)}
>
<span className="text-white font-bold text-[8px]">
{task.tablos.name.charAt(0).toUpperCase()}
</span>
</div>
<span className="text-xs text-gray-500 dark:text-gray-400 truncate">
{task.tablos.name}
</span>
</div>
<span className="text-sm text-gray-700 dark:text-gray-300 hidden sm:inline truncate">
{task.tablos.name}
</>
)}
{formattedDate && (
<span className="text-xs text-gray-400 dark:text-gray-500 hidden sm:inline whitespace-nowrap">
{formattedDate}
</span>
</>
)}
)}
</div>
</div>
{/* Date */}
<span className="text-sm text-gray-500 dark:text-gray-400 hidden md:inline whitespace-nowrap">
{formattedDate}
</span>
{/* Status badge */}
<span
className={cn(
"px-3 py-1 rounded-full text-xs font-medium whitespace-nowrap",
"px-2 sm:px-3 py-1 rounded-full text-xs font-medium whitespace-nowrap shrink-0",
badge.className
)}
>
@ -151,24 +151,22 @@ export function DashboardTaskList() {
return (
<>
<div className="bg-white dark:bg-gray-800 rounded-2xl border border-gray-100 dark:border-gray-700">
<div className="flex items-center justify-between px-4 py-5 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-2xl font-semibold text-gray-900 dark:text-gray-100">
<div className="flex items-center justify-between px-4 py-4 sm:py-5 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-xl sm:text-2xl font-semibold text-gray-900 dark:text-gray-100">
{t("dashboard.taskList.title")}
</h2>
<button
className="flex items-center gap-2 px-4 py-2 bg-white dark:bg-gray-700 rounded-lg border border-gray-200 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300"
className="flex items-center gap-2 px-4 py-2.5 bg-white dark:bg-gray-700 rounded-lg border border-gray-200 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300 min-h-[44px]"
onClick={() => setIsTaskModalOpen(true)}
>
<Plus className="w-4 h-4" />
<span>{t("dashboard.taskList.addTask")}</span>
</button>
</div>
<div className="overflow-x-auto">
<div className="min-w-[600px]">
{myTasks.map((task) => (
<TaskRow key={task.id} task={task} onToggleDone={handleToggleDone} />
))}
</div>
<div>
{myTasks.map((task) => (
<TaskRow key={task.id} task={task} onToggleDone={handleToggleDone} />
))}
</div>
</div>

View file

@ -24,9 +24,9 @@ export const DeleteTabloModal = ({
};
return (
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50">
<div className="fixed inset-0 bg-black/60 flex items-end sm:items-center justify-center z-50">
<ClickOutside onClickOutside={onClose}>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-md mx-4">
<div className="bg-white dark:bg-gray-800 rounded-t-2xl sm:rounded-lg shadow-xl p-4 sm:p-6 w-full sm:max-w-md sm:mx-4">
{/* Header */}
<div className="flex items-center mb-4">
<div className="w-12 h-12 bg-red-100 dark:bg-red-900/20 rounded-full flex items-center justify-center mr-4">
@ -70,10 +70,10 @@ export const DeleteTabloModal = ({
</div>
{/* Actions */}
<div className="flex justify-end space-x-3">
<div className="flex flex-col-reverse sm:flex-row justify-end gap-2 sm:gap-3">
<button
type="button"
className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-md transition-colors"
className="px-4 py-3 sm:py-2.5 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors min-h-[44px]"
onClick={onClose}
disabled={isDeleting}
>
@ -81,7 +81,7 @@ export const DeleteTabloModal = ({
</button>
<button
type="button"
className="px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
className="px-4 py-3 sm:py-2.5 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 min-h-[44px]"
onClick={handleConfirm}
disabled={isDeleting}
>

View file

@ -41,7 +41,7 @@ export function ProjectCardList({
</button>
)}
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
{visibleTablos.map((tablo) => (
<ProjectCard
key={tablo.id}
@ -54,7 +54,7 @@ export function ProjectCardList({
{hasMore && (
<div className="flex justify-center mt-6">
<button
className="flex items-center gap-1.5 text-purple-600 hover:text-purple-500 dark:text-purple-400 dark:hover:text-purple-300 font-medium text-sm"
className="flex items-center gap-1.5 text-purple-600 hover:text-purple-500 dark:text-purple-400 dark:hover:text-purple-300 font-medium text-sm min-h-[44px] px-4"
onClick={() => setExpanded((prev) => !prev)}
>
{expanded ? (

View file

@ -142,8 +142,8 @@ export const TaskModal = ({
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-card border border-border rounded-lg p-6 w-full max-w-md shadow-xl">
<div className="fixed inset-0 bg-black/50 flex items-end sm:items-center justify-center z-50">
<div className="bg-card border border-border rounded-t-2xl sm:rounded-lg p-4 sm:p-6 w-full sm:max-w-md shadow-xl max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<TypographyH2 className="text-xl font-bold text-foreground">

View file

@ -399,10 +399,10 @@ export const TabloDetailsPage = () => {
<h1 className="text-xl md:text-3xl font-bold text-foreground">{tablo.name}</h1>
</div>
<div className="flex flex-wrap items-center gap-3">
<div className="flex items-center gap-3 w-full sm:w-auto">
<Link
to={`/chat/${tabloId}`}
className="bg-[#804EEC] hover:bg-[#6f3fd4] text-white font-medium py-2 px-4 rounded-lg flex items-center gap-2 transition-colors"
className="bg-[#804EEC] hover:bg-[#6f3fd4] text-white font-medium py-2.5 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors flex-1 sm:flex-none min-h-[44px]"
>
<MessageCircleIcon className="w-5 h-5" />
Discussion
@ -411,7 +411,7 @@ export const TabloDetailsPage = () => {
<button
type="button"
onClick={() => setIsShareDialogOpen(true)}
className="border border-[#804EEC] text-[#804EEC] hover:bg-[#804EEC]/10 font-medium py-2 px-4 rounded-lg flex items-center gap-2 transition-colors"
className="border border-[#804EEC] text-[#804EEC] hover:bg-[#804EEC]/10 font-medium py-2.5 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors flex-1 sm:flex-none min-h-[44px]"
>
<UserPlusIcon className="w-5 h-5" />
Inviter
@ -421,12 +421,12 @@ export const TabloDetailsPage = () => {
</div>
{/* ── Metadata bar ──────────────────────────────────────────────── */}
<div className="flex flex-wrap items-center gap-6 text-sm border-b border-[#F2F4F7] dark:border-gray-700 pb-4 mb-4">
<div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
<div className="flex flex-wrap items-center gap-3 sm:gap-6 text-sm border-b border-[#F2F4F7] dark:border-gray-700 pb-4 mb-4">
<div className="flex items-center gap-2 sm:border-r border-[#D0D5DD] dark:border-gray-600 sm:pr-4">
<span className="text-muted-foreground">Rôle :</span>
<span className="text-foreground font-medium">{isAdmin ? "Admin" : "Invité"}</span>
</div>
<div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
<div className="flex items-center gap-2 sm:border-r border-[#D0D5DD] dark:border-gray-600 sm:pr-4">
<span className="text-muted-foreground">Créé le :</span>
<span className="text-foreground">
{new Intl.DateTimeFormat("fr-FR", {
@ -436,7 +436,7 @@ export const TabloDetailsPage = () => {
}).format(new Date(tablo.created_at))}
</span>
</div>
<div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
<div className="flex items-center gap-2 sm:border-r border-[#D0D5DD] dark:border-gray-600 sm:pr-4">
<span className="text-muted-foreground">Statut :</span>
<span className={cn("px-3 py-1 rounded-full text-xs font-medium", badgeClass)}>
{statusLabel}
@ -462,7 +462,7 @@ export const TabloDetailsPage = () => {
{/* ── Tab navigation ──────────────────────────────────────────────── */}
<div className="w-full bg-white dark:bg-background sticky top-0 z-40">
<div className="px-4 py-2">
<div className="flex flex-wrap items-center gap-6 mb-4 border-b border-[#F2F4F7] dark:border-gray-700">
<div className="flex items-center gap-4 sm:gap-6 mb-4 border-b border-[#F2F4F7] dark:border-gray-700 overflow-x-auto scrollbar-none -mx-4 px-4">
{TABS.map((tab) => {
const isActive = activeSection === tab.id;
return (
@ -472,7 +472,7 @@ export const TabloDetailsPage = () => {
disabled={tab.disabled}
onClick={() => !tab.disabled && setSearchParams({ section: tab.id })}
className={cn(
"flex items-center gap-2 pb-3 px-1 text-sm font-semibold transition-colors border-b-2",
"flex items-center gap-2 pb-3 px-1 text-sm font-semibold transition-colors border-b-2 shrink-0 min-h-[44px]",
isActive
? "text-[#804EEC] border-[#804EEC]"
: "text-[#667085] border-transparent hover:text-gray-900 dark:hover:text-gray-100",
@ -824,13 +824,13 @@ export const TabloDetailsPage = () => {
<div className="space-y-4">
{/* Invite Input */}
<div className="flex space-x-2">
<div className="flex flex-col sm:flex-row gap-2">
<Input
type="email"
value={inviteEmail}
onChange={(e) => setInviteEmail(e.target.value)}
placeholder="Email de l'utilisateur"
className="flex-1"
className="flex-1 min-h-[44px]"
/>
{isInvitingUser ? (
<div className="flex justify-center items-center px-4">
@ -1027,7 +1027,7 @@ function EtapesSection({
return (
<div className="space-y-4">
{isAdmin && (
<div className="flex items-center gap-2">
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2">
<Input
value={newEtapeTitle}
onChange={(event) => setNewEtapeTitle(event.target.value)}
@ -1037,11 +1037,12 @@ function EtapesSection({
void handleAddEtape();
}
}}
className="h-9 sm:w-80"
className="h-11 sm:h-9 sm:w-80"
/>
<Button
onClick={() => void handleAddEtape()}
disabled={isCreatingEtape || !newEtapeTitle.trim()}
className="min-h-[44px] sm:min-h-0"
>
<PlusIcon className="w-4 h-4" />
Ajouter une étape
@ -1085,7 +1086,7 @@ function EtapesSection({
<button
type="button"
onClick={() => toggleEtape(etape.id)}
className="w-full flex items-center gap-4 px-5 py-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors text-left"
className="w-full flex items-center gap-3 sm:gap-4 px-3 sm:px-5 py-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors text-left min-h-[56px]"
>
{isExpanded ? (
<ChevronDownIcon className="w-5 h-5 text-gray-400 shrink-0" />
@ -1100,58 +1101,60 @@ function EtapesSection({
</div>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 dark:text-gray-100 truncate">
<h3 className="font-semibold text-gray-900 dark:text-gray-100 truncate text-sm sm:text-base">
{etape.title}
</h3>
{etape.description && (
<p className="text-sm text-muted-foreground truncate mt-0.5">
<p className="text-xs sm:text-sm text-muted-foreground truncate mt-0.5">
{etape.description}
</p>
)}
</div>
{etape.due_date && (
<div
<div className="flex items-center gap-2 shrink-0">
{etape.due_date && (
<div
className={cn(
"items-center gap-1 text-xs hidden sm:flex",
derivedStatus !== "done" &&
new Date(etape.due_date) < new Date(new Date().toDateString())
? "text-red-500"
: "text-muted-foreground"
)}
>
<CalendarIcon className="w-3.5 h-3.5" />
<span>
{new Intl.DateTimeFormat("fr-FR", {
day: "2-digit",
month: "short",
}).format(new Date(etape.due_date))}
</span>
</div>
)}
<span
className={cn(
"flex items-center gap-1 text-xs shrink-0",
derivedStatus !== "done" &&
new Date(etape.due_date) < new Date(new Date().toDateString())
? "text-red-500"
: "text-muted-foreground"
"px-2 sm:px-2.5 py-1 rounded-full text-[10px] sm:text-xs font-medium",
status.color
)}
>
<CalendarIcon className="w-3.5 h-3.5" />
<span>
{new Intl.DateTimeFormat("fr-FR", {
day: "2-digit",
month: "short",
}).format(new Date(etape.due_date))}
</span>
</div>
)}
{status.label}
</span>
<span
className={cn(
"px-2.5 py-1 rounded-full text-xs font-medium shrink-0",
status.color
)}
>
{status.label}
</span>
{totalCount > 0 && (
<div className="flex items-center gap-2 shrink-0">
<div className="w-16 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full bg-green-500 rounded-full transition-all"
style={{ width: `${progressPct}%` }}
/>
{totalCount > 0 && (
<div className="hidden sm:flex items-center gap-2">
<div className="w-16 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full bg-green-500 rounded-full transition-all"
style={{ width: `${progressPct}%` }}
/>
</div>
<span className="text-xs text-muted-foreground whitespace-nowrap">
{doneCount}/{totalCount}
</span>
</div>
<span className="text-xs text-muted-foreground whitespace-nowrap">
{doneCount}/{totalCount}
</span>
</div>
)}
)}
</div>
</button>
{/* Child tasks + add task */}
@ -1162,7 +1165,7 @@ function EtapesSection({
{childTasks.map((task) => (
<div
key={task.id}
className="flex items-center gap-3 px-5 py-3 pl-16 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
className="flex items-center gap-3 px-3 sm:px-5 py-3 pl-8 sm:pl-16 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
{task.status === "done" ? (
<CircleCheckIcon className="w-4 h-4 text-green-500 shrink-0" />
@ -1214,14 +1217,14 @@ function EtapesSection({
)}
{childTasks.length === 0 && addingTaskToEtape !== etape.id && (
<div className="px-5 py-4 pl-16 text-sm text-muted-foreground">
<div className="px-3 sm:px-5 py-4 pl-8 sm:pl-16 text-sm text-muted-foreground">
Aucune tâche dans cette étape
</div>
)}
{/* Inline add task */}
{addingTaskToEtape === etape.id ? (
<div className="flex items-center gap-2 px-5 py-3 pl-16 border-t border-gray-100 dark:border-gray-700">
<div className="flex items-center gap-2 px-3 sm:px-5 py-3 pl-8 sm:pl-16 border-t border-gray-100 dark:border-gray-700">
<div className="w-4 h-4 rounded-full border-2 border-gray-300 dark:border-gray-600 shrink-0" />
<input
autoFocus
@ -1236,13 +1239,13 @@ function EtapesSection({
}
}}
placeholder="Nom de la tâche..."
className="flex-1 text-sm bg-transparent border-none outline-none text-gray-900 dark:text-gray-100 placeholder-gray-400"
className="flex-1 text-sm bg-transparent border-none outline-none text-gray-900 dark:text-gray-100 placeholder-gray-400 min-w-0"
/>
<button
type="button"
onClick={() => handleAddTask(etape.id)}
disabled={!newTaskTitle.trim()}
className="text-xs font-medium px-3 py-1 rounded-md bg-[#804EEC] text-white hover:bg-[#6f3fd4] disabled:opacity-40 transition-colors"
className="text-xs font-medium px-3 py-2 rounded-md bg-[#804EEC] text-white hover:bg-[#6f3fd4] disabled:opacity-40 transition-colors min-h-[36px] shrink-0"
>
Ajouter
</button>
@ -1252,7 +1255,7 @@ function EtapesSection({
setAddingTaskToEtape(null);
setNewTaskTitle("");
}}
className="text-xs text-muted-foreground hover:text-foreground px-2 py-1"
className="text-xs text-muted-foreground hover:text-foreground px-2 py-2 min-h-[36px] shrink-0"
>
Annuler
</button>
@ -1265,7 +1268,7 @@ function EtapesSection({
setAddingTaskToEtape(etape.id);
setNewTaskTitle("");
}}
className="flex items-center gap-2 px-5 py-2.5 pl-16 text-sm text-muted-foreground hover:text-[#804EEC] hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors w-full text-left border-t border-gray-100 dark:border-gray-700"
className="flex items-center gap-2 px-3 sm:px-5 py-3 pl-8 sm:pl-16 text-sm text-muted-foreground hover:text-[#804EEC] hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors w-full text-left border-t border-gray-100 dark:border-gray-700 min-h-[44px]"
>
<PlusIcon className="w-4 h-4" />
Ajouter une tâche

View file

@ -381,7 +381,7 @@ export const TabloPage = () => {
}}
>
<div
className={`bg-card rounded-lg shadow-lg transition-all duration-300 w-56 overflow-hidden border border-border ${
className={`bg-card rounded-lg shadow-lg transition-all duration-300 w-full overflow-hidden border border-border ${
isAdmin ? "hover:shadow-xl cursor-pointer" : "hover:shadow-xl cursor-pointer opacity-75"
}`}
onClick={(e) => {
@ -430,11 +430,11 @@ export const TabloPage = () => {
<span>{getUserRole(tablo)}</span>
</div>
{/* Action buttons */}
<div className="flex items-center gap-1 pt-1">
<div className="flex items-center gap-2 pt-1">
<Button
variant="outline"
size="icon-sm"
className="p-1.5"
className="min-w-[44px] min-h-[44px] p-2"
onClick={(e) => {
e.stopPropagation();
navigate(`/chat/${tablo.id}`);
@ -446,7 +446,7 @@ export const TabloPage = () => {
<Button
variant="outline"
size="icon-sm"
className="p-1.5"
className="min-w-[44px] min-h-[44px] p-2"
onClick={(e) => {
e.stopPropagation();
navigate(`/tablos/${tablo.id}?section=members`);
@ -458,7 +458,7 @@ export const TabloPage = () => {
<Button
variant="outline"
size="icon-sm"
className="p-1.5 text-destructive hover:text-destructive"
className="min-w-[44px] min-h-[44px] p-2 text-destructive hover:text-destructive"
onClick={(e) => {
e.stopPropagation();
handleDeleteTablo(tablo.id);
@ -509,12 +509,12 @@ export const TabloPage = () => {
setContextMenuPosition(null);
}}
>
<header className="px-6 pt-6 pb-4">
<p className="text-base text-[#475467] dark:text-gray-400 mb-2 font-medium">
<header className="px-4 sm:px-6 pt-6 pb-4">
<p className="text-sm sm:text-base text-[#475467] dark:text-gray-400 mb-2 font-medium">
{formattedDate}
</p>
<div className="flex items-center gap-3 flex-wrap">
<h1 className="text-[24px] font-medium text-[#475467] dark:text-gray-400">
<div className="flex items-center justify-between flex-wrap gap-4">
<h1 className="text-xl sm:text-[24px] font-medium text-[#475467] dark:text-gray-400">
{getGreeting()},{" "}
<span className="text-gray-900 dark:text-gray-100 font-medium">
{user.first_name ?? user.name}
@ -656,10 +656,10 @@ export const TabloPage = () => {
onSendMessage={() => navigate("/chat")}
/>
<div className="container mx-auto px-4 py-8">
<div className="py-8">
{filteredTablos && filteredTablos.length > 0 ? (
viewMode === "grid" ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{filteredTablos.map((tablo) => renderTablo(tablo))}
</div>
) : (

View file

@ -130,7 +130,7 @@ function TabloCard({
</span>
<button
type="button"
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors"
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors p-2 -m-2 min-w-[44px] min-h-[44px] flex items-center justify-center"
onClick={(e) => {
e.stopPropagation();
onDelete(tablo.id);
@ -262,7 +262,7 @@ function TabloRow({
<td className="px-6 py-4 text-right">
<button
type="button"
className="text-gray-400 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-400 transition-colors p-1 rounded"
className="text-gray-400 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-400 transition-colors p-2 rounded min-w-[44px] min-h-[44px] inline-flex items-center justify-center"
onClick={(e) => {
e.stopPropagation();
onDelete(tablo.id);
@ -317,7 +317,7 @@ export function TablosPage() {
<button
type="button"
onClick={() => setShowCreateModal(true)}
className="bg-purple-600 hover:bg-purple-700 text-white px-6 py-3 rounded-lg font-medium flex items-center justify-center gap-2 transition-colors"
className="bg-purple-600 hover:bg-purple-700 text-white px-6 py-3 rounded-lg font-medium flex items-center justify-center gap-2 transition-colors w-full sm:w-auto min-h-[44px]"
>
<PlusIcon className="w-5 h-5" />
{t("tablo.createButton")}
@ -397,7 +397,7 @@ export function TablosPage() {
</p>
</div>
) : viewMode === "card" ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 sm:gap-6">
{filteredTablos.map((tablo) => (
<TabloCard
key={tablo.id}
@ -408,8 +408,8 @@ export function TablosPage() {
))}
</div>
) : (
<div className="bg-white dark:bg-gray-800 rounded-xl border border-[#EAECF0] dark:border-gray-700 overflow-hidden">
<table className="w-full">
<div className="bg-white dark:bg-gray-800 rounded-xl border border-[#EAECF0] dark:border-gray-700 overflow-x-auto -mx-4 sm:mx-0">
<table className="w-full min-w-[600px]">
<thead className="bg-gray-50 dark:bg-gray-800/80 border-b border-[#EAECF0] dark:border-gray-700">
<tr>
<th className="px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider">