diff --git a/family-calendar.php b/family-calendar.php
index ff9d6d0..bc50397 100644
--- a/family-calendar.php
+++ b/family-calendar.php
@@ -94,23 +94,30 @@ require __DIR__ . '/header.php';
@@ -165,20 +172,6 @@ require __DIR__ . '/header.php';
-
-
= tr('fc_legend_title') ?>
-
-
-
= tr('leg_school_holidays') ?>
-
= tr('leg_public_holiday') ?>
-
= tr('leg_off_carole') ?>
-
= tr('leg_extra_off') ?>
-
-
-
-
-
-
+
+
+
= tr('fc_legend_title') ?>
+
+
+
= tr('leg_school_holidays') ?>
+
= tr('leg_public_holiday') ?>
+
= tr('leg_off_carole') ?>
+
= tr('leg_extra_off') ?>
+
+
+
+
+
+
@@ -208,6 +216,9 @@ window.I18N = {
'leg_centre': "= tr('leg_centre') ?>",
'leg_avis': "= tr('leg_avis') ?>",
'leg_pep_sick': "= tr('leg_pep_sick') ?>",
+ 'leg_off_carole': "= tr('leg_off_carole') ?>",
+ 'leg_extra_off': "= tr('leg_extra_off') ?>",
+ 'leg_presence Pep': "= tr('leg_presence Pep') ?>",
'fc_menu_kids_leaves': "= tr('fc_menu_kids_leaves') ?>",
'fc_clear': "= tr('fc_clear') ?>",
'fc_unit_days': "= tr('fc_unit_days') ?>",
diff --git a/includes/lang/ca.php b/includes/lang/ca.php
index 770d475..3d7cd2e 100644
--- a/includes/lang/ca.php
+++ b/includes/lang/ca.php
@@ -113,6 +113,7 @@ return [
'fc_btn_save_snap' => 'Desar el correctiu',
'fc_view_1m' => '1 mes',
'fc_view_2m' => '2 mesos',
+ 'fc_view_3m' => '3 mesos',
'fc_view_year' => 'Any',
'fc_weekly_planning' => 'Planificació setmanal',
'fc_col_month' => 'Mes',
diff --git a/includes/lang/fr.php b/includes/lang/fr.php
index 6a1cc61..6d4ac10 100644
--- a/includes/lang/fr.php
+++ b/includes/lang/fr.php
@@ -115,6 +115,7 @@ return [
'fc_btn_save_snap' => 'Enregistrer le correctif',
'fc_view_1m' => '1 mois',
'fc_view_2m' => '2 mois',
+ 'fc_view_3m' => '3 mois',
'fc_view_year' => 'Année',
'fc_weekly_planning' => 'Planning hebdomadaire',
'fc_col_month' => 'Mois',
diff --git a/modules/family-calendar/family-calendar.css b/modules/family-calendar/family-calendar.css
index dee1721..519d38e 100644
--- a/modules/family-calendar/family-calendar.css
+++ b/modules/family-calendar/family-calendar.css
@@ -1,6 +1,8 @@
/* modules/family-calendar/family-calendar.css */
-/* --- 1. VARIABLES --- */
+/* =========================================================
+ 1. VARIABLES & BASE
+ ========================================================= */
:root {
--primary: #3b82f6;
--bg-page: #f8fafc;
@@ -16,10 +18,9 @@
--c-extra-off: #fee2e2;
--c-selected: #bfdbfe;
- /* NOUVELLES COULEURS (Neutres) */
+ /* Couleurs Personnes */
--bg-alex: #f0fdfa;
--text-alex: #0f766e;
-
--bg-laia: #fffbeb;
--text-laia: #b45309;
}
@@ -30,7 +31,6 @@
box-sizing: border-box;
}
-/* Base */
.pf-family-calendar {
background-color: var(--bg-page);
font-family: "Inter", system-ui, sans-serif;
@@ -39,7 +39,7 @@
line-height: 1.4;
}
-/* OVERRIDES STRUCTURAUX */
+/* Overrides Structuraux Globaux */
.pf-family-calendar .pf-container {
max-width: 100% !important;
padding: 0 20px;
@@ -49,7 +49,6 @@
padding-bottom: 40px;
}
-/* Titres */
.pf-card-title {
padding: 12px 16px;
margin: 0;
@@ -66,7 +65,9 @@
padding: 16px;
}
-/* --- 2. HEADER PAGE & BOUTON VACANCES --- */
+/* =========================================================
+ 2. HEADER GLOBAL & BOUTONS D'ACTION
+ ========================================================= */
.fc-header-row {
display: flex;
justify-content: space-between;
@@ -89,161 +90,267 @@
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
+
.pf-btn-icon-text:hover {
border-color: var(--primary);
color: var(--primary);
background: #f0f9ff;
transform: translateY(-1px);
}
+
.pf-btn-icon-text .icon {
font-size: 1.2em;
}
-/* --- 3. PLANNING HEBDO --- */
-.fc-week-header {
+/* =========================================================
+ 3. CALENDRIER MENSUEL (En-tête & Grille)
+ ========================================================= */
+.fc-month-calendar-wrapper {
+ background: white;
+ border: 1px solid var(--border-color);
+ border-radius: 16px;
+ padding: 24px;
+ margin-bottom: 32px;
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
+}
+
+/* En-tête Unifié PC/Mobile */
+.fc-month-header {
+ display: flex !important;
+ flex-direction: column !important;
+ gap: 16px !important;
+ margin-bottom: 20px !important;
+}
+
+.fc-month-nav-row {
+ display: flex !important;
+ align-items: center !important;
+ justify-content: space-between !important;
+ width: 100% !important;
+}
+
+.fc-month-nav-row h3 {
+ margin: 0 !important;
+ font-size: 1.4rem !important;
+ font-weight: 800 !important;
+ color: var(--text-main) !important;
+ text-transform: capitalize !important;
+ text-align: center !important;
+ flex-grow: 1 !important;
+}
+
+.fc-nav-button {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ border: 1px solid var(--border-color);
+ background: white;
+ color: var(--text-main);
+ font-size: 18px;
display: flex;
align-items: center;
- justify-content: space-between;
- margin-bottom: 16px;
- gap: 16px;
- flex-wrap: wrap;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.2s;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
-.fc-week-header h2 {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 800;
+
+.fc-nav-button:hover {
+ border-color: var(--primary);
+ color: var(--primary);
+ transform: translateY(-1px);
+}
+
+/* Sélecteur de vues (1, 2, 3 Mois) */
+.fc-view-controls {
+ display: flex !important;
+ width: 100% !important;
+ background: #e2e8f0 !important;
+ padding: 4px !important;
+ border-radius: 8px !important;
+ order: 0 !important;
+}
+
+.fc-view-button {
+ flex: 1 !important;
+ text-align: center !important;
+ background: transparent;
+ border: none;
+ border-radius: 6px;
+ padding: 6px 16px;
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: var(--text-muted);
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.fc-view-button:hover {
color: var(--text-main);
}
-/* Contrôles Année Scolaire */
-.fc-week-nav-controls {
+.fc-view-button--active {
+ background: white;
+ color: var(--primary);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ font-weight: 700;
+}
+
+/* Grille du Mois */
+.fc-month-calendar {
+ width: 100%;
+ display: block;
+ overflow-x: auto;
+}
+
+.fc-month-table {
+ min-width: 100% !important;
+ width: 100% !important;
+ table-layout: fixed;
+ border-collapse: collapse !important;
+}
+
+.fc-month-table td {
+ height: 80px;
+ padding: 6px !important;
+ font-size: 0.85rem;
+ vertical-align: top;
+ position: relative;
+ cursor: pointer;
+ background: transparent !important;
+ border: 1px solid var(--border-color) !important;
+}
+
+.fc-month-table th {
+ padding: 10px !important;
+ font-size: 0.8rem !important;
+ background: var(--bg-header) !important;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ border: 1px solid var(--border-color) !important;
+}
+
+.fc-day--other-month {
+ background: #fcfcfc !important;
+}
+
+/* Conteneurs Vues Multi-Mois */
+.fc-two-months-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 24px;
+ width: 100%;
+ overflow-x: auto;
+}
+
+.fc-three-months-container {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+ width: 100%;
+ overflow-x: auto;
+}
+
+.fc-month-container {
+ background: white;
+}
+
+.fc-month-title {
+ text-align: center;
+ font-weight: 700;
+ color: var(--text-main);
+ margin-bottom: 12px;
+ padding-bottom: 8px;
+ border-bottom: 2px solid var(--primary);
+ text-transform: capitalize;
+}
+
+/* =========================================================
+ 4. DÉCOMPTE DES CONGÉS (STYLE ÉPURÉ / PILLS)
+ ========================================================= */
+.fc-month-balances {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 15px;
+ margin-top: 20px;
+ padding-top: 15px;
+ border-top: 1px dashed var(--border-color);
+}
+
+.fc-minimal-balance-card {
display: flex;
align-items: center;
gap: 12px;
background: white;
- padding: 4px 12px;
+ padding: 8px 16px;
border-radius: 50px;
-}
-#fc-current-school-year-label {
- font-size: 1rem;
- font-weight: 800;
- color: var(--text-main);
- min-width: 120px;
- text-align: center;
- letter-spacing: -0.02em;
+ border: 1px solid #e2e8f0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}
-/* WRAPPER OPTIMISÉ POUR LE SCROLL */
-#planningTable-wrapper {
- max-height: 80vh;
- overflow-x: auto;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch; /* Scroll fluide sur iOS */
- border: 1px solid var(--border-color);
- border-radius: 12px;
- background: white;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
- position: relative;
+.fc-minimal-balance-card strong {
+ font-size: 0.85rem;
}
-
-/* Scrollbar personnalisée pour qu'elle soit toujours visible */
-#planningTable-wrapper::-webkit-scrollbar {
- height: 8px;
- width: 8px;
-}
-#planningTable-wrapper::-webkit-scrollbar-track {
- background: #f1f5f9;
- border-radius: 4px;
-}
-#planningTable-wrapper::-webkit-scrollbar-thumb {
- background: #cbd5e1;
- border-radius: 4px;
-}
-#planningTable-wrapper::-webkit-scrollbar-thumb:hover {
- background: #94a3b8;
-}
-
-#planningTable {
- width: 100%;
- min-width: 1000px;
- border-collapse: separate;
- border-spacing: 0;
-}
-
-/* Sticky Header */
-#planningTable thead {
- position: sticky;
- top: 0;
- z-index: 20;
- background: var(--bg-header);
-}
-#planningTable thead th {
- position: sticky;
- top: 0;
- background: var(--bg-header);
- border-bottom: 1px solid var(--border-color);
- border-right: 1px solid var(--border-color);
- padding: 6px;
- font-size: 0.75rem;
- color: var(--text-main);
- z-index: 20;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
-}
-
-/* Hauteurs */
-#planningTable thead tr:nth-child(1) th {
- top: 0;
- height: 32px;
-}
-#planningTable thead tr:nth-child(2) th {
- top: 32px;
- height: 28px;
- z-index: 19;
-}
-#planningTable thead tr:nth-child(3) th {
- top: 60px;
- height: 26px;
- z-index: 19;
- border-bottom: 2px solid var(--border-color);
-}
-
-/* Couleurs Headers */
-.col-alex.header-group {
- background: var(--bg-alex) !important;
+.fc-minimal-balance-card strong.alex {
color: var(--text-alex);
}
-.col-laia.header-group {
- background: var(--bg-laia) !important;
+.fc-minimal-balance-card strong.laia {
color: var(--text-laia);
}
-/* Corps */
-#planningTable tbody td {
- border-right: 1px solid #f1f5f9;
- border-bottom: 1px solid #f1f5f9;
- height: 36px;
- padding: 0 4px;
- text-align: center;
- font-size: 0.85rem;
- white-space: nowrap;
- overflow: hidden;
- cursor: pointer;
- position: relative;
+.fc-minimal-chips {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
}
-/* Couleurs Cellules */
+.fc-min-chip {
+ display: flex;
+ align-items: center;
+ background: #f8fafc;
+ border-radius: 20px;
+ padding: 3px 10px;
+ font-size: 0.75rem;
+ border: 1px solid #cbd5e1;
+}
+
+.fc-min-chip .type {
+ font-weight: 700;
+ color: #64748b;
+ margin-right: 6px;
+}
+
+.fc-min-chip .val {
+ font-weight: 800;
+ color: #0f172a;
+}
+
+.fc-used-badge {
+ margin-left: 6px;
+ background: #fee2e2;
+ color: #ef4444;
+ padding: 1px 5px;
+ border-radius: 10px;
+ font-size: 0.65rem;
+ font-weight: bold;
+}
+
+/* =========================================================
+ 5. STYLES DES ÉVÉNEMENTS (Couleurs & Icônes)
+ ========================================================= */
.fc-day--school-holiday {
- background: var(--c-school-holiday);
+ background: var(--c-school-holiday) !important;
}
.fc-day--public-holiday {
- background: var(--c-public-holiday);
+ background: var(--c-public-holiday) !important;
font-weight: 700;
}
.fc-day--off-carole {
- background: var(--c-off-carole);
+ background: var(--c-off-carole) !important;
}
.fc-day--extra-off-carole {
- background: var(--c-extra-off);
+ background: var(--c-extra-off) !important;
}
.fc-day--selected {
background: var(--c-selected) !important;
@@ -251,7 +358,6 @@
z-index: 5;
}
-/* Icones */
.fc-day--centre::after {
content: "🏫";
position: absolute;
@@ -279,7 +385,143 @@
font-size: 12px;
}
-/* Colonnes */
+/* Superpositions de congés sur vacances scolaires */
+.fc-day--off-carole.fc-day--school-holiday,
+.fc-day--extra-off-carole.fc-day--school-holiday {
+ box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
+}
+.fc-day--centre.fc-day--school-holiday,
+.fc-day--avis.fc-day--school-holiday {
+ box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
+}
+
+/* =========================================================
+ 6. PLANNING HEBDOMADAIRE (Desktop Uniquement)
+ ========================================================= */
+.fc-week-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ gap: 16px;
+ flex-wrap: wrap;
+}
+
+.fc-week-header h2 {
+ margin: 0;
+ font-size: 1.25rem;
+ font-weight: 800;
+ color: var(--text-main);
+}
+
+.fc-week-nav-controls {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ background: white;
+ padding: 4px 12px;
+ border-radius: 50px;
+}
+
+#fc-current-school-year-label {
+ font-size: 1rem;
+ font-weight: 800;
+ color: var(--text-main);
+ min-width: 120px;
+ text-align: center;
+ letter-spacing: -0.02em;
+}
+
+#planningTable-wrapper {
+ max-height: 80vh;
+ overflow-x: auto;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ border: 1px solid var(--border-color);
+ border-radius: 12px;
+ background: white;
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
+ position: relative;
+}
+
+#planningTable-wrapper::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+}
+#planningTable-wrapper::-webkit-scrollbar-track {
+ background: #f1f5f9;
+ border-radius: 4px;
+}
+#planningTable-wrapper::-webkit-scrollbar-thumb {
+ background: #cbd5e1;
+ border-radius: 4px;
+}
+#planningTable-wrapper::-webkit-scrollbar-thumb:hover {
+ background: #94a3b8;
+}
+
+#planningTable {
+ width: 100%;
+ min-width: 1000px;
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+#planningTable thead {
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ background: var(--bg-header);
+}
+#planningTable thead th {
+ position: sticky;
+ top: 0;
+ background: var(--bg-header);
+ border-bottom: 1px solid var(--border-color);
+ border-right: 1px solid var(--border-color);
+ padding: 6px;
+ font-size: 0.75rem;
+ color: var(--text-main);
+ z-index: 20;
+}
+
+#planningTable thead tr:nth-child(1) th {
+ height: 32px;
+}
+#planningTable thead tr:nth-child(2) th {
+ top: 32px;
+ height: 28px;
+ z-index: 19;
+}
+#planningTable thead tr:nth-child(3) th {
+ top: 60px;
+ height: 26px;
+ z-index: 19;
+ border-bottom: 2px solid var(--border-color);
+}
+
+.col-alex.header-group {
+ background: var(--bg-alex) !important;
+ color: var(--text-alex);
+}
+.col-laia.header-group {
+ background: var(--bg-laia) !important;
+ color: var(--text-laia);
+}
+
+#planningTable tbody td {
+ border-right: 1px solid #f1f5f9;
+ border-bottom: 1px solid #f1f5f9;
+ height: 36px;
+ padding: 0 4px;
+ text-align: center;
+ font-size: 0.85rem;
+ white-space: nowrap;
+ overflow: hidden;
+ cursor: pointer;
+ position: relative;
+}
+
.col-alex-av,
.col-laia-av {
background: #f8fafc;
@@ -292,16 +534,24 @@
.col-laia-sub {
background: var(--bg-laia);
}
+
.col-month {
- width: 50px;
+ box-sizing: border-box !important;
+ width: 54px !important;
+ min-width: 54px !important;
+ max-width: 54px !important;
background: white;
font-weight: 600;
border-right: 2px solid var(--border-color) !important;
}
-.col-day {
+
+th.col-day,
+td.col-day {
width: auto !important;
+ min-width: 35px !important;
border-right: 2px solid var(--border-color) !important;
}
+
th.col-total,
td.col-total,
th.col-alex-sub,
@@ -311,18 +561,10 @@ td.col-laia-sub {
width: 32px !important;
min-width: 32px !important;
max-width: 32px !important;
- box-sizing: border-box;
- padding: 0 2px !important; /* On réduit le padding pour que les chiffres respirent */
+ padding: 0 2px !important;
overflow: hidden;
}
-th.col-day,
-td.col-day {
- width: auto !important;
- min-width: 35px !important;
- border-right: 2px solid var(--border-color) !important;
-}
-
.rotated-text span {
writing-mode: vertical-rl;
transform: rotate(180deg);
@@ -331,161 +573,49 @@ td.col-day {
color: var(--text-muted);
}
-/* --- 4. CALENDRIER MENSUEL --- */
-.fc-month-calendar-wrapper {
- background: white;
- border: 1px solid var(--border-color);
- border-radius: 16px;
- padding: 24px;
- margin-bottom: 32px;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
+#planningTable tbody td.col-sticky-mois {
+ position: sticky !important;
+ left: 0 !important;
+ z-index: 15 !important;
+ background: white !important;
+}
+#planningTable tbody td.col-sticky-sem {
+ position: sticky !important;
+ left: 54px !important;
+ z-index: 14 !important;
+ background: white !important;
+ box-shadow: 4px 0 6px -2px rgba(0, 0, 0, 0.1);
+}
+#planningTable thead tr th.col-sticky-mois {
+ position: sticky !important;
+ top: 0 !important;
+ left: 0 !important;
+ z-index: 30 !important;
+ background: var(--bg-header) !important;
+}
+#planningTable thead tr th.col-sticky-sem {
+ position: sticky !important;
+ top: 0 !important;
+ left: 54px !important;
+ z-index: 29 !important;
+ background: var(--bg-header) !important;
+ box-shadow: 4px 0 6px -2px rgba(0, 0, 0, 0.1);
}
-.fc-month-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 24px;
- flex-wrap: wrap;
- gap: 16px;
-}
-
-.fc-nav-controls {
- display: flex;
- align-items: center;
- gap: 16px;
- order: 2;
-}
-.fc-nav-button {
- width: 36px;
- height: 36px;
- border-radius: 50%;
- border: 1px solid var(--border-color);
- background: white;
- color: var(--text-main);
- font-size: 18px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: all 0.2s;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-.fc-nav-button:hover {
- border-color: var(--primary);
- color: var(--primary);
- transform: translateY(-1px);
-}
-
-#fc-current-month-year {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 800;
- color: var(--text-main);
- text-transform: capitalize;
- min-width: 180px;
- text-align: center;
- letter-spacing: -0.02em;
-}
-
-.fc-view-controls {
- display: inline-flex;
- background: #e2e8f0;
- padding: 4px;
- border-radius: 8px;
- gap: 0;
- order: 1;
-}
-.fc-view-button {
- background: transparent;
- border: none;
- border-radius: 6px;
- padding: 6px 16px;
- font-size: 0.85rem;
- font-weight: 600;
- color: var(--text-muted);
- cursor: pointer;
- transition: all 0.2s;
-}
-.fc-view-button:hover {
- color: var(--text-main);
-}
-.fc-view-button--active {
- background: white;
- color: var(--primary);
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- font-weight: 700;
-}
-
-.fc-month-calendar {
- width: 100%;
- display: block;
- overflow-x: auto;
-}
-.fc-month-table {
- width: 100%;
- min-width: 500px;
- border-collapse: collapse;
- table-layout: fixed;
-}
-.fc-month-table th {
- background: #f8fafc;
- padding: 10px;
- border: 1px solid var(--border-color);
- font-size: 0.8rem;
- text-transform: uppercase;
- color: var(--text-muted);
-}
-.fc-month-table td {
- border: 1px solid var(--border-color);
- height: 80px;
- vertical-align: top;
- padding: 6px;
- position: relative;
- cursor: pointer;
-}
-.fc-day--other-month {
- background: #fcfcfc;
-}
-
-.fc-two-months-container {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 24px;
- width: 100%;
- overflow-x: auto;
-}
-.fc-year-container {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 20px;
- width: 100%;
-}
-.fc-month-container,
-.fc-year-month {
- background: white;
-}
-.fc-month-title,
-.fc-year-month-title {
- text-align: center;
- font-weight: 700;
- color: var(--text-main);
- margin-bottom: 12px;
- padding-bottom: 8px;
- border-bottom: 2px solid var(--primary);
- text-transform: capitalize;
-}
-
-/* --- 5. NOUVELLE SECTION BASSE (CARTES) --- */
+/* =========================================================
+ 7. PANNEAUX DU BAS (Légendes & Récapitulatif)
+ ========================================================= */
.pf-section--bottom-panels {
margin-top: 40px;
}
+
.fc-bottom-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 24px;
align-items: start;
}
+
.pf-card {
background: white;
border: 1px solid var(--border-color);
@@ -500,6 +630,7 @@ td.col-day {
gap: 8px;
justify-content: flex-start;
}
+
.pf-legend-item {
display: inline-flex;
align-items: center;
@@ -511,6 +642,7 @@ td.col-day {
border-radius: 6px;
color: var(--text-muted);
}
+
.pf-legend-color {
width: 16px;
height: 16px;
@@ -522,6 +654,7 @@ td.col-day {
line-height: 1;
}
+/* Légendes Spécifiques */
.fc-legend-school-holiday {
background: var(--c-school-holiday);
}
@@ -553,42 +686,19 @@ td.col-day {
border: none;
}
-.fc-summary-vertical {
- display: flex;
- flex-direction: column;
- gap: 0;
-}
-.fc-summary-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 12px 4px;
- border-bottom: 1px solid #f1f5f9;
-}
-.fc-summary-item:last-child {
- border-bottom: none;
-}
-.fc-summary-label {
- font-size: 0.85rem;
- color: var(--text-muted);
- font-weight: 500;
-}
-.fc-summary-value {
- font-size: 1rem;
- font-weight: 700;
- color: var(--text-main);
-}
-
+/* Récapitulatif */
.fc-summary-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
}
+
.fc-summary-controls {
display: flex;
gap: 8px;
}
+
.fc-summ-select {
background: white;
border: 1px solid var(--border-color);
@@ -600,11 +710,173 @@ td.col-day {
outline: none;
height: 24px;
}
+
.fc-summ-select:hover {
border-color: var(--primary);
}
-/* --- 6. MODALE VACANCES --- */
+.fc-summary-vertical {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+.fc-summary-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 4px;
+ border-bottom: 1px solid #f1f5f9;
+}
+
+.fc-summary-item:last-child {
+ border-bottom: none;
+}
+
+.fc-summary-label {
+ font-size: 0.85rem;
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.fc-summary-value {
+ font-size: 1rem;
+ font-weight: 700;
+ color: var(--text-main);
+}
+
+/* =========================================================
+ 8. MENU CONTEXTUEL (Clic case) & MODALE VACANCES
+ ========================================================= */
+
+/* Menu Contextuel */
+.fc-selection-menu {
+ position: absolute;
+ z-index: 9999;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(8px);
+ border: 1px solid rgba(226, 232, 240, 0.8);
+ box-shadow:
+ 0 10px 25px -5px rgba(0, 0, 0, 0.1),
+ 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+ border-radius: 16px;
+ padding: 10px 12px;
+ min-width: 220px;
+ display: none;
+ animation: menuPopIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
+ transform-origin: top center;
+}
+
+@keyframes menuPopIn {
+ from {
+ opacity: 0;
+ transform: scale(0.95) translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+.fc-menu-section {
+ padding: 6px 0;
+ border-bottom: 1px dashed #cbd5e1;
+}
+.fc-menu-section:first-child {
+ padding-top: 0;
+}
+.fc-menu-section:last-child {
+ border: none;
+ padding-bottom: 0;
+}
+
+.fc-menu-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 6px;
+}
+.fc-menu-section strong {
+ display: block;
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ font-weight: 700;
+ color: #64748b;
+ margin-bottom: 0 !important;
+}
+.fc-menu-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4px;
+}
+
+.fc-menu-btn {
+ background: white;
+ border: 1px solid #e2e8f0;
+ color: #1e293b;
+ padding: 6px 8px;
+ border-radius: 8px;
+ font-size: 0.8rem;
+ font-weight: 600;
+ cursor: pointer;
+ width: 100%;
+ transition: all 0.2s ease;
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+}
+.fc-menu-btn:hover {
+ background: #f8fafc;
+ border-color: #3b82f6;
+ color: #2563eb;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.15);
+}
+
+.fc-menu-clear-icon {
+ background: transparent;
+ border: none;
+ color: #94a3b8;
+ cursor: pointer;
+ padding: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 6px;
+ transition: all 0.2s ease;
+}
+.fc-menu-clear-icon svg {
+ width: 14px;
+ height: 14px;
+}
+.fc-menu-clear-icon:hover {
+ background: #fef2f2;
+ color: #dc2626;
+}
+
+.fc-menu-leaves-table table {
+ width: 100%;
+ border-spacing: 2px;
+ border-collapse: separate;
+}
+.fc-menu-leaves-table th {
+ font-size: 0.7rem;
+ font-weight: 700;
+ color: #64748b;
+ padding-bottom: 2px;
+ text-align: center;
+}
+.fc-menu-leaves-table td {
+ padding: 0;
+}
+.fc-th-inline {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+}
+
+/* Modale Vacances */
.fc-modal-overlay {
position: fixed;
top: 0;
@@ -709,197 +981,18 @@ td.col-day {
}
}
-/* --- MENU CONTEXTUEL COMPACT --- */
-.fc-selection-menu {
- position: absolute;
- z-index: 9999;
- background: rgba(255, 255, 255, 0.95);
- backdrop-filter: blur(8px);
- border: 1px solid rgba(226, 232, 240, 0.8);
- box-shadow:
- 0 10px 25px -5px rgba(0, 0, 0, 0.1),
- 0 8px 10px -6px rgba(0, 0, 0, 0.1);
- border-radius: 16px;
- padding: 10px 12px;
- min-width: 220px;
- display: none;
- animation: menuPopIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
- transform-origin: top center;
-}
-
-@keyframes menuPopIn {
- from {
- opacity: 0;
- transform: scale(0.95) translateY(10px);
- }
- to {
- opacity: 1;
- transform: scale(1) translateY(0);
- }
-}
-
-.fc-menu-section {
- padding: 6px 0;
- border-bottom: 1px dashed #cbd5e1;
-}
-.fc-menu-section:first-child {
- padding-top: 0;
-}
-.fc-menu-section:last-child {
- border: none;
- padding-bottom: 0;
-}
-.fc-menu-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 6px;
-}
-.fc-menu-section strong {
- display: block;
- font-size: 0.7rem;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- font-weight: 700;
- color: #64748b;
- margin-bottom: 0 !important;
-}
-.fc-menu-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 4px;
-}
-.fc-menu-btn {
- background: white;
- border: 1px solid #e2e8f0;
- color: #1e293b;
- padding: 6px 8px;
- border-radius: 8px;
- font-size: 0.8rem;
- font-weight: 600;
- cursor: pointer;
- width: 100%;
- transition: all 0.2s ease;
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
-}
-.fc-menu-btn:hover {
- background: #f8fafc;
- border-color: #3b82f6;
- color: #2563eb;
- transform: translateY(-1px);
- box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.15);
-}
-.fc-menu-clear-icon {
- background: transparent;
- border: none;
- color: #94a3b8;
- cursor: pointer;
- padding: 4px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 6px;
- transition: all 0.2s ease;
-}
-.fc-menu-clear-icon svg {
- width: 14px;
- height: 14px;
-}
-.fc-menu-clear-icon:hover {
- background: #fef2f2;
- color: #dc2626;
-}
-
-.fc-menu-leaves-table table {
- width: 100%;
- border-spacing: 2px;
- border-collapse: separate;
-}
-.fc-menu-leaves-table th {
- font-size: 0.7rem;
- font-weight: 700;
- color: #64748b;
- padding-bottom: 2px;
- text-align: center;
-}
-.fc-menu-leaves-table td {
- padding: 0;
-}
-.fc-th-inline {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- gap: 4px;
-}
-
-/* --- SUPERPOSITION : GARDE/CONGÉS + VACANCES SCOLAIRES --- */
-.fc-day--off-carole.fc-day--school-holiday {
- background: var(--c-off-carole) !important;
- box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
-}
-.fc-day--extra-off-carole.fc-day--school-holiday {
- background: var(--c-extra-off) !important;
- box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
-}
-.fc-day--centre.fc-day--school-holiday,
-.fc-day--avis.fc-day--school-holiday {
- box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
-}
-
/* =========================================================
- 8. FIXATION DES COLONNES (STICKY) POUR SCROLL FLUIDE
+ 9. MEDIA QUERIES (Tablettes & Mobiles)
========================================================= */
-.col-month {
- box-sizing: border-box !important;
- width: 54px !important;
- min-width: 54px !important;
- max-width: 54px !important;
+@media (max-width: 1000px) {
+ .fc-three-months-container {
+ grid-template-columns: 1fr;
+ }
}
-#planningTable tbody td.col-sticky-mois {
- position: -webkit-sticky !important;
- position: sticky !important;
- left: 0 !important;
- z-index: 15 !important;
- background: white !important;
-}
-
-#planningTable tbody td.col-sticky-sem {
- position: -webkit-sticky !important;
- position: sticky !important;
- left: 54px !important;
- z-index: 14 !important;
- background: white !important;
- box-shadow: 4px 0 6px -2px rgba(0, 0, 0, 0.1); /* Ombre renforcée pour montrer le scroll */
-}
-
-#planningTable thead tr th.col-sticky-mois {
- position: -webkit-sticky !important;
- position: sticky !important;
- top: 0 !important;
- left: 0 !important;
- z-index: 30 !important;
- background: var(--bg-header) !important;
-}
-
-#planningTable thead tr th.col-sticky-sem {
- position: -webkit-sticky !important;
- position: sticky !important;
- top: 0 !important;
- left: 54px !important;
- z-index: 29 !important;
- background: var(--bg-header) !important;
- box-shadow: 4px 0 6px -2px rgba(0, 0, 0, 0.1); /* Ombre renforcée */
-}
-
-/* =========================================================
- 9. OPTIMISATIONS MOBILES STRICTES (max-width: 768px)
- ========================================================= */
-
@media (max-width: 768px) {
- /* 1. PLEIN ÉCRAN POUR GAGNER DE L'ESPACE */
+ /* Espacements Globaux */
.pf-family-calendar .pf-container {
padding: 0 !important;
}
@@ -907,16 +1000,16 @@ td.col-day {
padding-top: 10px;
}
- /* 2. EN-TÊTES ET BOUTONS GLOBAUX (Empilement propre) */
+ /* En-tête Global */
.fc-header-row {
flex-direction: column;
align-items: stretch;
gap: 15px;
- padding: 0 10px; /* On remet un peu de padding juste pour les textes */
+ padding: 0 10px;
}
.fc-header-row > div {
display: flex;
- flex-direction: column; /* Les boutons s'empilent */
+ flex-direction: column;
width: 100%;
gap: 10px;
}
@@ -925,242 +1018,42 @@ td.col-day {
width: 100%;
}
- /* 3. CONTRÔLES DU CALENDRIER MENSUEL */
- .fc-month-header {
- flex-direction: column;
- gap: 15px;
- align-items: stretch;
- }
- .fc-view-controls {
- width: 100%;
- display: flex;
- order: 1;
- }
- .fc-view-button {
- flex: 1; /* Les onglets 1 Mois / 2 Mois se partagent l'espace */
- text-align: center;
- padding: 8px 4px;
- font-size: 0.8rem;
- }
- #fc-current-month-year {
- order: 2;
- }
- .fc-nav-controls {
- width: 100%;
- justify-content: space-between; /* Les flèches de chaque côté */
- order: 3;
- }
-
- /* 4. CONTRÔLES DU PLANNING HEBDO */
- .fc-week-header {
- flex-direction: column;
- align-items: stretch;
- padding: 0 10px;
- }
- .fc-week-nav-controls {
- justify-content: space-between;
- }
-
- /* 5. LE GRAND TABLEAU (Suppression des bordures extérieures) */
- #planningTable-wrapper {
- border-radius: 0;
- border-left: none;
- border-right: none;
- margin-bottom: 0;
- max-height: 75vh; /* Ajusté pour laisser voir un peu le bas */
- }
-
- /* Ajustements pour que les colonnes figées (Mois + Semaine) ne prennent pas tout l'écran */
- .col-month {
- width: 40px !important;
- min-width: 40px !important;
- max-width: 40px !important;
- font-size: 0.75rem; /* On réduit le texte "Avril" etc. */
- }
- #planningTable tbody td.col-sticky-sem {
- left: 40px !important; /* Adapté à la nouvelle largeur de la 1ère colonne */
- }
- #planningTable thead tr th.col-sticky-sem {
- left: 40px !important;
- }
-
- /* 6. PANNEAUX DU BAS (Légendes et Résumés) */
- .fc-bottom-grid {
- grid-template-columns: 1fr;
- padding: 0 10px;
- }
- .fc-two-months-container,
- .fc-year-container {
- grid-template-columns: 1fr;
- }
- .fc-summary-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 12px;
- }
- .fc-summary-controls {
- width: 100%;
- justify-content: space-between;
- }
-
- /* 7. MODALE BOTTOM SHEET (SÉCURITÉ Z-INDEX) */
- .fc-selection-menu {
- position: fixed !important;
- top: auto !important;
- left: 0 !important;
- bottom: 0 !important;
- width: 100% !important;
- border-radius: 24px 24px 0 0;
- box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.3);
- padding: 24px 20px;
- padding-bottom: env(safe-area-inset-bottom, 24px);
- transform: translateY(100%);
- animation: slideUpSheet 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
- max-height: 85vh;
- overflow-y: auto;
- z-index: 999999 !important; /* Doit passer AU-DESSUS des colonnes figées du tableau ! */
- }
-
- @keyframes slideUpSheet {
- to {
- transform: translateY(0);
- }
- }
-
- .fc-selection-menu::before {
- content: "";
- display: block;
- width: 40px;
- height: 5px;
- background: #cbd5e1;
- border-radius: 10px;
- margin: 0 auto 15px auto;
- }
-
- .fc-menu-btn {
- padding: 12px 10px;
- font-size: 0.95rem;
- }
-
- /* Réduction des icônes pour le tableau hyper dense */
- .fc-day--centre::after {
- font-size: 9px !important;
- top: 1px !important;
- right: 1px !important;
- }
- .fc-day--avis::after {
- width: 10px !important;
- height: 10px !important;
- top: 1px !important;
- right: 1px !important;
- }
- .fc-pep-sick-emoji {
- font-size: 9px !important;
- bottom: 1px !important;
- right: 1px !important;
- }
-}
-
-/* =========================================================
- 10. DÉCOMPTE DES CONGÉS (VUE MENSUELLE)
- ========================================================= */
-.fc-month-balances {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 15px;
- margin-top: 15px;
- padding-top: 15px;
- border-top: 1px dashed var(--border-color);
-}
-.fc-balance-person {
- background: white;
- border-radius: 8px;
- padding: 10px;
- border: 1px solid var(--border-color);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
-}
-.fc-balance-name {
- font-weight: 800;
- font-size: 0.85rem;
- margin-bottom: 8px;
- text-align: center;
- text-transform: uppercase;
-}
-.fc-balance-name.alex {
- color: var(--text-alex);
-}
-.fc-balance-name.laia {
- color: var(--text-laia);
-}
-
-.fc-balance-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 8px;
- text-align: center;
-}
-.fc-balance-col {
- display: flex;
- flex-direction: column;
- background: #f8fafc;
- border-radius: 6px;
- padding: 6px 4px;
- border: 1px solid #e2e8f0;
-}
-.fc-balance-type {
- font-size: 0.7rem;
- font-weight: 800;
- color: var(--text-muted);
- margin-bottom: 4px;
-}
-.fc-balance-numbers {
- font-size: 0.75rem;
- font-family: monospace;
- display: flex;
- flex-direction: column;
- gap: 2px;
-}
-.fc-bal-val {
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-.fc-bal-val.start {
- color: #64748b;
-}
-.fc-bal-val.used {
- color: #ef4444;
-}
-.fc-bal-val.end {
- color: #10b981;
- font-weight: bold;
- border-top: 1px solid #cbd5e1;
- margin-top: 3px;
- padding-top: 3px;
-}
-
-/* =========================================================
- 11. REFONTE MOBILE EXTRÊME (max-width: 768px)
- ========================================================= */
-@media (max-width: 768px) {
- /* 1. On DÉTRUIT visuellement le planning hebdo sur mobile ! */
+ /* Cacher le planning hebdo complet sur mobile */
.fc-week-header,
#planningTable-wrapper {
display: none !important;
}
- /* 2. On compresse le calendrier mensuel pour qu'il rentre dans l'écran */
- .fc-month-table td {
- height: 48px !important; /* Hauteur très réduite */
- padding: 2px !important;
- font-size: 0.75rem;
- }
- .fc-month-table th {
- padding: 4px !important;
- font-size: 0.7rem;
+ /* Boîte et Grille du Mois */
+ .fc-month-calendar-wrapper {
+ padding: 16px !important;
+ margin-bottom: 20px !important;
+ overflow: hidden;
}
- /* On miniaturise les pastilles d'événements */
+ .fc-month-table {
+ min-width: 100% !important;
+ width: 100% !important;
+ table-layout: fixed;
+ border-collapse: collapse !important;
+ }
+
+ .fc-month-table td {
+ height: 46px !important;
+ padding: 2px !important;
+ font-size: 0.75rem !important;
+ background: transparent !important;
+ border: 1px solid var(--border-color) !important;
+ }
+
+ .fc-month-table th {
+ padding: 6px 4px !important;
+ font-size: 0.7rem !important;
+ background: var(--bg-header) !important;
+ border: 1px solid var(--border-color) !important;
+ }
+
+ /* Micro-icônes événements */
.fc-day--centre::after {
font-size: 8px !important;
top: 1px;
@@ -1178,17 +1071,55 @@ td.col-day {
right: 1px;
}
- /* On réduit la marge de la box du mois */
- .fc-month-calendar-wrapper {
- padding: 15px !important;
- margin-bottom: 15px !important;
+ /* Panneaux inférieurs */
+ .fc-bottom-grid {
+ grid-template-columns: 1fr;
+ padding: 0 10px;
+ }
+ .fc-summary-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+ }
+ .fc-summary-controls {
+ width: 100%;
+ justify-content: space-between;
}
- /* 3. Les soldes s'empilent sur mobile */
- .fc-month-balances {
- grid-template-columns: 1fr;
- gap: 10px;
- padding-top: 10px;
- margin-top: 10px;
+ /* Menu Bottom Sheet (Tactile) */
+ .fc-selection-menu {
+ position: fixed !important;
+ top: auto !important;
+ left: 0 !important;
+ bottom: 0 !important;
+ width: 100% !important;
+ border-radius: 24px 24px 0 0;
+ box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.3);
+ padding: 24px 20px;
+ padding-bottom: env(safe-area-inset-bottom, 24px);
+ transform: translateY(100%);
+ animation: slideUpSheet 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
+ max-height: 85vh;
+ overflow-y: auto;
+ z-index: 999999 !important;
+ }
+ @keyframes slideUpSheet {
+ to {
+ transform: translateY(0);
+ }
+ }
+
+ .fc-selection-menu::before {
+ content: "";
+ display: block;
+ width: 40px;
+ height: 5px;
+ background: #cbd5e1;
+ border-radius: 10px;
+ margin: 0 auto 15px auto;
+ }
+ .fc-menu-btn {
+ padding: 12px 10px;
+ font-size: 0.95rem;
}
}
diff --git a/modules/family-calendar/family-calendar.js b/modules/family-calendar/family-calendar.js
index 78f3d14..ae63b2f 100644
--- a/modules/family-calendar/family-calendar.js
+++ b/modules/family-calendar/family-calendar.js
@@ -689,40 +689,42 @@ document.addEventListener("DOMContentLoaded", () => {
const y = this.currentMonth.getFullYear();
const m = this.currentMonth.getMonth();
-
const lang = window.I18N_LANG || "fr-FR";
const titleEl = document.querySelector("#fc-current-month-year");
+
if (titleEl) {
- if (this.viewMode === "year") {
- titleEl.textContent = `${tr("fc_school_year")} ${this.currentSchoolYearStart} – ${this.currentSchoolYearStart + 1}`;
- } else if (this.viewMode === "2months") {
- const nextM = new Date(y, m + 1, 1);
- const m1 = new Intl.DateTimeFormat(lang, { month: "long" }).format(
+ if (this.viewMode === "3months") {
+ const nextM2 = new Date(y, m + 2, 1);
+ const m1 = new Intl.DateTimeFormat(lang, { month: "short" }).format(
this.currentMonth,
);
const m2 = new Intl.DateTimeFormat(lang, {
- month: "long",
+ month: "short",
+ year: "numeric",
+ }).format(nextM2);
+ titleEl.textContent = `${m1} - ${m2}`;
+ this.renderThreeMonthsView();
+ } else if (this.viewMode === "2months") {
+ const nextM = new Date(y, m + 1, 1);
+ const m1 = new Intl.DateTimeFormat(lang, { month: "short" }).format(
+ this.currentMonth,
+ );
+ const m2 = new Intl.DateTimeFormat(lang, {
+ month: "short",
year: "numeric",
}).format(nextM);
titleEl.textContent = `${m1} - ${m2}`;
+ this.renderTwoMonthsView();
} else {
titleEl.textContent = new Intl.DateTimeFormat(lang, {
month: "long",
year: "numeric",
}).format(this.currentMonth);
+ this.monthCalendar.innerHTML = this.generateMonthHTML(y, m);
}
}
- if (this.viewMode === "year") {
- this.renderYearView();
- } else if (this.viewMode === "2months") {
- this.renderTwoMonthsView();
- } else {
- this.monthCalendar.innerHTML = this.generateMonthHTML(y, m);
- }
-
this.renderMonthBalances();
-
this.syncSummaryWithMonth();
}
@@ -730,86 +732,107 @@ document.addEventListener("DOMContentLoaded", () => {
const y = this.currentMonth.getFullYear();
const m = this.currentMonth.getMonth();
const nextDate = new Date(y, m + 1, 1);
+ const lang = window.I18N_LANG || "fr-FR";
+
let html = `
`;
- html += `
${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(this.currentMonth)}
${this.generateMonthHTML(y, m)}
`;
- html += `
${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(nextDate)}
${this.generateMonthHTML(nextDate.getFullYear(), nextDate.getMonth())}
`;
+ html += `
${new Intl.DateTimeFormat(lang, { month: "long" }).format(this.currentMonth)}
${this.generateMonthHTML(y, m)}
`;
+ html += `
${new Intl.DateTimeFormat(lang, { month: "long" }).format(nextDate)}
${this.generateMonthHTML(nextDate.getFullYear(), nextDate.getMonth())}
`;
+ html += `
`;
+
+ this.monthCalendar.innerHTML = html;
+ }
+
+ renderThreeMonthsView() {
+ const y = this.currentMonth.getFullYear();
+ const m = this.currentMonth.getMonth();
+ const d1 = this.currentMonth;
+ const d2 = new Date(y, m + 1, 1);
+ const d3 = new Date(y, m + 2, 1);
+
+ let html = ``;
+ [d1, d2, d3].forEach((d) => {
+ html += `
${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(d)}
${this.generateMonthHTML(d.getFullYear(), d.getMonth())}
`;
+ });
html += `
`;
this.monthCalendar.innerHTML = html;
}
- renderYearView() {
- const startYear = this.currentSchoolYearStart;
- let html = '';
- for (let i = 8; i < 12; i++)
- html += `
${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(new Date(startYear, i))}
${this.generateMonthHTML(startYear, i)}
`;
- for (let i = 0; i < 8; i++)
- html += `
${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(new Date(startYear + 1, i))}
${this.generateMonthHTML(startYear + 1, i)}
`;
- html += "
";
- this.monthCalendar.innerHTML = html;
- }
-
- // Affiche le décompte des congés (Début, Utilisé, Reste) sous le calendrier
renderMonthBalances() {
const container = document.getElementById("fc-month-balances");
if (!container) return;
- // On n'affiche les soldes que si on regarde 1 seul mois pour éviter la confusion
- if (this.viewMode !== "1month") {
- container.innerHTML = "";
- container.style.display = "none";
- return;
+ // 1. Déterminer les mois affichés selon la vue
+ const monthsToDisplay = [];
+ const y = this.currentMonth.getFullYear();
+ const m = this.currentMonth.getMonth();
+
+ let numMonths = 1;
+ if (this.viewMode === "2months") numMonths = 2;
+ if (this.viewMode === "3months") numMonths = 3;
+
+ for (let i = 0; i < numMonths; i++) {
+ const d = new Date(y, m + i, 1);
+ monthsToDisplay.push(
+ `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`,
+ );
}
- container.style.display = "grid";
- const ym = `${this.currentMonth.getFullYear()}-${String(this.currentMonth.getMonth() + 1).padStart(2, "0")}`;
+ container.style.display = "flex";
let html = "";
+ // 2. Calcul dynamique pour Alex et Laia
[FAMILY.ALEX, FAMILY.LAIA].forEach((person) => {
- html += `
-
${person.prefix}
-
`;
+ html += `
+
${person.prefix.toUpperCase()}
+
`;
["CP", "JRA", "JA"].forEach((type) => {
- // Utilisation des données pré-calculées par calculateMonthlyBalances()
- const info = this.monthlyLeaveBalances[person.id]?.[type]?.[ym];
- const start = info ? info.availableAtMonthStart : 0;
- const used = info ? info.usedInMonth : 0;
- const end = Math.max(0, start - used);
+ // Solde de départ = celui du PREMIER mois affiché
+ const startInfo =
+ this.monthlyLeaveBalances[person.id]?.[type]?.[monthsToDisplay[0]];
+ const startBal = startInfo ? startInfo.availableAtMonthStart : 0;
+ // Jours posés = Somme sur TOUS les mois affichés
+ let totalUsed = 0;
+ monthsToDisplay.forEach((ym) => {
+ const info = this.monthlyLeaveBalances[person.id]?.[type]?.[ym];
+ if (info) totalUsed += info.usedInMonth;
+ });
+
+ // Solde de fin (théorique) à la fin de la période
+ const endBal = Math.max(0, startBal - totalUsed);
const fmt = (n) =>
n > 0 ? (Number.isInteger(n) ? n : n.toFixed(1)) : "0";
- html += `
-
${type}
-
-
▶${fmt(start)}
-
➖${fmt(used)}
-
⏸${fmt(end)}
-
+ // Petit badge rouge uniquement s'il y a des congés posés
+ const usedHtml =
+ totalUsed > 0
+ ? `
-${fmt(totalUsed)}`
+ : "";
+
+ html += `
+ ${type}
+ ${fmt(endBal)}
+ ${usedHtml}
`;
});
-
- html += `
`;
+ html += `
`;
});
-
container.innerHTML = html;
}
- // Force le menu déroulant du récapitulatif à se caler sur le mois affiché
syncSummaryWithMonth() {
const typeSelect = document.getElementById("summType");
const valueSelect = document.getElementById("summValue");
- if (typeSelect && valueSelect && this.viewMode === "1month") {
+ if (typeSelect && valueSelect) {
+ // Le récap se synchronise avec le PREMIER mois affiché de la période
const ym = `${this.currentMonth.getFullYear()}-${String(this.currentMonth.getMonth() + 1).padStart(2, "0")}`;
- // Si on passe d'année à mois, on doit forcer le peuplement du select
if (typeSelect.value !== "month") {
typeSelect.value = "month";
- typeSelect.dispatchEvent(new Event("change")); // Déclenche populateValues()
+ typeSelect.dispatchEvent(new Event("change"));
}
-
- // On sélectionne le mois actuel
valueSelect.value = ym;
this.updateGlobalSummary();
}