diff --git a/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.scss b/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.scss index 58b4e71..ed73c4f 100644 --- a/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.scss +++ b/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.scss @@ -6,16 +6,23 @@ display: flex; align-items: center; justify-content: space-between; - margin-bottom: 0.5rem; + margin-bottom: 1rem; + padding: 0 0.25rem; } &__month-title { - font-size: 0.875rem; + font-size: 1rem; font-weight: 500; text-transform: capitalize; color: var(--c--theme--colors--greyscale-800); } + &__nav { + display: flex; + align-items: center; + gap: 0.25rem; + } + &__nav-btn { display: flex; align-items: center; @@ -26,11 +33,12 @@ background: transparent; border-radius: 50%; cursor: pointer; - color: var(--c--theme--colors--greyscale-600); - transition: background-color 0.15s; + color: var(--c--theme--colors--greyscale-500); + transition: background-color 0.15s, color 0.15s; &:hover { background-color: var(--c--theme--colors--greyscale-100); + color: var(--c--theme--colors--greyscale-700); } .material-icons { @@ -38,9 +46,14 @@ } } + &__grid { + display: flex; + flex-direction: column; + } + &__weekdays { display: grid; - grid-template-columns: repeat(7, 1fr); + grid-template-columns: 2rem repeat(7, 1fr); gap: 0; margin-bottom: 0.25rem; } @@ -50,16 +63,37 @@ align-items: center; justify-content: center; height: 1.5rem; - font-size: 0.625rem; - font-weight: 500; - color: var(--c--theme--colors--greyscale-500); - text-transform: uppercase; + font-size: 0.75rem; + font-weight: 600; + color: var(--c--theme--colors--greyscale-800); + text-transform: lowercase; + + &--week-num { + color: var(--c--theme--colors--greyscale-500); + font-weight: 500; + font-size: 0.7rem; + } } - &__days { + &__body { + display: flex; + flex-direction: column; + gap: 2px; + } + + &__week { display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 1px; + grid-template-columns: 2rem repeat(7, 1fr); + gap: 0; + } + + &__week-number { + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + color: var(--c--theme--colors--greyscale-400); + font-weight: 400; } &__day { @@ -70,10 +104,11 @@ aspect-ratio: 1; border: none; background: transparent; - border-radius: 50%; + border-radius: 4px; cursor: pointer; - font-size: 0.75rem; + font-size: 0.8rem; color: var(--c--theme--colors--greyscale-800); + font-weight: 500; transition: background-color 0.15s; &:hover { @@ -82,21 +117,22 @@ &--outside { color: var(--c--theme--colors--greyscale-400); + font-weight: 400; } &--today { - background-color: var(--c--theme--colors--primary-100); color: var(--c--theme--colors--primary-600); font-weight: 600; } &--selected { - background-color: var(--c--theme--colors--primary-500); + background-color: #8b4513; color: white; font-weight: 600; + border-radius: 4px; &:hover { - background-color: var(--c--theme--colors--primary-600); + background-color: #7a3d11; } } } diff --git a/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.tsx b/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.tsx index d265ff1..7946dce 100644 --- a/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.tsx +++ b/src/frontend/apps/calendars/src/features/calendar/components/MiniCalendar.tsx @@ -2,7 +2,7 @@ * MiniCalendar component - A small month calendar for date navigation. */ -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { addMonths, @@ -10,6 +10,7 @@ import { endOfMonth, endOfWeek, format, + getWeek, isSameDay, isSameMonth, startOfMonth, @@ -17,18 +18,42 @@ import { subMonths, } from "date-fns"; import { fr } from "date-fns/locale"; +import { useTranslation } from "react-i18next"; +import { useCalendarContext } from "../contexts"; interface MiniCalendarProps { selectedDate: Date; onDateSelect: (date: Date) => void; } +// Helper to chunk array into groups of n +const chunkArray = (arr: T[], size: number): T[][] => { + const result: T[][] = []; + for (let i = 0; i < arr.length; i += size) { + result.push(arr.slice(i, i + size)); + } + return result; +}; + export const MiniCalendar = ({ selectedDate, onDateSelect, }: MiniCalendarProps) => { + const { t } = useTranslation(); + const { goToDate, currentDate } = useCalendarContext(); const [viewDate, setViewDate] = useState(selectedDate); + // Sync viewDate when main calendar navigates (via prev/next buttons) + useEffect(() => { + setViewDate((prevViewDate) => { + // Only update if the month changed to avoid unnecessary re-renders + if (!isSameMonth(prevViewDate, currentDate)) { + return currentDate; + } + return prevViewDate; + }); + }, [currentDate]); + const days = useMemo(() => { const monthStart = startOfMonth(viewDate); const monthEnd = endOfMonth(viewDate); @@ -38,7 +63,10 @@ export const MiniCalendar = ({ return eachDayOfInterval({ start: calendarStart, end: calendarEnd }); }, [viewDate]); - const weekDays = ["L", "M", "M", "J", "V", "S", "D"]; + // Group days by weeks + const weeks = useMemo(() => chunkArray(days, 7), [days]); + + const weekDays = ["lu", "ma", "me", "je", "ve", "sa", "di"]; const handlePrevMonth = () => { setViewDate(subMonths(viewDate, 1)); @@ -50,58 +78,76 @@ export const MiniCalendar = ({ const handleDayClick = (day: Date) => { onDateSelect(day); + goToDate(day); }; return (
- {format(viewDate, "MMMM yyyy", { locale: fr })} - +
+ + +
-
- {weekDays.map((day, index) => ( -
- {day} +
+ {/* Header row with week number column and days */} +
+
+ Sem.
- ))} -
+ {weekDays.map((day, index) => ( +
+ {day} +
+ ))} +
-
- {days.map((day, index) => { - const isCurrentMonth = isSameMonth(day, viewDate); - const isSelected = isSameDay(day, selectedDate); - const isToday = isSameDay(day, new Date()); + {/* Calendar body with weeks */} +
+ {weeks.map((week, weekIndex) => { + const weekNumber = getWeek(week[0], { weekStartsOn: 1 }); + return ( +
+
{weekNumber}
+ {week.map((day, dayIndex) => { + const isCurrentMonth = isSameMonth(day, viewDate); + const isSelected = isSameDay(day, selectedDate); + const isToday = isSameDay(day, new Date()); - return ( - - ); - })} + return ( + + ); + })} +
+ ); + })} +
);