diff --git a/src/components/gif-mood/GifMoodCard.tsx b/src/components/gif-mood/GifMoodCard.tsx
index 63787ef..2dffbb1 100644
--- a/src/components/gif-mood/GifMoodCard.tsx
+++ b/src/components/gif-mood/GifMoodCard.tsx
@@ -2,6 +2,7 @@
import { memo, useState, useTransition } from 'react';
import { updateGifMoodItem, deleteGifMoodItem } from '@/actions/gif-mood';
+import { IconClose } from '@/components/ui';
interface GifMoodCardProps {
sessionId: string;
@@ -83,9 +84,7 @@ export const GifMoodCard = memo(function GifMoodCard({
className="absolute top-2 right-2 p-1.5 rounded-full bg-black/50 text-white opacity-0 group-hover:opacity-100 hover:bg-black/70 transition-all backdrop-blur-sm"
title="Supprimer ce GIF"
>
-
+
)}
diff --git a/src/components/swot/SwotCard.tsx b/src/components/swot/SwotCard.tsx
index 488df03..b2309d7 100644
--- a/src/components/swot/SwotCard.tsx
+++ b/src/components/swot/SwotCard.tsx
@@ -3,6 +3,7 @@
import { forwardRef, memo, useState, useTransition } from 'react';
import type { SwotItem, SwotCategory } from '@prisma/client';
import { updateSwotItem, deleteSwotItem, duplicateSwotItem } from '@/actions/swot';
+import { IconEdit, IconTrash, IconDuplicate, IconCheck } from '@/components/ui';
interface SwotCardProps {
item: SwotItem;
@@ -121,63 +122,21 @@ export const SwotCard = memo(
className="rounded p-1 text-muted hover:bg-card-hover hover:text-foreground"
aria-label="Modifier"
>
-
+
)}
@@ -187,9 +146,7 @@ export const SwotCard = memo(
)}
>
diff --git a/src/components/swot/SwotQuadrant.tsx b/src/components/swot/SwotQuadrant.tsx
index 7ea2f91..d657d98 100644
--- a/src/components/swot/SwotQuadrant.tsx
+++ b/src/components/swot/SwotQuadrant.tsx
@@ -4,6 +4,7 @@ import { forwardRef, useState, useTransition, useRef, ReactNode } from 'react';
import type { SwotCategory } from '@prisma/client';
import { createSwotItem } from '@/actions/swot';
import { QuadrantHelpPanel } from './QuadrantHelp';
+import { IconPlus, InlineFormActions } from '@/components/ui';
interface SwotQuadrantProps {
category: SwotCategory;
@@ -115,14 +116,7 @@ export const SwotQuadrant = forwardRef(
`}
aria-label={`Ajouter un item ${title}`}
>
-
+
@@ -152,28 +146,14 @@ export const SwotQuadrant = forwardRef(
rows={2}
disabled={isPending}
/>
-
-
-
-
+ { setIsAdding(false); setNewContent(''); }}
+ onSubmit={handleAdd}
+ isPending={isPending}
+ disabled={!newContent.trim()}
+ submitColorClass={`${styles.text} hover:bg-white/50`}
+ className="mt-1"
+ />
)}
diff --git a/src/components/ui/EditableTitle.tsx b/src/components/ui/EditableTitle.tsx
index 2bb5600..e72fda3 100644
--- a/src/components/ui/EditableTitle.tsx
+++ b/src/components/ui/EditableTitle.tsx
@@ -1,6 +1,7 @@
'use client';
import { useState, useTransition, useRef, useEffect, useMemo } from 'react';
+import { IconEdit } from './Icons';
interface EditableTitleProps {
sessionId: string;
@@ -92,19 +93,7 @@ export function EditableTitle({ sessionId, initialTitle, canEdit, onUpdate }: Ed
title="Cliquez pour modifier"
>
{title}
-
+
);
}
diff --git a/src/components/ui/Icons.tsx b/src/components/ui/Icons.tsx
new file mode 100644
index 0000000..7c474e4
--- /dev/null
+++ b/src/components/ui/Icons.tsx
@@ -0,0 +1,54 @@
+interface IconProps {
+ className?: string;
+}
+
+const base = { fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' } as const;
+const path = { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2 } as const;
+
+export function IconEdit({ className = 'h-3.5 w-3.5' }: IconProps) {
+ return (
+
+ );
+}
+
+export function IconTrash({ className = 'h-3.5 w-3.5' }: IconProps) {
+ return (
+
+ );
+}
+
+export function IconDuplicate({ className = 'h-3.5 w-3.5' }: IconProps) {
+ return (
+
+ );
+}
+
+export function IconPlus({ className = 'h-5 w-5' }: IconProps) {
+ return (
+
+ );
+}
+
+export function IconCheck({ className = 'h-4 w-4' }: IconProps) {
+ return (
+
+ );
+}
+
+export function IconClose({ className = 'h-5 w-5' }: IconProps) {
+ return (
+
+ );
+}
diff --git a/src/components/ui/InlineFormActions.tsx b/src/components/ui/InlineFormActions.tsx
new file mode 100644
index 0000000..099f2f1
--- /dev/null
+++ b/src/components/ui/InlineFormActions.tsx
@@ -0,0 +1,39 @@
+interface InlineFormActionsProps {
+ onCancel: () => void;
+ onSubmit: () => void;
+ isPending: boolean;
+ disabled?: boolean;
+ submitLabel?: string;
+ submitColorClass?: string;
+ className?: string;
+}
+
+export function InlineFormActions({
+ onCancel,
+ onSubmit,
+ isPending,
+ disabled = false,
+ submitLabel = 'Ajouter',
+ submitColorClass = 'text-primary hover:bg-primary/10',
+ className = '',
+}: InlineFormActionsProps) {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
index db26c97..958a70f 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal.tsx
@@ -1,6 +1,7 @@
'use client';
import { Fragment, ReactNode, useEffect, useSyncExternalStore } from 'react';
+import { IconClose } from './Icons';
import { createPortal } from 'react-dom';
interface ModalProps {
@@ -84,14 +85,7 @@ export function Modal({ isOpen, onClose, title, children, size = 'md' }: ModalPr
className="rounded-lg p-1 text-muted hover:bg-card-hover hover:text-foreground transition-colors"
aria-label="Fermer"
>
-
+
)}
diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts
index ec411b4..3f7e877 100644
--- a/src/components/ui/index.ts
+++ b/src/components/ui/index.ts
@@ -12,6 +12,8 @@ export {
EditableWeatherTitle,
EditableGifMoodTitle,
} from './EditableTitles';
+export { IconEdit, IconTrash, IconDuplicate, IconPlus, IconCheck, IconClose } from './Icons';
+export { InlineFormActions } from './InlineFormActions';
export { PageHeader } from './PageHeader';
export { SessionPageHeader } from './SessionPageHeader';
export { Input } from './Input';
diff --git a/src/components/weekly-checkin/WeeklyCheckInCard.tsx b/src/components/weekly-checkin/WeeklyCheckInCard.tsx
index a6fbb0e..bc2a5c8 100644
--- a/src/components/weekly-checkin/WeeklyCheckInCard.tsx
+++ b/src/components/weekly-checkin/WeeklyCheckInCard.tsx
@@ -4,6 +4,7 @@ import { forwardRef, memo, useState, useTransition } from 'react';
import type { WeeklyCheckInItem } from '@prisma/client';
import { updateWeeklyCheckInItem, deleteWeeklyCheckInItem } from '@/actions/weekly-checkin';
import { WEEKLY_CHECK_IN_BY_CATEGORY, EMOTION_BY_TYPE } from '@/lib/types';
+import { IconEdit, IconTrash, InlineFormActions } from '@/components/ui';
import { Select } from '@/components/ui/Select';
interface WeeklyCheckInCardProps {
@@ -113,26 +114,13 @@ export const WeeklyCheckInCard = memo(
label: `${em.icon} ${em.label}`,
}))}
/>
-
-
-
-
+ { setContent(item.content); setEmotion(item.emotion); setIsEditing(false); }}
+ onSubmit={handleSave}
+ isPending={isPending}
+ disabled={!content.trim()}
+ submitLabel="Enregistrer"
+ />
) : (
<>
@@ -164,41 +152,14 @@ export const WeeklyCheckInCard = memo(
className="rounded p-1 text-muted hover:bg-card-hover hover:text-foreground"
aria-label="Modifier"
>
-
+
>
diff --git a/src/components/weekly-checkin/WeeklyCheckInSection.tsx b/src/components/weekly-checkin/WeeklyCheckInSection.tsx
index 334696d..87c2cde 100644
--- a/src/components/weekly-checkin/WeeklyCheckInSection.tsx
+++ b/src/components/weekly-checkin/WeeklyCheckInSection.tsx
@@ -4,6 +4,7 @@ import { forwardRef, useState, useTransition, useRef, ReactNode } from 'react';
import type { WeeklyCheckInCategory } from '@prisma/client';
import { createWeeklyCheckInItem } from '@/actions/weekly-checkin';
import { WEEKLY_CHECK_IN_BY_CATEGORY, EMOTION_BY_TYPE } from '@/lib/types';
+import { IconPlus, InlineFormActions } from '@/components/ui';
import { Select } from '@/components/ui/Select';
interface WeeklyCheckInSectionProps {
@@ -82,14 +83,7 @@ export const WeeklyCheckInSection = forwardRef
-
+
@@ -138,29 +132,12 @@ export const WeeklyCheckInSection = forwardRef
-
-
-
-
+ { setIsAdding(false); setNewContent(''); setNewEmotion('NONE'); }}
+ onSubmit={handleAdd}
+ isPending={isPending}
+ disabled={!newContent.trim()}
+ />
)}
diff --git a/src/components/year-review/YearReviewCard.tsx b/src/components/year-review/YearReviewCard.tsx
index 1135110..063bef9 100644
--- a/src/components/year-review/YearReviewCard.tsx
+++ b/src/components/year-review/YearReviewCard.tsx
@@ -4,6 +4,7 @@ import { forwardRef, memo, useState, useTransition } from 'react';
import type { YearReviewItem } from '@prisma/client';
import { updateYearReviewItem, deleteYearReviewItem } from '@/actions/year-review';
import { YEAR_REVIEW_BY_CATEGORY } from '@/lib/types';
+import { IconEdit, IconTrash } from '@/components/ui';
interface YearReviewCardProps {
item: YearReviewItem;
@@ -95,41 +96,14 @@ export const YearReviewCard = memo(
className="rounded p-1 text-muted hover:bg-card-hover hover:text-foreground"
aria-label="Modifier"
>
-
+
>
diff --git a/src/components/year-review/YearReviewSection.tsx b/src/components/year-review/YearReviewSection.tsx
index ccdf8ce..ec80146 100644
--- a/src/components/year-review/YearReviewSection.tsx
+++ b/src/components/year-review/YearReviewSection.tsx
@@ -4,6 +4,7 @@ import { forwardRef, useState, useTransition, useRef, ReactNode } from 'react';
import type { YearReviewCategory } from '@prisma/client';
import { createYearReviewItem } from '@/actions/year-review';
import { YEAR_REVIEW_BY_CATEGORY } from '@/lib/types';
+import { IconPlus, InlineFormActions } from '@/components/ui';
interface YearReviewSectionProps {
category: YearReviewCategory;
@@ -77,14 +78,7 @@ export const YearReviewSection = forwardRef
-
+
@@ -111,28 +105,13 @@ export const YearReviewSection = forwardRef
-
-
-
-
+ { setIsAdding(false); setNewContent(''); }}
+ onSubmit={handleAdd}
+ isPending={isPending}
+ disabled={!newContent.trim()}
+ className="mt-1"
+ />
)}