Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. <!DOCTYPE html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>
  13. Inclusion
  14. — David Larlet</title>
  15. <script>
  16. function toggleTheme(themeName) {
  17. document.documentElement.classList.toggle(
  18. 'forced-dark',
  19. themeName === 'dark'
  20. )
  21. document.documentElement.classList.toggle(
  22. 'forced-light',
  23. themeName === 'light'
  24. )
  25. }
  26. const selectedTheme = localStorage.getItem('theme')
  27. if (selectedTheme !== 'undefined') {
  28. toggleTheme(selectedTheme)
  29. }
  30. </script>
  31. <!-- Documented, feel free to shoot an email. -->
  32. <link rel="stylesheet" href="/static/david/css/style_2024-03-09.css">
  33. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  34. <link rel="preload"
  35. href="/static/david/css/fonts/century_supra_ot_a_regular.woff2"
  36. as="font"
  37. type="font/woff2"
  38. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  39. crossorigin>
  40. <link rel="preload"
  41. href="/static/david/css/fonts/century_supra_ot_a_bold.woff2"
  42. as="font"
  43. type="font/woff2"
  44. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  45. crossorigin>
  46. <link rel="preload"
  47. href="/static/david/css/fonts/century_supra_ot_a_italic.woff2"
  48. as="font"
  49. type="font/woff2"
  50. media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  51. crossorigin>
  52. <link rel="preload"
  53. href="/static/david/css/fonts/century_supra_ot_b_regular.woff2"
  54. as="font"
  55. type="font/woff2"
  56. media="(prefers-color-scheme: dark)"
  57. crossorigin>
  58. <link rel="preload"
  59. href="/static/david/css/fonts/century_supra_ot_b_bold.woff2"
  60. as="font"
  61. type="font/woff2"
  62. media="(prefers-color-scheme: dark)"
  63. crossorigin>
  64. <link rel="preload"
  65. href="/static/david/css/fonts/century_supra_ot_b_italic.woff2"
  66. as="font"
  67. type="font/woff2"
  68. media="(prefers-color-scheme: dark)"
  69. crossorigin>
  70. <meta name="description" content="Dans le cadre de manger ma propre bouffe pour chien mon autoéquipement, je voulais vérifier si l’implémentation de oEmbed dans uMap était utilisable… et il se trouve que ce n’était pas le cas avant aujourd’hui. Il y aurait encore des pistes d’améliorations mais au moins ça affiche une carte (si vous autorisez les requêtes externes en JS) :">
  71. <!-- That good ol' feed, subscribe :). -->
  72. <link rel="alternate"
  73. type="application/atom+xml"
  74. title="Feed"
  75. href="/david/log/">
  76. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  77. <link rel="apple-touch-icon"
  78. sizes="180x180"
  79. href="/static/david/icons2/apple-touch-icon.png">
  80. <link rel="icon"
  81. type="image/png"
  82. sizes="32x32"
  83. href="/static/david/icons2/favicon-32x32.png">
  84. <link rel="icon"
  85. type="image/png"
  86. sizes="16x16"
  87. href="/static/david/icons2/favicon-16x16.png">
  88. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  89. <link rel="mask-icon"
  90. href="/static/david/icons2/safari-pinned-tab.svg"
  91. color="#07486c">
  92. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  93. <meta name="msapplication-TileColor" content="#f7f7f7">
  94. <meta name="msapplication-config"
  95. content="/static/david/icons2/browserconfig.xml">
  96. <meta name="theme-color"
  97. content="#f7f7f7"
  98. media="(prefers-color-scheme: light)">
  99. <meta name="theme-color"
  100. content="#272727"
  101. media="(prefers-color-scheme: dark)">
  102. <!-- Is that even respected? Retrospectively? What a shAItshow…
  103. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  104. <meta name="robots" content="noai, noimageai">
  105. <style type="text/css">
  106. .tippy-content {
  107. min-width: 280px;
  108. padding: .5rem;
  109. font-size: calc(var(--fluid-0) * 0.8);
  110. font-family: var(--labor-font);
  111. letter-spacing: initial;
  112. text-align: left;
  113. }
  114. .tippy-content h3 {
  115. margin-top: 0;
  116. }
  117. .tippy-content h3 img {
  118. max-width: 2rem;
  119. max-height: 2rem;
  120. display: inline-block;
  121. }
  122. .tippy-content .tippy-links {
  123. display: flex;
  124. justify-content: space-around;
  125. }
  126. .tippy-content a {
  127. padding: .4rem;
  128. color: #F06048;
  129. }
  130. </style>
  131. <body data-instant-intensity="viewport-all">
  132. <article>
  133. <header>
  134. <hgroup>
  135. <h1>Inclusion</h1>
  136. <p>Le <time datetime="2024-03-25">25 mars 2024</time></p>
  137. </hgroup>
  138. </header>
  139. <nav>
  140. <p>
  141. <a rel="prev"
  142. href="/david/2024/03/24/"
  143. title="Publication précédente : Cage">← Précédent</a> •
  144. <a href="/david/" title="Aller à l’accueil" rel="up">Accueil</a>
  145. <a href="/david/recherche/"
  146. title="Aller à la page de recherche"
  147. rel="search" data-no-instant>Recherche</a>
  148. </p>
  149. </nav>
  150. <p>Dans le cadre de <del><a data-link-domain="en.wikipedia.org" href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food">manger ma propre bouffe pour chien</a></del> mon <a data-link-domain="fr.wikipedia.org" href="https://fr.wikipedia.org/wiki/Auto%C3%A9quipement">autoéquipement</a>, je voulais vérifier si l’implémentation de <a data-link-domain="oembed.com" href="https://oembed.com/">oEmbed</a> dans <a data-link-domain="umap-project.org" href="https://umap-project.org/fr/">uMap</a> était utilisable… et il se trouve que ce n’était pas le cas avant aujourd’hui. Il y aurait encore des pistes d’améliorations mais au moins ça affiche une carte (si vous autorisez les requêtes externes en&nbsp;JS)&nbsp;:</p>
  151. <style type="text/css">
  152. o-embed {
  153. /* Size of the oembed + paragraph + margins. */
  154. height: calc(300px + 1rem + 3rem);
  155. }
  156. </style>
  157. <o-embed url="https://umap.openstreetmap.fr/fr/map/grand-tour-de-la-foret-de-ouareau_1037457">
  158. <p>
  159. Vous devriez voir s’afficher une carte de mon « Grand Tour de la forêt de Ouareau »,
  160. il est probable que cela ne s’exécute pas dans un agrégateur par exemple.
  161. </p>
  162. </o-embed>
  163. <script type="module">
  164. class OEmbed extends HTMLElement {
  165. static tagName = 'o-embed'
  166. static register(tagName, registry) {
  167. if(!registry && ('customElements' in globalThis)) {
  168. registry = globalThis.customElements
  169. }
  170. registry?.define(tagName || this.tagName, this)
  171. }
  172. get url() {
  173. return this.getAttribute('url') || ''
  174. }
  175. constructor() {
  176. super()
  177. this.attachShadow({ mode: 'open' })
  178. }
  179. async connectedCallback() {
  180. let slot = document.createElement('slot')
  181. this.shadowRoot.appendChild(slot)
  182. const html = await this.fetchText(this.url)
  183. const oEmbedLink = this.extractOembedLink(html)
  184. const oEmbedJson = await this.fetchJson(oEmbedLink)
  185. this.innerHTML = oEmbedJson.html
  186. }
  187. fetchText(url) {
  188. return fetch(url)
  189. .then((data) => data.text())
  190. .catch(console.error.bind(this))
  191. }
  192. fetchJson(url) {
  193. return fetch(url, { type: 'json' })
  194. .then((data) => data.json())
  195. .catch(console.error.bind(this))
  196. }
  197. extractOembedLink(html) {
  198. const parser = new DOMParser()
  199. const htmlDocument = parser.parseFromString(html, "text/html")
  200. const oEmbedMeta = htmlDocument.documentElement.querySelector(
  201. 'link[type="application/json+oembed"]'
  202. )
  203. return oEmbedMeta.href
  204. }
  205. }
  206. OEmbed.register()
  207. </script>
  208. <p>J’en ai fait un <em>web component</em> car je compte explorer / publier davantage de cartes par la suite. Je vais essayer d’ajouter des options lorsqu’elles deviendront disponibles côté uMap. Pour l’instant, il faudra vous contenter d’un <code>view-source:</code> (meilleure fonctionnalité du Web, ne l’oublions&nbsp;jamais).</p>
  209. <p>Au passage, j’ai mis à jour le moteur de ce site pour pouvoir injecter des morceaux de HTML (et donc CSS/JS) sur des billets en particulier. Je m’amuse&nbsp;bien&nbsp;🧑‍🔬.</p>
  210. <p>Je compte <a href="/david/2024/03/11/#hr-109">reparler de cette carte</a>.</p>
  211. <a href="#hr-134" title="Lien vers cette section de la page"><hr id="hr-134" /></a>
  212. <p>Beaucoup moins glorieux, j’ai participé à <a data-link-domain="forum.openstreetmap.fr" href="https://forum.openstreetmap.fr/t/mise-en-production-umap-v2-1-x-compliquee-perte-des-dernieres-donnees-sauvegardees-sur-52-cartes/22336">de la perte de données</a> aujourd’hui. Nous avons eu besoin de trois cerveaux et pas mal d’heures pour comprendre ce qu’il se passait. Il était difficile de tester / imaginer / reproduire autrement que sur le serveur de production. C’est déjà pas mal d’avoir eu la possibilité de passer en lecture seule avant que ça ne touche trop de&nbsp;cartes.</p>
  213. <p>J’ai appris qu’il ne fallait pas se fier à l’ordre des IDs… lorsqu’ils deviennent des&nbsp;UUIDs&#8239;!</p>
  214. <a href="#hr-135" title="Lien vers cette section de la page"><hr id="hr-135" /></a>
  215. <blockquote lang="en">
  216. <p>A data hoarder’s dream come true: bundle any web page into a single HTML file. You can finally replace that gazillion of open tabs with a gazillion of .html files stored somewhere on your precious little&nbsp;drive.</p>
  217. <p>Unlike the conventional “Save page as”, monolith not only saves the target document, <mark>it embeds CSS, image, and JavaScript assets all at once,</mark> producing a single HTML5 document that is a joy to store and&nbsp;share.</p>
  218. <p><cite><em><a data-link-domain="github.com" href="https://github.com/Y2Z/monolith">monolith</a></em></cite></p>
  219. </blockquote>
  220. <p>Je me demande si je ne devrais pas avoir recours à ce type d’outil plutôt que de n’extraire que la partie de HTML qui m’intéresse pour garder <a href="/david/2024/02/03/" title="Archives">une copie des liens</a> que je lie par ici. C’est pour l’instant un peu fastidieux mais ça me fait aussi découvrir des choses en explorant le code des&nbsp;autres.</p>
  221. <a href="#hr-136" title="Lien vers cette section de la page"><hr id="hr-136" /></a>
  222. <blockquote lang="en">
  223. <p>For this reason, I got more into <mark>“Conflict-free Resolution Data Types” (CRDTs),</mark> with the goal of understanding what they are, how they work, what are the different libraries out there, and which one would be a good fit for us, if&nbsp;any.</p>
  224. <p><cite><em><a data-link-domain="blog.notmyidea.org" href="https://blog.notmyidea.org/a-comparison-of-javascript-crdts.html" hreflang="fr"
  225. title="Consultation de l’article">A comparison of JavaScript CRDTs</a>
  226. <a href="/david/cache/2024/2c0b2588dfcd3a194da4133c7505cd3e/" hreflang="fr"
  227. data-tippy data-description=""
  228. data-source="https://blog.notmyidea.org/a-comparison-of-javascript-crdts.html"
  229. data-date="2024-03-25"
  230. data-favicon="https://blog.notmyidea.org/favicon-32x32.png"
  231. data-domain="blog.notmyidea.org"
  232. ><svg xmlns="http://www.w3.org/2000/svg"
  233. width="24" height="24" viewBox="0 0 24 24" fill="none"
  234. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  235. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  236. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  237. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  238. </svg>
  239. <span class="sr-only">[archive]</span></a></em></cite></p>
  240. </blockquote>
  241. <p>J’apprends plein de choses à ce sujet grâce à Alexis, c’est chouette à explorer par&nbsp;procuration.</p>
  242. <a href="#hr-137" title="Lien vers cette section de la page"><hr id="hr-137" /></a>
  243. <blockquote lang="en">
  244. <p>To summarize, digital information requires maintenance. It's not sufficient to make backups; the backups also need to be maintained, upgraded, transferred, and curated. Without conscientious care, the data of today will be lost forever in a few years. Even with care, it's possible through software or hardware changes to lose access forever. That shoebox of old backup CDs will be unreadable&nbsp;soon.</p>
  245. <p>Which brings us back to those old photo caches. They held negatives and prints, physical objects that stored images. They needed no attention, no curating, no updating. They sat untended and forgotten for decades, but through all that time faithfully held their information, waiting for a future discoverer. As a result, we can all see what the Scott Antarctic expedition saw, and I can see what my great-grandparents looked&nbsp;like.</p>
  246. <p><mark>It is a sad irony that modern technology makes it unlikely that future generations will see the images made&nbsp;today.</mark></p>
  247. <p>Ask yourself whether your great-grandchildren will be able to see your photographs. If the images exist only as a digital image file, the answer is almost certainly, &quot;No&quot;. If, however, there are physical prints, the odds improve. Those digital images need to be made real to endure. Without a print, a digital photograph has no&nbsp;future.</p>
  248. <p><cite><em><a data-link-domain="commandcenter.blogspot.com" href="https://commandcenter.blogspot.com/2014/08/prints.html" hreflang="en"
  249. title="Consultation de l’article (anglais)">command center: Prints</a>
  250. <a href="/david/cache/2024/46dc6f44f3e34c4c0626ad4b13dba768/" hreflang="en"
  251. data-tippy data-description="Two long-buried caches of photographs came to light last year. One was a stack of cellulose nitrate negatives made on the Scott Antarctic ex..."
  252. data-source="https://commandcenter.blogspot.com/2014/08/prints.html"
  253. data-date="2024-03-25"
  254. data-favicon="https://commandcenter.blogspot.com/favicon.ico"
  255. data-domain="commandcenter.blogspot.com"
  256. ><svg xmlns="http://www.w3.org/2000/svg"
  257. width="24" height="24" viewBox="0 0 24 24" fill="none"
  258. stroke="currentColor" stroke-width="2" stroke-linecap="square"
  259. stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle>
  260. <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
  261. <line x1="12" y1="17" x2="12.01" y2="17"></line>
  262. </svg>
  263. <span class="sr-only">[archive]</span></a></em></cite></p>
  264. </blockquote>
  265. <p>Très vrai <em>et</em> je me demande si le fait d’avoir des artefacts qui perdurent sur plusieurs générations sans entretien / transmission n’est pas justement un épiphénomène. Le numérique est peut-être plus proche de la transmission orale, une information qui a besoin d’être appropriée par læ récepteur·ice pour qu’elle continue à&nbsp;vivre.</p>
  266. <p>Ce sera à moi d’apprendre à ma descendance comment garder en vie cette flamme numérique qui vacille à chaque coup de vent de format&nbsp;propriétaire.</p>
  267. <nav>
  268. <p>
  269. <a href="/david/2024/dependance/"
  270. title="Liste de tous les articles 2024 associés à cette étiquette"
  271. rel="tag">#dépendance</a>
  272. <a href="/david/2024/partage/"
  273. title="Liste de tous les articles 2024 associés à cette étiquette"
  274. rel="tag">#partage</a>
  275. <a href="/david/2024/technique/"
  276. title="Liste de tous les articles 2024 associés à cette étiquette"
  277. rel="tag">#technique</a>
  278. <a href="/david/2024/#tags" title="Liste de toutes les étiquettes 2024">tous ?</a>
  279. </p>
  280. </nav>
  281. <nav>
  282. <p>
  283. <a rel="prev"
  284. href="/david/2024/03/24/"
  285. title="Publication précédente : Cage">← Précédent</a> •
  286. <a href="/david/2024/" title="Liste des publications récentes">↑ En 2024</a>
  287. </p>
  288. </nav>
  289. <form action="/david/recherche/" method="get">
  290. <fieldset>
  291. <legend>Recherche</legend>
  292. <label for="input-search">Termes de votre recherche :</label>
  293. <input id="input-search" type="search" name="s" aria-describedby="indexation-infos" required>
  294. <input type="submit" value="Chercher">
  295. <p id="indexation-infos">
  296. <small>
  297. Seuls les contenus de ces 8 dernières années sont indexés.
  298. </small>
  299. </p>
  300. </fieldset>
  301. </form>
  302. <aside>
  303. <theme-toggle></theme-toggle>
  304. </aside>
  305. </article>
  306. <hr>
  307. <footer>
  308. <p>
  309. <a href="/david/" title="Aller à l’accueil">Accueil</a>
  310. <a href="/david/log/" title="Accès au flux RSS">Suivre</a>
  311. <a href="http://larlet.com"
  312. title="Go to my English profile"
  313. data-instant>Pro</a>
  314. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">Email</a>
  315. <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">Légal</abbr>
  316. </p>
  317. <template id="theme-selector">
  318. <form>
  319. <style type="text/css">
  320. fieldset div {
  321. text-align: center;
  322. }
  323. </style>
  324. <fieldset>
  325. <legend>Thème</legend>
  326. <div>
  327. <label>
  328. <input type="radio" value="auto" name="chosen-color-scheme" checked>
  329. Auto
  330. </label>
  331. <label>
  332. <input type="radio" value="dark" name="chosen-color-scheme">
  333. Foncé
  334. </label>
  335. <label>
  336. <input type="radio" value="light" name="chosen-color-scheme">
  337. Clair
  338. </label>
  339. </div>
  340. </fieldset>
  341. </form>
  342. </template>
  343. </footer>
  344. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  345. <script>
  346. class ThemeToggle extends HTMLElement {
  347. constructor() {
  348. super()
  349. const themeSelectorTemplate = document.querySelector('#theme-selector')
  350. const form = themeSelectorTemplate.content.firstElementChild
  351. this.attachShadow({ mode: 'open' })
  352. this.shadowRoot.appendChild(form.cloneNode(true))
  353. }
  354. connectedCallback() {
  355. const form = this.shadowRoot.querySelector('form')
  356. form.addEventListener('change', (e) => {
  357. const chosenColorScheme = e.target.value
  358. localStorage.setItem('theme', chosenColorScheme)
  359. toggleTheme(chosenColorScheme)
  360. })
  361. const selectedTheme = localStorage.getItem('theme')
  362. if (selectedTheme && selectedTheme !== 'undefined') {
  363. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  364. }
  365. }
  366. }
  367. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  368. window.addEventListener('load', () => {
  369. let colorsLayer = undefined
  370. let hasDarkRules = false
  371. for (const styleSheet of Array.from(document.styleSheets)) {
  372. let mediaRules = []
  373. for (const layerRule of styleSheet.cssRules) {
  374. if (!(layerRule instanceof CSSLayerBlockRule)) {
  375. continue
  376. }
  377. if (layerRule.name === 'colors') {
  378. colorsLayer = layerRule
  379. }
  380. for (const cssRule of layerRule.cssRules) {
  381. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  382. continue
  383. }
  384. // WARNING: Safari does not have/supports `conditionText`.
  385. if (cssRule.conditionText) {
  386. if (cssRule.conditionText !== prefersColorSchemeDark) {
  387. continue
  388. }
  389. } else {
  390. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  391. continue
  392. }
  393. }
  394. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  395. }
  396. }
  397. // WARNING: do not try to insert a Rule to a styleSheet you are
  398. // currently iterating on, otherwise the browser will be stuck
  399. // in a infinite loop…
  400. for (const mediaRule of mediaRules) {
  401. // Safari requires the `0` second parameter (even if default).
  402. colorsLayer.insertRule(mediaRule.cssText, 0)
  403. hasDarkRules = true
  404. }
  405. }
  406. if (hasDarkRules) {
  407. if ('customElements' in window && !customElements.get('theme-toggle')) {
  408. customElements.define('theme-toggle', ThemeToggle)
  409. }
  410. }
  411. })
  412. </script>
  413. <script src="/static/david/js/popper-2.11.8.min.js"></script>
  414. <script src="/static/david/js/tippy-bundle-6.3.7.umd.min.js"></script>
  415. <script>
  416. tippy('[data-tippy]', {
  417. content(reference) {
  418. reference.addEventListener('click', (e) => e.preventDefault())
  419. return `
  420. <h3 lang="fr">
  421. <img src="${reference.dataset.favicon}" loading="lazy">
  422. <a href="${reference.dataset.source}"
  423. >Article sur ${reference.dataset.domain}</a></h3>
  424. <p lang="${reference.hreflang}"><em>${reference.dataset.description}</em></p>
  425. <div class="tippy-links" lang="fr">
  426. <a href="${reference.href}">Archive au ${reference.dataset.date}</a>
  427. </div>
  428. `
  429. },
  430. allowHTML: true,
  431. interactive: true,
  432. delay: [150, 700],
  433. hideOnClick: false
  434. })
  435. </script>
  436. <script type="module">
  437. import { annotate } from '/static/david/js/rough-notation-0.5.1.esm.min.js'
  438. const markObserver = new IntersectionObserver((entries, observer) => {
  439. const computedStyle = getComputedStyle(document.documentElement)
  440. const markBackground = computedStyle.getPropertyValue('--mark-background')
  441. for (const entry of entries) {
  442. if (entry.intersectionRatio === 0) continue
  443. const markElement = entry.target
  444. markElement.style.backgroundColor = 'inherit'
  445. const annotation = annotate(
  446. markElement, {
  447. type: 'highlight',
  448. multiline: true,
  449. color: markBackground,
  450. // animate: !window.matchMedia('(prefers-reduced-motion: reduce)').matches
  451. animate: false
  452. }
  453. )
  454. annotation.show()
  455. observer.unobserve(markElement)
  456. }
  457. }, {threshold: 1.0})
  458. for (const markElement of document.querySelectorAll('mark')) {
  459. markObserver.observe(markElement)
  460. }
  461. </script>
  462. </body>
  463. </html>