Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
Suivi de vos véhicules et vélos : entretiens, carburant, coûts, documents.
Translation pending
LifestyleJavaScript · CSSGitHub @benjbepoix-stackOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Suivi de mes véhicules et vélos : entretiens et rappels, carburant / recharge, coûts (prêt, LOA, LLD, frais fixes, revente), documents et échéances, usure des composants de vélo. HTML/CSS/JavaScript purs (modules ES, sans build) + Firebase gratuit (Auth e-mail et Realtime Database). Données • Local : localStorage, préfixe mon_garage_v2_ ; les données de la première version (monGarage_v1) sont reprises automatiquement. • Cloud : users/ /garage, une clé par rubrique et par véhicule ; photos réduites (JPEG ~1200 px).Read the full README ↗
Suivi de mes véhicules et vélos : entretiens et rappels, carburant / recharge, coûts (prêt, LOA, LLD, frais fixes, revente), documents et échéances, usure des composants de vélo. HTML/CSS/JavaScript purs (modules ES, sans build) + Firebase gratuit (Auth e-mail et Realtime Database).
index.html accueil (cartes) et fiche véhicule à onglets
css/ tokens, thème graphite (sombre / clair), composants, vues
js/core/ schéma des données, store (local + synchro clé par clé), calculs (coûts, prêt, conso, échéances)
js/services/ Firebase, stockage local, pièces jointes (files.js), liens Carnet / Mon budget
js/features/ export calendrier .ics / Outlook, dossier de revente imprimable,
migration des pièces jointes
js/ui/ icônes, toasts, fenêtres, graphiques
js/views/ accueil, fiche, entretiens, carburant, usure, coûts, documents
js/config/ configuration Firebase (null = fonctionnement local)
database.rules.json règles Realtime Database (chaque compte ne voit que ses données)
localStorage, préfixe mon_garage_v2_ ; les données de la première version (monGarage_v1) sont reprises automatiquement.users/<uid>/garage, une clé par rubrique et par véhicule ; photos réduites (JPEG ~1200 px).users/<uid>/garage_files/<id> + IndexedDB mon_garage_files.database.rules.json) n'autorisent que users/<uid> du compte connecté : les nouveaux nœuds (garage_files, carnet/garage_alerts, budget/linked/garage) n'ont rien à republier.garage_last_uid) : données locales, écritures et envois de fichiers en attente de l'ancien compte effacés ; une copie ou un envoi de pièce jointe commencé pour l'ancien compte est abandonné (jamais rangé ni envoyé dans le nouveau) ; rien n'est publié vers Carnet ni Mon budget avant le chargement des données du nouveau compte.garage_adopt_uid).Ligne continue : une voiture dessinée d'un seul trait, de la route au toit, en dégradé turquoise → vert sur fond blanc (icon.svg, décliné en icon-192.png, icon-512.png, apple-touch-icon.png), aussi utilisé comme logo sur l'écran de connexion. Même famille que les logos de Ma Maison et Mon Budget.
Bouton réglages (en-tête de l'accueil) → feuille « Réglages » : thème Auto (par défaut : suit le réglage clair / sombre de l'iPhone, prefers-color-scheme, en direct), Sombre ou Clair. Un thème « Sombre » enregistré (ancien défaut) devient « Auto » une seule fois (drapeau garage_theme_auto, sur l'appareil puis à la première réception des données du compte) ; « Clair » reste « Clair » ; un choix fait dans les réglages n'est plus jamais migré. Le script anti-flash de index.html résout « Auto » avant l'affichage ; data-theme vaut toujours dark ou light (CSS inchangé) et la couleur de la barre d'état suit (#0f1011 sombre, #f5f5f3 clair). Un seul style graphique, Acier, appliqué à tous les comptes (attribut data-style).
À la création d'une fiche, le plan d'entretien (rappels) est pré-rempli automatiquement selon la motorisation choisie (essence, diesel, hybride, électrique, GPL) pour une voiture, ou selon le type de vélo (VTT, vélo électrique…). Ce sont des préconisations généralisées à partir des usages courants (vidange, distribution, freins, liquide de frein, filtre à air, batterie 12 V, refroidissement de la batterie pour l'électrique…), pas le carnet d'entretien exact du modèle précis — chaque rappel reste modifiable ou supprimable ensuite. Détail dans js/core/schema.js (FUEL_REMINDERS, BIKE_TYPE_REMINDERS).
users/<uid>/carnet/garage_alerts (même projet Firebase, écriture par le SDK via linkSet de js/services/firebase.js — plus aucun fetch vers l'ancienne base publique de Carnet). Format inchangé : { <vehicleId>: { vehicleId, vehicleName, kind, updatedAt, alerts } }, pur résumé, aucune donnée financière. Le nœud est réécrit en entier à chaque changement : un véhicule vendu, archivé ou supprimé (ici ou sur un autre appareil) disparaît aussi de Carnet, qui le lit sans jamais l'écrire (section « Garage » de l'onglet Tâches, calendrier du mois et pop-up des retards). Contenu inchangé = pas d'envoi ; best-effort : une erreur est ignorée et retentée au prochain changement. Sans compte (mode hors ligne) : rien n'est publié. Détail dans js/services/carnet-sync.js.Chaque carte de l'accueil affiche une vignette (80 px), distincte du bouton qui ouvre la fiche : toucher la photo l'affiche en plein écran (sans ouvrir la fiche), toucher le reste de la carte ouvre la fiche. Sous le nom : seulement la marque, le modèle et, pour un véhicule, la plaque d'immatriculation (pas l'année, le kilométrage ni la motorisation) ; l'échéance la plus urgente s'affiche en dessous.
Depuis la fiche d'un véhicule existant, « Déclarer vendu / accidenté… » demande un motif (vendu, accidenté / épave, volé, autre) et une date, puis masque le véhicule de l'accueil — ses entretiens, coûts, documents et rappels sont conservés, pas supprimés, et il ne remonte plus dans le pop-up des entretiens en retard ni vers Carnet. Un lien « Archives (N) » apparaît en bas de l'accueil dès qu'au moins un véhicule est archivé : il liste les véhicules archivés avec leur motif et leur date, permet de rouvrir leur fiche (consultation et modification normales) ou de les restaurer (bouton dédié, ou directement depuis leur fiche).
Libellés courts pour que les 5 onglets tiennent sans défilement sur un écran de 375 px : Aperçu, Entretien, Carburant (Recharge pour un électrique), Coûts, Docs ; pour un vélo : Aperçu, Usure, Entretien, Coûts, Docs.
Chaque document (onglet Docs) peut avoir plusieurs pièces jointes — photos ou PDF (scan de la carte grise, de l'attestation d'assurance, et son avenant…) — ajoutées en une ou plusieurs fois depuis le formulaire (10 maximum par document). S'il n'y en a qu'une, le trombone l'ouvre directement ; s'il y en a plusieurs, un badge affiche leur nombre et le trombone rouvre la fiche du document pour les lister et les ouvrir une à une. Les images sont réduites comme les photos de véhicule ; chaque fichier est limité à 4 Mo.
js/ui/attachment-viewer.js) — pages rendues avec pdf.js (chargé à la demande depuis cdnjs, puis gardé en cache par le service worker pour l'aperçu hors ligne), zoom −/+, et bouton « Ouvrir / Partager » (feuille de partage native sur iPhone : Fichiers, Imprimer, Mail… ; sinon nouvel onglet). Si l'aperçu est impossible (tout premier affichage hors ligne, PDF protégé), ce bouton reste proposé. Avant, le PDF était « téléchargé » via un lien data: : en mode app sur iPhone il s'ouvrait sans bouton retour, ou pas du tout.application/pdf à l'ajout (et vérifié par son en-tête %PDF) : il était auparavant rejeté au stockage et la pièce jointe disparaissait.Stockage hors du nœud synchronisé (js/services/files.js, sur le modèle de Ma Maison) : le document ne garde que les métadonnées { id, name, mime } de chaque fichier ; le contenu (data URL) est rangé sur l'appareil (IndexedDB, base mon_garage_files) et dans le cloud sous users/<uid>/garage_files/<id>, lu à la demande à l'ouverture (copie de l'appareil, sinon cloud, puis gardé sur l'appareil). Avant, tout était dans v_<id>_docs : téléchargé à chaque ouverture de l'app et renvoyé à chaque modification. Un envoi impossible (hors ligne) reste en attente (garage_files_pending) et est retenté au lancement suivant ; une suppression aussi (garage_files_deleted). Supprimer un document, l'entretien ou la dépense d'une facture, ou le véhicule, supprime ses fichiers. Changement de compte sur l'appareil : fichiers locaux et envois en attente de l'ancien compte effacés.
Migration automatique et sûre (js/features/files-migration.js) : une fois les données chargées (et à chaque réception de données d'un appareil resté à l'ancienne version), chaque fichier encore contenu dans un document (file) est copié dans le nouveau stockage, puis la data URL est retirée du document — jamais avant que la copie locale soit faite et relue, ni, si un compte est utilisé sur l'appareil, avant que la copie cloud soit confirmée (sinon, nouvel essai plus tard). Le normaliseur (schema.js) accepte les deux formats pendant la transition, y compris l'ancien format à un seul fichier. Une pièce jointe n'est jamais rattachée au fichier d'une autre (même contenu) : supprimer l'une effacerait l'autre ; un identifiant porté par deux pièces jointes les laisse dans leur document. Si aucun stockage n'est disponible (IndexedDB indisponible et pas de compte), un nouveau fichier reste dans le document comme avant : rien n'est perdu.
Un entretien (onglet Entretien) ou une autre dépense (onglet Coûts) peut recevoir sa facture (photos ou PDF) directement dans son formulaire : elle est rangée automatiquement dans l'onglet Docs, comme document « Facture » relié à sa saisie (étiquette « Entretien » ou « Dépense »), ses fichiers hors du nœud synchronisé comme toute pièce jointe. Retirer tous les fichiers retire ce document ; supprimer l'entretien ou la dépense supprime aussi sa facture et ses fichiers. Un trombone sur la ligne ouvre la facture. Détail dans js/features/linked-doc.js.
Section « Autres dépenses » de l'onglet Coûts : achats ponctuels hors entretien (roues carbone, accessoires, équipement…), avec catégorie, montant et facture. Comptés dans les coûts (série « Autres dépenses » du graphique et de la répartition). Clé v_<id>_expenses.
Les entretiens (avec un coût) et autres dépenses datés à partir du 1er octobre 2026 sont publiés dans le nœud de Mon Budget du même compte, users/<uid>/budget/linked/garage ({ updatedAt, items: { <id>: { date, amount (centimes), label, kind } } }, sans pièce jointe, écriture par le SDK via linkSet — plus aucun fetch vers l'ancienne base publique de Mon budget), et y apparaissent comme dépenses « Transport » en lecture seule — plus de double saisie. Best-effort, uniquement une fois les données du compte chargées, contenu inchangé = pas d'envoi ; sans compte, rien n'est publié. Détail dans js/services/budget-sync.js.
Dans un rappel d'entretien, la case « Jamais réalisé depuis la mise en circulation » remplace la saisie du dernier entretien : l'échéance et la barre d'avancement se comptent alors depuis la date de mise en circulation du véhicule (champ de la fiche véhicule, case B de la carte grise), à 0 km. Pour un vélo (pas de carte grise), le départ est la date d'achat (onglet Coûts), à 0 km. Sans cette date, seul le critère en km s'applique et la carte du rappel indique où la renseigner. Dès qu'un entretien coche ce rappel, il repart normalement de cet entretien.
Au lancement de l'app (une fois par session, après l'écran de connexion), si des rappels d'entretien sont en retard — tous véhicules confondus —, une fenêtre les liste en une seule fois (véhicule, rappel, retard). Un appui sur une ligne ouvre directement la saisie de l'entretien, rappel déjà coché ; un seul bouton « Fermer ».
À chaque entretien enregistré (onglet Entretien), plusieurs rappels peuvent être cochés d'un coup (ex. vidange + filtre à huile + filtre à air faits le même jour) : chacun repart de la date et du kilométrage de cet entretien. Pour un vélo, les composants suivis en usure (onglet Usure : chaîne, pneus, plaquettes…) peuvent aussi être cochés et remis à zéro en même temps, sans repasser par le bouton « Remplacé ».
L'onglet Carburant ne propose plus que ça : une estimation mensuelle (consommation en L ou kWh/100 km, prix) — pas de plein à saisir, pas de graphique. Le kilométrage moyen par mois est calculé automatiquement (distance parcourue depuis l'achat ÷ nombre de mois). Elle compte comme du carburant dans les coûts (pas un frais fixe). À la première activation, l'estimation est appliquée rétroactivement depuis la date d'achat du véhicule, pour rattraper l'historique sans avoir à saisir chaque mois passé. Modifier ensuite la consommation ou le prix ne change jamais les mois déjà écoulés : une nouvelle période démarre au 1er du mois en cours (l'ancienne se clôt à la fin du mois précédent), sauf si la modification a lieu le même mois que la précédente mise à jour, auquel cas elle s'ajuste sur place. Les coûts se comptant par mois entier (jamais au prorata du jour), la bascule entre deux périodes se fait toujours sur une frontière de mois, pour qu'un même mois ne soit jamais compté par les deux à la fois. Le bouton « Réinitialiser » efface tout l'historique estimé pour repartir de zéro (utile pour corriger une estimation mal rattrapée) : la saisie suivante rattrape de nouveau tout l'historique depuis l'achat. Les anciens pleins saisis à la main (fonctionnalité retirée) ne comptent plus du tout dans les coûts ; toute donnée résiduelle de ce type est purgée automatiquement (localement et côté cloud) à l'ouverture de l'app.
Dans « Achat & financement » (onglet Coûts), un crédit soldé par anticipation peut être renseigné (montant réglé, date) : les mensualités s'arrêtent à cette date, remplacées par ce montant dans les coûts, le capital restant dû retombe à 0 et le coût du crédit (intérêts) est recalculé en conséquence.
sw.js pré-met en cache l'app-shell à l'installation : l'app s'ouvre même sans réseau (au garage, en concession…), y compris dès le tout premier lancement hors ligne. Il vérifie aussi à chaque ouverture si les fichiers ont changé sur le serveur, pour afficher la dernière version publiée.
Sur la fiche d'un véhicule (onglet Aperçu) → « Exporter le dossier de revente » : ouvre dans un nouvel onglet un document regroupant identité, achat, coût réel, historique d'entretien, consommation et documents (avec le nombre de pièces jointes), avec un bouton « Imprimer / Enregistrer en PDF ». À remettre à l'acheteur. Les photos jointes aux documents (factures, carte grise…) sont ajoutées en annexe une fois lues via le service de fichiers ; les PDF y sont listés, à joindre séparément.
python3 -m http.server 8000
puis http://localhost:8000.
Style Carrousel (css/carrousel.css, chargé en dernier) : minimaliste monochrome, police Geist commune avec Carnet (fonts/), aucune image de fond ni dégradé. L'accueil montre les noms des véhicules en onglets, puis une grande carte par véhicule qu'on fait glisser : nom, encadré photo (agrandie au toucher), compteur en grand avec sa mise à jour, et les trois échéances les plus proches, chacune soulignée d'un trait d'avancement. Dans la fiche, le compteur est en grand à côté de la photo, et les échéances, rappels et documents à date défilent en cartes ; l'historique est une frise. Seules couleurs : l'état des échéances. Cartes 26px, éléments interactifs en pilule, champs 12px. Thème Auto, sombre ou clair. Textes au vouvoiement. Logo : voiture en ligne continue (voir « Logo »).