Créer un Outil HTML#
Ce guide vous accompagne dans la création d'un outil HTML standalone pour Playlab42.
Objectif#
Créer un outil simple et autonome qui sera intégré au catalogue du portail.
Caractéristiques d'un outil :
- Un seul fichier HTML (tout inclus : CSS + JS)
- Utilise
lib/theme.csspour les styles et thèmes - Utilise
lib/dom.jspour les utilitaires DOM - Utile et pratique
- Style cohérent avec la plateforme (dark/light)
Prérequis#
- Connaissances de base en HTML, CSS, JavaScript
- Docker installé (
make servepour tester)
Structure d'un outil#
Un outil Playlab42 se compose de :
tools/
├── mon-outil.html # L'outil (fichier unique)
└── mon-outil.json # Métadonnées (optionnel)
Étapes#
1. Créer le fichier HTML#
Créez un fichier tools/mon-outil.html avec la structure suivante :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mon Outil - Playlab42</title>
<link rel="stylesheet" href="../lib/theme.css">
<style>
/* Vos styles ici - utilisez les variables CSS */
</style>
<script type="module">
import { initTheme } from '../lib/theme.js';
initTheme();
</script>
</head>
<body>
<!-- Interface ici -->
<script type="module">
import { $, on, escapeHtml, debounce } from '../lib/dom.js';
// Logique ici
</script>
</body>
</html>
2. Utiliser les variables CSS du thème#
Importez lib/theme.css pour avoir accès aux variables de design :
/* Variables disponibles */
--color-bg /* Fond principal */
--color-bg-secondary /* Fond secondaire */
--color-bg-card /* Fond des cartes */
--color-text /* Texte principal */
--color-text-muted /* Texte secondaire */
--color-accent /* Couleur d'accent */
--color-accent-hover /* Accent au survol */
--color-success /* Succès */
--color-error /* Erreur */
--color-border /* Bordures */
--space-sm/md/lg/xl /* Espacements */
--radius-sm/md/lg /* Rayons de bordure */
--transition-normal /* Transitions */
--font-family /* Police système */
--font-mono /* Police monospace */
Le thème (dark/light) est géré automatiquement via lib/theme.js.
3. Créer le manifest (optionnel mais recommandé)#
Créez tools/mon-outil.json :
{
"id": "mon-outil",
"name": "Mon Outil",
"description": "Description courte de l'outil",
"tags": ["utility", "dev"],
"author": "Votre nom",
"icon": "🔧",
"version": "1.0.0"
}
Champs du manifest :
| Champ | Obligatoire | Description |
|---|---|---|
id | Oui | Identifiant unique (kebab-case) |
name | Oui | Nom affiché |
description | Oui | Description courte |
tags | Non | Tags pour filtrage |
author | Non | Auteur |
icon | Non | Emoji pour la vignette |
version | Non | Version de l'outil |
4. Régénérer le catalogue#
make npm CMD="run build:catalogue"
5. Tester#
make serve
# Ouvrir http://localhost:3000
Exemple complet : Compteur de mots#
Voici un outil simple qui compte les mots et caractères d'un texte.
tools/word-counter.html#
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Compteur de mots - Playlab42</title>
<style>
/* Variables de couleur Playlab42 */
:root {
--bg: #1a1a2e;
--bg-secondary: #16213e;
--text: #eee;
--text-muted: #888;
--accent: #e94560;
--border: #333;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* En-tête */
header {
padding: 1rem;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
}
header h1 {
font-size: 1.25rem;
}
header h1 span {
color: var(--accent);
}
/* Zone principale */
main {
flex: 1;
display: flex;
flex-direction: column;
padding: 1rem;
gap: 1rem;
}
/* Zone de texte */
textarea {
flex: 1;
padding: 1rem;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
font-size: 1rem;
resize: none;
outline: none;
}
textarea:focus {
border-color: var(--accent);
}
textarea::placeholder {
color: var(--text-muted);
}
/* Statistiques */
.stats {
display: flex;
gap: 1.5rem;
flex-wrap: wrap;
}
.stat {
background: var(--bg-secondary);
padding: 1rem 1.5rem;
border-radius: 8px;
text-align: center;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: var(--accent);
}
.stat-label {
font-size: 0.875rem;
color: var(--text-muted);
margin-top: 0.25rem;
}
/* Pied de page */
footer {
padding: 0.5rem 1rem;
background: var(--bg-secondary);
border-top: 1px solid var(--border);
font-size: 0.75rem;
color: var(--text-muted);
}
</style>
</head>
<body>
<header>
<h1><span>📝</span> Compteur de mots</h1>
</header>
<main>
<textarea
id="input"
placeholder="Tapez ou collez votre texte ici..."
></textarea>
<div class="stats">
<div class="stat">
<div class="stat-value" id="words">0</div>
<div class="stat-label">Mots</div>
</div>
<div class="stat">
<div class="stat-value" id="chars">0</div>
<div class="stat-label">Caractères</div>
</div>
<div class="stat">
<div class="stat-value" id="chars-no-space">0</div>
<div class="stat-label">Sans espaces</div>
</div>
<div class="stat">
<div class="stat-value" id="lines">0</div>
<div class="stat-label">Lignes</div>
</div>
</div>
</main>
<footer>
Playlab42 - Compteur de mots
</footer>
<script>
// Éléments DOM
const inputEl = document.getElementById('input');
const wordsEl = document.getElementById('words');
const charsEl = document.getElementById('chars');
const charsNoSpaceEl = document.getElementById('chars-no-space');
const linesEl = document.getElementById('lines');
/**
* Compte les statistiques du texte
*/
function countStats() {
const text = inputEl.value;
// Mots : séparer par espaces et filtrer les vides
const words = text.trim() ? text.trim().split(/\s+/).length : 0;
// Caractères
const chars = text.length;
// Caractères sans espaces
const charsNoSpace = text.replace(/\s/g, '').length;
// Lignes
const lines = text ? text.split('\n').length : 0;
// Mise à jour affichage
wordsEl.textContent = words;
charsEl.textContent = chars;
charsNoSpaceEl.textContent = charsNoSpace;
linesEl.textContent = lines;
}
// Écouter les changements
inputEl.addEventListener('input', countStats);
// Focus initial
inputEl.focus();
</script>
</body>
</html>
tools/word-counter.json#
{
"id": "word-counter",
"name": "Compteur de mots",
"description": "Compte les mots, caractères et lignes d'un texte",
"tags": ["utility", "text"],
"author": "Playlab42",
"icon": "📝",
"version": "1.0.0"
}
Bonnes pratiques#
Structure du code#
- Un seul fichier : Tout le CSS et JS dans le HTML
- Imports : Utilisez
lib/theme.css,lib/dom.js,lib/theme.js - Responsive : Fonctionne sur mobile et desktop
Style#
- Variables CSS : Utilisez
var(--color-bg), etc. depuis theme.css - Support thèmes : Les variables s'adaptent automatiquement dark/light
- Transitions : Ajoutez
transition: background-color var(--transition-normal)pour une transition fluide - Cohérence : Header avec titre, main, footer
- Accessibilité : Labels, placeholders, contraste
JavaScript#
- Utilitaires DOM : Utilisez
$(),on(),escapeHtml()depuis lib/dom.js - Sécurité XSS : Toujours
escapeHtml()sur les entrées utilisateur - Commentaires : En français
- Fonctions pures : Faciles à tester
Performance#
- Debounce : Pour les événements fréquents (input)
- Pas de boucles infinies : Attention aux watchers
- Léger : Pas de bibliothèques lourdes
Pour aller plus loin#
Ajouter des raccourcis clavier#
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
saveData();
}
});
Sauvegarder dans localStorage#
// Sauvegarder
localStorage.setItem('mon-outil-data', JSON.stringify(data));
// Charger
const saved = localStorage.getItem('mon-outil-data');
if (saved) {
data = JSON.parse(saved);
}
Charger depuis l'URL#
const params = new URLSearchParams(window.location.search);
const value = params.get('data');
if (value) {
inputEl.value = decodeURIComponent(value);
}
Voir aussi#
- Architecture - Vue d'ensemble
- JSON Formatter - Exemple réel
- Spec Manifests (source Markdown) - Format des manifests