Mise à jour des fichiers CSS, ajout des mécanismes de mise à jour de Ship2net avec info sur la page du bateau.

This commit is contained in:
2026-10-06 16:25:29 +00:00
parent ce81084cdc
commit 0a2ec261ec
24 changed files with 2682 additions and 2263 deletions
+43
View File
@@ -0,0 +1,43 @@
<?php
//************************************************************************************************************
// bateau_etat.php - État léger d'un bateau, interrogé toutes les 30 s par la page "Données du bateau" pour détecter
// l'arrivée d'une nouvelle archive (synthèse §50). Réponse JSON : {"date": "<date UTC de la dernière archive traitée,
// ISO 8601>"} ou {"date": null}. Mêmes droits que la page du bateau : administrateur, ou accès actif à ce bateau.
//************************************************************************************************************
// Réponse JSON : aucun avertissement PHP ne doit s'y écrire (il la rendrait illisible) - ils vont dans le journal.
ini_set('display_errors', '0');
require_once("../config/config.php");
Init_session(basename(__FILE__));
header('Content-Type: application/json; charset=UTF-8');
header('Cache-Control: no-store');
if (empty($_SESSION['acces_valide']))
{
http_response_code(401);
echo '{}';
exit();
}
$id_bateau = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$niveau_admin = NIVEAU_ACCES_MINI_ADMINISTRATEUR;
$est_administrateur = ((int)$_SESSION['shipmember']['Niveau_acces'] >= $niveau_admin) ? 1 : 0;
Ouverture_bdd();
$reponse = Requete_preparee_bdd("SELECT B.Date_derniere_maj FROM TB_Bateaux B
WHERE B.Cle_primaire=? AND B.Validite=1
AND (? = 1 OR EXISTS (SELECT 1 FROM TB_Lien_bateau_shipmember L
WHERE L.ID_Bateau=B.Cle_primaire AND L.ID_Shipmember=? AND L.Statut='actif' AND L.Fin_validite >= NOW()))",
array(array('i', $id_bateau), array('i', $est_administrateur), array('i', $_SESSION['shipmember']['Cle_primaire'])),
__FILE__, __LINE__);
$donnees = Recherche_ligne_bdd($reponse, MYSQLI_ASSOC);
Liberation_jeu_de_resultat_bdd($reponse);
Fermeture_bdd();
if (!$donnees)
{
http_response_code(403);
echo '{}';
exit();
}
echo json_encode(array('date' => $donnees['Date_derniere_maj']), JSON_INVALID_UTF8_SUBSTITUTE);
+69
View File
@@ -0,0 +1,69 @@
<?php
//************************************************************************************************************
// bateau_mesures.php - Données d'une courbe historique, pour la page "Données du bateau" (synthèse §50, étape 3c).
// Paramètres (GET) : bateau, generation (0 = génération active), type (circuits, capteurs, batteries, reservoirs),
// element, variable (circuits, batteries), periode (24h, 7j, 30j, 3m, 1a). Réponse JSON (cf Courbe_element()).
// Droits : ceux de la page du bateau - administrateur, ou accès actif à ce bateau avec un type d'accès autorisant la
// consultation des données ; la génération doit appartenir au bateau.
//************************************************************************************************************
// Réponse JSON : aucun avertissement PHP ne doit s'y écrire (il la rendrait illisible) - ils vont dans le journal.
ini_set('display_errors', '0');
require_once("../config/config.php");
Init_session(basename(__FILE__));
header('Content-Type: application/json; charset=UTF-8');
header('Cache-Control: no-store');
function Repondre($code_http, $donnees)
{
http_response_code($code_http);
echo json_encode($donnees, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE); // Caractère mal encodé : remplacé, pas d'échec
exit();
}
if (empty($_SESSION['acces_valide'])) Repondre(401, array('erreur' => "session expirée"));
$id_bateau = (int)($_GET['bateau'] ?? 0);
$id_generation = (int)($_GET['generation'] ?? 0);
$type = (string)($_GET['type'] ?? '');
$id_element = (int)($_GET['element'] ?? 0);
$variable = (string)($_GET['variable'] ?? '');
$periode = (string)($_GET['periode'] ?? '');
$est_administrateur = ((int)$_SESSION['shipmember']['Niveau_acces'] >= NIVEAU_ACCES_MINI_ADMINISTRATEUR) ? 1 : 0;
Ouverture_bdd();
// Bateau accessible (et date de la dernière archive) :
$reponse = Requete_preparee_bdd("SELECT B.Date_derniere_maj FROM TB_Bateaux B
WHERE B.Cle_primaire=? AND B.Validite=1
AND (? = 1 OR EXISTS (SELECT 1 FROM TB_Lien_bateau_shipmember L
JOIN TB_Types_acces_bateau_shipmember T ON T.Cle_primaire = L.ID_Type_acces_bateau_shipmember
WHERE L.ID_Bateau=B.Cle_primaire AND L.ID_Shipmember=? AND L.Statut='actif'
AND L.Fin_validite >= NOW() AND T.Consultation_donnees >= 1))",
array(array('i', $id_bateau), array('i', $est_administrateur), array('i', $_SESSION['shipmember']['Cle_primaire'])),
__FILE__, __LINE__);
$bateau = Recherche_ligne_bdd($reponse, MYSQLI_ASSOC);
Liberation_jeu_de_resultat_bdd($reponse);
if (!$bateau) { Fermeture_bdd(); Repondre(403, array('erreur' => "accès refusé")); }
// Génération : celle demandée si elle appartient à ce bateau, sinon la génération active :
$generation = null;
foreach (Generations_bateau($id_bateau) as $g)
{
if ((int)$g['Cle_primaire'] == $id_generation) { $generation = $g; break; }
if ($g['Date_fin'] === null && $generation === null) $generation = $g;
}
Fermeture_bdd();
if ($generation === null) Repondre(404, array('erreur' => "aucune donnée pour ce bateau"));
// Fin de la courbe : dernière archive (génération active) ou fin de la génération (génération antérieure) :
$date_fin = ($generation['Date_fin'] === null) ? $bateau['Date_derniere_maj'] : $generation['Date_fin'];
if ($date_fin === null) Repondre(404, array('erreur' => "aucune archive reçue"));
$db = Connexion_generation($generation['Nom_base']);
if ($db === null) Repondre(503, array('erreur' => "données momentanément inaccessibles"));
$courbe = Courbe_element($db, $type, $id_element, $variable, $periode, $date_fin);
$db->close();
if (isset($courbe['erreur'])) Repondre(400, $courbe);
Repondre(200, $courbe);
+438 -5
View File
@@ -135,6 +135,7 @@ Init_session(basename($_SERVER['SCRIPT_NAME'])); // Fonction ouvrant la session
{
$_SESSION['Bateaux']['bateau']['Cle_primaire'] = (int)$_GET['id_bateau'];
$_SESSION['Bateaux']['type_details_bateau'] = "resume";
$_SESSION['Bateaux']['generation'] = 0; // Nouveau bateau : génération active
$_SESSION['Bateaux']['page'] = "Details_bateau";
if (isset($_GET['origine'])) $_SESSION['Bateaux']['origine'] = $_GET['origine'];
@@ -152,6 +153,16 @@ Init_session(basename($_SERVER['SCRIPT_NAME'])); // Fonction ouvrant la session
break;
}
//===================================
// Génération consultée (synthèse §50) : 0 = génération active. La valeur n'est utilisée qu'après vérification
// qu'elle appartient bien au bateau affiché (préparation de la page).
case "choix_generation":
{
$_SESSION['Bateaux']['generation'] = isset($_GET['generation']) ? (int)$_GET['generation'] : 0;
$_SESSION['Bateaux']['type_details_bateau'] = "resume";
break;
}
//===================================
case "modification_bateau":
{
@@ -370,7 +381,7 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
// Mise en forme de certaines variables :
$bateaux[$nb_bateaux]['version'] = ($donnees['version'] == "") ? '<i>inconnue</i>' : htmlspecialchars($donnees['version']);
if ($donnees['Date_derniere_maj'] < "2020-01-02") $bateaux[$nb_bateaux]['Date_derniere_maj'] = "<i>Jamais</i>";
else $bateaux[$nb_bateaux]['Date_derniere_maj'] = Formatage_date($donnees['Date_derniere_maj']);
else $bateaux[$nb_bateaux]['Date_derniere_maj'] = '<span data-date-utc="'.htmlspecialchars(str_replace(' ', 'T', $donnees['Date_derniere_maj']).'Z').'">'.htmlspecialchars($donnees['Date_derniere_maj']).' UTC</span>';
$nb_bateaux ++;
}
@@ -400,6 +411,7 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
while ($donnees = Recherche_ligne_bdd($reponse))
{
$bateau = $donnees;
$bateau['Date_derniere_maj_utc'] = $donnees['Date_derniere_maj']; // Brute (UTC), pour l'indicateur de fraîcheur
// Mise en forme de textes :
if ($donnees['Date_derniere_maj'] < "2020-01-02") $bateau['Date_derniere_maj'] = "<i>".t("Jamais")."</i>";
@@ -632,7 +644,41 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
Liberation_jeu_de_resultat_bdd($reponse);
break;
}
default: break;
//-------------------------------------------------------------------------------------------------------
// Données du bateau (synthèse §50) : lues dans la base de la génération consultée (active par défaut), par
// une connexion dédiée - la connexion principale du site n'est pas touchée.
default:
{
$consultation = array('autorisee' => ($est_administrateur || (int)($acces_profil['Consultation_donnees'] ?? 0) >= 1),
'generations' => array(), 'generation' => null, 'domaines' => array(), 'erreur' => null,
'periode_archivage' => CONSULTATION_PERIODE_ARCHIVAGE_DEFAUT);
if (!$consultation['autorisee']) break;
$consultation['generations'] = Generations_bateau($bateau['Cle_primaire']);
foreach ($consultation['generations'] as $generation)
{
// Génération demandée si elle appartient bien à ce bateau, sinon la génération active :
if ((int)$generation['Cle_primaire'] == (int)($_SESSION['Bateaux']['generation'] ?? 0)) { $consultation['generation'] = $generation; break; }
if ($generation['Date_fin'] === null && $consultation['generation'] === null) $consultation['generation'] = $generation;
}
if ($consultation['generation'] === null) break; // Aucune archive reçue pour ce bateau
$db_generation = Connexion_generation($consultation['generation']['Nom_base']);
if ($db_generation === null) { $consultation['erreur'] = t("Les données de ce bateau sont momentanément inaccessibles."); break; }
$consultation['periode_archivage'] = Periode_archivage_bateau($db_generation);
$consultation['alarmes'] = Episodes_alarmes($db_generation, 20);
foreach (array('circuits' => t("Circuits"), 'capteurs' => t("Capteurs"), 'batteries' => t("Batteries"), 'reservoirs' => t("Réservoirs")) as $domaine => $titre)
{
$consultation['domaines'][$domaine] = array('titre' => $titre, 'familles' => Elements_domaine($db_generation, $domaine));
}
$db_generation->close();
// Génération active : demande d'archive immédiate (si les données ne sont pas déjà récentes - étape 3d) :
$consultation['demande'] = ($consultation['generation']['Date_fin'] === null)
? Demander_archive_si_besoin($bateau['Cle_primaire'], $bateau['Date_derniere_maj_utc']) : null;
$consultation['demande_archive'] = (($consultation['demande']['statut'] ?? '') == 'demandee');
break;
}
} // Fin du switch 'type_details_bateau'
@@ -741,7 +787,7 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
// echo '<th><a href="bateaux.php?action=tri_liste&colonne=Carte">ShipBase</a></th>';
echo '<th><a href="bateaux.php?action=tri_liste&colonne=Adresse_mac">Adresse MAC</a></th>';
echo '<th><a href="bateaux.php?action=tri_liste&colonne=Version">Version</a></th>';
echo '<th><a href="bateaux.php?action=tri_liste&colonne=Date_maj">Dernière mise à jour [UTC]</a></th>';
echo '<th><a href="bateaux.php?action=tri_liste&colonne=Date_maj">'.t("Dernières données reçues").'</a></th>';
// echo '<th>Commentaires</th>';
echo '</tr>
</thead>
@@ -808,7 +854,30 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
else echo '<span class="live_indisponible" title="'.t("Aucun module ShipBase joignable n'est affecté à ce bateau").'">'.t("Live indisponible").'</span>';
echo '</div>';
echo '<div class="derniere_maj">'.t("Dernières données reçues").' : <span class="gras">'.$bateau['Date_derniere_maj'].' [UTC]</span></div>';
// Indicateur de fraîcheur (synthèse §44.6, §50) : date UTC transmise au navigateur, qui l'affiche dans le fuseau
// de l'utilisateur et colore selon l'ancienneté (seuil orange/rouge = 1,25 x la période d'archivage du bateau) :
echo '<div class="derniere_maj">'.t("Dernières données reçues").' : ';
if ($bateau['Date_derniere_maj_utc'] === null || $bateau['Date_derniere_maj_utc'] < "2020-01-02") echo '<span class="gras"><i>'.t("Jamais").'</i></span>';
else echo '<span class="gras fraicheur" data-date-utc="'.htmlspecialchars(str_replace(' ', 'T', $bateau['Date_derniere_maj_utc']).'Z').'" data-seuil-rouge="'
.(int)round(1.25 * ($consultation['periode_archivage'] ?? CONSULTATION_PERIODE_ARCHIVAGE_DEFAUT)).'">'.htmlspecialchars($bateau['Date_derniere_maj_utc']).' UTC</span>';
// Mise à jour à l'ouverture (étape 3d) : ce qui a été fait, et pourquoi (synthèse §50) :
$minutes = function($secondes) { return max(1, (int)ceil($secondes / 60)); };
switch ($consultation['demande']['statut'] ?? '')
{
case 'demandee':
echo '<span class="info_mise_a_jour en_cours" id="info_mise_a_jour">'.t("Mise à jour demandée au bateau...").'</span>';
break;
case 'donnees_recentes':
echo '<span class="info_mise_a_jour">'.str_replace("[[M]]", $minutes($consultation['demande']['attente']),
t("Données récentes : pas de nouvelle demande au bateau avant [[M]] min.")).'</span>';
break;
case 'deja_demandee':
echo '<span class="info_mise_a_jour">'.str_replace("[[M]]", $minutes($consultation['demande']['attente']),
t("Mise à jour déjà demandée récemment : nouvelle demande possible dans [[M]] min.")).'</span>';
break;
}
echo '</div>';
echo '</div>';
//--------------------------------
// Boutons de haut de page (les anciens onglets Carte/Batteries/Circuits/Réservoirs/Capteurs/Système, liés au
@@ -968,7 +1037,120 @@ $requete .= ' TB_Bateaux.Date_derniere_maj AS Date_derniere_maj, ';
// 'resume' (et toute ancienne valeur de session) :
default:
{
echo '<p>'.t("La consultation des données du bateau sera disponible prochainement.").'</p>';
if (!$consultation['autorisee']) { echo '<p>'.t("Votre type d'accès ne permet pas de consulter les données de ce bateau.").'</p>'; break; }
if ($consultation['generation'] === null) { echo '<p>'.t("Aucune donnée n'a encore été reçue de ce bateau.").'</p>'; break; }
if ($consultation['erreur'] !== null) { echo '<p>'.htmlspecialchars($consultation['erreur']).'</p>'; break; }
echo '<div class="consultation">';
// Rafraîchissement à l'arrivée d'une nouvelle archive (synthèse §50) - génération active seulement :
if ($consultation['generation']['Date_fin'] === null)
{
echo '<span id="surveillance_archive" hidden data-id-bateau="'.(int)$bateau['Cle_primaire'].'" data-date="'.htmlspecialchars((string)$bateau['Date_derniere_maj_utc']).'"'
.(!empty($consultation['demande_archive']) ? ' data-demande="1"' : '').'></span>';
}
//--------------------------------
// Génération consultée, et choix d'une génération antérieure :
$format_date = function($date) { return ($date === null) ? '' : date_format(date_create($date), 'd/m/Y'); };
echo '<form class="choix_generation" action="bateaux.php" method="get">';
echo '<input type="hidden" name="action" value="choix_generation">';
echo '<label for="generation">'.t("Données").' : </label>';
echo '<select name="generation" id="generation" onchange="this.form.submit()">';
foreach ($consultation['generations'] as $generation)
{
$libelle = str_replace("[[N]]", (int)$generation['Numero_generation'], t("Génération [[N]]"));
if ($generation['Date_fin'] === null) $libelle .= ' - '.str_replace("[[Date]]", $format_date($generation['Date_debut']), t("en cours, depuis le [[Date]]"));
else $libelle .= ' - '.str_replace(array("[[Debut]]", "[[Fin]]"), array($format_date($generation['Date_debut']), $format_date($generation['Date_fin'])), t("du [[Debut]] au [[Fin]]"));
if ($generation['Version_soft'] !== null) $libelle .= ' (v'.$generation['Version_soft'].')';
echo '<option value="'.(int)$generation['Cle_primaire'].'"'.(((int)$generation['Cle_primaire'] == (int)$consultation['generation']['Cle_primaire']) ? ' selected' : '').'>'.htmlspecialchars($libelle).'</option>';
}
echo '</select>';
echo '<noscript><button type="submit">'.t("Afficher").'</button></noscript>';
echo '</form>';
if ($consultation['generation']['Date_fin'] !== null)
{
echo '<p class="generation_ancienne">'.t("Vous consultez une génération antérieure : les valeurs ci-dessous sont celles de sa dernière archive, pas l'état actuel du bateau.").'</p>';
}
//--------------------------------
// Dernières alarmes (synthèse §50) : déclenchements, du plus récent au plus ancien, dates dans le fuseau du
// navigateur. (Pas d'état "alarme en cours" : vieux de jusqu'à une période d'archivage, il ne serait ni
// fiable ni exploitable.)
echo '<section class="dernieres_alarmes">';
echo '<h2>'.t("Dernières alarmes").'</h2>';
if (count($consultation['alarmes'] ?? array()) == 0) echo '<p class="aucune_alarme">'.t("Aucune alarme enregistrée.").'</p>';
else
{
$date_affichee = function($iso) { return '<span data-date-utc="'.htmlspecialchars($iso).'">'.htmlspecialchars($iso).'</span>'; };
echo '<table>';
echo '<tr><th>'.t("Début").'</th><th>'.t("Fin").'</th><th>'.t("Durée").'</th><th>'.t("Alarme").'</th><th></th></tr>';
foreach ($consultation['alarmes'] as $alarme)
{
switch ($alarme['statut'])
{
case 'termine': $fin = $date_affichee($alarme['fin_utc']); break;
case 'en_cours': $fin = '<span class="alarme_en_cours">'.t("en cours à la dernière archive").'</span>'; break;
case 'fin_non_enregistree': $fin = '<i>'.t("fin non enregistrée").'</i>'; break;
case 'debut_anterieur': $fin = $date_affichee($alarme['fin_utc']); break;
default: $fin = '<i>'.t("ponctuel").'</i>'; break;
}
echo '<tr class="alarme_'.$alarme['statut'].'">';
echo '<td class="date_alarme">'.(($alarme['debut_utc'] !== null) ? $date_affichee($alarme['debut_utc']) : '<i>'.t("début antérieur").'</i>').'</td>';
echo '<td class="date_alarme">'.$fin.'</td>';
echo '<td class="duree_alarme">'.(($alarme['duree'] !== null) ? htmlspecialchars(Duree_lisible($alarme['duree'])) : '').'</td>';
echo '<td class="nom_alarme">'.htmlspecialchars($alarme['nom']).'</td>';
echo '<td class="message_alarme">'.htmlspecialchars($alarme['message']).'</td>';
echo '</tr>';
}
echo '</table>';
}
echo '</section>';
//--------------------------------
// Les quatre domaines, par famille, avec leurs dernières valeurs :
foreach ($consultation['domaines'] as $domaine => $donnees_domaine)
{
if (count($donnees_domaine['familles']) == 0) continue;
echo '<section class="domaine domaine_'.$domaine.'">';
echo '<h2>'.htmlspecialchars($donnees_domaine['titre']).'</h2>';
foreach ($donnees_domaine['familles'] as $famille)
{
echo '<div class="famille">';
echo '<h3>'.htmlspecialchars($famille['nom']).'</h3>';
echo '<table>';
foreach ($famille['elements'] as $element)
{
// Élément avec courbe historique : ligne cliquable (synthèse §50, étape 3c)
$classes = array();
if ($element['defaut'] !== null) $classes[] = 'en_defaut';
if ($element['courbe']) $classes[] = 'avec_courbe';
echo '<tr'.((count($classes) > 0) ? ' class="'.implode(' ', $classes).'"' : '')
.($element['courbe'] ? ' data-type="'.$domaine.'" data-element="'.(int)$element['id'].'" data-nom="'.htmlspecialchars($element['nom']).'" title="'.t("Afficher la courbe").'"' : '').'>';
echo '<td class="nom_element">'.htmlspecialchars($element['nom']).'</td>';
echo '<td class="valeurs_element">'.htmlspecialchars(implode(' ', $element['valeurs'])).'</td>';
echo '<td class="defaut_element">'.(($element['defaut'] !== null) ? htmlspecialchars($element['defaut']) : '').'</td>';
echo '</tr>';
}
echo '</table>';
echo '</div>';
}
echo '</section>';
}
//--------------------------------
// Panneau de courbe historique (synthèse §50, étape 3c), ouvert au clic sur un élément :
echo '<div id="panneau_courbe" hidden data-bateau="'.(int)$bateau['Cle_primaire'].'" data-generation="'.(int)$consultation['generation']['Cle_primaire'].'">';
echo '<div class="fenetre_courbe" role="dialog" aria-modal="true" aria-labelledby="titre_courbe">';
echo '<div class="entete_courbe"><h3 id="titre_courbe"></h3><button type="button" id="fermer_courbe" title="'.t("Fermer").'">&times;</button></div>';
echo '<div class="choix_courbe" id="choix_variable"></div>';
echo '<div class="choix_courbe" id="choix_periode"></div>';
echo '<div class="zone_courbe"><canvas id="canvas_courbe"></canvas><p id="message_courbe" hidden></p></div>';
echo '<p id="stats_courbe"></p>';
echo '</div>';
echo '</div>';
echo '<script src="/vendor/chartjs/chart.umd.min.js"></script>';
echo '</div>'; // Fin de class="consultation"
break;
}
}
@@ -1139,6 +1321,257 @@ Pied_de_page();
<script>
//------------------------------------------------------------------------------------------------------------
// Dates UTC (attribut data-date-utc) affichées dans le fuseau du navigateur ; indicateur de fraîcheur coloré si
// l'élément porte un seuil (data-seuil-rouge, en secondes) : vert < 5 min, orange jusqu'au seuil, rouge au-delà.
// Mis à jour toutes les 30 s : la couleur évolue sans recharger la page (synthèse §44.6, §50).
//------------------------------------------------------------------------------------------------------------
const TEXTES_FRAICHEUR = <?php echo json_encode(array('instant' => t("à l'instant"), 'minutes' => t("il y a [[M]] min"), 'heures' => t("il y a [[H]] h [[M]] min"), 'jours' => t("il y a [[J]] j")), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); ?>;
function Afficher_dates_et_fraicheur()
{
document.querySelectorAll('[data-date-utc]').forEach(function (element) {
const date = new Date(element.dataset.dateUtc);
if (isNaN(date)) return;
let texte = date.toLocaleString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' });
if (element.dataset.seuilRouge)
{
const age = Math.max(0, (Date.now() - date.getTime()) / 1000);
let relatif;
if (age < 60) relatif = TEXTES_FRAICHEUR.instant;
else if (age < 3600) relatif = TEXTES_FRAICHEUR.minutes.replace('[[M]]', Math.floor(age / 60));
else if (age < 86400) relatif = TEXTES_FRAICHEUR.heures.replace('[[H]]', Math.floor(age / 3600)).replace('[[M]]', Math.floor((age % 3600) / 60));
else relatif = TEXTES_FRAICHEUR.jours.replace('[[J]]', Math.floor(age / 86400));
texte += ' (' + relatif + ')';
element.classList.remove('fraicheur_verte', 'fraicheur_orange', 'fraicheur_rouge');
element.classList.add(age < 300 ? 'fraicheur_verte' : (age <= Number(element.dataset.seuilRouge) ? 'fraicheur_orange' : 'fraicheur_rouge'));
}
element.textContent = texte;
});
}
Afficher_dates_et_fraicheur();
setInterval(Afficher_dates_et_fraicheur, 30000);
//------------------------------------------------------------------------------------------------------------
// Courbes historiques (synthèse §50, étape 3c). Un clic sur un élément ouvre sa courbe (données : bateau_mesures.php).
// Courbe moyenne entourée d'une bande min-max (un pic bref reste visible sur une longue période). L'état de la
// courbe ouverte est mémorisé dans l'adresse (#courbe=type.element.variable.periode) : après un rechargement de la
// page (nouvelle archive), elle se rouvre d'elle-même.
//------------------------------------------------------------------------------------------------------------
const TEXTES_COURBE = <?php echo json_encode(array(
'periodes' => array('24h' => t("24 h"), '7j' => t("7 jours"), '30j' => t("30 jours"), '3m' => t("3 mois"), '1a' => t("1 an")),
'variables' => array(
'circuits' => array('intensite' => t("Intensité"), 'tension' => t("Tension"), 'consigne' => t("Consigne"), 'frequence' => t("Fréquence")),
'batteries' => array('soc' => t("SOC"), 'tension' => t("Tension"), 'temperature' => t("Température"), 'courant_charge' => t("Courant de charge"),
'courant_decharge' => t("Courant de décharge"), 'courant_differentiel' => t("Courant différentiel"), 'soh' => t("SOH"), 'autonomie' => t("Autonomie"))),
'moyenne' => t("Moyenne"), 'bande' => t("Min - max"), 'min' => t("Min"), 'max' => t("Max"),
'aucune' => t("Aucune mesure sur cette période."), 'erreur' => t("Courbe indisponible."), 'chargement' => t("Chargement..."),
'bibliotheque' => t("Bibliothèque de graphiques introuvable (vendor/chartjs).")),
JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); ?>;
const VARIABLE_PAR_DEFAUT = { circuits: 'intensite', batteries: 'soc' };
(function () {
const panneau = document.getElementById('panneau_courbe');
if (!panneau) return;
let etat = null, graphique = null, requete = 0;
const nombre = (v, p) => (v === null || v === undefined) ? '' : Number(v).toLocaleString(undefined, { minimumFractionDigits: p, maximumFractionDigits: p });
const date_heure = (ms) => new Date(ms).toLocaleString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' });
const format_axe = function (ms) {
const d = new Date(ms);
if (etat.periode === '24h') return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
if (etat.periode === '7j') return d.toLocaleDateString(undefined, { weekday: 'short', day: '2-digit' }); // graduations à minuit
if (etat.periode === '1a') return d.toLocaleDateString(undefined, { month: 'short', year: '2-digit' });
return d.toLocaleDateString(undefined, { day: '2-digit', month: '2-digit' });
};
// Graduations de l'axe du temps sur des instants "ronds" de l'heure LOCALE (toutes les 3 h sur 24 h, chaque jour
// à minuit sur 7 jours, tous les 5 jours sur 30 jours, le 1er et le 15 sur 3 mois, chaque 1er du mois sur 1 an) :
function Graduations(debut, fin)
{
const graduations = [];
const d = new Date(debut);
d.setMinutes(0, 0, 0);
if (etat.periode === '24h') d.setHours(Math.ceil(d.getHours() / 3) * 3); // prochaine heure multiple de 3
else { d.setHours(0); d.setDate(d.getDate() + 1); } // minuit suivant
for (let garde = 0; d.getTime() <= fin && garde < 400; garde++) {
const jour = d.getDate();
let retenir = true;
if (etat.periode === '30j') retenir = (jour % 5 === 1);
else if (etat.periode === '3m') retenir = (jour === 1 || jour === 15);
else if (etat.periode === '1a') retenir = (jour === 1);
if (retenir && d.getTime() >= debut) graduations.push({ value: d.getTime() });
if (etat.periode === '24h') d.setHours(d.getHours() + 3); else d.setDate(d.getDate() + 1);
}
return graduations;
}
function Boutons(conteneur, choix, actif, action)
{
conteneur.innerHTML = '';
Object.keys(choix).forEach(function (cle) {
const bouton = document.createElement('button');
bouton.type = 'button';
bouton.textContent = choix[cle];
if (cle === actif) bouton.classList.add('actif');
bouton.addEventListener('click', function () { action(cle); });
conteneur.appendChild(bouton);
});
}
function Message(texte)
{
const p = document.getElementById('message_courbe');
p.textContent = texte || '';
p.hidden = !texte;
}
function Afficher()
{
document.getElementById('titre_courbe').textContent = etat.nom;
const variables = TEXTES_COURBE.variables[etat.type];
const zone_variables = document.getElementById('choix_variable');
if (variables) Boutons(zone_variables, variables, etat.variable, function (v) { etat.variable = v; Afficher(); });
else zone_variables.innerHTML = '';
Boutons(document.getElementById('choix_periode'), TEXTES_COURBE.periodes, etat.periode, function (p) { etat.periode = p; Afficher(); });
history.replaceState(null, '', '#courbe=' + [etat.type, etat.element, etat.variable || '-', etat.periode].join('.'));
document.getElementById('stats_courbe').textContent = '';
Message(TEXTES_COURBE.chargement);
const numero = ++requete; // Seule la réponse à la DERNIÈRE demande est affichée
const parametres = new URLSearchParams({ bateau: panneau.dataset.bateau, generation: panneau.dataset.generation, type: etat.type,
element: etat.element, variable: etat.variable || '', periode: etat.periode });
// Causes distinguées (synthèse §50) : bibliothèque absente, refus motivé du serveur, erreur technique (détail
// dans la console du navigateur) - un message unique masquait la vraie raison.
if (typeof Chart === 'undefined') { Message(TEXTES_COURBE.bibliotheque); return; }
fetch('bateau_mesures.php?' + parametres.toString(), { cache: 'no-store', credentials: 'same-origin' })
.then(r => r.json().then(d => ({ ok: r.ok, d: d })))
.then(function (reponse) {
if (numero !== requete) return;
if (!reponse.ok) { Message(TEXTES_COURBE.erreur + (reponse.d && reponse.d.erreur ? ' (' + reponse.d.erreur + ')' : '')); return; }
Dessiner(reponse.d);
})
.catch(function (erreur) {
console.error('Courbe :', erreur);
if (numero === requete) Message(TEXTES_COURBE.erreur);
});
}
function Dessiner(donnees)
{
if (graphique) { graphique.destroy(); graphique = null; }
if (donnees.points.length === 0) { Message(TEXTES_COURBE.aucune); return; }
Message('');
const p = donnees.precision, u = donnees.unite ? ' ' + donnees.unite : '';
const serie = (cle) => donnees.points.map(pt => ({ x: pt.t, y: pt[cle] }));
graphique = new Chart(document.getElementById('canvas_courbe'), {
type: 'line',
data: { datasets: [
{ label: TEXTES_COURBE.bande, data: serie('max'), borderWidth: 0, pointRadius: 0, fill: '+1', backgroundColor: 'rgba(115, 183, 214, 0.30)' },
{ label: 'min', data: serie('min'), borderWidth: 0, pointRadius: 0, fill: false },
{ label: TEXTES_COURBE.moyenne, data: serie('v'), borderColor: '#004563', borderWidth: 1.5, pointRadius: 0, fill: false }
] },
options: {
animation: false, maintainAspectRatio: false, normalized: true,
interaction: { mode: 'index', intersect: false },
scales: {
x: { type: 'linear', min: donnees.debut, max: donnees.fin, afterBuildTicks: (axe) => { axe.ticks = Graduations(donnees.debut, donnees.fin); },
ticks: { autoSkip: false, maxRotation: 0, callback: (v) => format_axe(v) } },
y: { title: { display: !!donnees.unite, text: donnees.unite }, ticks: { callback: (v) => nombre(v, p) } }
},
plugins: {
legend: { labels: { filter: (item) => item.datasetIndex !== 1 } },
tooltip: { callbacks: {
title: (items) => items.length ? date_heure(items[0].parsed.x) : '',
label: function (item) {
if (item.datasetIndex === 1) return null;
if (item.datasetIndex === 0) {
const pt = donnees.points[item.dataIndex];
return TEXTES_COURBE.bande + ' : ' + nombre(pt.min, p) + ' / ' + nombre(pt.max, p) + u;
}
return TEXTES_COURBE.moyenne + ' : ' + nombre(item.parsed.y, p) + u;
}
} }
}
}
});
if (donnees.stats) {
const s = donnees.stats;
document.getElementById('stats_courbe').textContent =
TEXTES_COURBE.min + ' : ' + nombre(s.min.v, p) + u + ' (' + date_heure(s.min.t) + ') ' +
TEXTES_COURBE.max + ' : ' + nombre(s.max.v, p) + u + ' (' + date_heure(s.max.t) + ') ' +
TEXTES_COURBE.moyenne + ' : ' + nombre(s.moyenne, p) + u;
}
}
function Ouvrir(type, element, nom, variable, periode)
{
etat = { type: type, element: element, nom: nom,
variable: (TEXTES_COURBE.variables[type] && TEXTES_COURBE.variables[type][variable]) ? variable : (VARIABLE_PAR_DEFAUT[type] || null),
periode: TEXTES_COURBE.periodes[periode] ? periode : '24h' };
panneau.hidden = false;
Afficher();
}
function Fermer()
{
panneau.hidden = true;
requete++;
if (graphique) { graphique.destroy(); graphique = null; }
etat = null;
history.replaceState(null, '', location.pathname + location.search);
}
document.addEventListener('click', function (e) {
const ligne = e.target.closest('tr.avec_courbe');
if (ligne && !panneau.contains(ligne)) Ouvrir(ligne.dataset.type, ligne.dataset.element, ligne.dataset.nom, null, null);
});
document.getElementById('fermer_courbe').addEventListener('click', Fermer);
panneau.addEventListener('click', function (e) { if (e.target === panneau) Fermer(); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !panneau.hidden) Fermer(); });
// Réouverture après rechargement (adresse #courbe=type.element.variable.periode), si l'élément existe toujours :
const m = location.hash.match(/^#courbe=(\w+)\.(\d+)\.([\w-]+)\.(\w+)$/);
if (m) {
const ligne = document.querySelector('tr.avec_courbe[data-type="' + m[1] + '"][data-element="' + m[2] + '"]');
if (ligne) Ouvrir(m[1], m[2], ligne.dataset.nom, m[3], m[4]);
}
})();
//------------------------------------------------------------------------------------------------------------
// Arrivée d'une nouvelle archive (synthèse §50) : sur la vue "Données du bateau" (génération active), toutes les
// 30 s, la page demande au portail la date de la dernière archive traitée pour ce bateau (bateau_etat.php : une
// requête légère, droits contrôlés) ; si elle a changé depuis l'affichage, la page se recharge. Arrêt en cas de
// session expirée ou de refus.
//------------------------------------------------------------------------------------------------------------
// Juste après une demande d'archive (étape 3d, data-demande) : vérification toutes les 3 s pendant 90 s, pour une mise
// à jour quasi immédiate dès que l'archive est chargée ; ensuite (ou sans demande) : toutes les 30 s.
const TEXTE_SANS_REPONSE = <?php echo json_encode(t("Pas de réponse du bateau pour l'instant (hors connexion ?) : affichage des dernières données reçues."), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); ?>;
(function () {
const surveillance = document.getElementById('surveillance_archive');
if (!surveillance) return;
const fin_rapide = (surveillance.dataset.demande === '1') ? Date.now() + 90000 : 0;
function Verifier()
{
fetch('bateau_etat.php?id=' + encodeURIComponent(surveillance.dataset.idBateau), { cache: 'no-store', credentials: 'same-origin' })
.then(function (reponse) {
if (!reponse.ok) return 'arret'; // session expirée ou accès refusé : on arrête de vérifier
return reponse.json();
})
.then(function (etat) {
if (etat === 'arret') return;
if (etat && (etat.date || '') !== surveillance.dataset.date) { location.reload(); return; }
const info = document.getElementById('info_mise_a_jour');
if (info && fin_rapide && Date.now() >= fin_rapide && info.classList.contains('en_cours')) {
info.classList.remove('en_cours');
info.textContent = TEXTE_SANS_REPONSE;
}
setTimeout(Verifier, Date.now() < fin_rapide ? 3000 : 30000);
})
.catch(function () { setTimeout(Verifier, 30000); }); // réseau momentanément indisponible
}
setTimeout(Verifier, fin_rapide ? 3000 : 30000);
})();
function toggle_help(){
var help = document.getElementById("help");
+772 -1071
View File
File diff suppressed because it is too large Load Diff
+14 -397
View File
@@ -18,17 +18,7 @@ body {
}
/********************************************************* ENTETE **************************************************/
#entete #ligne_icones {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}
#entete #ligne_icones a {
background-size: 50%;
width: 90%;
}
#entete #ligne_icones #home {
text-align:center;
padding-left:0px;
}
#entete nav {
grid-template-columns: 1fr;
@@ -47,13 +37,6 @@ body {
/* line-height: 2em; */
}
#espace_menu.replie {
padding-top:40px;
}
#espace_menu.deploye {
padding-top:360px;
}
/*********************************************************** PIED DE PAGE *********************************************/
#pied_de_page {
@@ -113,15 +96,9 @@ select {
::placeholder {
/* font-size: 1.8em; */
}
.boutons_formulaire button {
padding:50px 30px;
/* font-size: 1.8em; */
}
/********************************************************* LIENS HYPERTEXTES ***************************************/
a.renforce {
padding:3px 30px;
}
ul {
padding-inline-start: 20px; /* C'est une valeur par défaut de 40px, ce qui est beaucoup sur un affichage téléphone... */
@@ -141,10 +118,6 @@ p {
/* padding-top: 350px; /* Taille du menu déployé */
/*margin-top: -350px; Même valeur que ci-dessus pour compenser */
}
.ancre.sans_menu {
/*padding-top: 40px;*/ /* Taille du menu replié */
/*margin-top: -40px;*/ /* Même valeur que ci-dessus pour compenser */
}
/************************************* MESSAGE D'ERREUR ***************************************/
@@ -185,27 +158,7 @@ p {
}
/************************************* IMAGES ZOOMEES ***************************************/
#zoom {
grid-template-columns: 1fr;
row-gap: 20px;
width: 95%;
padding:5px;
}
#zoom a {
display: block;
text-align: center;
}
#zoom a img {
width: 50px;
}
#zoom .photo_zoomee {
width: 100%;
}
#zoom .photo_zoomee img {
max-height: 250px;
max-width: 90%;
border-radius: 5px;
}
/***********************************************************************************************************************
Fichier accueil.php
@@ -221,101 +174,12 @@ Fichier accueil.php
margin: auto;
}
#Accueil #bandeau_accueil {
height:300px; /* Fige la hauteur du bloc 'bandeau-accueil' sinon on n'arrive à rien... */
line-height: 300px; /* Permet ensuite d'utiliser le vertical-align sur le <p> inclus */
}
#Accueil #bandeau_accueil p {
font-size:1.8em;
}
#Accueil #notre_actualite p {
margin-bottom: 2em;
}
#Accueil #notre_actualite a {
width: 90%;
border-radius: 1em;
padding: 30px 0px;
}
#Accueil #qu_est_ce_que_shipheart .corps {
padding:50px 0px 50px 0px;
border-bottom:10px solid var(--bleu_koriolan_transparent);
font-weight: 300;
font-size: 1em;
}
#Accueil #qu_est_ce_que_shipheart .corps p {
margin-top: 10px;
margin-bottom: 10px;
}
#Accueil #qu_est_ce_que_shipheart .corps .made_in_france {
margin:20px 5% 50px 5%;
}
#Accueil #qu_est_ce_que_shipheart .corps .made_in_france img {
width: 99%;
}
#Accueil #marguerite {
padding:0.5em 0px;
}
#Accueil #marguerite .corps {
grid-template-columns: 1fr;
row-gap:60px;
}
#Accueil #marguerite .corps .rubrique {
border: none;
border-bottom:10px solid var(--bleu_koriolan_transparent);
padding:10px 10px;
}
#Accueil #boutique .corps a {
margin: 20px auto 20px auto;
padding: 30px 0px;
width: 96%;
/* font-size: 2.0em; */
}
#Accueil #faq .corps .rubriques {
grid-template-columns: 1fr;
row-gap: 50px;
}
#Accueil #qui_sommes_nous img {
/* width:100%; */
}
#Accueil #qui_sommes_nous .image_bandeau {
height:200px;
}
#Accueil #qui_sommes_nous .corps {
/* padding:50px 0px; */
}
#Accueil #qui_sommes_nous .carte_de_visite {
grid-template-columns: 1% 1fr 2fr;
}
#Accueil #qui_sommes_nous .carte_de_visite .texte p {
font-size: 0.8em;
}
#Accueil #qui_sommes_nous .contact {
/* grid-template-columns: 20px 1fr 20px; */
padding-top: 50px;
/* font-size: 1.8em; */
}
#Accueil #qui_sommes_nous .contact a {
width: 95%;
margin: 60px auto;
padding: 30px 0px;
}
/***********************************************************************************************************************
Fichier actualites.php
***********************************************************************************************************************/
/*----------------------------------------*/
#Actualites #accueil .photos {
grid-template-columns: 1fr;
}
@@ -324,256 +188,37 @@ Fichier actualites.php
/***********************************************************************************************************************
Fichier boutique.php
***********************************************************************************************************************/
#Boutique .info_mobile {
display: inline-block;
}
#Boutique .boutons_bas_de_page {
grid-template-columns: 1fr;
grid-template-areas:
" suivant "
" retour ";
margin-top: 20px;
}
#Boutique .boutons_bas_de_page a {
margin: 30px 0px;
}
/*--------------------------------------------------*/
#Boutique #bandeau_avancement {
grid-template-columns: repeat(7, auto);
font-size:0.6em;
}
#Boutique #bandeau_avancement .etape:first-child {
border-radius: 0px;
}
#Boutique #bandeau_avancement .etape:last-child {
border-radius: 0px;
}
/*--------------------------------------------------*/
#Boutique #accueil .famille {
grid-template-columns: 1fr;
}
#Boutique #accueil .famille .produit {
/* border-top:10px solid var(--bleu_koriolan_fonce); */
grid-template-rows: auto;
row-gap:20px;
}
#Boutique #accueil .famille .produit .image img {
height: auto;
width: min(80%, 350px);
margin-top: 20px;
}
#Boutique #accueil .famille .produit .boutons a {
width: calc(96% - 20px);
/* padding: 40px 10px; */
margin-bottom: 20px;
}
#Boutique #accueil .famille .produit .boutons a:hover {
}
/*--------------------------------------------------*/
#Boutique #panier .liste_produits {
grid-row-gap: 10px;
}
#Boutique #panier .liste_produits .titre {
display:none;
}
#Boutique #panier .liste_produits .produit {
border: 3px solid var(--bleu_koriolan_fonce);
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
row-gap: 10px;
grid-template-areas:
" image image "
" nom nom "
" descriptif descriptif "
" delai delai "
" boutons quantite "
" prix_ht prix_ht "
" prix_ttc prix_ttc ";
align-items: center;
justify-items: center;
margin: 10px 0px 50px 0px;
padding: 20px 10px;
/* font-size: 0.8em; */
}
#Boutique #panier .liste_produits .produit .image {
text-align: center;
}
#Boutique #panier .liste_produits .produit .image img {
height: auto;
width: min(80%, 350px);
}
#Boutique #panier .liste_produits .produit .descriptif {
font-style: normal;
}
#Boutique #panier .liste_produits .produit .quantite {
/* font-size:1.5em; */
}
#Boutique #panier .liste_produits .produit .quantite .info_mobile {
font-size:0.8em;
}
#Boutique #panier .liste_produits .produit .boutons {
grid-template-columns: 1fr 1fr;
grid-template-areas:
" moins plus ";
grid-column-gap: 20px;
align-items: center;
}
#Boutique #panier .liste_produits .produit .boutons a {
height: 100%;
width: 100%;
}
#Boutique #panier .liste_produits .produit .boutons a img {
width: 100%;
}
#Boutique #panier .liste_produits .produit .delai {
line-height: normal;
}
#Boutique #panier .liste_produits .produit .prix_ht {
line-height: normal;
}
#Boutique #panier .liste_produits .produit .prix_ttc {
line-height: normal;
font-size:1.2em;
}
#Boutique #panier .liste_produits .synthese {
grid-template-columns: 2fr 2fr 2fr;
}
#Boutique #panier .liste_produits .synthese.titres.info_mobile {
display: block;
}
/*--------------------------------------------------*/
#Boutique #identification form {
grid-template-columns: 1fr;
grid-template-areas:
" shipmember "
" new_shipmember ";
row-gap:10px;
}
/*--------------------------------------------------*/
#Boutique #validation .liste_produits .titre {
display:none;
}
#Boutique #validation .liste_produits .produit {
border: 3px solid var(--bleu_koriolan_fonce);
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
row-gap: 20px;
grid-template-areas:
" image image "
" nom nom "
" descriptif descriptif "
" delai delai "
" prix_ht prix_ht "
" prix_ttc prix_ttc "
" boutons quantite ";
align-items: center;
justify-items: center;
margin: 10px 0px 10px 0px;
padding: 20px 10px;
/* font-size: 0.8em; */
}
#Boutique #validation .liste_produits .produit .image {
text-align: center;
}
#Boutique #validation .liste_produits .produit .image img {
height: auto;
width: min(80%, 350px);
}
#Boutique #validation .liste_produits .produit .descriptif {
font-style: normale;
}
#Boutique #validation .liste_produits .produit .quantite {
font-size:1.5em;
line-height: 1.5em;
}
#Boutique #validation .liste_produits .produit .quantite .info_mobile {
font-size:0.8em;
}
#Boutique #validation .liste_produits .produit .boutons {
grid-template-columns: 1fr 1fr;
grid-template-areas:
" moins plus ";
grid-column-gap: 20px;
align-items: center;
}
#Boutique #validation .liste_produits .produit .boutons a {
height: 200px;
width: 200px;
line-height: 200px;
}
#Boutique #validation .liste_produits .produit .boutons a img {
width: 100px;
}
#Boutique #validation .liste_produits .produit .delai {
line-height: normal;
}
#Boutique #validation .liste_produits .produit .prix_ht {
line-height: normal;
}
#Boutique #validation .liste_produits .produit .prix_ttc {
line-height: normal;
font-size:1.2em;
}
#Boutique #validation .liste_produits .synthese {
grid-template-columns: 2fr 2fr 2fr;
}
#Boutique #validation .liste_produits .synthese.titres.info_mobile {
display: inline;
}
#Boutique #validation .message_validation_cgv input {
width: 40px;
}
#Boutique #validation .message_validation_cgv label {
line-height: 20px;
}
#Boutique #validation .message_validation_cgv a {
padding: 0px 30px;
/* background-color: var(--bleu_koriolan_fonce); */
}
/*--------------------------------------------------*/
/*--------------------------------------------------*/
/*--------------------------------------------------*/
#Boutique #paiement .saisie_paiement form {
/* padding: 20px 0px 100px 0px; */
}
#Boutique #paiement .saisie_paiement #card-element {
width: 90%;
margin-bottom: 50px;
/* margin: 50px 0px 150px 0px; */
/* background: var(--bleu_koriolan_transparent); */
}
/*--------------------------------------------------*/
#Boutique #cloture h2 {
margin-top: 50px;
}
@@ -600,9 +245,6 @@ Fichier faq.php
#Faq #accueil .famille .reponse {
margin:0px 10px 30px 10px;
}
#Faq #accueil .famille .reponse .photos {
grid-template-columns: 1fr;
}
@@ -611,15 +253,7 @@ Fichier faq.php
Fichier galerie.php
***********************************************************************************************************************/
#Galerie #accueil #photos {
grid-template-columns: 1fr;
}
#Galerie #accueil #photos .photo .legende {
/* font-size:1.6em; */
}
#Galerie #accueil #photos .photo {
grid-template-rows: 1fr auto;
}
/***********************************************************************************************************************
@@ -642,24 +276,7 @@ Fichier mentions_legales.php
/***********************************************************************************************************************
Fichier nautic2021.php
***********************************************************************************************************************/
#Nautic2021 .logo_sh {
height:80px;
}
#Nautic2021 .logo_nautic {
height:80px;
}
#Nautic2021 .champs .champs_valeur {
min-height: 50px;
line-height: 50px;
vertical-align: middle;
}
#Nautic2021 .champs .champs_valeur input[type="checkbox"] {
margin-left: 30px;
}
#Nautic2021 .champs .champs_valeur label {
width: 70%;
min-height: 50px;
}
/***********************************************************************************************************************
+105 -212
View File
@@ -77,19 +77,6 @@ Fichier bateaux.php
background-color: var(--bleu_koriolan);
color: var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .graphique .top_part_graph .vars .var{
cursor: pointer;
}
#Bateaux #details_bateau .graphique .top_part_graph .vars .var.actif {
border-radius: 5px;
background-color: var(--bleu_koriolan_transparent);
color: var(--bleu_koriolan_fonce);
font-weight: 600;
}
.page_principale {
width: 80% !important;
max-width: unset !important;
@@ -122,23 +109,6 @@ Fichier bateaux.php
padding: 0px;
}
#Bateaux #details_bateau .onglets a {
background-color: var(--bleu_koriolan_fonce);
border-radius: 1em 1em 0 0;
color: var(--blanc);
display: inline-block;
padding: 3px 20px;
margin: 1px 1px 0px 1px;
}
#Bateaux #details_bateau .onglets a:hover {
color: var(--bleu_koriolan);
background-color: var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .onglets a.actif {
background-color: var(--bleu_koriolan);
color: var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .corps_details_bateau {
background-color: var(--blanc_casse);
}
@@ -162,105 +132,6 @@ Fichier bateaux.php
text-align: left;
/* background-color: var(--blanc_casse); */
}
.red {
color: red;
}
.orange {
color: #ffa600;
}
.green {
color: #02a602;
}
.capteur_state{
display: block;
padding: 0px;
height: 60px;
line-height: 60px;
width: 80px;
text-align: center !important;
font-size: 1.5em;
border-radius: 5px;
}
.capteur_off{
background-color: rgba(255, 30, 0, 0.2);
color: rgb(255,30,0);
}
.consommation_instantanee {
font-size: 1em;
padding: 6px;
background-image: url(images/icone_consommation_electrique.png);
background-size: contain;
background-position: center;
background-repeat: no-repeat;
margin-right: 5px;
}
.capteur_on{
background-color: rgba(177, 251, 23, 0.3);
color: rgb(177, 251, 23);
}
#Bateaux #details_bateau .corps_details_bateau .champs .champs_description {
grid-column: 1 / span 2;
text-align: justify;
font-size:0.8em;
}
#Bateaux #details_bateau .boutons_graphique {
text-align: center;
display: grid;
grid-template-columns: 1fr ;
grid-column-gap: 20px;
align-items: center;
margin: 20px 0px 20px 0px;
}
#Bateaux #details_bateau .boutons_graphique a {
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
width: 300px;
margin: auto;
}
#Bateaux #details_bateau .boutons_graphique a:hover {
color: var(--bleu_koriolan);
background-color: var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .boutons_graphique a.actif {
background-color: var(--bleu_koriolan);
color: var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant {
display: grid;
grid-template-columns: 2fr 3fr 60px;
/* height: 70px; */
padding: 15px 0px 15px 0px;
margin: 2em 0px 0.2em 0px;
border-top: 1px solid var(--bleu_koriolan_fonce);
border-bottom: 1px solid var(--bleu_koriolan_fonce);
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant p{
margin: unset;
text-align : unset;
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .titre_text{
font-size: 1.8em;
font-weight: 500;
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .titre_desc{
/* font-size: 1.8em; */
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .titre_capt{
display: flex;
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .titre_icon {
background-size: contain;
background-repeat: no-repeat;
cursor: pointer;
background-position: center;
margin-right: 10px;
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .more {
background-image: url("images/show_more.png");
}
#Bateaux #details_bateau .corps_details_bateau .titre_composant .less {
background-image: url("images/show_less.png");
}
#Bateaux #creation_bateau .champs {
display: grid;
grid-template-columns: 1fr;
@@ -272,10 +143,6 @@ Fichier bateaux.php
#Bateaux #creation_bateau .champs .champs_valeur {
text-align: left;
}
#Bateaux #creation_bateau .champs .champs_valeur select option.selection_actuelle {
color: var(--bleu_koriolan_fonce);
font-weight: bold;
}
#Bateaux #creation_bateau .champs .champs_valeur select option[disabled] {
color: var(--gris_tres_pale);
background-color: var(--gris_tres_tres_pale);
@@ -326,18 +193,9 @@ Fichier bateaux.php
height: unset !important;
margin: 20px 0px 20px 0px !important;
}
.graphique .graph {
width: 100%;
height: 100%;
position: relative;
}
.graphique .titre{
margin-bottom: 20px;
}
.top_part_graph {
display: flex;
height: 100%;
}
.var {
/* display: flex; */
flex-direction: row;
@@ -349,36 +207,6 @@ Fichier bateaux.php
.var label{
display: unset !important;
}
.date_pick form{
display: flex;
flex-direction: column;
}
.date_pick input {
width: 100%;
position: relative;
margin: auto;
}
.date_pick label {
display: grid;
grid-template-columns: 2fr 3fr;
}
.date_pick span {
position: relative;
margin: auto;
}
.date_maj_version{
display: flex;
}
.date_maj_version input,.date_maj_version select{
width: 200px !important;
margin-left: 30px !important;
margin-right: 30px !important;
}
.gestion_acces{
/* height: 100; */
@@ -403,17 +231,6 @@ Fichier bateaux.php
padding: 3px 10px;
font-size: 0.9em;
}
.download{
font-weight: 800;
padding: 0;
color: red;
}
.download:hover {
background: red;
color: var(--blanc_casse);
}
#type_acces {
height: unset;
}
@@ -467,10 +284,6 @@ form.variables input{
padding-bottom: 20px;
z-index: 50;
}
#maCarte {
height: 600px;
z-index: 1;
}
/* --------------------- POP UP EDIT ACCESS----------------------*/
#popUpAcces{
@@ -545,9 +358,6 @@ form.variables input{
font-weight: 600;
background-color: white;
}
#popUpAccesModal form .buttons_acces{
display: grid;
}
/* --------------------- GESTION DES ACCÈS (synthèse §48) ----------------------*/
@@ -688,14 +498,7 @@ form.variables input{
}
/* ------------------ Autres ---------------- */
#dateSlider{
margin-bottom: 50px !important;
margin-top: 50px !important;
}
#dateSlider .noUi-connect{
background-color: var(--bleu_koriolan);
}
@media only screen and (max-width: 580px) {
#Bateaux .boutons_haut_de_page {
grid-template-columns: minmax(50px, auto);
@@ -706,10 +509,6 @@ form.variables input{
flex-direction: column;
padding : 0;
}
.vars {
display: grid !important;
grid-template-columns: 1fr !important;
}
#popUpAccesModal{
width: 95% !important;
height: 60% !important;
@@ -721,13 +520,6 @@ form.variables input{
}
@media only screen and (max-width: 850px) {
.top_part_graph {
flex-direction: column-reverse;
}
.vars {
display: grid !important;
grid-template-columns: 1fr 1fr;
}
.page_principale {
width: 96% !important;
}
@@ -749,10 +541,6 @@ form.variables input{
width: 80%;
height: 40%;
}
#dateSlider{
margin: auto;
width: 80%;
}
}
/* Petits écrans : formulaire d'invitation sur une colonne. Placé EN FIN de fichier : le bloc "max-width: 850px"
@@ -766,3 +554,108 @@ form.variables input{
grid-column: auto;
}
}
/* --------------------- CONSULTATION DES DONNÉES (synthèse §50) ----------------------*/
/* Indicateur de fraîcheur (en-tête de la page du bateau) */
#Bateaux .fraicheur { padding: 1px 8px; border-radius: 1em; }
#Bateaux .fraicheur_verte { background-color: rgba(2, 166, 2, 0.12); color: #027a02; }
#Bateaux .fraicheur_orange { background-color: rgba(255, 166, 0, 0.18); color: #8a5a00; }
#Bateaux .fraicheur_rouge { background-color: rgba(229, 57, 53, 0.15); color: #b71c1c; }
/* Choix de la génération consultée */
#Bateaux .consultation .choix_generation { text-align: left; margin: 10px 0px 20px 0px; }
#Bateaux .consultation .choix_generation select { width: auto; max-width: 100%; display: inline-block; height: 2.4em; padding: 0px 10px; }
#Bateaux .consultation .generation_ancienne {
text-align: left;
padding: 8px 15px;
border-radius: 10px;
background-color: var(--jaune_post_it_transparent);
}
/* Domaines : une grille de familles (cartes) par domaine */
#Bateaux .consultation .domaine { margin-bottom: 30px; }
#Bateaux .consultation .domaine h2 { text-align: left; margin-bottom: 10px; }
#Bateaux .consultation .domaine {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 15px;
align-items: start;
}
#Bateaux .consultation .domaine h2 { grid-column: 1 / -1; }
#Bateaux .consultation .famille {
border: 1px solid var(--bleu_koriolan_transparent);
border-radius: 10px;
padding: 5px 15px 10px 15px;
background-color: var(--blanc);
}
#Bateaux .consultation .famille h3 { text-align: left; font-size: 1.05em; margin: 8px 0px; }
#Bateaux .consultation .famille table { width: 100%; }
#Bateaux .consultation .famille td {
padding: 4px 6px;
border-top: 1px solid var(--gris_tres_tres_pale);
font-size: 0.9em;
text-align: left;
vertical-align: top;
}
#Bateaux .consultation .famille td.valeurs_element { text-align: right; white-space: pre; font-weight: 600; }
#Bateaux .consultation .famille td.defaut_element { text-align: right; color: #b71c1c; font-size: 0.8em; }
#Bateaux .consultation .famille tr.en_defaut td.nom_element::before { content: "\26A0\00A0"; color: #e53935; }
/* Dernières alarmes */
#Bateaux .consultation .dernieres_alarmes { margin-bottom: 30px; }
#Bateaux .consultation .dernieres_alarmes h2 { text-align: left; margin-bottom: 10px; }
#Bateaux .consultation .dernieres_alarmes .aucune_alarme { text-align: left; font-style: italic; color: var(--gris_pale); }
#Bateaux .consultation .dernieres_alarmes table { width: 100%; }
#Bateaux .consultation .dernieres_alarmes td {
text-align: left;
padding: 4px 8px;
border-top: 1px solid var(--gris_tres_tres_pale);
font-size: 0.9em;
vertical-align: top;
}
#Bateaux .consultation .dernieres_alarmes td.date_alarme { white-space: nowrap; width: 1%; }
#Bateaux .consultation .dernieres_alarmes th { text-align: left; padding: 4px 8px; font-size: 0.85em; }
#Bateaux .consultation .dernieres_alarmes td.duree_alarme { white-space: nowrap; width: 1%; }
#Bateaux .consultation .dernieres_alarmes td.nom_alarme { font-weight: 600; color: #b71c1c; white-space: nowrap; width: 1%; }
#Bateaux .consultation .dernieres_alarmes .alarme_en_cours { color: #b71c1c; font-weight: 600; }
#Bateaux .consultation .dernieres_alarmes tr.alarme_termine td.nom_alarme,
#Bateaux .consultation .dernieres_alarmes tr.alarme_ponctuel td.nom_alarme { color: var(--bleu_koriolan_fonce); }
/* Courbes historiques (étape 3c) */
#Bateaux .consultation tr.avec_courbe { cursor: pointer; }
#Bateaux .consultation tr.avec_courbe:hover td { background-color: var(--bleu_koriolan_transparent); }
#panneau_courbe {
position: fixed; inset: 0; z-index: 9999;
background: rgba(255, 255, 255, 0.8); backdrop-filter: blur(3px);
display: flex; align-items: center; justify-content: center;
}
#panneau_courbe[hidden] { display: none; }
#panneau_courbe .fenetre_courbe {
width: min(1000px, 95vw); max-height: 92vh; overflow-y: auto;
background: var(--blanc); border-radius: 10px; box-shadow: 0px 0px 7px 2px var(--bleu_koriolan);
padding: 10px 20px 15px 20px;
}
#panneau_courbe .entete_courbe { display: flex; justify-content: space-between; align-items: center; }
#panneau_courbe .entete_courbe h3 { margin: 5px 0px; text-align: left; }
#panneau_courbe #fermer_courbe {
background: none; border: none; color: var(--bleu_koriolan_fonce);
font-size: 2em; line-height: 1em; padding: 0px 8px; cursor: pointer;
}
#panneau_courbe .choix_courbe { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0px; }
#panneau_courbe .choix_courbe:empty { display: none; }
#panneau_courbe .choix_courbe button {
padding: 2px 12px; line-height: 1.6em; font-size: 0.85em; border-radius: 0.8em;
background-color: var(--blanc); color: var(--bleu_koriolan_fonce);
}
#panneau_courbe .choix_courbe button.actif { background-color: var(--bleu_koriolan_fonce); color: var(--blanc); }
#panneau_courbe .zone_courbe { position: relative; height: min(55vh, 420px); }
#panneau_courbe #message_courbe { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; margin: 0px; font-style: italic; }
#panneau_courbe #message_courbe[hidden] { display: none; }
#panneau_courbe #stats_courbe { font-size: 0.85em; text-align: left; white-space: pre-wrap; margin: 8px 0px 0px 0px; }
/* Information sur la mise à jour demandée à l'ouverture (étape 3d) */
#Bateaux .entete_bateau .info_mise_a_jour { display: block; font-size: 0.8em; font-style: italic; color: var(--gris_pale); margin-top: 3px; }
#Bateaux .entete_bateau .info_mise_a_jour.en_cours::before { content: "\21BB\00A0"; display: inline-block; animation: rotation_mise_a_jour 1.5s linear infinite; }
@keyframes rotation_mise_a_jour { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
#Bateaux .entete_bateau { height: auto; min-height: 60px; } /* place pour la ligne d'information ci-dessus */
+48 -152
View File
@@ -1,152 +1,48 @@
#Contact{
height: 60vh;
width: 100%;
position: relative;
margin: auto;
display: flex;
flex-direction: column;
}
.text_contact{
height: 50%;
padding-left: 20%;
padding-right: 20%;
align-items: center;
display: flex;
}
.text_contact p{
font-size: 25px;
font-style: unset;
position: relative;
margin: auto;
}
.content_contact{
height: 50%;
padding-left: 5%;
padding-right: 5%;
display: flex;
}
.linkedin{
width: 33%;
height: 100%;
/* padding: 5%; */
display: flex;
}
.linkedin img{
height: 50px;
position: relative;
object-fit: contain;
margin: auto;
}
.linkedin a {
margin: auto;
}
.mail{
width: 43%;
height: 100%;
display: flex;
}
.mail p{
position: relative;
margin: auto;
padding: 20px;
padding-left: 40px;
padding-right: 40px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 20px;
}
.phone{
width: 33%;
height: 100%;
/* padding: 5%; */
display: flex;
}
.phone p{
position: relative;
margin: auto;
padding: 20px;
padding-left: 40px;
padding-right: 40px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 20px;
white-space: nowrap;
}
a:hover {
color: white !important;
}
@media only screen and (max-width: 850px) {
.content_contact{
display: flex;
flex-direction: column;
margin-top: -10px;
padding-left: 10%;
padding-right: 10%;
}
.linkedin{
width: 80vw;
height: 33%;
padding: 5%;
}
.mail{
width: 80vw;
height: 33%;
padding: 5%;
}
.phone{
width: 80vw;
height: 33%;
padding: 5%;
}
.text_contact{
height: 50%;
padding-left: 5%;
padding-right: 5%;
align-items: center;
display: flex;
}
.text_contact p{
font-size: 18px;
background-color: var(--bleu_koriolan_transparent);
padding: 22px;
border: 3px solid var(--bleu_koriolan_transparent);
border-radius: 15px;
}
.linkedin img{
height: 50px;
position: relative;
object-fit: contain;
margin: auto;
border-radius: 14px;
}
.mail p{
position: relative;
margin: auto;
margin-top: -10px;
width: 80vw;
padding: 20px;
padding-left: 30px;
padding-right: 30px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 18px;
max-height: 67px;
}
.phone p{
position: relative;
width: 80vw;
margin: auto;
margin-top: -10px;
padding: 20px;
padding-left: 30px;
padding-right: 30px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 18px;
max-height: 67px;
}
}
#Contact{
height: 60vh;
width: 100%;
position: relative;
margin: auto;
display: flex;
flex-direction: column;
}
.mail{
width: 43%;
height: 100%;
display: flex;
}
.mail p{
position: relative;
margin: auto;
padding: 20px;
padding-left: 40px;
padding-right: 40px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 20px;
}
a:hover {
color: white !important;
}
@media only screen and (max-width: 850px) {
.mail{
width: 80vw;
height: 33%;
padding: 5%;
}
.mail p{
position: relative;
margin: auto;
margin-top: -10px;
width: 80vw;
padding: 20px;
padding-left: 30px;
padding-right: 30px;
background-color: var(--bleu_koriolan);
border-radius: 10px;
color: white;
font-size: 18px;
max-height: 67px;
}
}
+296 -332
View File
@@ -1,332 +1,296 @@
/***********************************************************************************************************************
Fichier shipmembers.php
***********************************************************************************************************************/
#Shipmembers h2 {
margin-bottom: 30px;
}
#Shipmembers .message p {
text-align: justify;
}
#Shipmembers .boutons_bas_de_page a {
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
text-align: center;
margin: 10px 0px 30px 0px;
display:block;
}
#Shipmembers .boutons_bas_de_page a:hover {
color: var(--bleu_koriolan);
}
#Shipmembers .boutons_bas_de_page button {
display:block;
margin: 10px 0px 30px 0px;
width: 100%;
}
/*--------------------------------------------------*/
#Shipmembers #login form {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #login .login {
display: grid;
grid-template-columns: 1fr;
row-gap:20px;
}
#Shipmembers #login .login .message_login {
text-align: justify;
}
#Shipmembers #login .login .champs {
display: grid;
grid-template-columns: 1fr;
}
#Shipmembers #login .login .champs .champs_titre {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur input {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur textarea {
border:1px solid var(--bleu_koriolan);
border-radius: 10px;
text-align: left;
}
/*--------------------------------------------------*/
#Shipmembers #activation form {
display: grid;
grid-template-columns: 1fr;
row-gap:80px;
align-items: start;
}
#Shipmembers #activation .shipmember {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #activation .shipmember .lignes {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #activation .shipmember .ligne {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #activation .shipmember .ligne .titre_ligne {
border-bottom: 1px solid var(--bleu_koriolan);
}
/*--------------------------------------------------*/
#Shipmembers #generation_mdp form {
display: grid;
grid-template-columns: 1fr;
row-gap:80px;
align-items: start;
}
#Shipmembers #generation_mdp .shipmember {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #generation_mdp .shipmember .lignes {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #generation_mdp .shipmember .ligne {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #generation_mdp .shipmember .ligne .titre_ligne {
border-bottom: 1px solid var(--bleu_koriolan);
}
/*--------------------------------------------------*/
#Shipmembers #accueil {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #accueil .message {
text-align: justify;
}
/* Mes invitations (synthèse §48) : une carte par invitation (texte, Accepter, Refuser), puis la saisie d'un code */
#Shipmembers #accueil .invitations .aucune {
text-align: left;
font-style: italic;
color: var(--gris_pale);
}
#Shipmembers #accueil .invitations form.invitation {
display: grid;
grid-template-columns: 1fr auto auto;
column-gap: 10px;
align-items: center;
margin-bottom: 10px;
padding: 10px 15px;
border: 1px solid var(--bleu_koriolan);
border-radius: 10px;
background-color: var(--bleu_koriolan_transparent);
}
#Shipmembers #accueil .invitations form.invitation p {
margin: 0px;
text-align: left;
}
#Shipmembers #accueil .invitations button {
padding: 2px 16px;
line-height: 1.8em;
border-radius: 0.8em;
white-space: nowrap;
}
#Shipmembers #accueil .invitations button.refuser {
background-color: var(--blanc);
border-color: var(--rouge);
color: var(--rouge);
}
#Shipmembers #accueil .invitations button.refuser:hover {
background-color: var(--rouge);
color: var(--blanc);
}
#Shipmembers #accueil .invitations form.saisie_code {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-top: 25px;
}
#Shipmembers #accueil .invitations form.saisie_code input {
width: 12em;
text-transform: uppercase;
letter-spacing: 0.15em;
text-align: center;
}
#Shipmembers #accueil .invitations form.saisie_code input::placeholder {
text-transform: none;
letter-spacing: normal;
}
@media only screen and (max-width: 580px) {
#Shipmembers #accueil .invitations form.invitation {
grid-template-columns: 1fr 1fr;
row-gap: 10px;
}
#Shipmembers #accueil .invitations form.invitation p {
grid-column: span 2;
}
}
/*--------------------------------------------------*/
#Shipmembers #profil form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #profil .profil {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #profil .profil .champs {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #profil .profil .champs .champs_titre {
text-align: left;
padding-left:20px;
line-height: 30px;
background-color: var(--bleu_koriolan_transparent);
border-bottom: 1px solid var(--bleu_koriolan);
border-radius: 5px 0px 0px 5px;
}
#Shipmembers #profil .profil .champs .champs_valeur {
text-align: left;
padding-left:20px;
line-height: 30px;
border-bottom: 1px solid var(--bleu_koriolan);
border-radius: 0px 5px 5px 0px;
}
/*--------------------------------------------------*/
#Shipmembers #modifier_profil form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #modifier_profil .profil {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #modifier_profil .profil .message {
margin-top: 20px;
}
/*--------------------------------------------------*/
#Shipmembers #historique form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
}
#Shipmembers #historique .liste_commandes {
display: grid;
grid-template-columns: 1fr;
text-align: center;
}
#Shipmembers #historique .liste_commandes .titre {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
line-height:40px;
}
#Shipmembers #historique .liste_commandes .commande {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
line-height:30px;
}
#Shipmembers #historique .liste_commandes .commande:nth-child(even) {
background-color: var(--bleu_koriolan_transparent);
}
#Shipmembers #historique .liste_commandes .commande .prix_ttc {
text-align: right;
}
#Shipmembers #historique .liste_commandes .commande .download a {
line-height:30px;
}
#Shipmembers #historique .liste_commandes .commande .download img {
width: 30px;
vertical-align: middle;
}
/*--------------------------------------------------*/
#Shipmembers #bateau form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
/* align-items: start; */
}
#Shipmembers #bateau form a {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
/* align-items: start; */
}
#Shipmembers #bateau .acces_bateau a {
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
text-align: left;
padding-left: 20px;
margin: 10px 30px 30px 30px;
display:block;
}
#Shipmembers #bateau .acces_bateau a:hover {
color: var(--bleu_koriolan);
}
#Shipmembers #bateau .acces_bateau button {
display:block;
margin: 10px 0px 30px 0px;
width: 100%;
}
/***********************************************************************************************************************
Fichier shipmembers.php
***********************************************************************************************************************/
#Shipmembers h2 {
margin-bottom: 30px;
}
#Shipmembers .message p {
text-align: justify;
}
#Shipmembers .boutons_bas_de_page a {
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
text-align: center;
margin: 10px 0px 30px 0px;
display:block;
}
#Shipmembers .boutons_bas_de_page a:hover {
color: var(--bleu_koriolan);
}
#Shipmembers .boutons_bas_de_page button {
display:block;
margin: 10px 0px 30px 0px;
width: 100%;
}
/*--------------------------------------------------*/
#Shipmembers #login form {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #login .login {
display: grid;
grid-template-columns: 1fr;
row-gap:20px;
}
#Shipmembers #login .login .champs {
display: grid;
grid-template-columns: 1fr;
}
#Shipmembers #login .login .champs .champs_titre {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur input {
text-align: left;
}
#Shipmembers #login .login .champs .champs_valeur textarea {
border:1px solid var(--bleu_koriolan);
border-radius: 10px;
text-align: left;
}
/*--------------------------------------------------*/
#Shipmembers #activation form {
display: grid;
grid-template-columns: 1fr;
row-gap:80px;
align-items: start;
}
#Shipmembers #activation .shipmember {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #activation .shipmember .lignes {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #activation .shipmember .ligne {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #activation .shipmember .ligne .titre_ligne {
border-bottom: 1px solid var(--bleu_koriolan);
}
/*--------------------------------------------------*/
#Shipmembers #generation_mdp form {
display: grid;
grid-template-columns: 1fr;
row-gap:80px;
align-items: start;
}
#Shipmembers #generation_mdp .shipmember {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #generation_mdp .shipmember .lignes {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #generation_mdp .shipmember .ligne {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #generation_mdp .shipmember .ligne .titre_ligne {
border-bottom: 1px solid var(--bleu_koriolan);
}
/*--------------------------------------------------*/
#Shipmembers #accueil {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #accueil .message {
text-align: justify;
}
/* Mes invitations (synthèse §48) : une carte par invitation (texte, Accepter, Refuser), puis la saisie d'un code */
#Shipmembers #accueil .invitations .aucune {
text-align: left;
font-style: italic;
color: var(--gris_pale);
}
#Shipmembers #accueil .invitations form.invitation {
display: grid;
grid-template-columns: 1fr auto auto;
column-gap: 10px;
align-items: center;
margin-bottom: 10px;
padding: 10px 15px;
border: 1px solid var(--bleu_koriolan);
border-radius: 10px;
background-color: var(--bleu_koriolan_transparent);
}
#Shipmembers #accueil .invitations form.invitation p {
margin: 0px;
text-align: left;
}
#Shipmembers #accueil .invitations button {
padding: 2px 16px;
line-height: 1.8em;
border-radius: 0.8em;
white-space: nowrap;
}
#Shipmembers #accueil .invitations button.refuser {
background-color: var(--blanc);
border-color: var(--rouge);
color: var(--rouge);
}
#Shipmembers #accueil .invitations button.refuser:hover {
background-color: var(--rouge);
color: var(--blanc);
}
#Shipmembers #accueil .invitations form.saisie_code {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-top: 25px;
}
#Shipmembers #accueil .invitations form.saisie_code input {
width: 12em;
text-transform: uppercase;
letter-spacing: 0.15em;
text-align: center;
}
#Shipmembers #accueil .invitations form.saisie_code input::placeholder {
text-transform: none;
letter-spacing: normal;
}
@media only screen and (max-width: 580px) {
#Shipmembers #accueil .invitations form.invitation {
grid-template-columns: 1fr 1fr;
row-gap: 10px;
}
#Shipmembers #accueil .invitations form.invitation p {
grid-column: span 2;
}
}
/*--------------------------------------------------*/
#Shipmembers #profil form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #profil .profil {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #profil .profil .champs {
display: grid;
grid-template-columns: 1fr 3fr;
}
#Shipmembers #profil .profil .champs .champs_titre {
text-align: left;
padding-left:20px;
line-height: 30px;
background-color: var(--bleu_koriolan_transparent);
border-bottom: 1px solid var(--bleu_koriolan);
border-radius: 5px 0px 0px 5px;
}
#Shipmembers #profil .profil .champs .champs_valeur {
text-align: left;
padding-left:20px;
line-height: 30px;
border-bottom: 1px solid var(--bleu_koriolan);
border-radius: 0px 5px 5px 0px;
}
/*--------------------------------------------------*/
#Shipmembers #modifier_profil form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
align-items: start;
}
#Shipmembers #modifier_profil .profil {
display: grid;
grid-template-columns: 1fr;
row-gap:10px;
}
#Shipmembers #modifier_profil .profil .message {
margin-top: 20px;
}
/*--------------------------------------------------*/
#Shipmembers #historique form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
}
/*--------------------------------------------------*/
#Shipmembers #bateau form {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
/* align-items: start; */
}
#Shipmembers #bateau form a {
display: grid;
grid-template-columns: 1fr;
column-gap:40px;
row-gap:80px;
/* align-items: start; */
}
#Shipmembers #bateau .acces_bateau a {
background-color: var(--bleu_koriolan_fonce);
color: var(--blanc);
text-align: left;
padding-left: 20px;
margin: 10px 30px 30px 30px;
display:block;
}
#Shipmembers #bateau .acces_bateau a:hover {
color: var(--bleu_koriolan);
}
#Shipmembers #bateau .acces_bateau button {
display:block;
margin: 10px 0px 30px 0px;
width: 100%;
}
+9
View File
@@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright (c) 2014-2024 Chart.js Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File diff suppressed because one or more lines are too long