Thomas CitharelJe m’appelle Thomas, et je crée des outils web.2022-09-25T16:07:05Zhttps://tcit.fr/Thomas Citharelcontact@tcit.frInternationalisation simple des dates dans le navigateur2019-10-20T10:36:42Zhttps://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/<p>Nous allons voir dans cet article comment formatter des dates facilement dans le navigateur en évitant de faire appel à des bibliothèques tierces.</p>
<h2 id="formater-avec-momentjs" tabindex="-1">Formater avec MomentJS <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#formater-avec-momentjs" aria-hidden="true">#</a></h2>
<p>Lorsque l'on veut manipuler des données temporelles avec Javascript dans le navigateur, on se repose souvent sur la bibliothèque <a href="https://momentjs.com/">Moment.js</a>.<br />
Elle permet en effet de formater des dates à sa convenance :</p>
<pre class="language-js"><code class="language-js"><span class="token function">moment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'MMMM Do YYYY, HH:mm:ss'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /><span class="token comment">// October 19th 2019, 19:04:56</span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token function">moment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'dddd, MMMM do YYYY'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /><span class="token comment">// Saturday, October 6th 2019</span></code></pre>
<p>Si vous chargez aussi le support des différentes <em>locales</em>, ça peut vous donner ceci :</p>
<pre class="language-js"><code class="language-js">moment<span class="token punctuation">.</span><span class="token function">locale</span><span class="token punctuation">(</span><span class="token string">'fr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /><span class="token function">moment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">'LLL'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <br /><span class="token comment">// 19 octobre 2019 19:09</span></code></pre>
<p>Plutôt pratique, n'est-ce pas ? Du coup Moment.js est très populaire (42k <em>stars</em> sur Github) et très utilisé (presque <a href="https://npm-stat.com/charts.html?package=moment">2 millions d'installations journalières</a> via npm, où plus de 36 000 paquets en sont dépendants ).</p>
<h2 id="confort-vs-poids" tabindex="-1">Confort vs poids <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#confort-vs-poids" aria-hidden="true">#</a></h2>
<p>Le souci de Moment.js, c'est son poids énorme de 329Ko (non compressé, et avec toutes les locales).<br />
Du coup ça fait un sacré module à charger (et il faut mieux qu'il soit chargé dès le début, c'est pas très joli quand les dates s'affichent une fois seulement que la page est chargée).</p>
<p>Y a quelques solutions pour améliorer cela, par exemple charger uniquement la <em>locale</em> de l'utilisateur qui peut être fournie par le backend en fonction de l'en-tête <code>Accept-Language</code>.<br />
On peut ensuite éventuellement charger dynamiquement d'autres locales si jamais l'utilisateur⋅ice décide de changer de langue.</p>
<p>Cela dit, même en chargeant uniquement le cœur de Moment.js, on reste à plusieurs dizaines de kilo-octets pour une utilisé potentiellement très limitée.</p>
<p>En réaction à cette problématique, les bibliothèques <a href="https://github.com/iamkun/dayjs">dayjs</a> et <a href="https://date-fns.org/">date-fns</a> - de poids beaucoup plus réduit - existent. Date-fns permet de faire du <em>tree-shaking</em> avec Webpack pour importer uniquement les modules dont on a besoin et dayjs n'incorpore que le minimum, en externalisant les fonctionnalités supplémentaires via des plugins.</p>
<p>Pour la plupart des fonctionnalités, ça remplace très bien Moment.js. Vous pouvez voir un comparatif sur ce dépôt : <a href="https://github.com/you-dont-need/You-Dont-Need-Momentjs">You don't (may not) need Moment.js</a>.</p>
<h2 id="encore-plus-leger" tabindex="-1">Encore plus léger <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#encore-plus-leger" aria-hidden="true">#</a></h2>
<p>Et si on voulait s'épargner encore quelques kilo-octets, on regarderait du côté…de Javascript. En effet, il existe depuis relativement assez longtemps (<a href="https://www.ecma-international.org/ecma-402/1.0">2012</a>) une API <code>Intl</code> avec notamment un objet <code>DateTimeFormat</code> fait pour formater des dates en fonction de la <code>locale</code>.</p>
<p>Ça s'utilise comme cela :</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'fr-FR'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 10/19/2019</span></code></pre>
<p>Ça prend en charge correctement les caractères non-latins et le sens d'écriture de droite à gauche :</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'ar-EG'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// ١٩/١٠/٢٠١٩</span></code></pre>
<p>Si on ne veut pas spécifier de <em>locale</em>, on peut passer l'argument <code>'default'</code> ou bien <code>undefined</code> au constructeur de <code>Intl.DateTimeFormat</code>, ça utilisera la <em>locale</em> configurée du navigateur :</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 10/19/2019</span></code></pre>
<p>Bon, et maintenant si on veut une vraie date formattée, comment on fait ?</p>
<p>Avec le second argument du constructeur, pardi !</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">weekday</span><span class="token operator">:</span> <span class="token string">'long'</span><span class="token punctuation">,</span> <span class="token literal-property property">year</span><span class="token operator">:</span> <span class="token string">'numeric'</span><span class="token punctuation">,</span> <span class="token literal-property property">month</span><span class="token operator">:</span> <span class="token string">'long'</span><span class="token punctuation">,</span> <span class="token literal-property property">day</span><span class="token operator">:</span> <span class="token string">'numeric'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'default'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// samedi 19 octobre 2019</span><br /><span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'ar-EG'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// السبت، ١٩ أكتوبر ٢٠١٩</span></code></pre>
<p>La référence de ces options se trouve sur <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat">cette page du MDN</a>.</p>
<p>Comme l'API Intl est assez ancienne, <a href="https://caniuse.com/#feat=internationalization">le support</a> est plutôt bon (Internet Explorer 11, Safari 10).</p>
<h2 id="formatage-de-dates-relatives" tabindex="-1">Formatage de dates relatives <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#formatage-de-dates-relatives" aria-hidden="true">#</a></h2>
<p>Je note qu'il existe aussi un objet <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/RelativeTimeFormat"><code>Intl.RelativeTimeFormat</code></a> pour afficher des temps relatifs :</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> rtf <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>RelativeTimeFormat</span><span class="token punctuation">(</span><span class="token string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">numeric</span><span class="token operator">:</span> <span class="token string">"auto"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />rtf<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"day"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 'hier'</span><br /><br />rtf<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"day"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 'dans 3 jours'</span><br /><br />rtf<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token string">"month"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// 'il y a 6 mois'</span></code></pre>
<p>Cette fois par contre, <a href="https://caniuse.com/#feat=mdn-javascript_builtins_intl_relativetimeformat">pas de support pour Internet Explorer, Edge ou Safari</a>, ce qui rend son emploi plus hasardeux. On peut bien entendu détecter cela avec</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>Intl<span class="token punctuation">.</span>DateTimeFormat<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// do something</span><br /> <span class="token comment">// it should probably work</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">if</span> <span class="token punctuation">(</span>Intl<span class="token punctuation">.</span>RelativeTimeFormat<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// do something</span><br /> <span class="token comment">// you're using Firefox or Chrome</span><br /><span class="token punctuation">}</span></code></pre>
<h2 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#conclusion" aria-hidden="true">#</a></h2>
<p>Voilà, même avec l'addition récente de <code>RelativeTimeFormat</code>, l'API <code>Intl</code> est vraiment loin d'avoir toutes les fonctionnalités de Moment.js ou même de date-fns, mais s'il vous faut juste afficher quelques dates au bon format, pas besoin de charger des centaines de kilooctets pour rien.🙂</p>
<h2 id="bonus" tabindex="-1">Bonus <a class="direct-link" href="https://tcit.fr/post/internationalisation-simple-des-dates-dans-le-navigateur/#bonus" aria-hidden="true">#</a></h2>
<p>En utilisant l'API Intl, on peut facilement récupérer la liste des mois et des noms des jours traduits dans la langue de l'utilisateur :</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">localeMonthNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> monthNames <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">12</span><span class="token punctuation">;</span> i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2019</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> month <span class="token operator">=</span> d<span class="token punctuation">.</span><span class="token function">toLocaleString</span><span class="token punctuation">(</span><span class="token string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">month</span><span class="token operator">:</span> <span class="token string">'long'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> monthNames<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>month<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">return</span> monthNames<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token function">localeMonthNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// [ "janvier", "février", "mars", "avril", "mai", "juin", "juillet", … ]</span></code></pre>
<p>Là, c'est plutôt simple, on n'a qu'à itérer chaque mois dans le constructeur de <code>Date</code> pour avoir son nom textuel. On note quand même que les mois commencent à 0.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">localeShortWeekDayNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> weekDayNames <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">13</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">20</span><span class="token punctuation">;</span> i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2019</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> weekDay <span class="token operator">=</span> d<span class="token punctuation">.</span><span class="token function">toLocaleString</span><span class="token punctuation">(</span><span class="token string">'default'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">weekday</span><span class="token operator">:</span> <span class="token string">'short'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> weekDayNames<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>weekDay<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">return</span> weekDayNames<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token function">localeShortWeekDayNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// [ "dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam." ]</span></code></pre>
<p>Ici, c'est plus compliqué, il faut partir d'une date où l'on sait qu'il s'agit d'un dimanche, puis itérer sur les 7 jours de la semaine. Et oui, le jour <code>0</code> est bien un Dimanche. Ici j'ai mis les versions courtes des noms des jours, mais ça marche aussi évidemment avec la fonction complète.</p>
<p>Ça peut éviter de traduire des informations inutiles.</p>
<p>Un truc qui manque par contre, c'est déterminer en fonction de la <em>locale</em> quel jour de la semaine celle-ci commence. En effet, si la fameuse norme ISO 8601 définit lundi comme le premier jour de la semaine, certains pays comme les États-Unis d'Amérique, le Canada, le Japon et l'Australie entament leur semaine le Dimanche. Au Moyen-Orient, elle commence le Samedi. Du coup si vous n'avez pas de bibliothèque tierce, il faut fournir l'option aux traducteurs pour qu'ils mettent leur propre valeur.</p>
<p><em><a href="https://pixabay.com/fr/photos/calendrier-calendrier-mural-jours-1990453/">Image « Calendrier Mural Jours »</a> par <a href="https://pixabay.com/fr/users/webandi-1460261/">Andreas Lischka</a> sur <a href="https://pixabay.com/fr/">Pixabay</a></em></p>
Terre Brûlée2019-11-09T22:57:27Zhttps://tcit.fr/post/terre-brulee/<p>Au vent, des landes de pierre…<br />
Maintenant que cette chanson est en tête, je voulais juste partager quelques photos d'Irlande.</p>
<p>J'y étais en Juin, en <em>road trip</em> sur la plus grande partie du littoral de la moitié Nord.<br />
Voici des photos de mes coins préférés, surtout dans le comté de Mayo, de Downpatrick Head à la vallée de Doolough, en passant par l'île d'Achill et en poussant jusqu'au parc national du Connemara.</p>
<p>Elles sont classées par ordre chronologique.</p>
Publier un blog statique avec Gridsome2020-05-22T20:35:53Zhttps://tcit.fr/post/publier-un-blog-statique-avec-gridsome/<p><strong>Gridsome</strong> est un <em>framework</em> pour générer des sites statiques à l'aide de VueJS et GraphQL.</p>
<p>On parle aussi de <em>framework</em> <a href="https://jamstatic.fr/2019/02/07/c-est-quoi-la-jamstack/">JAMStack</a>, pour Javascript, APIs et <em>Markup</em>. En gros, ce terme décrit simplement d'avoir la possibilité d'ajouter des fonctionnalités dynamiques par dessus votre site statique généré à partir de fichiers sources comme du Markdown, le HTML étant hydraté avec l'application Javascript.</p>
<p>Il n'y a pas de fonctionnalités statiques ici, j'ai juste besoin d'un blog, il n'y aura pas grande différence à l'utilisation si jamais vous avez le Javascript activé ou non dans votre navigateur[^1].</p>
<p>J'ai choisi Gridsome car il utilise le <em>framework</em> VueJS avec lequel je suis plus familiarisé, mais c'est quasiment le même fonctionnement que <a href="https://www.gatsbyjs.com/">GatsbyJS</a> qui utilise ReactJS.</p>
<p>J'avais eu l'occasion d'utiliser Gatsby pour <a href="https://entraide.chatons.org/">entraide.chatons.org</a> et j'avais trouvé le concept intéressant. Aujourd'hui, cet article que vous lisez est justement affiché dans une page d'un site statique généré par Gridsome.</p>
<p>Comme indiqué <a href="https://gridsome.org/">sur la page de présentation de Gridsome</a> : vous prenez des sources de données en entrée, vous effectuez des traitements sur les données (sélection, transformation, affichage) et vous déployez les fichiers HTML et <em>assets</em> produits.</p>
<h2 id="creer-un-projet-gridsome" tabindex="-1">Créer un projet Gridsome <a class="direct-link" href="https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#creer-un-projet-gridsome" aria-hidden="true">#</a></h2>
<p>On commence par installer le module qui fournit la ligne de commande :</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">yarn</span> global <span class="token function">add</span> @gridsome/cli</code></pre>
<p>J'utilise <a href="https://yarnpkg.com/"><code>yarn</code></a> dans les commandes, mais vous pouvez bien sûr utiliser les équivalents <code>npm</code> si c'est ce que vous préférez.</p>
<p>Puis on crée un nouveau projet :</p>
<pre class="language-shell"><code class="language-shell">gridsome create mon-site</code></pre>
<p>Cela récupère le modèle du projet, le met à jour avec le nom du projet, et installe les dépendances.</p>
<p>On peut alors se mettre dans le dossier du projet nouvellement créé puis lance le serveur de développement, par défaut sur le port 8080.</p>
<pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> mon-site<br />gridsome develop</code></pre>
<h2 id="structure-du-projet" tabindex="-1">Structure du projet <a class="direct-link" href="https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#structure-du-projet" aria-hidden="true">#</a></h2>
<p>Vous devriez avoir une structure de projet équivalente voire égale à celle ci-dessous :</p>
<pre><code>├── gridsome.config.js
├── gridsome.server.js
├── package.json
├── README.md
├── src
│ ├── components
│ │ └── README.md
│ ├── favicon.png
│ ├── layouts
│ │ ├── Default.vue
│ │ └── README.md
│ ├── main.js
│ ├── pages
│ │ ├── About.vue
│ │ ├── Index.vue
│ │ └── README.md
│ └── templates
│ └── README.md
├── static
│ └── README.md
└── yarn.lock
</code></pre>
<p>On voit dans <code>src/pages/</code> les fichiers <code>About.vue</code> et <code>Index.vue</code>, qui correspondent aux deux routes accessibles via la barre de navigation. Notez donc que le routage de base se fait via les fichiers disponibles dans <code>/pages/</code>. <code>Index.vue</code> correspond à la page d'accueil <code>/</code>, et un fichier <code>MonProjet.vue</code> donnerait une route <code>/mon-projet</code>.</p>
<p>On a également le fichier <code>Default.vue</code> dans <code>/src/layouts/</code>. Les <em>layouts</em> sont utilisés pour envelopper vos pages avec des éléments communs aux pages, typiquement l'en-tête de la page, la barre de navigation, le pied-de-page… Dans nos pages, par exemple <code>About.vue</code>, le contenu est enveloppé par l'élément <code><Layout></code> :</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Layout</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>About us<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error doloremque omnis animi, eligendi magni a voluptatum, vitae, consequuntur rerum illum odit fugit assumenda rem dolores inventore iste reprehenderit maxime! Iusto.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Layout</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span></code></pre>
<h2 id="ajout-et-representation-des-donnees" tabindex="-1">Ajout et représentation des données <a class="direct-link" href="https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#ajout-et-representation-des-donnees" aria-hidden="true">#</a></h2>
<p>Le squelette de notre site étant exploré, voyons comment y insérer nos données. Gridsome utilise <a href="https://graphql.org/">GraphQL</a>, un langage de requêtes. Nous avons par exemple un premier exemple de requête GraphQL dans le fichier <code>layouts/Default.vue</code>, où le nom du site (défini dans le fichier de configuration <code>gridsome.config.js</code>) est récupéré avec la requête suivante :</p>
<pre class="language-graphql"><code class="language-graphql"><span class="token keyword">query</span> <span class="token punctuation">{</span><br /> <span class="token object">metadata</span> <span class="token punctuation">{</span><br /> <span class="token property">siteName</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>La variable <code>siteName</code> est alors disponible via l'expression <code>$static.metadata.siteName</code> dans notre template VueJS.</p>
<p>Pour importer nos propres données, prenons l'exemple basique de billets de blog sous forme de fichiers locaux au format Markdown.</p>
<p>Installons les modules <a href="https://gridsome.org/plugins/@gridsome/source-filesystem"><code>@gridsome/source-filesystem</code></a> afin de récupérer le contenu des fichiers et <a href="https://gridsome.org/plugins/@gridsome/transformer-remark"><code>@gridsome/transformer-remark</code></a> afin de transformer notre contenu markdown en HTML et surtout convertir l'éventuel <em>front matter</em> YAML en métadonnées utilisables.</p>
<p>Nous allons ajouter la configuration donnée en exemple dans <code>gridsome.config.js</code> :</p>
<pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><br /> <span class="token literal-property property">use</span><span class="token operator">:</span> <span class="token string">'@gridsome/source-filesystem'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">typeName</span><span class="token operator">:</span> <span class="token string">'BlogPost'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'./content/blog/**/*.md'</span><span class="token punctuation">,</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">templates</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">BlogPost</span><span class="token operator">:</span> <span class="token string">'/blog/:year/:month/:day/:title'</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Puis créons l'arborescence <code>content/blog/2020</code> et un fichier <code>hello world.md</code> au bout avec le contenu de base suivant :</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token front-matter-block"><span class="token punctuation">---</span><br /><span class="token front-matter yaml language-yaml">date: 2020-01-05<br />title: "Hello World"</span><br /><span class="token punctuation">---</span></span><br />Il s'agit de mon <span class="token bold"><span class="token punctuation">**</span><span class="token content">premier</span><span class="token punctuation">**</span></span> contenu !</code></pre>
<p>On redémarre le serveur de développement Gridsome car on a changé la configuration puis on ouvre <a href="http://localhost:8080/___explore">le bac à sable</a> GraphQL pour effectuer nos premières requêtes et voir le résultat facilement.</p>
<p>Par exemple, pour récupérer la liste de tous nos posts, on écrira :</p>
<pre class="language-graphql"><code class="language-graphql"><span class="token keyword">query</span> <span class="token punctuation">{</span><br /> <span class="token object">allBlogPost</span> <span class="token punctuation">{</span><br /> <span class="token object">edges</span> <span class="token punctuation">{</span><br /> <span class="token object">node</span> <span class="token punctuation">{</span><br /> <span class="token property">title</span><span class="token punctuation">,</span><br /> <span class="token property-query">date</span><span class="token punctuation">(</span><span class="token attr-name">format</span><span class="token punctuation">:</span> <span class="token string">"DD/MM/YYYY"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token property">path</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Si on édite notre page <code>Index.vue</code>, on peut rajouter cette requête dans un bloc <code><page-query></code> et ensuite accéder aux données via <code>$page.allBlogPost</code>, comme par comme dans l'exemple suivant où nous rajoutons une liste des billets au template :</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>edge in $page.allBlogPost.edges<span class="token punctuation">"</span></span> <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>edge.node.id<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span></code></pre>
<p>Ajoutons ensuite un fichier <code>BlogPost.vue</code> dans nos <code>templates/</code> pour représenter ces entités:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Layout</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>article</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>{{ $page.blogPost.title }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>{{ $page.blogPost.date }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">v-html</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$page.blogPost.content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>article</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Layout</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span><br /><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>page-query</span><span class="token punctuation">></span></span><br />query BlogPost($path: String!) {<br /> blogPost(path: $path) {<br /> title,<br /> date(format: "DD/MM/YYYY"),<br /> content<br /> path<br /> }<br />}<br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>page-query</span><span class="token punctuation">></span></span></code></pre>
<p>Comme on l'a vu, les données de la requête GraphQL <code>blogPost</code> sont injectées dans la variable <code>$page</code> accessible dans mon template. Maintenant que l'on a une page dédiée pour afficher chaque billet, ajoutons un lien depuis notre liste sur la page <code>Index.vue</code>, en changeant notre <code><li></code> en :</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>g-link</span> <span class="token attr-name">:to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>edge.node.path<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>g-link</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span></code></pre>
<p>La balise <code><g-link></code> crée lors du rendu des balises <code><a></code> tout ce qu'il y a de plus basique, mais permet aussi le préchargement des liens (voir les notes de bas de page). En cliquant dessus, on arrive finalement sur notre page montrant un article en particulier.</p>
<h2 id="generation-et-publication" tabindex="-1">Génération et publication <a class="direct-link" href="https://tcit.fr/post/publier-un-blog-statique-avec-gridsome/#generation-et-publication" aria-hidden="true">#</a></h2>
<p>Générons maintenant notre site avec <code>gridsome build</code>, puis servons le contenu du dossier <code>dist</code>, par exemple avec <a href="https://github.com/vercel/serve">serve</a> : <code>serve dist</code>.</p>
<p>Je vous laisse vérifier que la navigation fonctionne bien et que le HTML produit contient bien notre contenu.</p>
<p>On peut publier le contenu de <code>dist</code> là où on le souhaite, voici un exemple de fichier de configuration pour le publier sur Gitlab Pages :</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">image</span><span class="token punctuation">:</span> node<span class="token punctuation">:</span><span class="token number">14</span><br /><span class="token key atrule">deploy</span><span class="token punctuation">:</span><br /> <span class="token key atrule">stage</span><span class="token punctuation">:</span> deploy<br /> <span class="token key atrule">script</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> yarn install<br /> <span class="token punctuation">-</span> yarn build<br /> <span class="token punctuation">-</span> gzip <span class="token punctuation">-</span>kv <span class="token punctuation">-</span>6 <span class="token punctuation">-</span>r public<br /> <span class="token key atrule">artifacts</span><span class="token punctuation">:</span><br /> <span class="token key atrule">paths</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> public</code></pre>
<p>Je m'arrête là pour parler de Gridsome, mais j'ai quand même prévu de parler de comment gérer mes contenus sur ce site avec <a href="https://www.netlifycms.org/">NetlifyCMS</a>, et comment mettre en place un <code>chroot</code> sur un serveur pour y faire un rsync depuis notre CI afin de déployer notre site.</p>
<p>[^1]: Une différence est que si le Javascript est activé, Gridsome est censé observer les liens internes actuellement affichés à l'écran (avec <a href="https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API"><code>IntersectionObserver</code></a>) pour les précharger afin que les chargements de page soient effectués avant même le clic éventuel sur le lien. Les gains devraient rester minimaux étant donné qu'il n'y a qu'un contenu HTML à récupérer depuis le serveur.</p>
Faire fonctionner le wifi Intel sous Fedora 352021-10-04T09:20:00Zhttps://tcit.fr/post/faire-fonctionner-le-wifi-intel-sous-fedora-35/<p>Si vous avez migré vers la version 35 de Fedora et que vous utilisez une carte Wi-Fi Intel, cela peut vous aider.</p>
<p>Tout d'abord, voyons si vous êtes concerné :</p>
<pre><code>lspci | grep "Network controller"
02:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)
</code></pre>
<p>Si la référence de votre carte correspond à <code>AX2xx</code>, vous êtes probablement concerné.</p>
<p>En Octobre 2021 le microcode pour cette carte <a href="https://bodhi.fedoraproject.org/updates/FEDORA-2021-e353a56911">a été migré</a> dans un paquet séparé du fameux <code>linux-firmware</code>.</p>
<p>Il faut alors installer <code>iwlax2xx-firmware</code> pour faire refonctionner le Wi-Fi. Un redémarrage et c'est reparti.</p>
Imprimer en PDF2022-01-17T09:20:00Zhttps://tcit.fr/post/imprimer-en-pdf/<p>Quand je veux imprimer un fichier PDF sur une imprimante jamais configurée, ça prend souvent des heures sans raison.</p>
<p>Je constate alors ce message dans les logs :</p>
<pre><code>Use "pdftops-renderer" option (see README file) to use Ghostscript or MuPDF for the PDF -> PostScript conversion
</code></pre>
<p>Globalement il me semble que c'est la conversion de PDF en un truc compréhensible par l'imprimante (Ghostscript, PostScript) qui rate.</p>
<p>Sur le web, il est proposé d'utiliser <code>pdftops</code> comme outil de rendu (qui semble utiliser <code>Poppler</code>), mais ce qui marche le mieux pour moi c'est directement d'utiliser <code>Ghostscript</code>.</p>
<pre class="language-bash"><code class="language-bash">lpadmin <span class="token parameter variable">-p</span> mon_imprimante <span class="token parameter variable">-o</span> pdftops-renderer-default<span class="token operator">=</span>gs</code></pre>
<p>Où <code>mon_imprimante</code> est le nom de l'imprimante, que vous pouvez trouver avec <code>lpstat -p</code>.</p>
<p>L'impression se fait alors quasi-instantanément.</p>
Dynamically add enum values in Elixir's GraphQL Library Absinthe2022-03-27T18:22:36Zhttps://tcit.fr/post/dynamically-add-enum-values-in-elixir's-graphql-library-absinthe/<p>Do you have a huge list of value acceptable for a GraphQL enum? Absinthe can dynamically extend the schema at runtime.</p>
<p>While adding a "category" feature to the events in <a href="https://joinmobilizon.org/">Mobilizon</a>, I wanted to restict the values this field could take. Usually I use an enum in the GraphQL schema definition for this kind of situation, for instance:</p>
<pre class="language-elixir"><code class="language-elixir"><span class="token attribute variable">@desc</span> <span class="token string">"The list of join options for an event"</span><br /> enum <span class="token atom symbol">:event_join_options</span> <span class="token keyword">do</span><br /> <span class="token function">value</span><span class="token punctuation">(</span><span class="token atom symbol">:free</span><span class="token punctuation">,</span> <span class="token attr-name">description:</span> <span class="token string">"Anyone can join and is automatically accepted"</span><span class="token punctuation">)</span><br /> <span class="token function">value</span><span class="token punctuation">(</span><span class="token atom symbol">:restricted</span><span class="token punctuation">,</span> <span class="token attr-name">description:</span> <span class="token string">"Manual acceptation"</span><span class="token punctuation">)</span><br /> <span class="token function">value</span><span class="token punctuation">(</span><span class="token atom symbol">:invite</span><span class="token punctuation">,</span> <span class="token attr-name">description:</span> <span class="token string">"Participants must be invited"</span><span class="token punctuation">)</span><br /> <span class="token keyword">end</span></code></pre>
<p>This uses the <code>enum</code> macro and three <code>value</code> macros. But in this case there would be <em>a lot</em> of options for <code>value</code>, so it wouldn't make sense to have them all in the schema declaration.</p>
<p>Moreover, I want this list of categories to be extendable in the future by the instance administrator, who doesn't want to recompile to extend the list.</p>
<p>So the Absinthe docs are far from being perfect, but you can find <a href="https://hexdocs.pm/absinthe/Absinthe.Schema.html#module-custom-schema-manipulation-in-progress">mention of custom schema manipulation</a>. This page, with the help of a few Github issues and <a href="https://github.com/absinthe-graphql/absinthe/blob/master/test/absinthe/schema/manipulation_test.exs#L84-L130">a test file</a>, helped me see clear through this.</p>
<p>For starters, let's create a new module to dynamically build our new enum. There's a few comments inline.</p>
<pre class="language-elixir"><code class="language-elixir"><span class="token keyword">defmodule</span> <span class="token module class-name">Mobilizon</span><span class="token punctuation">.</span><span class="token module class-name">GraphQL</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span><span class="token punctuation">.</span><span class="token module class-name">Custom</span><span class="token punctuation">.</span><span class="token module class-name">EnumTypes</span> <span class="token keyword">do</span><br /> <span class="token keyword">alias</span> <span class="token module class-name">Absinthe</span><span class="token punctuation">.</span><span class="token module class-name">Blueprint</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span><br /> <span class="token keyword">alias</span> <span class="token module class-name">Absinthe</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span><span class="token punctuation">.</span><span class="token module class-name">Notation</span><br /> <span class="token keyword">alias</span> <span class="token module class-name">Absinthe</span><span class="token punctuation">.</span><span class="token punctuation">{</span><span class="token module class-name">Blueprint</span><span class="token punctuation">,</span> <span class="token module class-name">Pipeline</span><span class="token punctuation">,</span> <span class="token module class-name">Phase</span><span class="token punctuation">}</span><br /><br /> <span class="token comment"># The list of categories</span><br /> <span class="token comment"># having an atom identifier and a string label</span><br /> <span class="token comment"># This is currently being defined as a module attribute,</span><br /> <span class="token comment"># but in the future it will be expanded by some admin</span><br /> <span class="token comment"># configuration as well</span><br /> <span class="token attribute variable">@categories</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">%</span><span class="token punctuation">{</span><br /> <span class="token attr-name">id:</span> <span class="token atom symbol">:arts</span><span class="token punctuation">,</span><br /> <span class="token attr-name">label:</span> <span class="token string">"ARTS"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token comment"># … a long list of categories</span><br /> <span class="token punctuation">]</span><br /><br /> <span class="token keyword">def</span> <span class="token function">pipeline</span><span class="token punctuation">(</span>pipeline<span class="token punctuation">)</span> <span class="token keyword">do</span><br /> <span class="token comment"># When to insert this override</span><br /> <span class="token module class-name">Pipeline</span><span class="token punctuation">.</span><span class="token function">insert_after</span><span class="token punctuation">(</span>pipeline<span class="token punctuation">,</span> <span class="token module class-name">Phase</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span><span class="token punctuation">.</span><span class="token module class-name">TypeImports</span><span class="token punctuation">,</span> __MODULE__<span class="token punctuation">)</span><br /> <span class="token keyword">end</span><br /><br /> <span class="token comment"># Adding this enum to the list of schema definitions</span><br /> <span class="token keyword">def</span> <span class="token function">run</span><span class="token punctuation">(</span>blueprint <span class="token operator">=</span> <span class="token punctuation">%</span><span class="token module class-name">Blueprint</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> _<span class="token punctuation">)</span> <span class="token keyword">do</span><br /> <span class="token punctuation">%</span><span class="token punctuation">{</span><span class="token attr-name">schema_definitions:</span> <span class="token punctuation">[</span>schema<span class="token punctuation">]</span><span class="token punctuation">}</span> <span class="token operator">=</span> blueprint<br /><br /> new_enum <span class="token operator">=</span> <span class="token function">build_dynamic_enum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><br /> schema <span class="token operator">=</span><br /> <span class="token module class-name">Map</span><span class="token punctuation">.</span><span class="token function">update!</span><span class="token punctuation">(</span>schema<span class="token punctuation">,</span> <span class="token atom symbol">:type_definitions</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> type_definitions <span class="token operator">-></span><br /> <span class="token punctuation">[</span>new_enum <span class="token operator">|</span> type_definitions<span class="token punctuation">]</span><br /> <span class="token keyword">end</span><span class="token punctuation">)</span><br /><br /> <span class="token punctuation">{</span><span class="token atom symbol">:ok</span><span class="token punctuation">,</span> <span class="token punctuation">%</span><span class="token punctuation">{</span>blueprint <span class="token operator">|</span> <span class="token attr-name">schema_definitions:</span> <span class="token punctuation">[</span>schema<span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">}</span><br /> <span class="token keyword">end</span><br /><br /> <span class="token comment"># Building the enum itself</span><br /> <span class="token keyword">def</span> build_dynamic_enum <span class="token keyword">do</span><br /> <span class="token punctuation">%</span><span class="token module class-name">Schema</span><span class="token punctuation">.</span><span class="token module class-name">EnumTypeDefinition</span><span class="token punctuation">{</span><br /> <span class="token attr-name">name:</span> <span class="token string">"EventCategory"</span><span class="token punctuation">,</span><br /> <span class="token attr-name">identifier:</span> <span class="token atom symbol">:event_category</span><span class="token punctuation">,</span><br /> <span class="token attr-name">module:</span> __MODULE__<span class="token punctuation">,</span><br /> <span class="token attr-name">__reference__:</span> <span class="token module class-name">Notation</span><span class="token punctuation">.</span><span class="token function">build_reference</span><span class="token punctuation">(</span>__ENV__<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token attr-name">values:</span><br /> <span class="token comment"># Create a `Schema.EnumValueDefinition`</span><br /> <span class="token comment"># for each value in `@categories`</span><br /> <span class="token module class-name">Enum</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token attribute variable">@categories</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">%</span><span class="token punctuation">{</span><span class="token attr-name">id:</span> id<span class="token punctuation">,</span> <span class="token attr-name">label:</span> label<span class="token punctuation">}</span> <span class="token operator">-></span><br /> <span class="token punctuation">%</span><span class="token module class-name">Schema</span><span class="token punctuation">.</span><span class="token module class-name">EnumValueDefinition</span><span class="token punctuation">{</span><br /> <span class="token attr-name">identifier:</span> id<span class="token punctuation">,</span><br /> <span class="token comment"># The `value` can either be `id` or `label`</span><br /> <span class="token comment"># depending whether what you want to be given</span><br /> <span class="token attr-name">value:</span> label<span class="token punctuation">,</span><br /> <span class="token attr-name">name:</span> label<span class="token punctuation">,</span><br /> <span class="token attr-name">module:</span> __MODULE__<span class="token punctuation">,</span><br /> <span class="token attr-name">__reference__:</span> <span class="token module class-name">Notation</span><span class="token punctuation">.</span><span class="token function">build_reference</span><span class="token punctuation">(</span>__ENV__<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">end</span><span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">end</span><br /><span class="token keyword">end</span></code></pre>
<p>Finally, we just have to add in our schema definition file the following <code>@pipeline_modifier</code> attribute:</p>
<pre class="language-elixir"><code class="language-elixir"><span class="token keyword">defmodule</span> <span class="token module class-name">Mobilizon</span><span class="token punctuation">.</span><span class="token module class-name">GraphQL</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span> <span class="token keyword">do</span><br /> <span class="token keyword">use</span> <span class="token module class-name">Absinthe</span><span class="token punctuation">.</span><span class="token module class-name">Schema</span><br /><br /> <span class="token attribute variable">@pipeline_modifier</span> <span class="token module class-name">Custom</span><span class="token punctuation">.</span><span class="token module class-name">EnumTypes</span><br /><br /> <span class="token comment"># [… our whole schema]</span><br /><span class="token keyword">end</span></code></pre>
<p>And boom, we can use our new enum just like this:</p>
<pre class="language-elixir"><code class="language-elixir">field <span class="token atom symbol">:create_event</span><span class="token punctuation">,</span> <span class="token attr-name">type:</span> <span class="token atom symbol">:event</span> <span class="token keyword">do</span><br /> <span class="token comment"># …</span><br /> <span class="token function">arg</span><span class="token punctuation">(</span><span class="token atom symbol">:category</span><span class="token punctuation">,</span><br /> <span class="token atom symbol">:event_category</span><span class="token punctuation">,</span><br /> <span class="token comment"># string or atom depending on what you use for value above</span><br /> <span class="token attr-name">default_value:</span> <span class="token string">"ARTS"</span><span class="token punctuation">,</span><br /> <span class="token attr-name">description:</span> <span class="token string">"The event's category"</span><br /> <span class="token punctuation">)</span><br /> <span class="token comment"># …</span><br /><span class="token keyword">end</span></code></pre>