Se rendre au contenu

CV-Editor 

void Genèse() 
{

Ce projet est né d'un besoin simple, et d'un constat.


Le besoin : mettre mon CV à jour, régulièrement, proprement — comme n'importe quelle personne qui postule ou fait évoluer sa carrière. Un CV à jour aujourd'hui, une variante un peu plus technique demain, une version resserrée pour telle candidature...


Et le constat, vite posé : les éditeurs de CV en ligne, c'est joli — jusqu'au moment où il faut exporter. 

« Créez un compte pour télécharger votre CV. » 

« Passez au plan Premium pour retirer notre logo. » 

Et mon CV, dedans, sur leur serveur, avec mon adresse, mon téléphone, parfois ma photo. Merci bien.


Deuxième constat, moins connu : le format lui-même. De plus en plus d'entreprises — tous secteurs confondus — ne lisent presque plus les CV à la main. Des logiciels de tri automatisés (les fameux ATS, pour Applicant Tracking System) les scannent, extraient le texte, et rejettent ce qu'ils ne savent pas lire. Un CV plein de blocs positionnés au pixel, d'ombres portées et de colonnes dans des images, c'est magnifique. Et illisible pour une machine.


Il me fallait donc un outil qui fasse les deux : un CV agréable à l'œil pour le recruteur humain, et une mise en page que le filtre automatique digère sans perte. Sans compte, sans abonnement, sans que mes données partent n'importe où.


Alors j'ai fait ce que je sais faire : j'ai ouvert un projet vide. Pas de framework, pas de build, pas de compte. Un index.html, du CSS, du JavaScript vanilla — et une seule exigence : le PDF final doit être lisible par une machine, et regardable par un humain. Sur ma machine, où mes données restent.

 

}
void Description_Du_Projet() 
{

CV-Editor est un éditeur de CV 100 % local : on ouvre index.html dans un navigateur (un double-clic suffit), on édite, on exporte un PDF A4 au texte sélectionnable — le format que les ATS digèrent le mieux.

Pas de backend, pas de compte, pas de tracking. Les données vivent dans le localStorage du navigateur, s'exportent et se réimportent en JSON. Une version est hébergée chez Free pour l'accès rapide, mais le code est pensé pour fonctionner en file://, déconnecté, chez soi.

Côté fonctionnalités :

  • 6 templates — du Classique sobre (mono-colonne ATS pur) au Suisse typographique, en passant par un Moderne à bandeau coloré. Tous pilotés par les mêmes réglages : 3 couleurs aux rôles définis, 7 polices sûres pour les ATS, taille, et une photo de profil optionnelle (redimensionnée en local, jamais envoyée nulle part).

  • Visibilité et ordre = des données — chaque rubrique, chaque expérience, chaque compétence peut être masquée d'une case à cocher, et l'ordre des sections comme celui des entrées se règle à la souris (glisser-déposer ou flèches). Un état masqué ou une section vide n'occupe aucune place dans le rendu. Rien n'est jamais supprimé : tout est réversible.

  • Analyse de mots-clés — on colle une offre d'emploi, l'outil en extrait les mots-clés principaux et les compare au contenu du CV. ✓ présent, ✗ absent.

 


}
void Comment_Ça_Marche() 
{

L'architecture tient en une phrase : un objet JSON est l'unique source de vérité. Chaque interaction modifie cet objet, le persiste, puis relance le rendu. Le reste en découle :

  1. Un répartiteur, pas des cascades de if — updateCvField() identifie la cible via des attributs data-bind / data-exp / data-key et délègue à une sous-fonction qui ne connaît qu'une partie du modèle. Ajouter un type d'élément = quelques lignes dans une table d'association, rien d'autre.


  2. La visibilité est filtrée à un seul endroit — rubrique() renvoie la collection si la rubrique est visible, sinon un tableau vide. Les 6 templates passent par cette porte : rubrique masquée, entrée masquée, section vide → le HTML produit est naturellement vide. Pas de if éparpillés dans les templates.


  3. L'ordre des sections est piloté par les données — chaque template construit un map { Accroche, Experiences, ... } puis une fonction partagée le déroule selon customisation.ordreSections. L'ordre n'est défini qu'à un endroit, et un ancien JSON sans cette clé retombe sur l'ordre historique. Migration invisible.


  4. La fusion profonde en filet de sécurité — à l'import et au chargement, deepMerge() complète les clés manquantes avec les défauts. Un JSON d'il y a six mois s'ouvre sans rien casser et sans rien masquer par accident.


  5. L'export PDF est un problème CSS, pas JS — @media print masque l'interface, @page { margin: 0 } supprime les en-têtes du navigateur, et print-color-adjust: exact force les couleurs de fond. Parce que oui : par défaut, les navigateurs les suppriment à l'impression. Je le sais maintenant — c'était le bug le plus satisfaisant à diagnostiquer du projet : le bandeau du template Moderne disparaissait du PDF, tout simplement parce que l'imprimante « économe » faisait son travail.


  6. La photo ne quitte jamais la machine — redimensionnée en canvas, stockée en data-URL JPEG, affichée par pur CSS avec des surcharges de classes plus spécifiques que les styles par template.

 

}
void Utilisation() 
{

Côté utilisation, c'est volontairement simple :

  1. Ouvrir src/index.html


  2. Remplir les onglets — aperçu en temps réel, sauvegarde automatique.


  3. 🖨 Exporter PDF (ATS) → « Enregistrer au format PDF ». C'est tout.


  4. Export JSON pour les sauvegardes, import JSON pour les restaurer.

Et si on veut un CV différent pour une candidature précise : on décoche, on réordonne, on exporte. Les données de base ne bougent pas.

}
void Limites() 
{
  • Le padding du CV ne se répète pas aux sauts de page — sur un CV de deux pages, le contenu colle un peu près du bord en page 2.

  • La validation d'import est légère : la fusion complète les clés manquantes, mais un JSON volontairement malformé n'est pas rejeté.

  • L'analyse de mots-clés reste basique (fréquence) : pas de synonymes, pas de racinisation.

  • La photo vit dans le localStorage (~5 Mo) — la réduction automatique limite le risque, mais l'export JSON reste le vrai plan de sauvegarde.

  • Le glisser-déposer suit l'API HTML5 : sur mobile, les boutons ↑/↓ sont le chemin garanti.


 

}

