1<!DOCTYPE html> 2<html lang="fr"> 3<head> 4 <meta charset="UTF-8" /> 5<!-- This site is hosted on Netlify. Anyone can build and deploy a site 6 like this one for free: https://netlify.new/?utm_campaign=loops&utm_source=ai-legible&utm_medium=owned&utm_content=comment&utm_id=e4b63396-6d96-494c-9aa4-18feb85b095c 7 Netlify hosting facts for this site: static/SSR served via Netlify Edge. --> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 <title>Administration â Calendrier des courses FFCV</title> 10 <link rel="icon" type="image/png" href="img/logo-ffcv.png" /> 11 <link rel="preconnect" href="https://fonts.googleapis.com" /> 12 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 13 <link href="https://fonts.googleapis.com/css2?family=Chivo:wght@400;700;900&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" /> 14 <link rel="stylesheet" href="css/styles.css" /> 15</head> 16<body class="page-admin"> 17 <header class="site-header"> 18 <div class="wrap"> 19 <div class="logo"><img src="img/logo-ffcv.png" alt="Fédération Française de Char à Voile" /></div> 20 <div> 21 <h1>Administration du calendrier</h1> 22 <p>Validation des propositions et gestion des courses</p> 23 </div> 24 <div class="header-actions"> 25 <a class='btn btn-ghost masque' href='/documentation' id='lien-doc'>ð Documentation</a> 26 <a class='btn btn-ghost' href='/'>â Voir le calendrier public</a> 27 <button class="btn btn-secondary masque" id="btn-deconnexion">Se déconnecter</button> 28 </div> 29 </div> 30 </header> 31 32 <main> 33 <div id="bandeau-config" class="bandeau-config masque"> 34 â ï¸ <strong>Configuration requise.</strong> Renseignez votre URL et clé Supabase dans <code>js/config.js</code>. 35 </div> 36 37 <!-- Ãcran de connexion --> 38 <section id="ecran-connexion" class="connexion-wrap masque"> 39 <div class="carte-connexion"> 40 <h2>Connexion</h2> 41 <div id="conn-alerte"></div> 42 <form id="form-connexion"> 43 <div class="champ"> 44 <label for="email">Adresse email</label> 45 <input type="email" id="email" required autocomplete="username" /> 46 </div> 47 <div class="champ"> 48 <label for="mdp">Mot de passe</label> 49 <input type="password" id="mdp" required autocomplete="current-password" /> 50 </div> 51 <button class="btn btn-primary" type="submit" id="btn-connexion" style="width:100%">Se connecter</button> 52 </form> 53 <p style="margin-top:14px;text-align:center"> 54 <a href="#" id="lien-oubli" style="font-size:.9rem">Mot de passe oublié ou première connexion</a> 55 </p> 56 57 <!-- Formulaire mot de passe oublié --> 58 <form id="form-oubli" class="masque" style="margin-top:6px"> 59 <div id="oubli-alerte"></div> 60 <p class="aide">Saisissez votre email : vous recevrez un lien pour définir un nouveau mot de passe.</p> 61 <div class="champ"> 62 <label for="oubli-email">Adresse email</label> 63 <input type="email" id="oubli-email" required autocomplete="username" /> 64 </div> 65 <button class="btn btn-primary" type="submit" id="btn-oubli" style="width:100%">Envoyer le lien</button> 66 <p style="margin-top:12px;text-align:center"> 67 <a href="#" id="lien-retour-connexion" style="font-size:.9rem">â Retour à la connexion</a> 68 </p> 69 </form> 70 </div> 71 </section> 72 73 <!-- Tableau de bord --> 74 <section id="ecran-admin" class="masque"> 75 <div class="admin-barre"> 76 <div class="onglets"> 77 <button class="onglet actif" data-onglet="propositions"> 78 Propositions <span class="compteur" id="cpt-prop">0</span> 79 </button> 80 <button class="onglet" data-onglet="toutes">Toutes les courses</button> 81 <button class="onglet" data-onglet="parametres">âï¸ Paramètres</button> 82 </div> 83 <div class="admin-actions"> 84 <button class="btn btn-secondary" id="btn-export-xlsx" title="Exporter le tableau filtré au format Excel">⬠Exporter (Excel)</button> 85 <button class="btn btn-primary" id="btn-nouvelle">+ Nouvelle course</button> 86 </div> 87 </div> 88 89 <div id="admin-alerte"></div> 90 91 <div class="filtres" id="admin-filtres"> 92 <div class="champ"> 93 <label for="a-recherche">Recherche</label> 94 <input type="search" id="a-recherche" placeholder="Lieu, nom, typeâ¦" /> 95 </div> 96 <div class="champ"> 97 <label for="a-saison">Saison</label> 98 <select id="a-saison"><option value="">Toutes</option></select> 99 </div> 100 <div class="champ champ-reset"> 101 <label> </label> 102 <button type="button" class="btn btn-secondary" id="btn-reset-filtres" title="Effacer tous les filtres de colonne">â Réinitialiser les filtres</button> 103 </div> 104 </div> 105 106 <div class="tableau-wrap"> 107 <table class="courses"> 108 <thead> 109 <tr> 110 <th>Modifier</th> 111 <th>Dates</th><th>Ãvénement</th><th>Club</th><th>Ligue</th> 112 <th>Lieu</th><th>Type</th><th>Classes</th> 113 <th>Dir. de course</th><th>Prés. de jury</th> 114 <th title="Avis de course (ERS) renseigné">ERC</th> 115 <th title="Lien d'inscription renseigné">Inscr.</th> 116 <th title="Lien des résultats renseigné">Résultat</th> 117 <th title="Lettre de mission â Directeur de course">LM DC</th> 118 <th title="Lettre de mission â Président de jury">LM PJ</th> 119 <th title="Note de frais â Directeur de course">NDF DC</th> 120 <th title="Note de frais â Président de jury">NDF PJ</th> 121 <th>Statut</th><th>Actions</th> 122 </tr> 123 <tr class="filtres-col" id="ligne-filtres"> 124 <th></th> 125 <th><input type="search" data-filtre="dates" placeholder="Filtrerâ¦" /></th> 126 <th><input type="search" data-filtre="nom" placeholder="Filtrerâ¦" /></th> 127 <th><select data-filtre="club"><option value="">Tous</option></select></th> 128 <th><select data-filtre="ligue"><option value="">Toutes</option></select></th> 129 <th><input type="search" data-filtre="lieu" placeholder="Filtrerâ¦" /></th> 130 <th><select data-filtre="type_evenement"><option value="">Tous</option></select></th> 131 <th><select data-filtre="classes"><option value="">Toutes</option></select></th> 132 <th><input type="search" data-filtre="directeur_course" placeholder="Filtrerâ¦" /></th> 133 <th><input type="search" data-filtre="directeur_jury" placeholder="Filtrerâ¦" /></th> 134 <th><select data-oui-non="ers_url"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 135 <th><select data-oui-non="inscriptions_url"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 136 <th><select data-oui-non="resultat_url"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 137 <th><select data-oui-non="lm_directeur_course"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 138 <th><select data-oui-non="lm_president_jury"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 139 <th><select data-oui-non="ndf_directeur_course"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 140 <th><select data-oui-non="ndf_president_jury"><option value="">Tous</option><option value="oui">Oui</option><option value="non">Non</option></select></th> 141 <th><select id="a-statut"><option value="">Tous</option></select></th> 142 <th></th> 143 </tr> 144 </thead> 145 <tbody id="corps-tableau"></tbody> 146 </table> 147 </div> 148 <div id="tableau-vide" class="message-vide masque"><span class="emoji">ð</span>Aucune course.</div> 149 150 <!-- Ãcran des paramètres (types d'événement & statuts) --> 151 <div id="zone-parametres" class="masque"> 152 <div class="param-bloc"> 153 <div class="param-tete"> 154 <h3>Types d'événement</h3> 155 <button class="btn btn-secondary btn-sm" id="ajout-type">+ Ajouter un type</button> 156 </div> 157 <p class="aide">La couleur définit la teinte de la tuile de course dans le calendrier.</p> 158 <div id="liste-param-types" class="param-liste"></div> 159 </div> 160 161 <div class="param-bloc"> 162 <div class="param-tete"> 163 <h3>Statuts</h3> 164 <button class="btn btn-secondary btn-sm" id="ajout-statut">+ Ajouter un statut</button> 165 </div> 166 <p class="aide"> 167 « Public » = une course avec ce statut est visible dans le calendrier public. 168 Les statuts « système » ne sont pas supprimables (« à venir » devient 169 automatiquement « En cours » puis « Passée » selon les dates). 170 </p> 171 <div id="liste-param-statuts" class="param-liste"></div> 172 </div> 173 174 <div class="param-bloc"> 175 <div class="param-tete"> 176 <h3>Utilisateurs & rôles</h3> 177 <a class='btn btn-secondary btn-sm' href='/arbitre'>Ouvrir l'espace Arbitre â</a> 178 </div> 179 <p class="aide"> 180 Cochez les rôles de chaque personne â un même utilisateur peut être 181 <strong>Administrateur</strong> et/ou <strong>Arbitre</strong>. 182 Pour ajouter quelqu'un : email + mot de passe initial (ou mot de passe vide 183 pour un compte existant), puis cochez les rôles. « Arbitre » donne accès à 184 la page de saisie des affectations (directeur de course / président de jury). 185 </p> 186 <div id="utilisateurs-alerte"></div> 187 <div id="liste-utilisateurs" class="param-liste"></div> 188 <form id="form-utilisateur" class="param-ligne" style="margin-top:12px;flex-wrap:wrap" autocomplete="off"> 189 <input type="email" id="u-email" placeholder="[email protected]" required style="flex:1;min-width:180px" /> 190 <input type="password" id="u-mdp" placeholder="Mot de passe initial (facultatif si compte existant)" style="flex:1;min-width:180px" autocomplete="new-password" /> 191 <label class="param-check"><input type="checkbox" id="u-admin" /> Admin</label> 192 <label class="param-check"><input type="checkbox" id="u-arbitre" /> Arbitre</label> 193 <button class="btn btn-primary btn-sm" type="submit" id="bt
193n-ajout-utilisateur">Ajouter</button> 194 </form> 195 </div> 196 197 <div class="param-bloc"> 198 <div class="param-tete"> 199 <h3>Journal de connexions</h3> 200 <button class="btn btn-secondary btn-sm" id="btn-rafraichir-connexions">â» Rafraîchir</button> 201 </div> 202 <p class="aide"> 203 Enregistre chaque <strong>connexion</strong> et <strong>déconnexion</strong> d'un utilisateur 204 identifié (administrateur ou arbitre). Les 200 dernières entrées sont affichées. 205 </p> 206 <div class="conn-barre"> 207 <div class="champ"> 208 <label for="conn-filtre-user">Utilisateur</label> 209 <select id="conn-filtre-user"><option value="">Tous</option></select> 210 </div> 211 <div class="champ"> 212 <label for="conn-filtre-evt">Ãvénement</label> 213 <select id="conn-filtre-evt"> 214 <option value="">Tous</option> 215 <option value="connexion">Connexions</option> 216 <option value="deconnexion">Déconnexions</option> 217 </select> 218 </div> 219 </div> 220 <div id="connexions-alerte"></div> 221 <div class="tableau-wrap"> 222 <table class="courses" id="table-connexions"> 223 <thead> 224 <tr><th>Date & heure</th><th>Ãvénement</th><th>Utilisateur</th><th>Rôles</th><th>Navigateur</th></tr> 225 </thead> 226 <tbody id="corps-connexions"></tbody> 227 </table> 228 </div> 229 <div class="conn-purge"> 230 <label for="conn-purge-periode">Purger les entrées de plus de</label> 231 <select id="conn-purge-periode"> 232 <option value="30">30 jours</option> 233 <option value="90">90 jours</option> 234 <option value="180">180 jours</option> 235 <option value="365" selected>1 an</option> 236 <option value="0">tout le journal</option> 237 </select>
238 <button class="btn btn-danger btn-sm" id="btn-purger-connexions">Purger</button> 239 </div> 240 </div> 241 </div> 242 </section> 243 </main> 244 245 <!-- Modale d'édition / création --> 246 <div class="modale-fond" id="modale-edition"> 247 <div class="modale" role="dialog" aria-modal="true"> 248 <div class="modale-tete"> 249 <h2 id="titre-edition">Modifier la course</h2> 250 <button class="fermer" data-fermer aria-label="Fermer">×</button> 251 </div> 252 <div class="modale-corps"> 253 <div id="edit-alerte"></div> 254 <form id="form-edition" class="form-grille"> 255 <input type="hidden" name="id" /> 256 <div class="pleine"> 257 <label>Nom de l'événement</label> 258 <input name="nom" /> 259 </div> 260 <div> 261 <label>Club organisateur</label> 262 <input name="club" list="liste-clubs" placeholder="Ex. Club de char à voile deâ¦" /> 263 <datalist id="liste-clubs"></datalist> 264 </div> 265 <div> 266 <label>Ligue de rattachement</label> 267 <input name="ligue" list="liste-ligues" placeholder="Ex. Ligue Hauts-de-France" /> 268 <datalist id="liste-ligues"></datalist> 269 </div> 270 <div> 271 <label>Lieu</label> 272 <input name="lieu" /> 273 </div> 274 <div> 275 <label>Type d'événement</label> 276 <input name="type_evenement" list="liste-types" /> 277 <datalist id="liste-types"></datalist> 278 </div> 279 <div> 280 <label>Date de début</label> 281 <input type="date" name="date_debut" /> 282 </div> 283 <div> 284 <label>Date de fin</label> 285 <input type="date" name="date_fin" /> 286 </div> 287 <div> 288 <label>Saison</label> 289 <input name="saison" placeholder="2026/2027" /> 290 </div> 291 <div> 292 <label>Statut</label> 293 <select name="statut" id="edit-statut"></select> 294 <p class="aide">« à venir » devient seul « En cours » puis « Passée » selon les dates.</p> 295 </div> 296 <div class="pleine"> 297 <label>Classes concernées</label>
298 <div class="cases-classes" id="edit-classes"></div> 299 </div> 300 <div> 301 <label>Directeur de course</label> 302 <input name="directeur_course" /> 303 </div> 304 <div> 305 <label>Président de jury</label> 306 <input name="directeur_jury" /> 307 </div> 308 <div> 309 <label>Lien d'inscription</label> 310 <input name="inscriptions_url" type="url" placeholder="https://â¦" /> 311 </div> 312 <div class="pleine"> 313 <label>Avis de course / ERS (lien)</label> 314 <input name="ers_url" type="url" placeholder="https://â¦" /> 315 </div> 316 <div class="pleine"> 317 <label>Suivi administratif</label> 318 <div class="cases-classes"> 319 <label class="case-classe"><input type="checkbox" name="lm_directeur_course" /> Lettre mission â Directeur de course</label> 320 <label class="case-classe"><input type="checkbox" name="lm_president_jury" /> Lettre mission â Président de jury</label> 321 <label class="case-classe"><input type="checkbox" name="ndf_directeur_course" /> Note de frais â Directeur de course</label> 322 <label class="case-classe"><input type="checkbox" name="ndf_president_jury" /> Note de frais â Président de jury</label> 323 </div> 324 </div> 325 <div class="pleine"> 326 <label>Résultats (lien)</label> 327 <input name="resultat_url" type="url" placeholder="https://â¦" /> 328 </div> 329 <div class="pleine" id="bloc-proposeur" style="background:var(--sable);padding:12px;border-radius:9px"> 330 <label>Informations du proposeur</label> 331 <p class="aide" id="txt-proposeur" style="margin:0"></p> 332 </div> 333 </form> 334 </div> 335 <div class="modale-pied"> 336 <button class="btn btn-danger" id="btn-supprimer" style="margin-right:auto">Supprimer</button> 337 <button class="btn btn-outline" data-fermer>Annuler</button> 338 <button class="btn btn-primary" id="btn-enregistrer" form="form-edition" type="submit">Enregistrer</button> 339 </div> 340 </div> 341 </div> 342 343 <footer class="pied-page">Espace réservé aux administrateurs.</footer> 344 345
345<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
345 346
346<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/xlsx.full.min.js"></script>
346 347
347<script src="js/config.js"></script>
347 348
348<script src="js/common.js"></script>
348 349
349<script src="js/admin.js"></script>
349 350</body> 351</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.