Browse Source

Links

master
David Larlet 1 month ago
parent
commit
e4eba0b24e
Signed by: David Larlet <david@larlet.fr> GPG Key ID: 3E2953A359E7E7BD

+ 178
- 0
cache/2024/55c19feff784a41d2527b5f1589d931d/index.html View File

@@ -0,0 +1,178 @@
<!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` element
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>activitypub-powered wikis (archive) — David Larlet</title>
<meta name="description" content="Publication mise en cache pour en conserver une trace.">
<!-- 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="#f7f7f7">
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
<meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
<!-- Is that even respected? Retrospectively? What a shAItshow…
https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
<meta name="robots" content="noai, noimageai">
<!-- Documented, feel free to shoot an email. -->
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.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>
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>

<meta name="robots" content="noindex, nofollow">
<meta content="origin-when-cross-origin" name="referrer">
<!-- Canonical URL for SEO purposes -->
<link rel="canonical" href="https://alexsirac.com/activitypub-powered-wikis/">

<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">


<article>
<header>
<h1>activitypub-powered wikis</h1>
</header>
<nav>
<p class="center">
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="https://alexsirac.com/activitypub-powered-wikis/" title="Lien vers le contenu original">Source originale</a>
<br>
Mis en cache le 2024-03-26
</p>
</nav>
<hr>
<p>what i <em>would</em> like to see in terms of ActivityPub-powered wikis is a beautiful federated network of very focused wikis. more of a fandom.org competitor than a wikipedia.org competitor, really − get the torchlight wiki and the asoiaf wiki and the grenoble wiki talking together, let us contribute to all with our personal accounts,</p>
<p>idk if it’s possible <a href="https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki">to beat wikipedia</a>, but i don’t think it’s really valuable − wikipedia works because it has 20 years of building rules and a relatively homogeneous community, which has the good and the bad. i just think it’s more worthwhile to think about building an alternative for all the wikis that would actually benefit from this.</p>
</article>


<hr>

<footer>
<p>
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
</svg> Suivre</a> •
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
</svg> Pro</a> •
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
</svg> Email</a> •
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
</svg> Légal</abbr>
</p>
<template id="theme-selector">
<form>
<fieldset>
<legend><svg class="icon icon-brightness-contrast">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
</svg> 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-5.1.0.min.js" type="module"></script>
<script>
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 && selectedTheme !== 'undefined') {
form.querySelector(`[value="${selectedTheme}"]`).checked = true
}
}

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>

+ 11
- 0
cache/2024/55c19feff784a41d2527b5f1589d931d/index.md View File

@@ -0,0 +1,11 @@
title: activitypub-powered wikis
url: https://alexsirac.com/activitypub-powered-wikis/
hash_url: 55c19feff784a41d2527b5f1589d931d
archive_date: 2024-03-26
og_image: https://alexsirac.com/wp-content/uploads/2023/01/cropped-cropped-portraitplante-32x32.webp
description:
favicon: https://alexsirac.com/wp-content/uploads/2023/01/cropped-cropped-portraitplante-32x32.webp
language: fr_FR

<p>what i <em>would</em> like to see in terms of ActivityPub-powered wikis is a beautiful federated network of very focused wikis. more of a fandom.org competitor than a wikipedia.org competitor, really − get the torchlight wiki and the asoiaf wiki and the grenoble wiki talking together, let us contribute to all with our personal accounts,</p>
<p>idk if it’s possible <a href="https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki">to beat wikipedia</a>, but i don’t think it’s really valuable − wikipedia works because it has 20 years of building rules and a relatively homogeneous community, which has the good and the bad. i just think it’s more worthwhile to think about building an alternative for all the wikis that would actually benefit from this.</p>

+ 318
- 0
cache/2024/65fba9cd025cd2403f932cb2c928cf14/index.html View File

@@ -0,0 +1,318 @@
<!doctype html><!-- This is a valid HTML5 document. -->
<!-- Screen readers, SEO, extensions and so on. -->
<html lang="en">
<!-- Has to be within the first 1024 bytes, hence before the `title` element
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>A microdata enhanced HTML Webcomponent for Leaflet (archive) — David Larlet</title>
<meta name="description" content="Publication mise en cache pour en conserver une trace.">
<!-- 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="#f7f7f7">
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
<meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
<!-- Is that even respected? Retrospectively? What a shAItshow…
https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
<meta name="robots" content="noai, noimageai">
<!-- Documented, feel free to shoot an email. -->
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.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>
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>

<meta name="robots" content="noindex, nofollow">
<meta content="origin-when-cross-origin" name="referrer">
<!-- Canonical URL for SEO purposes -->
<link rel="canonical" href="https://blog.k-nut.eu/leaflet-microdata-html-webcomponent">

<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">


<article>
<header>
<h1>A microdata enhanced HTML Webcomponent for Leaflet</h1>
</header>
<nav>
<p class="center">
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="https://blog.k-nut.eu/leaflet-microdata-html-webcomponent" title="Lien vers le contenu original">Source originale</a>
<br>
Mis en cache le 2024-03-25
</p>
</nav>
<hr>
<p>The people in my RSS reader have been talking some more about Web Components in the
past couple of months. Jim Nielsen had <a href="https://blog.jim-nielsen.com/2023/html-web-components/">a post</a>
referring to Jeremy Keith coining the term <a href="https://adactio.com/journal/20618">HTML Web Components</a>
for a special kind of Web Components. The idea essentially is that you have regular HTML markup that is wrapped
by a custom Web Component which enhances the user experience.</p>

<p>I thought that this was quite an interesting idea and thought about situations in which
it could be applied. Working with open data quite a bit, we often find ourselves in
situations where we build maps. Additionally, the German open data scene has been lobbying for
more linked open data in the past couple of months. I think I came up with an example which
combines these three things - HTML Web Components, maps and Linked Data (or a flavor
thereof) quite nicely.</p>

<p>As an example, assume that we want to render schools on a map. The data in
our example is taken from our <a href="https://jedeschule.codefor.de/docs">jedeschule.de API</a>
which has the goal of making all primary and secondary schools in Germany
searchable and queryable.</p>

<p>With the approach I’m proposing, we can author markup that looks like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;leaflet-map&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"map"</span><span class="nt">&gt;&lt;/div&gt;</span>
<span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"locations"</span><span class="nt">&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-153710"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Dahlingschule, Städt. Förderschule im integr. Verbund, FSP Lernen u. Emot. und soziale Entwicklung,-Primarstufe u. SekI<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Dahlingstr. 40<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>47229<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Duisburg<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"51.38331874331818"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"6.700606101666003"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-166480"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Montessori-Gymnasium Städt. Gymnasium für Jungen und Mädchen<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Rochusstr. 145<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>50827<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Köln<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"50.963204818343755"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"6.904840537750957"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-167782"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Städt. Grillo-Gymnasium<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Hauptstr. 60<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>45879<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Gelsenkirchen<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"51.5130837882258"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"7.099798427442939"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/leaflet-map&gt;</span>
<span class="nt">&lt;style&gt;</span>
<span class="nf">#map</span> <span class="p">{</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">800px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span>
<span class="py">aspect-ratio</span><span class="p">:</span> <span class="m">16</span><span class="p">/</span><span class="m">9</span><span class="p">;</span>
<span class="nl">background-image</span><span class="p">:</span> <span class="sx">url("/map.png")</span><span class="p">;</span>
<span class="nl">background-size</span><span class="p">:</span> <span class="n">contain</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">&lt;/style&gt;</span>
</code></pre></div></div>

<p>In this form, this isn’t interactive yet but it can already be easily consumed by both humans
and computers. Humans will see a static map (I simply took a screenshot and set is as a
background image for the <code class="highlighter-rouge">#map</code> node) and a list of schools with their addresses.
Computers will be able to also parse the schema.org annotations to extract structured data out of the list.</p>

<p>Since the data is semi-structured and machine readable, we can now also consume it from
a Web Component to add interactivity with <a href="https://leafletjs.com">Leaflet</a>. The code to do so
looks like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">LeafletMap</span> <span class="kd">extends</span> <span class="nx">HTMLElement</span> <span class="p">{</span>
<span class="nx">connectedCallback</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">mapElement</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">"#map"</span><span class="p">);</span>
<span class="nx">mapElement</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundImage</span> <span class="o">=</span> <span class="s2">"none"</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">schools</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span>
<span class="s1">'[itemType="https://schema.org/School"]'</span><span class="p">,</span>
<span class="p">);</span>

<span class="kd">var</span> <span class="nx">map</span> <span class="o">=</span> <span class="nx">L</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">mapElement</span><span class="p">).</span><span class="nx">setView</span><span class="p">([</span><span class="mf">51.505</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.09</span><span class="p">],</span> <span class="mi">13</span><span class="p">);</span>
<span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">(</span><span class="s2">"https://tile.openstreetmap.org/{z}/{x}/{y}.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="na">attribution</span><span class="p">:</span>
<span class="s1">'&amp;copy; &lt;a href="https://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt; contributors'</span><span class="p">,</span>
<span class="p">}).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">markers</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">L</span><span class="p">.</span><span class="nx">featureGroup</span><span class="p">();</span>
<span class="nx">schools</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">school</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">latitude</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="latitude"]'</span><span class="p">).</span><span class="nx">content</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">longitude</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="longitude"]'</span><span class="p">).</span><span class="nx">content</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="name"]'</span><span class="p">).</span><span class="nx">textContent</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">address</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="address"]'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">h2</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"h2"</span><span class="p">);</span>
<span class="nx">h2</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">popup</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"div"</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="s2">"popup"</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">h2</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">address</span><span class="p">.</span><span class="nx">cloneNode</span><span class="p">(</span><span class="kc">true</span><span class="p">));</span>

<span class="kd">const</span> <span class="nx">marker</span> <span class="o">=</span> <span class="nx">L</span><span class="p">.</span><span class="nx">marker</span><span class="p">([</span><span class="nx">latitude</span><span class="p">,</span> <span class="nx">longitude</span><span class="p">]).</span><span class="nx">bindPopup</span><span class="p">(</span><span class="nx">popup</span><span class="p">);</span>
<span class="nx">marker</span><span class="p">.</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">markers</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">markers</span><span class="p">.</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="nx">map</span><span class="p">.</span><span class="nx">fitBounds</span><span class="p">(</span><span class="nx">markers</span><span class="p">.</span><span class="nx">getBounds</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>

<span class="nb">window</span><span class="p">.</span><span class="nx">customElements</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span><span class="s2">"leaflet-map"</span><span class="p">,</span> <span class="nx">LeafletMap</span><span class="p">);</span>
</code></pre></div></div>

<p>I quite like the way that this reads. The <code class="highlighter-rouge">itemProp</code>s make for very nice selectors and actually
allow developers to completely change the structure of the HTML. As long as the annotations
are kept, the Web Component will be able to still extract the locations and to load them into
leaflet.</p>

<p>You can try this on CodePen:</p>

<p>This of course is nowhere from production ready but shall only serve as a proof of concept.
In a more advanced version, we wouldn’t limit our initial query selector to <code class="highlighter-rouge">[itemType="https://schema.org/School]</code>
but would probably want to find a way to query for everything that is a child of <code class="highlighter-rouge">https://schema.org/Place</code>.
We would also need to adapt the static image if we wanted to change the underlying data. If we have server
side rendering at our disposal, we could use something like the <a href="https://docs.mapbox.com/api/maps/static-images/">Mapbox Static Images
API</a> to dynamically create the fallback
images for clients that do not support JavaScript or Web Components.</p>

<p>All in all, this feels like a nice approach to me though. It provides content
that can be consumed by computers and humans with up to date or legacy (or privacy concious)
devices easily. Using the <code class="highlighter-rouge">itemProp</code>s for query selectors also makes for a nice
authoring experience with good separation of concerns.</p>

<p>What do you think? Let me know on <a href="https://berlin.social/@knut">mastodon</a>.</p>
</article>


<hr>

<footer>
<p>
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
</svg> Suivre</a> •
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
</svg> Pro</a> •
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
</svg> Email</a> •
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
</svg> Légal</abbr>
</p>
<template id="theme-selector">
<form>
<fieldset>
<legend><svg class="icon icon-brightness-contrast">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
</svg> 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-5.1.0.min.js" type="module"></script>
<script>
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 && selectedTheme !== 'undefined') {
form.querySelector(`[value="${selectedTheme}"]`).checked = true
}
}

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>

+ 152
- 0
cache/2024/65fba9cd025cd2403f932cb2c928cf14/index.md View File

@@ -0,0 +1,152 @@
title: A microdata enhanced HTML Webcomponent for Leaflet
url: https://blog.k-nut.eu/leaflet-microdata-html-webcomponent
hash_url: 65fba9cd025cd2403f932cb2c928cf14
archive_date: 2024-03-25
og_image:
description: An example of using schema.org microdata to build a HTML Webcomponent for Leaflet
favicon: https://blog.k-nut.eu/favicon-32x32.png
language: en_US

<p>The people in my RSS reader have been talking some more about Web Components in the
past couple of months. Jim Nielsen had <a href="https://blog.jim-nielsen.com/2023/html-web-components/">a post</a>
referring to Jeremy Keith coining the term <a href="https://adactio.com/journal/20618">HTML Web Components</a>
for a special kind of Web Components. The idea essentially is that you have regular HTML markup that is wrapped
by a custom Web Component which enhances the user experience.</p>

<p>I thought that this was quite an interesting idea and thought about situations in which
it could be applied. Working with open data quite a bit, we often find ourselves in
situations where we build maps. Additionally, the German open data scene has been lobbying for
more linked open data in the past couple of months. I think I came up with an example which
combines these three things - HTML Web Components, maps and Linked Data (or a flavor
thereof) quite nicely.</p>

<p>As an example, assume that we want to render schools on a map. The data in
our example is taken from our <a href="https://jedeschule.codefor.de/docs">jedeschule.de API</a>
which has the goal of making all primary and secondary schools in Germany
searchable and queryable.</p>

<p>With the approach I’m proposing, we can author markup that looks like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;leaflet-map&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"map"</span><span class="nt">&gt;&lt;/div&gt;</span>
<span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"locations"</span><span class="nt">&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-153710"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Dahlingschule, Städt. Förderschule im integr. Verbund, FSP Lernen u. Emot. und soziale Entwicklung,-Primarstufe u. SekI<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Dahlingstr. 40<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>47229<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Duisburg<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"51.38331874331818"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"6.700606101666003"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-166480"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Montessori-Gymnasium Städt. Gymnasium für Jungen und Mädchen<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Rochusstr. 145<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>50827<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Köln<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"50.963204818343755"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"6.904840537750957"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;li</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/School"</span> <span class="na">data-fresh-key=</span><span class="s">"NW-167782"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h2</span> <span class="na">itemprop=</span><span class="s">"name"</span><span class="nt">&gt;</span>Städt. Grillo-Gymnasium<span class="nt">&lt;/h2&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"address"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/PostalAddress"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"streetAddress"</span><span class="nt">&gt;</span>Hauptstr. 60<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"postalCode"</span><span class="nt">&gt;</span>45879<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">itemprop=</span><span class="s">"addressLocality"</span><span class="nt">&gt;</span>Gelsenkirchen<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">itemprop=</span><span class="s">"geo"</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"https://schema.org/GeoCoordinates"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"latitude"</span> <span class="na">content=</span><span class="s">"51.5130837882258"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">itemprop=</span><span class="s">"longitude"</span> <span class="na">content=</span><span class="s">"7.099798427442939"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/leaflet-map&gt;</span>
<span class="nt">&lt;style&gt;</span>
<span class="nf">#map</span> <span class="p">{</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">800px</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span>
<span class="py">aspect-ratio</span><span class="p">:</span> <span class="m">16</span><span class="p">/</span><span class="m">9</span><span class="p">;</span>
<span class="nl">background-image</span><span class="p">:</span> <span class="sx">url("/map.png")</span><span class="p">;</span>
<span class="nl">background-size</span><span class="p">:</span> <span class="n">contain</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">&lt;/style&gt;</span>
</code></pre></div></div>

<p>In this form, this isn’t interactive yet but it can already be easily consumed by both humans
and computers. Humans will see a static map (I simply took a screenshot and set is as a
background image for the <code class="highlighter-rouge">#map</code> node) and a list of schools with their addresses.
Computers will be able to also parse the schema.org annotations to extract structured data out of the list.</p>

<p>Since the data is semi-structured and machine readable, we can now also consume it from
a Web Component to add interactivity with <a href="https://leafletjs.com">Leaflet</a>. The code to do so
looks like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">LeafletMap</span> <span class="kd">extends</span> <span class="nx">HTMLElement</span> <span class="p">{</span>
<span class="nx">connectedCallback</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">mapElement</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">"#map"</span><span class="p">);</span>
<span class="nx">mapElement</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundImage</span> <span class="o">=</span> <span class="s2">"none"</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">schools</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span>
<span class="s1">'[itemType="https://schema.org/School"]'</span><span class="p">,</span>
<span class="p">);</span>

<span class="kd">var</span> <span class="nx">map</span> <span class="o">=</span> <span class="nx">L</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">mapElement</span><span class="p">).</span><span class="nx">setView</span><span class="p">([</span><span class="mf">51.505</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.09</span><span class="p">],</span> <span class="mi">13</span><span class="p">);</span>
<span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">(</span><span class="s2">"https://tile.openstreetmap.org/{z}/{x}/{y}.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="na">attribution</span><span class="p">:</span>
<span class="s1">'&amp;copy; &lt;a href="https://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt; contributors'</span><span class="p">,</span>
<span class="p">}).</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">markers</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">L</span><span class="p">.</span><span class="nx">featureGroup</span><span class="p">();</span>
<span class="nx">schools</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">school</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">latitude</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="latitude"]'</span><span class="p">).</span><span class="nx">content</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">longitude</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="longitude"]'</span><span class="p">).</span><span class="nx">content</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="name"]'</span><span class="p">).</span><span class="nx">textContent</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">address</span> <span class="o">=</span> <span class="nx">school</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">'[itemProp="address"]'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">h2</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"h2"</span><span class="p">);</span>
<span class="nx">h2</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">popup</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"div"</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="s2">"popup"</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">h2</span><span class="p">);</span>
<span class="nx">popup</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">address</span><span class="p">.</span><span class="nx">cloneNode</span><span class="p">(</span><span class="kc">true</span><span class="p">));</span>

<span class="kd">const</span> <span class="nx">marker</span> <span class="o">=</span> <span class="nx">L</span><span class="p">.</span><span class="nx">marker</span><span class="p">([</span><span class="nx">latitude</span><span class="p">,</span> <span class="nx">longitude</span><span class="p">]).</span><span class="nx">bindPopup</span><span class="p">(</span><span class="nx">popup</span><span class="p">);</span>
<span class="nx">marker</span><span class="p">.</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">markers</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">markers</span><span class="p">.</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>

<span class="nx">map</span><span class="p">.</span><span class="nx">fitBounds</span><span class="p">(</span><span class="nx">markers</span><span class="p">.</span><span class="nx">getBounds</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>

<span class="nb">window</span><span class="p">.</span><span class="nx">customElements</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span><span class="s2">"leaflet-map"</span><span class="p">,</span> <span class="nx">LeafletMap</span><span class="p">);</span>
</code></pre></div></div>

<p>I quite like the way that this reads. The <code class="highlighter-rouge">itemProp</code>s make for very nice selectors and actually
allow developers to completely change the structure of the HTML. As long as the annotations
are kept, the Web Component will be able to still extract the locations and to load them into
leaflet.</p>

<p>You can try this on CodePen:</p>


<p>This of course is nowhere from production ready but shall only serve as a proof of concept.
In a more advanced version, we wouldn’t limit our initial query selector to <code class="highlighter-rouge">[itemType="https://schema.org/School]</code>
but would probably want to find a way to query for everything that is a child of <code class="highlighter-rouge">https://schema.org/Place</code>.
We would also need to adapt the static image if we wanted to change the underlying data. If we have server
side rendering at our disposal, we could use something like the <a href="https://docs.mapbox.com/api/maps/static-images/">Mapbox Static Images
API</a> to dynamically create the fallback
images for clients that do not support JavaScript or Web Components.</p>

<p>All in all, this feels like a nice approach to me though. It provides content
that can be consumed by computers and humans with up to date or legacy (or privacy concious)
devices easily. Using the <code class="highlighter-rouge">itemProp</code>s for query selectors also makes for a nice
authoring experience with good separation of concerns.</p>

<p>What do you think? Let me know on <a href="https://berlin.social/@knut">mastodon</a>.</p>

+ 187
- 0
cache/2024/691120ebac09f68413501b7f5daa2db7/index.html View File

@@ -0,0 +1,187 @@
<!doctype html><!-- This is a valid HTML5 document. -->
<!-- Screen readers, SEO, extensions and so on. -->
<html lang="en">
<!-- Has to be within the first 1024 bytes, hence before the `title` element
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>Announcing Ibis, the federated Wikipedia Alternative (archive) — David Larlet</title>
<meta name="description" content="Publication mise en cache pour en conserver une trace.">
<!-- 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="#f7f7f7">
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
<meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
<!-- Is that even respected? Retrospectively? What a shAItshow…
https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
<meta name="robots" content="noai, noimageai">
<!-- Documented, feel free to shoot an email. -->
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.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>
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>

<meta name="robots" content="noindex, nofollow">
<meta content="origin-when-cross-origin" name="referrer">
<!-- Canonical URL for SEO purposes -->
<link rel="canonical" href="https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki">

<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">


<article>
<header>
<h1>Announcing Ibis, the federated Wikipedia Alternative</h1>
</header>
<nav>
<p class="center">
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki" title="Lien vers le contenu original">Source originale</a>
<br>
Mis en cache le 2024-03-26
</p>
</nav>
<hr>
<p>Wikipedia is the most popular online encyclopedia, and millions of people rely on it every day to provide trustworthy information on a wide variety of topics. It is not well known but there have been numerous scandals which put this trust into question. For example in 2012, a trustee of the Wikimedia Foundation UK used his position to place his PR client on <a href="https://www.cnet.com/tech/services-and-software/corruption-in-wikiland-paid-pr-scandal-erupts-at-wikipedia/">Wikipedia’s front page 17 times within a month</a>. Wikipedia founder Jimmy Wales made extensive edits to the article about himself, <a href="https://web.archive.org/web/20210501004803/https://www.wired.com/2005/12/wikipedia-founder-edits-own-bio/">removing mentions of co-founder Larry Sanger</a>. In 2007, a prolific editor who claimed to be a graduate professor and was recruited by Wikipedia staff to the Arbitration Committee was <a href="https://web.archive.org/web/20230205062217/https://www.telegraph.co.uk/news/uknews/1544803/Wikipedia-professor-is-24-year-old-college-dropout.html">revealed to be a 24-year-old college dropout</a>. These are only a few examples, journalist Helen Buyniski has collected much more information about the <a href="http://helenofdestroy.com/index.php/exposing-wikipedia/49-wikipedia-rotten-to-the-core">the rot in Wikipedia</a>.</p>
<p>These problems have been going on for a very long time, and there is no indication that Wikipedia is willing to solve them. There have also been numerous attempts to create new, centralized Wikipedia alternatives but all of them failed to gain critical mass. The fact is that we can’t rely on any single website to hold the whole world’s knowledge, because it can be corrupted sooner or later. The only solution is a distributed architecture, with many smaller websites connecting with each other and sharing information. This is where ActivityPub comes in, the protocol used by Mastodon, Lemmy, Peertube and many other federated social media projects.</p>
<p>I have worked on <a href="https://join-lemmy.org/">Lemmy</a> for the past four years, bringing it from a prototype to a fully functional Reddit alternative. I wrote the entire federation code and became very familiar with the protocol. I realized that the same technology easily be used to create a federated encyclopedia. As no one else took up such a project, I finally decided to do it on my own and create Ibis. Thanks to my previous experience with the tech stack and the ActivityPub library I created, I was able to complete a proof of concept in a relatively short time of four months. Just like Lemmy, Ibis is built on a stack of PostgreSQL and Rust, in this case with a frontend written in Rust Webassembly. This means it can efficiently run on low-powered servers or scale to high user numbers.</p>
<p>The proof of concept includes all the necessary core features. Users can create, read and edit articles. Each article has an edit history showing the individual changes. Edits are stored as diffs which means that conflicts can be resolved through merges, similar to git. Most importantly all of this is fully federated, so it is possible to synchronize articles between instances, and interact with remote articles as if they were on the local website. You can see it in action on this very website, or register an account on <a href="https://open.ibis.wiki">open.ibis.wiki</a> to start editing (no email verification necessary). All articles and edits are automatically synchronized between instances. You can also deploy Ibis on your own server by following the <a href="/article/Setup_Instructions@ibis.wiki">Setup_Instructions</a>.</p>
<p>Ibis is still in a very early stage, but it has the potential to completely change the way online encyclopedias work. Instead of individual, centralized websites there will be an interconnected network of encyclopedias. This means the same topic can be treated in completely different ways. For example <code>geology.wiki/article/Mountain</code> may be completely different different from <code>poetry.wiki/article/Mountain</code>. There can be Ibis instances strictly focused on a particular topic with a high quality standard, and others covering many areas in layman’s terms. Others may document fictional universes from television series or videogames. If one instance is badly moderated or presents manipulated information, an alternative can easily be created. Yet all of them will be interconnected, and users can read and edit without leaving their home website.</p>
<p>However Ibis is still in a very early stage of development. It is missing countless important features, such as user profile settings, discussions, localization, moderation tools, and so on. I have already worked on the project for four months, and estimate that it would take at least another year to make it ready for production. I won’t be able to do all of this work on my own for free. Additionally my daugher will be born within a few weeks, so there won’t be any time for programming. That’s why I hope that other developers will help by contributing to the project. In particular the frontend is primitive and can use improvements, or even a completely new frontend in a language like Javascript. You can use the following channels for communication:</p>

<p>If you don’t have the time or skill to contribute personally, please consider making a donation. This signals that it is worth investing more of my time into the project. I am also interested to know about organizations which may provide grants for working on Ibis.</p>

<p>On a side note, ActivityPub federation can also be added to existing wiki platforms, with which I am willing to assist.</p>
<p>Felix “nutomic” Ableitner, 13. February 2024</p>
</article>


<hr>

<footer>
<p>
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
</svg> Suivre</a> •
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
</svg> Pro</a> •
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
</svg> Email</a> •
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
</svg> Légal</abbr>
</p>
<template id="theme-selector">
<form>
<fieldset>
<legend><svg class="icon icon-brightness-contrast">
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
</svg> 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-5.1.0.min.js" type="module"></script>
<script>
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 && selectedTheme !== 'undefined') {
form.querySelector(`[value="${selectedTheme}"]`).checked = true
}
}

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>

+ 20
- 0
cache/2024/691120ebac09f68413501b7f5daa2db7/index.md View File

@@ -0,0 +1,20 @@
title: Announcing Ibis, the federated Wikipedia Alternative
url: https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki
hash_url: 691120ebac09f68413501b7f5daa2db7
archive_date: 2024-03-26
og_image:
description:
favicon:
language: en_US

<p>Wikipedia is the most popular online encyclopedia, and millions of people rely on it every day to provide trustworthy information on a wide variety of topics. It is not well known but there have been numerous scandals which put this trust into question. For example in 2012, a trustee of the Wikimedia Foundation UK used his position to place his PR client on <a href="https://www.cnet.com/tech/services-and-software/corruption-in-wikiland-paid-pr-scandal-erupts-at-wikipedia/">Wikipedia’s front page 17 times within a month</a>. Wikipedia founder Jimmy Wales made extensive edits to the article about himself, <a href="https://web.archive.org/web/20210501004803/https://www.wired.com/2005/12/wikipedia-founder-edits-own-bio/">removing mentions of co-founder Larry Sanger</a>. In 2007, a prolific editor who claimed to be a graduate professor and was recruited by Wikipedia staff to the Arbitration Committee was <a href="https://web.archive.org/web/20230205062217/https://www.telegraph.co.uk/news/uknews/1544803/Wikipedia-professor-is-24-year-old-college-dropout.html">revealed to be a 24-year-old college dropout</a>. These are only a few examples, journalist Helen Buyniski has collected much more information about the <a href="http://helenofdestroy.com/index.php/exposing-wikipedia/49-wikipedia-rotten-to-the-core">the rot in Wikipedia</a>.</p>
<p>These problems have been going on for a very long time, and there is no indication that Wikipedia is willing to solve them. There have also been numerous attempts to create new, centralized Wikipedia alternatives but all of them failed to gain critical mass. The fact is that we can’t rely on any single website to hold the whole world’s knowledge, because it can be corrupted sooner or later. The only solution is a distributed architecture, with many smaller websites connecting with each other and sharing information. This is where ActivityPub comes in, the protocol used by Mastodon, Lemmy, Peertube and many other federated social media projects.</p>
<p>I have worked on <a href="https://join-lemmy.org/">Lemmy</a> for the past four years, bringing it from a prototype to a fully functional Reddit alternative. I wrote the entire federation code and became very familiar with the protocol. I realized that the same technology easily be used to create a federated encyclopedia. As no one else took up such a project, I finally decided to do it on my own and create Ibis. Thanks to my previous experience with the tech stack and the ActivityPub library I created, I was able to complete a proof of concept in a relatively short time of four months. Just like Lemmy, Ibis is built on a stack of PostgreSQL and Rust, in this case with a frontend written in Rust Webassembly. This means it can efficiently run on low-powered servers or scale to high user numbers.</p>
<p>The proof of concept includes all the necessary core features. Users can create, read and edit articles. Each article has an edit history showing the individual changes. Edits are stored as diffs which means that conflicts can be resolved through merges, similar to git. Most importantly all of this is fully federated, so it is possible to synchronize articles between instances, and interact with remote articles as if they were on the local website. You can see it in action on this very website, or register an account on <a href="https://open.ibis.wiki">open.ibis.wiki</a> to start editing (no email verification necessary). All articles and edits are automatically synchronized between instances. You can also deploy Ibis on your own server by following the <a href="/article/Setup_Instructions@ibis.wiki">Setup_Instructions</a>.</p>
<p>Ibis is still in a very early stage, but it has the potential to completely change the way online encyclopedias work. Instead of individual, centralized websites there will be an interconnected network of encyclopedias. This means the same topic can be treated in completely different ways. For example <code>geology.wiki/article/Mountain</code> may be completely different different from <code>poetry.wiki/article/Mountain</code>. There can be Ibis instances strictly focused on a particular topic with a high quality standard, and others covering many areas in layman’s terms. Others may document fictional universes from television series or videogames. If one instance is badly moderated or presents manipulated information, an alternative can easily be created. Yet all of them will be interconnected, and users can read and edit without leaving their home website.</p>
<p>However Ibis is still in a very early stage of development. It is missing countless important features, such as user profile settings, discussions, localization, moderation tools, and so on. I have already worked on the project for four months, and estimate that it would take at least another year to make it ready for production. I won’t be able to do all of this work on my own for free. Additionally my daugher will be born within a few weeks, so there won’t be any time for programming. That’s why I hope that other developers will help by contributing to the project. In particular the frontend is primitive and can use improvements, or even a completely new frontend in a language like Javascript. You can use the following channels for communication:</p>

<p>If you don’t have the time or skill to contribute personally, please consider making a donation. This signals that it is worth investing more of my time into the project. I am also interested to know about organizations which may provide grants for working on Ibis.</p>

<p>On a side note, ActivityPub federation can also be added to existing wiki platforms, with which I am willing to assist.</p>
<p>Felix “nutomic” Ableitner, 13. February 2024</p>

+ 6
- 0
cache/2024/index.html View File

@@ -70,6 +70,8 @@
<main>
<ul>
<li><a href="/david/cache/2024/691120ebac09f68413501b7f5daa2db7/" title="Accès à l’article dans le cache local : Announcing Ibis, the federated Wikipedia Alternative">Announcing Ibis, the federated Wikipedia Alternative</a> (<a href="https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative@ibis.wiki" title="Accès à l’article original distant : Announcing Ibis, the federated Wikipedia Alternative">original</a>)</li>
<li><a href="/david/cache/2024/5ff0fe74d43b57fa41db8851bc56ac88/" title="Accès à l’article dans le cache local : Highlight Text When a User Scrolls Down to That Piece of Text">Highlight Text When a User Scrolls Down to That Piece of Text</a> (<a href="https://frontendmasters.com/blog/highlight-text-when-a-user-scrolls-down-to-that-piece-of-text/" title="Accès à l’article original distant : Highlight Text When a User Scrolls Down to That Piece of Text">original</a>)</li>
<li><a href="/david/cache/2024/877ad04fd329c26c80113e15dec540df/" title="Accès à l’article dans le cache local : The Walk and Talk: Everything We Know">The Walk and Talk: Everything We Know</a> (<a href="https://craigmod.com/ridgeline/176/" title="Accès à l’article original distant : The Walk and Talk: Everything We Know">original</a>)</li>
@@ -310,6 +312,8 @@
<li><a href="/david/cache/2024/75c7b6350ba18a5a11ee3bbf8b3b64be/" title="Accès à l’article dans le cache local : Google will no longer back up the Internet: Cached webpages are dead">Google will no longer back up the Internet: Cached webpages are dead</a> (<a href="https://arstechnica.com/gadgets/2024/02/google-search-kills-off-cached-webpages/" title="Accès à l’article original distant : Google will no longer back up the Internet: Cached webpages are dead">original</a>)</li>
<li><a href="/david/cache/2024/65fba9cd025cd2403f932cb2c928cf14/" title="Accès à l’article dans le cache local : A microdata enhanced HTML Webcomponent for Leaflet">A microdata enhanced HTML Webcomponent for Leaflet</a> (<a href="https://blog.k-nut.eu/leaflet-microdata-html-webcomponent" title="Accès à l’article original distant : A microdata enhanced HTML Webcomponent for Leaflet">original</a>)</li>
<li><a href="/david/cache/2024/e401917f8e9785285afed817e5344443/" title="Accès à l’article dans le cache local : Interaction as Content">Interaction as Content</a> (<a href="https://gist.github.com/loreanvictor/bddd8824c744024d338e935bd7e96707" title="Accès à l’article original distant : Interaction as Content">original</a>)</li>
<li><a href="/david/cache/2024/1929f7183f694c7abeafeddb891fcf50/" title="Accès à l’article dans le cache local : Crise des opioïdes : pourquoi il ne faut ni l'oublier ni l'ignorer">Crise des opioïdes : pourquoi il ne faut ni l'oublier ni l'ignorer</a> (<a href="https://basta.media/crise-des-opioides-pourquoi-il-ne-faut-ni-oublier-ni-ignorer" title="Accès à l’article original distant : Crise des opioïdes : pourquoi il ne faut ni l'oublier ni l'ignorer">original</a>)</li>
@@ -344,6 +348,8 @@
<li><a href="/david/cache/2024/076169df8a4bd9dde9a4637c6b306dff/" title="Accès à l’article dans le cache local : Ma page /now (ou plutôt /en-ce-moment)">Ma page /now (ou plutôt /en-ce-moment)</a> (<a href="https://blog.professeurjoachim.com/billet/2024-01-05-ma-page-now-ou-plutot-en-ce-moment" title="Accès à l’article original distant : Ma page /now (ou plutôt /en-ce-moment)">original</a>)</li>
<li><a href="/david/cache/2024/55c19feff784a41d2527b5f1589d931d/" title="Accès à l’article dans le cache local : activitypub-powered wikis">activitypub-powered wikis</a> (<a href="https://alexsirac.com/activitypub-powered-wikis/" title="Accès à l’article original distant : activitypub-powered wikis">original</a>)</li>
<li><a href="/david/cache/2024/41e9f48de9ccd2449bceca518fff8606/" title="Accès à l’article dans le cache local : Time for a refresh!">Time for a refresh!</a> (<a href="https://vanschklift.com/blog/post/2020/06/19/Time-for-a-refresh%21" title="Accès à l’article original distant : Time for a refresh!">original</a>)</li>
<li><a href="/david/cache/2024/9b4b5364526390ba1db9c4a651ea8311/" title="Accès à l’article dans le cache local : Teaming is hard because you’re probably not really on a team">Teaming is hard because you’re probably not really on a team</a> (<a href="https://www.strategy-business.com/article/Teaming-is-hard-because-youre-probably-not-really-on-a-team" title="Accès à l’article original distant : Teaming is hard because you’re probably not really on a team">original</a>)</li>

Loading…
Cancel
Save