void Retour_Personnel() 
{

Ce projet, c'est le genre de truc que j'aime : un outil dont tout le monde a besoin, mais que personne ne veut vraiment écrire — et qui, une fois creusé, révèle les mêmes questions que le jeu vidéo.


Piloter l'affichage par des données plutôt que par du code, c'est exactement la réflexion d'un système de gameplay : ici, "ordreSections" et les "toggles" affiche sont l'équivalent d'un fichier de configuration de niveau. Les 6 templates ne « savent » rien de l'ordre — ils rendent ce qu'on leur donne. Et c'est précisément ce qui rend l'étape suivante passionnante : puisqu'un CV n'est plus qu'un état de données, un module pourrait le reprioriser tout seul en fonction d'une offre d'emploi. L'outil existe, la porte est ouverte.


Et puis il y a la satisfaction de base : quand j'envoie mon CV aujourd'hui, je sais exactement ce qu'il contient, pourquoi il est agencé ainsi, et quelles machines sauront le lire. Le besoin initial est réglé, et j'ai construit un outil au passage. Le meilleur des deux mondes, quoi.


}
void Amelioration_Possible() 
{
  • Adapter le CV à une annonce — le chantier roi : exploiter l'analyse de mots-clés pour reprioriser automatiquement les sections et suggérer les entrées à masquer. Tout est déjà en place côté modèle.

  • Valider la forme à l'import (rejeter les types inattendus et les null).

  • Une liste de chips indépendante pour le template « Compétences en tête ».

  • Peut-être un jour : une migration vers les modules ES — le découpage actuel est déjà « module-ready », il ne manque qu'un serveur local.

 

}