Sauvegarde
This commit is contained in:
+23
-7
@@ -12,11 +12,13 @@ function listeLogos($category = null) {
|
||||
global $dbh;
|
||||
|
||||
try {
|
||||
// SELECT * : la colonne icon est optionnelle (le bandeau continue de fonctionner
|
||||
// avec les logos déjà en place même si la migration SQL n'a pas encore été exécutée)
|
||||
if ($category !== null) {
|
||||
$stmt = $dbh->prepare('SELECT id, category, name, logo_url, link_url, position FROM logo_banners WHERE category = :category ORDER BY position ASC, id ASC');
|
||||
$stmt = $dbh->prepare('SELECT * FROM logo_banners WHERE category = :category ORDER BY position ASC, id ASC');
|
||||
$stmt->bindValue(':category', $category, PDO::PARAM_STR);
|
||||
} else {
|
||||
$stmt = $dbh->prepare('SELECT id, category, name, logo_url, link_url, position FROM logo_banners ORDER BY category ASC, position ASC, id ASC');
|
||||
$stmt = $dbh->prepare('SELECT * FROM logo_banners ORDER BY category ASC, position ASC, id ASC');
|
||||
}
|
||||
$stmt->execute();
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -30,7 +32,7 @@ function recupererLogoParId($id) {
|
||||
global $dbh;
|
||||
|
||||
try {
|
||||
$stmt = $dbh->prepare('SELECT id, category, name, logo_url, link_url, position FROM logo_banners WHERE id = :id');
|
||||
$stmt = $dbh->prepare('SELECT * FROM logo_banners WHERE id = :id');
|
||||
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
@@ -39,6 +41,20 @@ function recupererLogoParId($id) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction interne qui affiche le contenu visuel d'une tuile : une icône Devicon si elle est
|
||||
// renseignée (prioritaire), sinon l'image. Ne retourne rien si aucun des deux n'est présent.
|
||||
function afficherLogoVisuel($logo) {
|
||||
$icone = trim($logo['icon'] ?? '');
|
||||
$image = trim($logo['logo_url'] ?? '');
|
||||
$nom = htmlspecialchars($logo['name']);
|
||||
|
||||
if ($icone !== '') {
|
||||
echo '<i class="' . htmlspecialchars($icone) . '"></i>';
|
||||
} elseif ($image !== '') {
|
||||
echo '<img src="' . htmlspecialchars($image) . '" alt="' . $nom . '" loading="lazy">';
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction qui affiche le bandeau défilant d'une catégorie de logos sur la page publique
|
||||
// N'affiche rien si la catégorie est vide (la section entière est masquée côté page d'accueil)
|
||||
function afficherLogos($category) {
|
||||
@@ -58,7 +74,6 @@ function afficherLogos($category) {
|
||||
for ($repetition = 0; $repetition < 2; $repetition++) {
|
||||
foreach ($logos as $logo) {
|
||||
$nom = htmlspecialchars($logo['name']);
|
||||
$image = htmlspecialchars($logo['logo_url']);
|
||||
$lien = trim($logo['link_url'] ?? '');
|
||||
|
||||
if ($lien !== '') {
|
||||
@@ -67,7 +82,7 @@ function afficherLogos($category) {
|
||||
echo '<div class="logo-tile" title="' . $nom . '">';
|
||||
}
|
||||
|
||||
echo '<img src="' . $image . '" alt="' . $nom . '" loading="lazy">';
|
||||
afficherLogoVisuel($logo);
|
||||
echo $lien !== '' ? '</a>' : '</div>';
|
||||
}
|
||||
}
|
||||
@@ -91,11 +106,12 @@ function afficherLogosAdmin() {
|
||||
foreach ($logos as $logo) {
|
||||
$id = (int) $logo['id'];
|
||||
$nom = htmlspecialchars($logo['name']);
|
||||
$image = htmlspecialchars($logo['logo_url']);
|
||||
$badge = $logo['category'] === 'partner' ? 'Entreprise' : 'Outil';
|
||||
|
||||
echo '<div class="logo-admin-item">';
|
||||
echo '<div class="logo-admin-preview"><img src="' . $image . '" alt="' . $nom . '"></div>';
|
||||
echo '<div class="logo-admin-preview">';
|
||||
afficherLogoVisuel($logo);
|
||||
echo '</div>';
|
||||
echo '<div class="logo-admin-info">';
|
||||
echo '<span class="tag">' . $badge . '</span>';
|
||||
echo '<p>' . $nom . '</p>';
|
||||
|
||||
+115
-1
@@ -32,6 +32,41 @@ function recupererSkillParId($id) {
|
||||
}
|
||||
}
|
||||
|
||||
// Icônes Devicon dont la couleur de marque "colored" est noire ou quasi-noire (vérifié dans
|
||||
// devicon.min.css : linux #000, apple #000, bash #293138, ansible #1a1918) : invisibles sur
|
||||
// la tuile sombre du bandeau. On les affiche dans la couleur claire par défaut à la place.
|
||||
const DEVICON_COLORED_TROP_SOMBRE = ['devicon-linux-plain', 'devicon-apple-plain', 'devicon-bash-plain', 'devicon-ansible-plain'];
|
||||
|
||||
// Fonction interne qui affiche le visuel (icône ou image) d'un item de compétence.
|
||||
// Format accepté avant le "|" : soit des classes d'icône (Font Awesome ou Devicon), soit
|
||||
// "img:URL" pour utiliser une vraie image de logo (pour les outils absents des polices
|
||||
// d'icônes, ex : GLPI, FOG, Proxmox, VirtualBox, Guacamole).
|
||||
// $colorise active les vraies couleurs de marque des icônes Devicon (utilisé uniquement
|
||||
// pour le bandeau de la home : sur la page Compétences les icônes restent en orange
|
||||
// uniforme, cohérent avec le reste de la liste)
|
||||
function afficherVisuelItem($itemIcone, $classe = '', $colorise = false) {
|
||||
if (strpos($itemIcone, 'img:') === 0) {
|
||||
$image = htmlspecialchars(substr($itemIcone, 4));
|
||||
echo '<img class="' . $classe . '" src="' . $image . '" alt="" loading="lazy">';
|
||||
return;
|
||||
}
|
||||
|
||||
if ($colorise && strpos($itemIcone, 'devicon-') === 0 && strpos($itemIcone, 'colored') === false) {
|
||||
$estTropSombre = false;
|
||||
foreach (DEVICON_COLORED_TROP_SOMBRE as $slug) {
|
||||
if (strpos($itemIcone, $slug) === 0) {
|
||||
$estTropSombre = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$estTropSombre) {
|
||||
$itemIcone .= ' colored';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<i class="' . $classe . ' ' . htmlspecialchars($itemIcone) . '"></i>';
|
||||
}
|
||||
|
||||
// Fonction interne qui affiche une carte de compétences (utilisée par la page publique et le panel admin)
|
||||
// Les items sont stockés un par ligne, au format "classes-icone|Texte" (icône optionnelle)
|
||||
function afficherSkillCard($skill, $admin = false) {
|
||||
@@ -53,7 +88,9 @@ function afficherSkillCard($skill, $admin = false) {
|
||||
if (strpos($item, '|') !== false) {
|
||||
list($itemIcone, $label) = array_map('trim', explode('|', $item, 2));
|
||||
}
|
||||
echo '<li><i class="' . htmlspecialchars($itemIcone) . '"></i> ' . htmlspecialchars($label) . '</li>';
|
||||
echo '<li>';
|
||||
afficherVisuelItem($itemIcone, 'skill-item-visual');
|
||||
echo ' ' . htmlspecialchars($label) . '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
@@ -96,3 +133,80 @@ function afficherSkillsAdmin() {
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// Items exclus du bandeau de la home au cas par cas, en plus du filtre automatique
|
||||
// (icône Devicon "réelle" mais jugée pas assez reconnaissable seule, sans le texte à côté)
|
||||
const OUTILS_EXCLUS_DU_BANDEAU = ['Bash'];
|
||||
|
||||
// Fonction qui récupère tous les items de compétences représentant un vrai outil identifiable
|
||||
// (icône Devicon ou image "img:"), toutes catégories confondues. Les items en texte seul
|
||||
// SONT EXCLUS, ainsi que les icônes Font Awesome génériques (fa-solid/fa-brands) : dans un
|
||||
// bandeau qui n'affiche pas le texte à côté (juste une info-bulle au survol), une icône
|
||||
// générique comme un pictogramme "carte" pour "Adressage IP" ou "carnet de contact" pour
|
||||
// "LDAP" ne représente aucun outil reconnaissable — ça reste illisible pour un visiteur qui
|
||||
// ne survole pas. Ces items restent affichés normalement sur la page Compétences (avec leur
|
||||
// texte à côté, donc sans ambiguïté), seul le bandeau de la home les filtre.
|
||||
function listeIconesCompetences() {
|
||||
$categories = listeSkills();
|
||||
$resultats = [];
|
||||
|
||||
foreach ($categories as $categorie) {
|
||||
$items = array_filter(array_map('trim', preg_split('/\r\n|\r|\n/', $categorie['items'])));
|
||||
|
||||
foreach ($items as $item) {
|
||||
if (strpos($item, '|') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list($icone, $label) = array_map('trim', explode('|', $item, 2));
|
||||
if ($icone === '' || $label === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Seuls les vrais logos (Devicon ou image) sont assez reconnaissables sans texte
|
||||
$estUnVraiLogo = strpos($icone, 'devicon-') === 0 || strpos($icone, 'img:') === 0;
|
||||
if (!$estUnVraiLogo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($label, OUTILS_EXCLUS_DU_BANDEAU, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resultats[] = ['icon' => $icone, 'label' => $label];
|
||||
}
|
||||
}
|
||||
|
||||
return $resultats;
|
||||
}
|
||||
|
||||
// Fonction qui affiche le bandeau défilant des outils, directement à partir des icônes
|
||||
// de la page Compétences (voir listeIconesCompetences). Réutilise les mêmes classes CSS
|
||||
// que les bandeaux de logo_banners pour un rendu visuel identique (voir primary_css.css).
|
||||
// "logo-marquee-tools" désactive le filtre grayscale/survol : contrairement aux logos
|
||||
// d'entreprises, on veut que les vrais outils soient reconnaissables immédiatement.
|
||||
function afficherOutilsCompetences() {
|
||||
$outils = listeIconesCompetences();
|
||||
|
||||
if (empty($outils)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="logo-marquee logo-marquee-tools">';
|
||||
echo '<div class="logo-track">';
|
||||
|
||||
// On répète deux fois la liste : le défilement CSS boucle sur -50%, ce qui donne
|
||||
// un effet de scroll infini fluide et sans coupure
|
||||
for ($repetition = 0; $repetition < 2; $repetition++) {
|
||||
foreach ($outils as $outil) {
|
||||
$label = htmlspecialchars($outil['label']);
|
||||
|
||||
echo '<div class="logo-tile" title="' . $label . '">';
|
||||
afficherVisuelItem($outil['icon'], '', true);
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user