This commit is contained in:
2026-05-06 11:54:39 +02:00
parent 954c07a838
commit 902f093ced
5 changed files with 141 additions and 19 deletions
+63
View File
@@ -512,3 +512,66 @@ p {
.btn-icon-action.delete:hover { .btn-icon-action.delete:hover {
background: #fef2f2; /* Fond rouge très clair au survol */ background: #fef2f2; /* Fond rouge très clair au survol */
} }
/* === 13. PAGE DE CONNEXION (LOGIN) === */
.pf-login-wrapper {
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 200px);
padding: 20px;
}
.pf-login-card {
width: 100%;
max-width: 400px;
padding: 32px;
background: white;
border-radius: 16px;
box-shadow: var(--shadow-lg);
border: 1px solid var(--border-light);
}
.pf-login-header {
text-align: center;
margin-bottom: 24px;
}
.pf-login-header .pf-login-icon {
width: 60px; /* Tu peux ajuster cette valeur selon le rendu voulu */
height: auto;
margin-bottom: 15px;
border-radius: 12px; /* Optionnel : ajoute un léger arrondi si ton favicon est carré */
}
.pf-login-header h1 {
font-size: 1.8rem;
margin: 0;
color: var(--text-main);
}
.pf-login-header p {
color: var(--text-muted);
margin-top: 8px;
font-size: 0.95rem;
}
.pf-login-error {
background: #fef2f2;
color: #ef4444;
padding: 12px;
border-radius: 8px;
border: 1px solid #fca5a5;
margin-bottom: 20px;
font-size: 0.9rem;
text-align: center;
font-weight: 600;
}
.pf-btn-block {
width: 100%;
justify-content: center;
margin-top: 10px;
padding: 14px;
font-size: 1.05rem;
}
+7 -1
View File
@@ -13,7 +13,7 @@ return [
'tests_copy_report' => 'Copiar l\'informe', 'tests_copy_report' => 'Copiar l\'informe',
'tests_waiting' => 'Esperant l\'inici...', 'tests_waiting' => 'Esperant l\'inici...',
'tests_report_copied' => 'Informe copiat al porta-retalls!', 'tests_report_copied' => 'Informe copiat al porta-retalls!',
'tests_live_preview' => 'Previsualització en viu',
// ========================================== // ==========================================
// GLOBAL & NAVIGATION // GLOBAL & NAVIGATION
// ========================================== // ==========================================
@@ -70,6 +70,7 @@ return [
'btn_logout' => 'Tancar sessió', 'btn_logout' => 'Tancar sessió',
'error_missing_fields' => 'Camps obligatoris.', 'error_missing_fields' => 'Camps obligatoris.',
'error_invalid_credentials' => 'Identificadors incorrectes.', 'error_invalid_credentials' => 'Identificadors incorrectes.',
'login_subtitle' => 'Si us plau, identifiqueu-vos per continuar',
// ========================================== // ==========================================
// ACCUEIL / INDEX // ACCUEIL / INDEX
@@ -129,6 +130,11 @@ return [
'fc_menu_carole' => 'Permisos Carole', 'fc_menu_carole' => 'Permisos Carole',
'fc_clear' => 'Esborrar', 'fc_clear' => 'Esborrar',
'fc_menu_kids_leaves' => 'Permisos nens', 'fc_menu_kids_leaves' => 'Permisos nens',
'fc_err_save_snap' => 'Error en desar el correctiu.',
'fc_err_fetch_gov' => 'Error en la connexió amb lAPI governamental.',
'fc_err_no_data_gov' => 'No shan trobat dades a lAPI del govern per a aquest any.',
'fc_err_action' => 'Error en lacció: ',
'leg_presence_pep' => 'Presència Pep',
'leg_school_holidays' => 'Vacances Escolars', 'leg_school_holidays' => 'Vacances Escolars',
'leg_public_holiday' => 'Festiu', 'leg_public_holiday' => 'Festiu',
+7
View File
@@ -13,6 +13,7 @@ return [
'tests_copy_report' => 'Copier le rapport', 'tests_copy_report' => 'Copier le rapport',
'tests_waiting' => 'En attente du lancement...', 'tests_waiting' => 'En attente du lancement...',
'tests_report_copied' => 'Rapport copié dans le presse-papier !', 'tests_report_copied' => 'Rapport copié dans le presse-papier !',
'tests_live_preview' => 'Aperçu en direct',
// ========================================== // ==========================================
@@ -72,6 +73,7 @@ return [
'btn_logout' => 'Déconnexion', 'btn_logout' => 'Déconnexion',
'error_missing_fields' => 'Champs obligatoires.', 'error_missing_fields' => 'Champs obligatoires.',
'error_invalid_credentials' => 'Identifiants incorrects.', 'error_invalid_credentials' => 'Identifiants incorrects.',
'login_subtitle' => 'Veuillez vous identifier pour continuer',
// ========================================== // ==========================================
// ACCUEIL / INDEX // ACCUEIL / INDEX
@@ -131,6 +133,11 @@ return [
'fc_menu_carole' => 'Congés Carole', 'fc_menu_carole' => 'Congés Carole',
'fc_clear' => 'Effacer', 'fc_clear' => 'Effacer',
'fc_menu_kids_leaves' => 'Congés Enfants', 'fc_menu_kids_leaves' => 'Congés Enfants',
'fc_err_save_snap' => 'Erreur lors de la sauvegarde du correctif.',
'fc_err_fetch_gov' => 'Erreur lors de la connexion à lAPI gouvernementale.',
'fc_err_no_data_gov' => 'Aucune donnée trouvée sur lAPI du gouvernement pour cette année.',
'fc_err_action' => 'Erreur lors de laction : ',
'leg_presence_pep' => 'Présence Pep',
'leg_school_holidays' => 'Vacances Scolaires', 'leg_school_holidays' => 'Vacances Scolaires',
'leg_public_holiday' => 'Férié', 'leg_public_holiday' => 'Férié',
+34 -18
View File
@@ -42,26 +42,42 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require __DIR__ . '/header.php'; require __DIR__ . '/header.php';
?> ?>
<div class="pf-login-container"> <div class="pf-container pf-login-wrapper">
<h1 style="text-align:center; font-size:1.8rem;"><?= tr('login_header') ?></h1> <div class="pf-login-card">
<?php if ($error): ?> <div class="pf-login-header">
<div class="pf-error"><?= htmlspecialchars($error) ?></div> <img src="/favicon.png" alt="PachaFamily Logo" class="pf-login-icon">
<?php endif; ?> <h1><?= tr('login_header') ?></h1>
<p><?= tr('login_subtitle') ?></p>
</div>
<?php if ($error): ?>
<div class="pf-login-error">
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<form method="post" action="/login.php<?= isset($_GET['redirect']) ? '?redirect=' . urlencode($_GET['redirect']) : '' ?>"> <form method="post" action="/login.php<?= isset($_GET['redirect']) ? '?redirect=' . urlencode($_GET['redirect']) : '' ?>">
<div class="pf-form-group"> <div class="pf-form-group">
<label for="username"><?= tr('label_username') ?></label> <label class="pf-label" for="username"><?= tr('label_username') ?></label>
<input type="text" id="username" name="username" required autofocus placeholder="<?= tr('placeholder_username') ?>"> <input type="text" id="username" name="username" class="pf-input" required autofocus placeholder="<?= tr('placeholder_username') ?>">
</div>
<div class="pf-form-group">
<label class="pf-label" for="password"><?= tr('label_password') ?></label>
<input type="password" id="password" name="password" class="pf-input" required placeholder="••••••">
</div>
<button type="submit" class="pf-btn pf-btn-block">
<?= tr('btn_login_submit') ?>
</button>
</form>
</div> </div>
<div class="pf-form-group">
<label for="password"><?= tr('label_password') ?></label>
<input type="password" id="password" name="password" required placeholder="••••••">
</div>
<button type="submit" class="pf-btn"><?= tr('btn_login_submit') ?></button>
</form>
</div> </div>
<?php require __DIR__ . '/footer.php'; ?>
<?php require __DIR__ . '/footer.php'; ?>
<?php require __DIR__ . '/footer.php'; ?> <?php require __DIR__ . '/footer.php'; ?>
@@ -99,6 +99,8 @@ document.addEventListener("DOMContentLoaded", () => {
this.setupModalUI(); // Prépare le selecteur d'année dans la modale this.setupModalUI(); // Prépare le selecteur d'année dans la modale
await this.refreshAllData(); await this.refreshAllData();
this.updateSchoolYearLabel(); this.updateSchoolYearLabel();
setTimeout(() => this.scrollToCurrentMonth(), 100);
} }
// Modifie dynamiquement le titre de la modale pour y insérer le selecteur d'année // Modifie dynamiquement le titre de la modale pour y insérer le selecteur d'année
@@ -590,6 +592,7 @@ document.addEventListener("DOMContentLoaded", () => {
this.weeks.forEach((w, idx) => { this.weeks.forEach((w, idx) => {
const tr = document.createElement("tr"); const tr = document.createElement("tr");
tr.setAttribute("data-month", w.monthKey);
if (idx === 0 || this.weeks[idx - 1].monthKey !== w.monthKey) if (idx === 0 || this.weeks[idx - 1].monthKey !== w.monthKey)
tr.classList.add("fc-month-first-week-row"); tr.classList.add("fc-month-first-week-row");
if ( if (
@@ -688,6 +691,33 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
} }
// --- Auto-scroll vers le mois en cours ---
scrollToCurrentMonth() {
const wrapper = document.getElementById("planningTable-wrapper");
const thead = document.querySelector("#planningTable thead");
if (!wrapper || !thead) return;
const now = new Date();
// Construit la clé au format "YYYY-MM"
const currentYm = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
// Cherche la TOUTE PREMIÈRE ligne qui correspond à ce mois
const targetRow = document.querySelector(
`#planningTable tbody tr[data-month="${currentYm}"]`,
);
if (targetRow) {
// On donne 50ms au navigateur pour finir son rendu graphique avant de calculer les hauteurs
setTimeout(() => {
const scrollPos = targetRow.offsetTop - thead.offsetHeight;
wrapper.scrollTo({
top: scrollPos > 0 ? scrollPos : 0,
behavior: "smooth",
});
}, 50);
}
}
renderMonthCalendar() { renderMonthCalendar() {
if (!this.monthCalendar) return; if (!this.monthCalendar) return;
this.monthCalendar.innerHTML = ""; this.monthCalendar.innerHTML = "";