prepare('SELECT id, title, icon, items, position FROM skills ORDER BY position ASC, id ASC'); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { return []; } } // Fonction qui permet de récupérer une catégorie de compétences par id (pour la modification dans le panel Admin) function recupererSkillParId($id) { global $dbh; try { $stmt = $dbh->prepare('SELECT id, title, icon, items, position FROM skills WHERE id = :id'); $stmt->bindValue(':id', $id, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { return false; } } // 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 ''; 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 ''; } // 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) { $id = (int) $skill['id']; $titre = htmlspecialchars($skill['title']); $icone = htmlspecialchars(!empty($skill['icon']) ? $skill['icon'] : 'fa-solid fa-star'); echo '
'; echo '
'; echo '

' . $titre . '

'; echo ''; // Boutons de modification / suppression pour le panel admin if ($admin) { echo '
'; echo 'Modifier'; echo 'Supprimer'; echo '
'; } echo '
'; } // Fonction qui va afficher les compétences sur la page publique function afficherSkills() { $skills = listeSkills(); // Si la table est vide ou n'existe pas encore if (empty($skills)) { echo '

Les compétences seront bientôt disponibles.

'; return; } echo '
'; foreach ($skills as $skill) { afficherSkillCard($skill, false); } echo '
'; } // Fonction identique à celle en haut mais ajout de boutons pour le panel admin function afficherSkillsAdmin() { $skills = listeSkills(); echo '
'; foreach ($skills as $skill) { afficherSkillCard($skill, true); } echo '
'; } // 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 '
'; echo '
'; // 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 '
'; afficherVisuelItem($outil['icon'], '', true); echo '
'; } } echo '
'; echo '
'; }