123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <!doctype html><!-- This is a valid HTML5 document. -->
- <!-- Screen readers, SEO, extensions and so on. -->
- <html lang="fr">
- <!-- Has to be within the first 1024 bytes, hence before the <title>
- See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
- <meta charset="utf-8">
- <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
- <!-- The viewport meta is quite crowded and we are responsible for that.
- See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <!-- Required to make a valid HTML5 document. -->
- <title>Zam — David Larlet</title>
- <!-- That good ol' feed, subscribe :). -->
- <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
- <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
- <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
- <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
- <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
- <link rel="manifest" href="/static/david/icons2/site.webmanifest">
- <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
- <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
- <meta name="msapplication-TileColor" content="#f0f0ea">
- <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
- <meta name="theme-color" content="#f0f0ea">
- <!-- Documented, feel free to shoot an email. -->
- <link rel="stylesheet" href="/static/david/css/style_2020-06-19.css">
- <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
- <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
- <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
- <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
- <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
- <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
- <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
- <script type="text/javascript">
- function toggleTheme(themeName) {
- document.documentElement.classList.toggle(
- 'forced-dark',
- themeName === 'dark'
- )
- document.documentElement.classList.toggle(
- 'forced-light',
- themeName === 'light'
- )
- }
- const selectedTheme = localStorage.getItem('theme')
- if (selectedTheme !== 'undefined') {
- toggleTheme(selectedTheme)
- }
- </script>
-
- <body class="remarkdown h1-underline h2-underline h3-underline hr-center ul-star pre-tick">
-
- <article>
- <h1>Zam</h1>
- <nav>
- <p class="center">
- <a rel="prev" href="/david/2020/04/10/" title="Publication précédente : Résistance">←</a> •
- <a href="/david/" title="Aller à l’accueil" tabindex="1">🏠</a>
- • <a rel="next" href="/david/2020/05/18/" title="Publication suivante : Relance">→</a>
- </p>
- </nav>
- <hr>
-
- <p><em>L’histoire assez personnelle d’un produit collectif.</em></p>
- <h2 id="prologue">Prologue <a href="#prologue" title="Ancre vers cette partie" aria-hidden="true">#</a></h2>
- <blockquote>
- <p>L’archer qui ne partage pas avec les autres sa joie de l’arc et de la flèche ne connaîtra jamais ses propres qualités et ses propres défauts.</p>
- <p>Avant de commencer quoi que ce soit, donc, cherche des alliés — des gens qui s’intéressent à ce que tu fais.</p>
- <p>Attention, je ne suis pas en train de dire : « Cherche d’autres archers. » Je dis simplement : « Trouve des personnes qui ont d’autres talents, car la voie de l’archer n’est pas différente d’une autre voie suivie elle aussi avec enthousiasme. »</p>
- <p><cite><em>La Voie de l’Archer</em>, Paulo Coelho</cite></p>
- </blockquote>
- <figure>
- <img src="/static/david/2020/archer_a_genoux.jpg"
- alt="Un archer en position à genoux."
- loading="lazy" width="1024" height="1024" />
- <figcaption>Kamakura, avril 2012.</figcaption>
- </figure>
- <h2 id="contexte">Contexte <a href="#contexte" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Je suis contacté par Raphaël il y a deux ans pour rejoindre une <a href="https://beta.gouv.fr/">Startup d’État</a>, après avoir travaillé sur <a href="https://www.data.gouv.fr/fr/">datagouv</a> pendant un temps puis avoir planté <a href="https://beta.gouv.fr/startups/api-drones.html">une autre startup</a>. Dans un tel contexte, on ne sait jamais ce qui va pousser après. Dans mon cas, ça avait quand même fait germer une petite graine sur l’importance d’un·e responsable produit ainsi que la présence d’une personne ayant des compétences en <abbr title="Expérience utilisateur·ice">UX</abbr>.</p>
- <p>Je souligne l’aspect <em>personnel</em> de ce retour en introduction car nous sommes aussi en train de compiler une histoire collective de cette aventure et j’espère que nous pourrons la rendre publique tant les points de vue des autres membres de <a href="/david/blog/2019/faire-equipe/">l’équipe</a> sont riches et pertinents.</p>
- <hr />
- <p>Cela faisait un moment que je m’intéressais au processus législatif car il me semblait que cela était un élément clé de la démocratie. Aussi, je réponds naïvement « oui » et me voilà embarqué dans un wagonnet de montagnes russes. Enfin — canadiennes en fait — vu que nous avons pu concevoir l’intégralité du produit <a href="/david/blog/2018/penser-distance/">en étant à distance</a>.</p>
- <p>Ainsi naissait mon implication dans <a href="https://beta.gouv.fr/startups/zam.html">Zam</a> (<a href="/david/cache/2020/8d7e08c54e30cc6d35375da17e6a61c0/">cache</a>).</p>
- <figure>
- <img src="/static/david/2020/zam_journal.png"
- alt="Première rencontre avec Mélodie le 18 avril, avec Raphaël le 17."
- loading="lazy" width="1024" height="1024" />
- <figcaption>Première entrée dans mon journal pro, j’aime constater à quel point il a évolué dans le temps pour consigner davantage des émotions et ressentis une fois la confiance installée.</figcaption>
- </figure>
- <h2 id="objectif">Objectif <a href="#objectif" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>L’objectif est de proposer un outil numérique permettant de réduire la pénibilité (et le nombre de pages jusque là imprimées) lors de la rédaction des réponses aux amendements soumis par les député·e·s et/ou sénateur·ice·s de la part du gouvernement afin de préparer le débat législatif au sein des instances parlementaires (Assemblée Nationale et Sénat).</p>
- <p>Exprimé ainsi il faut s’accrocher, aussi je vous propose un exemple sous forme de chronologie et un peu simplifié (les dates sont inventées mais proches de la réalité) :</p>
- <ol>
- <li>Lundi, le gouvernement soumet un projet de loi à l’Assemblée Nationale ;</li>
- <li>Jusqu’à vendredi midi, les député·e·s soumettent des amendements dans l’intention d’améliorer le texte initial ;</li>
- <li>De vendredi midi à lundi, les services du gouvernement travaillent pour avoir une réponse précise/pertinente à chaque amendement (c’est généralement la nuit/fin de semaine, oui) ;</li>
- <li>Le lundi suivant, la séance publique commence et le ou la ministre dispose de réponses permettant de prendre la parole dans l’hémicycle ;</li>
- <li>Au cours du débat parlementaire qui prend quelques jours, les amendements sont acceptés ou rejetés en fonction des votes en séance, le texte est modifié en conséquence avant de passer au Sénat.</li>
- </ol>
- <p>Zam intervient à l’étape 3 lorsqu’il s’agit de rédiger ces réponses dans des délais courts, avec la plus grande expertise possible et une chaîne de validation conséquente. Cet outil vient remplacer un processus à base de (beaucoup de) papier, d’outils de traitement de texte/tableur et de longues heures de sommeil perdues.</p>
- <p>Zam est sporadiquement utilisé en étape 4 pour les conseillers qui sont sur les bancs de l’Assemblée Nationale et a même été utilisé par une ministre en <a href="http://videos.assemblee-nationale.fr/direct.php">direct</a> sur une tablette. <em>Achievement unlocked.</em></p>
- <h2 id="approche">Approche <a href="#approche" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Tout a commencé à échelle humaine sur un projet de loi bien précis et surtout avec une personne clé qui connaissait bien les rouages des processus existants, au point de vouloir les changer. Ce que l’on appelle une <em>intrapreneuse</em>. Puis ça s’est rapidement emballé suite à la satisfaction des utilisateur·ice·s qui ont apprécié les veillées moins stressantes et les nuits plus complètes (!), ces personnes étaient jusqu’alors en souffrance. On a commencé à enchaîner les projets de loi et les ministères concernés.</p>
- <p>Pour tenir dans la durée, il faut réussir à trouver un rythme qui soit soutenable pour tou·te·s. En étant à distance et sur un fuseau horaire différent, cela signifie s’adapter pour trouver un créneau quotidien d’échange qui tourne autour d’une heure. C’est un moment important autant pour le travail à réaliser que pour maintenir l’humeur de l’équipe à un niveau enthousiasmant. Non pas comme une suite de <em>sprints</em> mais comme un ultra-marathon avec plein de <em><a href="https://en.wikipedia.org/wiki/Pacemaker_(running)">pacers</a></em>.</p>
- <p>En parallèle de ces discussions, il y a nos échanges avec les personnes utilisant le produit dont l’avis est essentiel pour pouvoir continuer à être pertinents. Cela arrive environ toutes les deux semaines et nous mettons un canal de réception en place pour les personnes ne pouvant pas être sur place. C’est vraiment important pour moi d’arriver à avoir ces retours sans intermédiaires de façon à développer mon empathie pour les utilisateur·ice·s.</p>
- <p>Tous les six mois environ (?), on prend un peu de recul sur ce que l’on a fait et compris — sur notre nouvelle façon de voir les choses aussi — pour réajuster le cap si on en ressent le besoin. Cela permet d’échanger sur des émotions qui sont passées entre les mailles du filet quotidien.</p>
- <h2 id="technique">Technique <a href="#technique" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>J’ai parlé un peu de <a href="/david/2020/03/13/">technique</a> récemment et la pile de technologies que l’on a utilisé pour ce projet me semble être relativement stable et compréhensible. Le code est accessible sur <a href="https://github.com/betagouv/zam/">Microsoft Github</a> sous <a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">licence AGPL-3</a>, on peut voir que la répartition est assez équilibrée entre Ronan et moi. C’est du Python 3 annoté pour les types qui utilise <a href="https://trypyramid.com/">Pyramid</a> comme <em>framework</em> web. Rien de très exotique et c’est intentionnel considérant que nous souhaitions à un moment transmettre le produit (voir plus bas).</p>
- <figure>
- <img src="/static/david/2020/zam_meme_bootstrap.jpg"
- alt="Il y aura toujours Bootstrap sur Zam."
- loading="lazy" width="517" height="499" />
- <figcaption>Un petit mème <em>courtesy of</em> Maïtané 😅.</figcaption>
- </figure>
- <p>Ce qui est peut-être un peu plus inhabituel c’est de ne pas utiliser <a href="https://www.npmjs.com/">Microsoft npm</a> pour gérer nos dépendances JavaScript, cela permet de bien voir ce que l’on ajoute, une sorte de <a href="https://timkadlec.com/remembers/2020-03-18-building-with-friction/">friction</a> (<a href="/david/cache/2020/331eb17ffb3f4fbb5fdd8123c0dc1eeb/">cache</a>) manuelle qui m’est chère lorsqu’on parle de faire tourner mon code sur la machine de beaucoup d’autres.</p>
- <p>Les principaux défis techniques ont été de gérer des données en entrée en provenance des sites parlementaires qui n’étaient pas forcément très stables. Lorsque toute la pertinence du produit repose sur la fraîcheur des données à un moment clé du processus législatif, c’est quelque peu anxiogène de se dire que l’on n’a aucun contrôle dessus !</p>
- <p>La plus grande victoire technique est certainement d’avoir eu envie de reprendre ce code pour la suite (voir plus bas) au lieu de partir sur quelque chose de neuf.</p>
- <h2 id="transmission">Transmission <a href="#transmission" title="Ancre vers cette partie" aria-hidden="true">#</a></h2>
- <blockquote>
- <p>Une Startup d’État est un service public numérique développé par une équipe autonome pour répondre à un problème lié à une politique publique, financée par une administration porteuse. Elle n’a pas pour objectif de faire du profit et n’a le plus souvent pas de personnalité juridique propre au moment de son lancement (même si <mark>elle peut devenir par la suite un service national au sein d’une administration</mark> ou au sein d’un <a href="https://fr.wikipedia.org/wiki/Groupement_d%27int%C3%A9r%C3%AAt_public">GIP</a> autonome). Sa vocation est de maximiser son impact social en répondant aux besoins de ses utilisateurs.</p>
- <p><cite><em><a href="https://beta.gouv.fr/apropos/">À propos - beta.gouv.fr</a></em> (<a href="/david/cache/2020/86939b13f2cea3d1ffbaa5b544fe5e45/">cache</a>)</cite></p>
- </blockquote>
- <p>Au bout d’un moment, lorsqu’on s’est prouvé que le produit conçu a de la valeur pour des personnes grâce à leurs retours récurrents, on songe à décliner le service à plus large échelle. C’est ce qui s’est passé pour Zam avec une généralisation de l’outil numérique de gestion des amendements pour l’ensemble des administrations au début de l’année 2020.</p>
- <p>Je vais être honnête, ça s’est (pas) fait dans la douleur.</p>
- <p>Nous étions dans une optique de <em>transmission</em> là où la direction qui devait dorénavant assurer la continuité de ce service s’attendait à un produit fini qu’il suffirait de brancher comme on peut le faire avec de l’électroménager. Autant dire que le choc des cultures a été assez violent… et le résultat relativement frustrant.</p>
- <p>Le service est officiellement arrêté depuis le 1<sup>er</sup> janvier et nous avons tout de même maintenu une instance afin d’en assurer la continuité malgré tout, estimant qu’il était important pour nos utilisateur·ice·s de continuer à disposer d’un outil qui leur facilitait la vie au quotidien. D’autant plus lorsqu’un projet de loi comme celui des retraites s’en vient et que l’on pense pouvoir éviter l’abattage d’une forêt en rendant inutile l’impression <em>multiple</em> de 42 000 amendements !</p>
- <p>Bref, ça ressemble à un loupé. Mais l’essentiel n’était peut-être pas là :-).</p>
- <h2 id="entracte">Entracte <a href="#entracte" title="Ancre vers cette partie" aria-hidden="true">#</a></h2>
- <blockquote>
- <p>Il existe deux types de tir.</p>
- <p>Le premier est celui que l’on fait avec précision mais sans âme. Dans ce cas, l’archer, bien qu’il possède une grande maîtrise de la technique, s’est exclusivement concentré sur la cible — et il n’a donc pas évolué, il a machinalement répété un geste, il n’a pas réussi à grandir, et il abandonnera un jour la voie de l’archer parce qu’il trouvera que tout est devenu routine.</p>
- <p>Le second tir est celui que l’on fait de toute son âme. Lorsque l’intention de l’archer se transforme pour devenir le vol de la flèche, ses doigts s’ouvrent au bon moment, le son de la corde fait chanter les oiseaux et le fait de tirer en direction de quelque chose au loin provoque — paradoxalement — un retour sur soi, une rencontre avec soi-même.</p>
- <p><cite><em>La Voie de l’Archer</em>, Paulo Coelho</cite></p>
- </blockquote>
- <figure>
- <img src="/static/david/2020/archer_equipe.jpg"
- alt="Des archers en position."
- loading="lazy" width="1024" height="1537" />
- <figcaption>Kamakura, avril 2012.</figcaption>
- </figure>
- <h2 id="satisfactions">Satisfactions <a href="#satisfactions" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Je vais me concentrer sur trois satisfactions importantes au cours de ces deux dernières années :</p>
- <ol>
- <li>Être suffisamment à l’écoute des utilisateur·ice·s pour que cela crée un climat de confiance et que ces personnes prennent part à l’aventure, aboutir à une telle proximité est vraiment crucial pour concevoir un produit pertinent qui soit adopté. Cela a changé ma façon d’appréhender les problèmes en passant de la théorie à la pratique.</li>
- <li>Faire équipe, je me suis déjà <a href="/david/blog/2019/faire-equipe/">longuement exprimé sur le sujet</a> et cette <em>tension positive</em> entre ses membres transforme la qualité et la pertinence du produit.</li>
- <li>Collaborer à distance, pas seulement en <a href="/david/blog/2018/penser-distance/">pensant à distance</a> mais en apprenant et en grandissant à distance. Je mesure d’autant plus aujourd’hui — lorsque cette distance est imposée — à quel point c’est un avantage comparé à d’autres équipes qui se retrouvent désemparées. Non seulement pour être efficaces mais aussi et surtout pour continuer à avoir le sentiment d’<em>être ensemble</em> dans des moments d’incertitudes.</li>
- </ol>
- <p>D’un point de vue plus personnel, j’apprécie le fait de garder l’enthousiasme de travailler sur un même produit et avec une même équipe dans la durée. Au point de vouloir continuer à faire des choses avec l’un et l’autre. C’est assez rare pour que je m’en réjouisse :-).</p>
- <h2 id="regrets">Regrets <a href="#regrets" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Je vais en garder trois aussi pour équilibrer :</p>
- <ol>
- <li>La frustration de ne pas réussir à transmettre un produit et, peut-être pire, une façon de le produire. Cela remet en question pas mal de choses au sujet de mon implication dans des initiatives comme <em>betagouv</em>. C’est un regret qui est encore aujourd’hui assez difficile à digérer.</li>
- <li>La souffrance d’avoir construit un groupe de travail autour d’un produit qui va être ignoré alors qu’il est la clé de sa réussite auprès des utilisateur·ice·s actuel·le·s. Avoir un sentiment de gâchis d’énergie (et d’argent public).</li>
- <li>La peine d’avoir voulu essayer de transmettre le produit à une autre entité pour vérifier si cela était faisable alors qu’une externalisation au sein d’un <abbr title="Groupement d’Intérêt Public">GIP</abbr> ou autre aurait probablement été possible à un moment donné. J’espère que notre retour permettra aux <a href="https://beta.gouv.fr/startups/">autres équipes</a> de ne pas faire la même erreur.</li>
- </ol>
- <p>Il y en aurait un autre de regret un peu <em>meta</em> qui est la prise de conscience que l’appareil démocratique de la <a href="https://fr.wikipedia.org/wiki/Cinqui%C3%A8me_R%C3%A9publique_(France)">Cinquième République</a> est complètement défaillant lorsqu’il y a une majorité. J’aurais pu m’en rendre compte depuis l’extérieur mais avoir les mains dans ces données permet de constater à quel point les séances à l’Assemblée Nationale ou au Sénat peuvent être inutiles dans les faits. C’est bien triste car il s’agit ici du contre-pouvoir <em>nécessaire</em> à l’exécutif.</p>
- <h2 id="suite">Suite <a href="#suite" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Ce qui est réjouissant dans tout ça, c’est qu’il y a une saison 2 qui se prépare, nom de code : <a href="https://beta.gouv.fr/startups/visam.html">Visam</a> !</p>
- <p>On reprend l’équipe, une partie du code et on va rencontrer les personnes en souffrance pour proposer une solution adaptée. Ou du moins c’était le plan, et vu qu’il ne se déroule pas tout à fait comme prévu à cause d’un <a href="/david/2020/03/27/">petit bout d’ARN</a> plutôt <a href="/david/2020/04/10/">résistant</a>, on s’adapte.</p>
- <p>L’avantage d’être une équipe distribuée, c’est d’<em>a priori</em> être à même de pouvoir proposer des usages qui correspondent à la situation actuelle. La suite au prochain épisode…</p>
- <h2 id="ailleurs">Ailleurs <a href="#ailleurs" title="Ancre vers cette partie" aria-hidden="true">#</a></h2><p>Le code source de <a href="https://beta.gouv.fr/startup/zam.html">Zam</a> est <a href="https://github.com/betagouv/zam/">disponible</a> depuis le début sous <a href="https://github.com/betagouv/zam/blob/master/LICENSE">licence AGPL 3</a>.</p>
- <p>Maïtané a écrit une <a href="https://www.maiwann.net/blog/">série d’articles</a> sur le sujet, pour l’instant il y en a 9 de publiés mais 19 sont prévus (!!!). Cela permet de suivre l’évolution du produit dans le temps, c’est trop bien.</p>
- <p>Une <a href="https://cpu.dascritch.net/post/2020/02/06/Maitan%C3%A9-%E2%80%9CMaiwann%E2%80%9D-Lenoir-et-M%C3%A9lodie-Dahi%2C-intervenantes-sur-le-progiciel-d-%C3%89tat-ZAM">émission de radio</a> a été réalisée par DaScritch.</p>
- <p>Il y a eu au moins un <a href="https://www.rtl.fr/actu/politique/reforme-des-retraites-comment-sont-traites-les-milliers-d-amendements-deposes-7800107173">article dans la presse</a> (<a href="/david/cache/2020/2857bcda24e61cd80229ec230ee3d2b1/">cache</a>), en tout cas c’est le seul dont j’ai connaissance.</p>
- <p>On réfléchit à d’autres formes de transmissions/interactions, notamment orales, potentiellement en visio, bref si vous avez des idées et/ou questions on est super ouvert·e·s.</p>
- <h2 id="epilogue">Épilogue <a href="#epilogue" title="Ancre vers cette partie" aria-hidden="true">#</a></h2>
- <blockquote>
- <p>Une fois que la flèche a été décochée, l’archer ne peut plus rien faire, si ce n’est suivre des yeux son trajet vers la cible. Dès lors, la tension nécessaire au tir n’a plus de raison d’être.</p>
- <p>L’archer garde alors les yeux fixés sur le vol de la flèche, mais son cœur se repose, et il sourit.</p>
- <p><cite><em>La Voie de l’Archer</em>, Paulo Coelho</cite></p>
- </blockquote>
- <figure>
- <img src="/static/david/2020/archer_tir.jpg"
- alt="Un archer en train de tirer."
- loading="lazy" width="1024" height="1366" />
- <figcaption>Kamakura, avril 2012.</figcaption>
- </figure>
- <p><em>P.S.: le Japon me manque.</em></p>
- <p>Mise à jour quelques heures après publication : Karl répond en <a href="https://www.la-grange.net/2020/04/18/ombre">parlant de poisson</a> (<a href="/david/cache/2020/2ebe3ac9e09d2d0ca91f9814d7b56c4d/">cache</a>) et ne sait pas à quel point il tombe juste :-).</p>
-
- <nav>
- <p class="center">
- <a rel="prev" href="/david/2020/04/10/" title="Publication précédente : Résistance">←</a> •
- <a href="/david/2020/" title="Liste des publications récentes">↑</a>
- • <a rel="next" href="/david/2020/05/18/" title="Publication suivante : Relance">→</a>
- </p>
- </nav>
- </article>
-
-
- <hr>
-
- <footer>
- <p>
- <a href="/david/" title="Aller à l’accueil">🏠</a> •
- <a href="/david/log/" title="Accès au flux RSS">🤖</a> •
- <a href="http://larlet.com" title="Go to my English profile" data-instant>🇨🇦</a> •
- <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">📮</a> •
- <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">🧚</abbr>
- </p>
- <template id="theme-selector">
- <form>
- <fieldset>
- <legend>Thème</legend>
- <label>
- <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
- </label>
- <label>
- <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
- </label>
- <label>
- <input type="radio" value="light" name="chosen-color-scheme"> Clair
- </label>
- </fieldset>
- </form>
- </template>
- </footer>
- <script src="/static/david/js/instantpage-3.0.0.min.js" type="module" defer></script>
- <script type="text/javascript">
- function loadThemeForm(templateName) {
- const themeSelectorTemplate = document.querySelector(templateName)
- const form = themeSelectorTemplate.content.firstElementChild
- themeSelectorTemplate.replaceWith(form)
-
- form.addEventListener('change', (e) => {
- const chosenColorScheme = e.target.value
- localStorage.setItem('theme', chosenColorScheme)
- toggleTheme(chosenColorScheme)
- })
-
- const selectedTheme = localStorage.getItem('theme')
- if (selectedTheme !== 'undefined') {
- form.querySelector(`[value="${selectedTheme}"]`).checked = true
- toggleTheme(selectedTheme)
- }
- }
-
- const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
- window.addEventListener('load', () => {
- let hasDarkRules = false
- for (const styleSheet of Array.from(document.styleSheets)) {
- let mediaRules = []
- for (const cssRule of styleSheet.cssRules) {
- if (cssRule.type !== CSSRule.MEDIA_RULE) {
- continue
- }
- // WARNING: Safari does not have/supports `conditionText`.
- if (cssRule.conditionText) {
- if (cssRule.conditionText !== prefersColorSchemeDark) {
- continue
- }
- } else {
- if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
- continue
- }
- }
- mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
- }
-
- // WARNING: do not try to insert a Rule to a styleSheet you are
- // currently iterating on, otherwise the browser will be stuck
- // in a infinite loop…
- for (const mediaRule of mediaRules) {
- styleSheet.insertRule(mediaRule.cssText)
- hasDarkRules = true
- }
- }
- if (hasDarkRules) {
- loadThemeForm('#theme-selector')
- }
- })
- </script>
- </body>
- </html>
|