<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://aloxe.codeberg.page/huwindty">
  <title>Huwindty 🌬️</title>
  <description>A basic 11ty starter with tailwind and a CMS.</description>
  <image>
    <url>https://aloxe.codeberg.page/huwindty/img/logo192.png</url>
    <title>Huwindty 🌬️</title>
    <link>https://aloxe.codeberg.page/huwindty</link>
  </image>
  <link href="https://aloxe.codeberg.page/huwindty/feed.xml" rel="self"/>
  <link href="https://aloxe.codeberg.page/huwindty"/>
  <updated>2026-10-15T21:24:41Z</updated>
  <id>https://aloxe.codeberg.page/huwindty</id>
  <author>
    <name>Alix Guillard</name>
  </author>
  <entry>
    <title>Search</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/search/"/>
    <updated>2026-10-15T21:24:41Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/search/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Pagefind&lt;/h2&gt;&lt;p&gt;Pagefind is a search tool that can run on static sites like eleventy. &lt;a href=&quot;https://pagefind.app/&quot;&gt;It claims to perform well on large sites&lt;/a&gt;, but its main interest is to not rely on any external service or infrastructure and use very small bandwidth. This makes it a good choice for smaller sites too.&lt;/p&gt;&lt;p&gt;This choice was guided from &lt;a href=&quot;https://mikefallows.com/posts/adding-search-to-eleventy-site/&quot;&gt;a post from Mike Fallows&lt;/a&gt; going for this option after having checked solutions like Algolia (relying on an external service) and &lt;a href=&quot;https://www.raymondcamden.com/2019/10/20/adding-search-to-your-eleventy-static-site-with-lunr&quot;&gt;adding Lunr to an Eleventy site&lt;/a&gt; which is simpler, works well, but uses much more bandwidth.&lt;/p&gt;&lt;h2&gt;How Pagefind was added to huwindty&lt;/h2&gt;&lt;h3&gt;HTML only search form&lt;/h3&gt;&lt;p&gt;The first thing was to build a fallback search form for users without javascript. This is not a bad idea to think about such users on a static site. This search form, following an example from Zack Leatherman on his &lt;a href=&quot;https://www.zachleat.com/web/pagefind-search/&quot;&gt;pagefind-search web component&lt;/a&gt; is sending requests to DuckDuckGo with instruction to only show results from a certain domain (your site’s domain).&lt;/p&gt;&lt;p&gt;In this case search requests are sent to DuckDuckGo but you can use any other search engine of your choice.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;transition fixed -right-5 top-0 p-2 translate-y-0 mr-5&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;duckduckgo&amp;quot;&lt;/span&gt; &amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- default form is the fallback when nojs --&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;action&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;https://duckduckgo.com/&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;method&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;group/search min-h-2.5&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- min-height to reduce CLS --&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;label&lt;/span&gt;&amp;gt;&lt;/span&gt;
			&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;md:invisible group-focus-within/search:invisible align-bottom cursor-pointer fixed top-6 right-18&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sr-only&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Search :&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt;&amp;gt;&lt;/span&gt; 🔎 &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt;&amp;gt;&lt;/span&gt;
			&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Search this site&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;search&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;searchinput&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;q&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;autocomplete&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;
      w-0 md:w-35 p-0! md:p-2! -mr-6 border-0 border-black md:border bg-white rounded-xl
      fixed top-2 right-10
      delay-100 duration-300 ease-in-out 
      group-focus-within/search:p-2! group-focus-within/search:max-w-[calc(80vw-50px)] group-focus-within/search:w-150 group-focus-within/search:mt-18&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;onfocus&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;loadPagefindUI()&amp;quot;&lt;/span&gt;
      /&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;label&lt;/span&gt;&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sites&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;value&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{meta.url}}&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;form&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In that form, the input that helps the search engine only for your site is the hidden “sites” input. The value of your public site’s URL is coming from the &lt;code&gt;meta.json&lt;/code&gt; data file so that the search result page will only show links to that domain. Make sure this url is the right one.&lt;/p&gt;&lt;p&gt;You’ll also note the label and submit button with &lt;code&gt;&amp;quot;sr-only&amp;quot;&lt;/code&gt; class that make them available on screen readers only when on the screen users will see the magnifying glass.&lt;/p&gt;&lt;h3&gt;Pagefind block&lt;/h3&gt;&lt;p&gt;After that, &lt;a href=&quot;https://pagefind.app/docs/ui-usage/&quot;&gt;Pagefind documentation&lt;/a&gt; suggests to load the pagefind css and javascript files and then to perform some changes after all the page content is loaded.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/pagefind/pagefind-ui.css&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/pagefind/pagefind-ui.js&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;search&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;language-javascript&quot;&gt;
    &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;DOMContentLoaded&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;event&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PagefindUI&lt;/span&gt;({ &lt;span class=&quot;hljs-attr&quot;&gt;element&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#search&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-attr&quot;&gt;showSubResults&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; });
    });
&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To maintain the high performence of page load, I decided on another approach. Css will be added inline just before the html block for search.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;style&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;language-css&quot;&gt;
  &lt;span class=&quot;hljs-selector-class&quot;&gt;.pagefind-ui__message&lt;/span&gt; {
    &lt;span class=&quot;hljs-attribute&quot;&gt;font-weight&lt;/span&gt;: bold;
  }
  &lt;span class=&quot;hljs-selector-class&quot;&gt;.pagefind-ui__results&lt;/span&gt; {
    &lt;span class=&quot;hljs-attribute&quot;&gt;list-style-type&lt;/span&gt;: none;
  }
  &lt;span class=&quot;hljs-selector-class&quot;&gt;.pagefind-ui__result-title&lt;/span&gt; {
    &lt;span class=&quot;hljs-attribute&quot;&gt;margin&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;20px&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10px&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-selector-class&quot;&gt;.pagefind-ui__result-excerpt&lt;/span&gt; {
    &lt;span class=&quot;hljs-attribute&quot;&gt;margin&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;5px&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20px&lt;/span&gt;;
  }
&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;style&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;searchdiv&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;search&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then, the javascript file is loaded only when it is likely to be used, when the user focusses on the search input (by click of by tabulation). This is done with the &lt;code&gt;onfocus=&amp;quot;loadPagefindUI()&lt;/code&gt; that you can see above.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;loadPagefindUI&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) =&amp;gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PagefindUI&lt;/span&gt; === &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt;) {
      &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; script = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;createElement&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;script&amp;#x27;&lt;/span&gt;);
      script.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;type&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;text/javascript&amp;#x27;&lt;/span&gt;);
      script.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;src&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ meta.url }}/pagefind/pagefind-ui.js&amp;quot;&lt;/span&gt;);
      script.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;load&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) {
        &lt;span class=&quot;hljs-title function_&quot;&gt;initPagefindUI&lt;/span&gt;()
      });
      &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;body&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;appendChild&lt;/span&gt;(script);
    }
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When loading the script, you notice an event listener that is loaded once the script is loaded. &lt;code&gt;initPagefindUI()&lt;/code&gt; is the function that hides the fallback input and copies over its styles to the new pagefind input.&lt;/p&gt;&lt;p class=&quot;note&quot;&gt;The src attribute is an absolute URL with &lt;code&gt;{{ meta.url }}&lt;/code&gt;. If the Huwindty site is right after the domain, &lt;code&gt;/pagefind/pagefind-ui.js&lt;/code&gt; is sufficient.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;    &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;duckduckgo&amp;#x27;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;;

    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; searchInput = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;searchinput&amp;#x27;&lt;/span&gt;);
    searchInput.&lt;span class=&quot;hljs-title function_&quot;&gt;removeAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;id&amp;#x27;&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; pageFindForm = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByClassName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pagefind-ui__form&amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
    pageFindForm.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;group/search&amp;#x27;&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; pageFindInput = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByClassName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pagefind-ui__search-input&amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
    pageFindInput.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt; = searchInput.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;;
    pageFindInput.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;id&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;searchinput&amp;#x27;&lt;/span&gt;);
    pageFindInput.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;aria-label&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;search&amp;#x27;&lt;/span&gt;);
    pageFindInput.&lt;span class=&quot;hljs-title function_&quot;&gt;focus&lt;/span&gt;();
    &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByClassName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;pagefind-ui__search-clear &amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pagefind input doesn’t come with a label, so it is added with javascript:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; label = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;createElement&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;LABEL&amp;#x27;&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; labelText = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;createTextNode&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27; 🔎 &amp;#x27;&lt;/span&gt;);
  label.&lt;span class=&quot;hljs-title function_&quot;&gt;appendChild&lt;/span&gt;(labelText);
  label.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;md:invisible&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;group-focus-within/search:invisible&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;p-4&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;align-bottom&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;cursor-pointer&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;absolute&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;top-2&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;right-15&amp;#x27;&lt;/span&gt;);
  label.&lt;span class=&quot;hljs-title function_&quot;&gt;setAttribute&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;for&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;searchinput&amp;#x27;&lt;/span&gt;);
  pageFindInput.&lt;span class=&quot;hljs-title function_&quot;&gt;insertAdjacentElement&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;beforebegin&amp;#x27;&lt;/span&gt;, label);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It also performes a few other style modifications depending on the context. For exemple, the main content of the page is hidden to leave space to search results.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// hide page content if there is a search term&lt;/span&gt;
    pageFindInput.&lt;span class=&quot;hljs-property&quot;&gt;onkeyup&lt;/span&gt; = &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; {
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; hamburger = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hamburger&amp;#x27;&lt;/span&gt;);
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; header = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByTagName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;header&amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; article = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByTagName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;article&amp;#x27;&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; sections = [...&lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementsByTagName&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;section&amp;#x27;&lt;/span&gt;)];
      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (pageFindInput.&lt;span class=&quot;hljs-property&quot;&gt;value&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
        hamburger.&lt;span class=&quot;hljs-property&quot;&gt;checked&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
        header.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;);
        article.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;);
        sections.&lt;span class=&quot;hljs-title function_&quot;&gt;forEach&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;sections&lt;/span&gt;) =&amp;gt;&lt;/span&gt; { sections.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;); });
      } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
        header.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;);
        article.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;);
        sections.&lt;span class=&quot;hljs-title function_&quot;&gt;forEach&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;sections&lt;/span&gt;) =&amp;gt;&lt;/span&gt; { sections.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hidden&amp;#x27;&lt;/span&gt;); });
      }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Pagefind index generation&lt;/h3&gt;&lt;p&gt;The next step is to make sure that pagefind generates its index, right after eleventy generated the static pages. This is done by adding the pagefind command at the end of the &lt;code&gt;eleventy.js&lt;/code&gt; config file.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; { execSync } = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;child_process&amp;#x27;&lt;/span&gt;)
&lt;span class=&quot;hljs-comment&quot;&gt;// (…)&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;// pagefind search&lt;/span&gt;
  eleventyConfig.&lt;span class=&quot;hljs-title function_&quot;&gt;on&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;eleventy.after&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; {
    &lt;span class=&quot;hljs-title function_&quot;&gt;execSync&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;`npx pagefind --source _site --glob &#92;&amp;quot;**/*.html&#92;&amp;quot;`&lt;/span&gt;, { &lt;span class=&quot;hljs-attr&quot;&gt;encoding&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;utf-8&amp;#x27;&lt;/span&gt; })
  })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You may want to restrict the indexed pages by slightly editing the &lt;code&gt;&#92;&amp;quot;**/*.html&#92;&amp;quot;&lt;/code&gt; glob.&lt;/p&gt;&lt;h3&gt;Select useful content&lt;/h3&gt;&lt;p&gt;For each page, you typically want to avoid indexing header, menu and footer. In fact&lt;/p&gt;&lt;p&gt;It is also necessary to tell pagefind where is the useful content of the pages by adding the attribute &lt;code&gt;data-pagefind-body&lt;/code&gt; in the layout for the sections that contain content. Typically, we avoid to index the content of headers, footers and menus.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-pagefind-body&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On Huwindty, the attribute &lt;code&gt;data-pagefind-body&lt;/code&gt; was added to the article part of the home page, index page and the default layout. It doesn’t include the header with its title and headline, but you can add it yourself if this makes sense to you.&lt;/p&gt;&lt;h3&gt;How pagefind search works&lt;/h3&gt;&lt;p&gt;Once you’ve done all this and you generate the eleventy site, it will also generate the &lt;code&gt;pagefind&lt;/code&gt; folder that contains all search scripts and indexed data.&lt;/p&gt;&lt;p&gt;All pages also contain the &lt;code&gt;&amp;lt;div id=&amp;quot;searchdiv&amp;quot; class=&amp;quot;search&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; block that was added in the layout. This block contains the search field and will also contain the list of search results, right under the search input, when users perform a search.&lt;/p&gt;&lt;p&gt;When search result display, it shows in the current page and the page content hides to avoid confusion. All this is presented thanks to the additional styling explained bellow.&lt;/p&gt;&lt;h3&gt;Pagefind styling&lt;/h3&gt;&lt;p&gt;The search form style is handled with the init script.&lt;/p&gt;&lt;p&gt;For the result page, since we don’t use the default pagefind styles, the default styles apply. We made sure that the term highlighting and the button were defined in the default (tailwind.css) theme.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;  &amp;amp; &lt;span class=&quot;hljs-selector-tag&quot;&gt;mark&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;@apply&lt;/span&gt; bg-amber-&lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt;;
  }
  &amp;amp; &lt;span class=&quot;hljs-selector-tag&quot;&gt;button&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;@apply&lt;/span&gt; bg-blue-&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;hljs-attribute&quot;&gt;hover&lt;/span&gt;:bg-blue-&lt;span class=&quot;hljs-number&quot;&gt;800&lt;/span&gt; text-white font-bold py-&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; px-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; rounded-&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;xl;
  }
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Accessibility&lt;/h2&gt;&lt;p&gt;Both fallback and pagefind search should be fully accessible. To make it more accessible, search should be accessible early on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/tabindex&quot;&gt;tabindex&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Because there may be a long menu before the search form, a shortcut link labeled “Search this site” has been added on the very top of the page.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;#searchinput&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;searchthissite&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;fixed transition left-4 top-12 bg-secondary text-bg p-3 m-5 -translate-x-72 focus:translate-x-12 z-2&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Search this site&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Keyboard shortcut&lt;/h3&gt;&lt;p&gt;I had a discussion with Bob Monsour from &lt;a href=&quot;https://11tybundle.dev/&quot;&gt;11tybundle&lt;/a&gt; about adding a shortcut to perform this search. While this sounds practical, this &lt;a href=&quot;https://bobmonsour.com/til/who-knew-that-does-search-in-page-on-firefox/&quot;&gt;may interfere&lt;/a&gt; with some of the browser shortcut. If you want to implement this shortcut, Bob explains &lt;a href=&quot;https://bobmonsour.com/blog/a-keystroke-to-place-focus-in-the-search-box/&quot;&gt;how he did&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Navigation</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/navigation/"/>
    <updated>2026-10-15T21:24:41Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/navigation/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Navigation principles&lt;/h2&gt;&lt;h3&gt;11ty Navigation Plugin&lt;/h3&gt;&lt;p&gt;The &lt;a href=&quot;https://www.11ty.dev/docs/plugins/navigation/&quot;&gt;11ty Navigation Plugin&lt;/a&gt; is a plugin that allows to define and display a navigation menu form pages. It relies on a series of codes added to the &lt;a href=&quot;https://www.11ty.dev/docs/data-frontmatter/&quot;&gt;Front Matter&lt;/a&gt; of pages, giving eanch page at least a key.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;eleventyNavigation:
  key: Bats
  parent: Mammals
  title: The bats
  order: 2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Huwindty doesn’t use this plugin.&lt;/p&gt;&lt;h3&gt;Collections&lt;/h3&gt;&lt;p&gt;In Eleventy, &lt;a href=&quot;https://www.11ty.dev/docs/collections/&quot;&gt;collections&lt;/a&gt; allow you to group pages according to tags added in the front matter. By naming different tags, you can group content in an interesting manner. There is also a &lt;code&gt;collections.all&lt;/code&gt; that lists all pages, even those without tags.&lt;/p&gt;&lt;p&gt;&lt;code&gt;collections.all&lt;/code&gt; lists all pages in a folder that is identified by an index file with front matter. Empty folders or folders without an index.md or with an empty &lt;span&gt;index.md&lt;/span&gt; will not be taken into account.&lt;/p&gt;&lt;p&gt;If you want to exclude a page from the navigation (typically the 404 page and similar), you can exclude it from &lt;code&gt;collections.all&lt;/code&gt; by adding the following line in the page’s front matter:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;eleventyExcludeFromCollections&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Huwindty navigation menu is build automatically from &lt;code&gt;collections.all&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Navigation Menu Structure&lt;/h3&gt;&lt;p&gt;The navigation utilizes &lt;code&gt;collections.all&lt;/code&gt; to list all pages. It displays all first-level pages in the main menu, with nested pages organized under their respective submenus. The menu hierarchy mirrors the exact file structure of the collection’s pages.&lt;/p&gt;&lt;p class=&quot;note&quot;&gt;Collections are sorted by file date. The hierarchy of the navigation follows this order, older first and most recent at the bottom. If you want to change the order of the navigation, just add a &lt;code&gt;date:&lt;/code&gt; within the front matter of each page.&lt;br&gt;&lt;br&gt;You can also reverse the order of the navigation items by adding a filter to the collection value setting &lt;code&gt;{% set allEntries = collections.all | reverse %}&lt;/code&gt;. Doing it in the &lt;strong&gt;menu.njk&lt;/strong&gt; will revert the order in the horizontal menu and doing it in &lt;strong&gt;renderNavItem.njk&lt;/strong&gt; will revert the order in the vertical submenus.&lt;/p&gt;&lt;h3&gt;Index Pages&lt;/h3&gt;&lt;p&gt;Sections appear in the menu as clickable links. Since some of these pages might lack content, you can automatically list the pages within a section by using the &lt;code&gt;index&lt;/code&gt; layout. Additionally, you can include a title for this list using the &lt;code&gt;toc&lt;/code&gt; key in the front matter.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;layout: index
title: Documentation
toc: Table of content
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;How does it work?&lt;/h2&gt;&lt;p&gt;The navigation menu can be added to the nunjucks template of your choice by just including &lt;code&gt;menu.njk&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;{% include &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;menu.njk&amp;quot;&lt;/span&gt; %}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;First loop on collections&lt;/h3&gt;&lt;p&gt;&lt;code&gt;menu.njk&lt;/code&gt; will loop on &lt;code&gt;collections.all&lt;/code&gt; and parse the URL of each entry.&lt;/p&gt;&lt;p&gt;The first-level entries are the ones with 3 chunks (more if you have a long path). From this point we will use the nunjucks macro &lt;code&gt;renderNavItem(entry)&lt;/code&gt; to display the entry in the menu.&lt;/p&gt;&lt;p&gt;If the entry contains nested pages, the macro will handle it by loading itself again (see below).&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% set allEntries = collections.&lt;span class=&quot;hljs-property&quot;&gt;all&lt;/span&gt; %}
  &amp;lt;ul role=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;list&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;flex&amp;quot;&lt;/span&gt;&amp;gt;
    {%- &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; entry &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; allEntries %}
      {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; %}
        {{ &lt;span class=&quot;hljs-title function_&quot;&gt;renderNavItem&lt;/span&gt;(entry) }}
      {% endif %}
    {% endfor %}
  &amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The link to the home page, which has fewer chunks of URL, is hard-coded at the beginning of the navigation. This allows you to shape the link to home the way you want, with the word “home”, another word, or even directly by adding your website’s logo.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;relative group&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt; {% &lt;span class=&quot;hljs-attr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;entry.url&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt; %} &lt;span class=&quot;hljs-attr&quot;&gt;aria-current&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;page&amp;quot;&lt;/span&gt; {% &lt;span class=&quot;hljs-attr&quot;&gt;endif&lt;/span&gt; %}
      &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;block p-4 text-nowrap hover:text-blue-300&amp;quot;&lt;/span&gt;
      &amp;gt;&lt;/span&gt;ॐ sweet home&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Next loop on collections for nested pages&lt;/h3&gt;&lt;p&gt;For each entry, &lt;code&gt;renderNavItem(entry)&lt;/code&gt; will first look if the entry contains nested pages. If it does, it will set them as children.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; menuEntry &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Allentries&lt;/span&gt; %}
    {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; menuEntry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === level + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; %}
      {%  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; menuEntry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;)[level-&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;] === entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;)[level-&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;] %}
        {% set children = (children.&lt;span class=&quot;hljs-title function_&quot;&gt;push&lt;/span&gt;(menuEntry), children) %}
      {% endif %}
    {% endif %}
  {% endfor %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the entry has children it will contain a sub list where all entries will be handled, including their possible subsets, by calling the macro again.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;  {% if children.length %}
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ entry.url }}&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ entry.data.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;list&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
          {%- for child in children %}{{ renderNavItem(child) }}{% endfor -%}
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Entries without children will be displayed normally.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;  {% else %}
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;relative group&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ entry.url }}&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ entry.data.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
  {% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Styling the navigation menu items as needed&lt;/h3&gt;&lt;p&gt;Since the navigation menu is a list with possible sublists, it is rendered on the page the way lists are styled. The styled are applied using tailwind according to their level. They are added to the list loop using smaller macros &lt;code&gt;aClass&lt;/code&gt; and &lt;code&gt;ulClass&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;First level entries are styled with a different colour&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; %}
    block p-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; text-nowrap &lt;span class=&quot;hljs-attr&quot;&gt;hover&lt;/span&gt;:text-blue-&lt;span class=&quot;hljs-number&quot;&gt;300&lt;/span&gt;
  {% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and their sub-blocks display on &lt;code&gt;hover&lt;/code&gt;&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;{% macro &lt;span class=&quot;hljs-title function_&quot;&gt;ulClass&lt;/span&gt;(entry) %}
  {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; %}
    absolute left-&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; hidden bg-bg text-text shadow-lg group-&lt;span class=&quot;hljs-attr&quot;&gt;hover&lt;/span&gt;:block
  {% endif %}
{% endmacro %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Second level entries are displayed under their parent entry, in a drop-down menu.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; %}
    block p-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; text-nowrap &lt;span class=&quot;hljs-attr&quot;&gt;hover&lt;/span&gt;:underline
  {% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We also add a negative margin in case this section has children. These children will show closer to their parent so that the user can identify clearly each section.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  block p-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; text-nowrap &lt;span class=&quot;hljs-attr&quot;&gt;hover&lt;/span&gt;:underline {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; children.&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; %}-mb-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;{% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following entries will display in the same drop-down block with only smaller font and additional padding.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; &amp;gt;= &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; %}
    block px-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; py-&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; text-sm text-nowrap &lt;span class=&quot;hljs-attr&quot;&gt;hover&lt;/span&gt;:underline
  {% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Responsiveness&lt;/h2&gt;&lt;p&gt;On smaller screens the menu is hidden behind a hamburger icon that will toggle on and off the navigation menu without using javascript.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hamburger&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;checkbox&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hamburger&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;md:hidden sr-only peer&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;unchecked&lt;/span&gt; /&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hamburger&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;after:content-[&amp;#x27;≡&amp;#x27;] peer-checked:after:content-[&amp;#x27;✕&amp;#x27;] md:hidden cursor-pointer&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sr-only&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Menu&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;label&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The hamburger is not displayed on larger screens thanks to &lt;code&gt;md:hidden&lt;/code&gt; but it will be focusable and “visible” to screen readers thanks to &lt;code&gt;sr-only&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;What displays on the screen is the after content that depends on if the checkbox is checked (&lt;code&gt;peer-checked:after:content-[&#39;✕&#39;]&lt;/code&gt;) or not (&lt;code&gt;after:content-[&#39;≡&#39;]&lt;/code&gt;).&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;list&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;mt-12 md:mt-0 md:flex hidden peer-checked:block&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Accessibility&lt;/h2&gt;&lt;p&gt;Because the label of the hamburger is not visible on screen, it is necessary to add &lt;code&gt;aria-label=&amp;quot;menu&amp;quot;&lt;/code&gt; to the checkbox input.&lt;/p&gt;&lt;p&gt;Additionaly, there is an aria attribute on the menu entry of the current page.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;{% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; entry.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt; == page.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt; %} aria-current=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;page&amp;quot;&lt;/span&gt;{% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally we want each menu entry to be focussable even when it doesn’t display on the screen. For this we need to do two things: first display the submenus also when the entry menu is focussed, and second to make sure the submenu remains on display when any item is focused. This is the same logic as the &lt;code&gt;:hover&lt;/code&gt; pseudo class but with &lt;code&gt;:focus&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;To style an element depending on the pseudo class of the parent, tailwindcss allows the use of the &lt;a href=&quot;https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-the-descendants-of-a-group&quot;&gt;class &lt;code&gt;group&lt;/code&gt;&lt;/a&gt; that allows many conditions. For example, the following css code:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-selector-tag&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;hljs-selector-pseudo&quot;&gt;:hover&lt;/span&gt; &lt;span class=&quot;hljs-selector-tag&quot;&gt;ul&lt;/span&gt; { &lt;span class=&quot;hljs-attribute&quot;&gt;display&lt;/span&gt;: block; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;can be generated with the following tailwindcss classes:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;group&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/link&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Link&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hidden group-hover:block&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sublink&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;sublink&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same &lt;code&gt;group&lt;/code&gt; class is used for the focus. However, because focus only applies to an anchor without considering the parent elements, we need to use the pseudo-class &lt;code&gt;:focus-within&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;group&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/link&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;Link&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hidden group-hover:block group-focus-within:block&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;sublink&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;sublink&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;ul&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;li&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thanks to this we have a nice menu that can be browsed naturaly using tabindex. No entry can be mised even when using a touchscreen or a screen reader.&lt;/p&gt;&lt;h2&gt;The index pages&lt;/h2&gt;&lt;p&gt;The list of sub pages on &lt;code&gt;index.md&lt;/code&gt; and &lt;code&gt;index.html&lt;/code&gt; pages is displayed thanks to the &lt;code&gt;index.njk&lt;/code&gt; layout. It lists all pages with title and headline. It uses the default style for markdown pages but can be customised the way you want.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  {% &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; post &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; collections.&lt;span class=&quot;hljs-property&quot;&gt;all&lt;/span&gt; %}
    {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; post.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;startsWith&lt;/span&gt;(page.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;) %}
      {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; post.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt; !== page.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt; %}
        {% &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; post.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; === page.&lt;span class=&quot;hljs-property&quot;&gt;url&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;length&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; %}
        &amp;lt;p&amp;gt;
          &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ post.url }}&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ post.data.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;a&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&amp;lt;br&amp;gt;
          &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;em&lt;/span&gt;&amp;gt;&lt;/span&gt;{{post.data.headline}}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;em&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &amp;lt;/p&amp;gt;
        {% endif %}
      {% endif %}
    {% endif %}
  {% endfor %}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Collections and tags&lt;/h2&gt;&lt;p&gt;Huwindty doesn’t come with examples of index that spreads on several pages. This is possible thanks to &lt;a href=&quot;https://www.11ty.dev/docs/pagination/nav/&quot;&gt;eleventy build in pagination&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Tags are not collections and need a little work before they can be paginated. An example of paginated indexes with categories and tags have been implemented using Huwindty and is &lt;a href=&quot;https://alix.guillard.fr/notes/dotclear-to-eleventy/page-navigation/&quot;&gt;documented here&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;What next?&lt;/h2&gt;&lt;p&gt;You may want to update the styles directly in both &lt;code&gt;menu.njk&lt;/code&gt; and &lt;code&gt;renderNavItem.njk&lt;/code&gt; as well as &lt;code&gt;index.njk&lt;/code&gt; so that they fit your needs.&lt;/p&gt;&lt;p&gt;If you do not need such a menu in your website, just remove these files and carry on.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Styles</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/styles/"/>
    <updated>2025-10-15T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/styles/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Tailwind CSS&lt;/h2&gt;&lt;p&gt;Tailwind CSS is a CSS framework that allows you to write more concise and maintainable CSS code thanks to utility classes . Tailwind focuses on providing low-level utility classes that can be combined directly in the markup of any component.&lt;/p&gt;&lt;p&gt;Tailwind CSS generates CSS code using a combination of configuration files, JavaScript, and PostCSS plugins. This generated file only contains the utility classes that are used in the project, thus reducing the size of the final CSS file compared to other CSS frameworks.&lt;/p&gt;&lt;h2&gt;CSS generation&lt;/h2&gt;&lt;p&gt;In the origin starter &lt;a href=&quot;https://github.com/distantcam/windtysdsd&quot;&gt;windty&lt;/a&gt;, css was generated with a separate run script in packages.json. The default &lt;code&gt;npm start&lt;/code&gt; was triggering both 11ty and tailwind generation. The Postcss configuration was in a separate file.&lt;/p&gt;&lt;p&gt;For huwindty, the CSS generation is managed by directly in eleventy.js. It is gererated as any other template &lt;code&gt;styles.css.njk&lt;/code&gt; that includes the css from the main tailwind configuration file: &lt;code&gt;_assets/css/tailwind.css&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;---
&lt;span class=&quot;hljs-attr&quot;&gt;eleventyExcludeFromCollections&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;permalink&lt;/span&gt;: &lt;span class=&quot;hljs-regexp&quot;&gt;/css/&lt;/span&gt;styles.&lt;span class=&quot;hljs-property&quot;&gt;css&lt;/span&gt;
---

{% set css %}
  {% include &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;../../_assets/css/tailwind.css&amp;quot;&lt;/span&gt; %}
{% endset %}
{{css | postcss | safe}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thanks to the &lt;code&gt;permalink: /css/styles.css&lt;/code&gt;, the static site css file is generated in root of the &lt;code&gt;_site&lt;/code&gt; folder.&lt;/p&gt;&lt;p&gt;The file &lt;code&gt;tailwind.css&lt;/code&gt; is the css file that imoports tailwind, it loads it anc contains extra definiions that can but then used in your project. For examplpe it contains a &lt;code&gt;@theme&lt;/code&gt; defining the color scheme and &lt;code&gt;@utility mkdn&lt;/code&gt; that sets the default style of the page content.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;tailwindcss&amp;#x27;&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot;&gt;@theme&lt;/span&gt; {
  &lt;span class=&quot;hljs-attr&quot;&gt;--color-primary&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#155dfc&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* blue-600 */&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;--color-secondary&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#372aac&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* indigo-800 */&lt;/span&gt;
  (…)
}

&lt;span class=&quot;hljs-keyword&quot;&gt;@utility&lt;/span&gt; mkdn {
    &amp;amp; &lt;span class=&quot;hljs-selector-tag&quot;&gt;h2&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;@apply&lt;/span&gt; mt-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt; mb-&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt; text-left text-&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;xl font-bold leading-tight text-secondary &lt;span class=&quot;hljs-attribute&quot;&gt;dark&lt;/span&gt;:text-secondary-dark;
  }
  (…)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The style is processed with tailwind as part of the site generation with a postCSS filter that it added to the layouts in eleventy’s config.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;// Watch targets&lt;/span&gt;
  eleventyConfig.&lt;span class=&quot;hljs-title function_&quot;&gt;addWatchTarget&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;src/_layouts/css/tailwind.css&amp;#x27;&lt;/span&gt;);
  
  &lt;span class=&quot;hljs-comment&quot;&gt;// process css&lt;/span&gt;
  eleventyConfig.&lt;span class=&quot;hljs-title function_&quot;&gt;addNunjucksAsyncFilter&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;postcss&amp;#x27;&lt;/span&gt;, postcssFilter);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The filter is defined in &lt;code&gt;eleventy.js&lt;/code&gt; as a callback that sets the postCSS configuration. After processing the tailwind rendering, it minifies the css with cssnano.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;postcssFilter&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;cssCode, done&lt;/span&gt;) =&amp;gt; {
  &lt;span class=&quot;hljs-title function_&quot;&gt;postCss&lt;/span&gt;([
    &lt;span class=&quot;hljs-title function_&quot;&gt;tailwind&lt;/span&gt;(), &lt;span class=&quot;hljs-comment&quot;&gt;// process tailwind with postcss&lt;/span&gt;
    autoprefixer,
    &lt;span class=&quot;hljs-title function_&quot;&gt;cssnano&lt;/span&gt;({ &lt;span class=&quot;hljs-attr&quot;&gt;preset&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;default&amp;#x27;&lt;/span&gt; }) &lt;span class=&quot;hljs-comment&quot;&gt;// minify css&lt;/span&gt;
  ])
    .&lt;span class=&quot;hljs-title function_&quot;&gt;process&lt;/span&gt;(cssCode, {
      &lt;span class=&quot;hljs-attr&quot;&gt;from&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;./src/_layouts/css/tailwind.css&amp;#x27;&lt;/span&gt;
    })
    .&lt;span class=&quot;hljs-title function_&quot;&gt;then&lt;/span&gt;(
      &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;r&lt;/span&gt;) =&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;done&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;, r.&lt;span class=&quot;hljs-property&quot;&gt;css&lt;/span&gt;),
      &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;e&lt;/span&gt;) =&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;done&lt;/span&gt;(e, &lt;span class=&quot;hljs-literal&quot;&gt;null&lt;/span&gt;)
    );
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This configuration was inspired by the blog post &lt;a href=&quot;https://zenzes.me/eleventy-integrate-postcss-and-tailwind-css/&quot;&gt;How to Integrate PostCSS and Tailwind CSS&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Tailwind and Markdown&lt;/h2&gt;&lt;p&gt;Tailwind CSS is ideal to use in html files, but markdown doesn’t support tailwind utilities. For this, there are two solutions: &lt;em&gt;Create custom Tailwind components&lt;/em&gt; and &lt;em&gt;add classes to the Markdown output&lt;/em&gt;. Both are explained in detail in the blogpost &lt;a href=&quot;https://dev.to/matthewtole/eleventy-markdown-and-tailwind-css-14f8&quot;&gt;Eleventy, Markdown, and Tailwind CSS&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In order to keep markdown files to focus on content I chose to implement the first one (&lt;em&gt;Create custom Tailwind components&lt;/em&gt;) in this starter. These are the rules listed in &lt;code&gt;tailwind.css&lt;/code&gt; under &lt;code&gt;@utility mkdn&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;These default styles can also be rendered within an html file by adding a class &lt;code&gt;mkdn&lt;/code&gt; to an html wrapper element. This is the case for example in the &lt;code&gt;index.njk&lt;/code&gt; layout.&lt;/p&gt;&lt;h3&gt;Additional markdown styles&lt;/h3&gt;&lt;p&gt;In addition, the markdown-it-attrs plugins allows for additional classes to be added to the markdown output. This allows to add specific styles to markdown components.&lt;/p&gt;&lt;p&gt;To apply specific styles, the &lt;code&gt;markdown-it-attrs&lt;/code&gt; plugin is simply added to the call for the markdown parser &lt;code&gt;markdown-it&lt;/code&gt; that is loaded in &lt;code&gt;eleventy.js&lt;/code&gt;. (See &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/documentation/markdown/&quot;&gt;Markdown&lt;/a&gt;)&lt;/p&gt;&lt;p class=&quot;note&quot;&gt;This is capability can get styles look messy very quickly. It is recommanded to only use it for a few classes.&lt;/p&gt;&lt;p&gt;As an example the note above is generated with the following markdown text:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot; tabindex=&quot;0&quot;&gt;This is capability can get css messy very quickly. It is recommanded to only use it for a few classes.{.note}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and is styled thanks to the following css class that is also added under &lt;code&gt;@utility mkdn&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;  &lt;span class=&quot;hljs-selector-class&quot;&gt;.mkdn&lt;/span&gt; &lt;span class=&quot;hljs-selector-class&quot;&gt;.note&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;@apply&lt;/span&gt; text-cyan-&lt;span class=&quot;hljs-number&quot;&gt;900&lt;/span&gt; bg-sky-&lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; border p-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; border-cyan-&lt;span class=&quot;hljs-number&quot;&gt;900&lt;/span&gt; border-l-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;
    &lt;span class=&quot;hljs-attribute&quot;&gt;before&lt;/span&gt;:content-[&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;ⓘ_Note:_&amp;#x27;&lt;/span&gt;] &lt;span class=&quot;hljs-attribute&quot;&gt;before&lt;/span&gt;:font-bold
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is also possible to use tailwind utility classes in markdown. It can be used to add extra style but will not override the defaults defined with &lt;code&gt;@utility mkdn&lt;/code&gt;. These default will always take precedence.&lt;/p&gt;&lt;p class=&quot;p-8 bg-orange-800 text-sky-300 border border-4 border-sky-300&quot;&gt;In this text all utility classes are used except the text colour.&lt;/p&gt;&lt;p&gt;For example, the frame above is styled with the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot; tabindex=&quot;0&quot;&gt;{.p-8 .bg-orange-800 .text-sky-300 .border .border-4 .border-sky-300}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;but you can see that the text is not in the expected colour because the &lt;code&gt;@utility mkdn&lt;/code&gt; defines the colour of the text in every paragraphs and this takes precedence.&lt;/p&gt;&lt;p class=&quot;p-8 bg-orange-800 text-sky-300! border border-4 border-sky-300&quot;&gt;In this text all utility classes are used even the text colour.&lt;/p&gt;&lt;p&gt;You can make the text colour overide the base utility with the &lt;code&gt;!&lt;/code&gt; symbol that acts in tailwind as the usual &lt;code&gt;!important&lt;/code&gt; css. The example above is styled with the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot; tabindex=&quot;0&quot;&gt;{.p-8 .bg-orange-800 .text-sky-300! .border .border-4 .border-sky-300}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Even if you have the capability to use as many styles as you want, use all tailwind utility classes and even &lt;code&gt;!&lt;/code&gt; to orveride base utilities, it is recomanded to keep it simple and use it scarely. Markdown is great to help you focus on your content. You should not ruin it with distracting pieces of code.&lt;/p&gt;&lt;h2&gt;Dark theme&lt;/h2&gt;&lt;p&gt;Users can set their system and browser to favour a dark or light theme. In this case you should deliver pages that correspond to this wish. In CSS, this can be defined with the media feature &lt;code&gt;@media (prefers-color-scheme: dark)&lt;/code&gt;. But you on’t be using it since tailwind will do it for you.&lt;/p&gt;&lt;h3&gt;theme colours&lt;/h3&gt;&lt;p&gt;Themes are defined in &lt;code&gt;tailwind.css&lt;/code&gt; under &lt;code&gt;@theme&lt;/code&gt;. It consists of a collection of preset colours that are used throughout the layouts and templates. Some of these colour variables have a suffix &lt;code&gt;-dark&lt;/code&gt; that defines the colour for the dark theme.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@theme&lt;/span&gt; {
  &lt;span class=&quot;hljs-attr&quot;&gt;--color-primary&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#155dfc&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* blue-600 */&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;--color-secondary&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#372aac&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* indigo-800 */&lt;/span&gt;
(…)

  &lt;span class=&quot;hljs-attr&quot;&gt;--color-primary-dark&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#4657CE&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* blue-400 */&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;--color-secondary-dark&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;#7591f3&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;/* blue-300 */&lt;/span&gt;
(…)
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Using theme colours&lt;/h3&gt;&lt;p&gt;Tailwind allows to use these colour variables as a normal tailwind utility class, replacing the &lt;code&gt;colour&lt;/code&gt; with the name of the element you want to style. For example &lt;code&gt;bg-primary&lt;/code&gt; will be the same as &lt;code&gt;--bg-blue-600&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Every component that should change colour between light and dark theme will use both variables in two different classes. The light colour will be the default and the dark colour will be prefixed by &lt;code&gt;dark:&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For example the medu of the current site changes background colour from blue to dark indigo. &lt;code&gt;bg-primary&lt;/code&gt; and &lt;code&gt;dark:bg-bg-menu-dark&lt;/code&gt; but the text remain white as &lt;code&gt;text-bg&lt;/code&gt; is the only text colour class; there is no &lt;code&gt;dark:text-***&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;nav&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;w-full bg-primary text-bg dark:bg-bg-menu-dark text-xl md:flex-shrink-0&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;navigation&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tailwind documentation has &lt;a href=&quot;https://tailwindcss.com/docs/dark-mode&quot;&gt;more details on dark mode&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Manual theme switcher&lt;/h3&gt;&lt;p&gt;Most of the time the light or dark theme can be set in your browser under Web site appearence and the site that handles it can deliver the right theme for it. Some web sites offer users to manually switch from one theme to another (often with a terrible UX).&lt;/p&gt;&lt;p&gt;If you want to use such toggler, You can follow the instructions in &lt;a href=&quot;https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually&quot;&gt;Toggling dark mode manually&lt;/a&gt; from the Tailwind documentation ans add a custom variant in the main &lt;code&gt;tailwind.css&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;hljs language-css&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@custom-variant&lt;/span&gt; dark (&amp;amp;:where(.dark, .dark *));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The toggler that comes with Huwindty follows these instructions, it will add a class &lt;code&gt;dark&lt;/code&gt; or &lt;code&gt;light&lt;/code&gt; on the main document element &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; and all tailwind classes under &lt;code&gt;dark:&lt;/code&gt; will be generated with the &lt;code&gt;.dark&lt;/code&gt; prefix.&lt;/p&gt;&lt;p&gt;This switch has three positions: light, browser default and dark.&lt;/p&gt;&lt;p&gt;The widget is placed in the footer &lt;code&gt;footer.njk&lt;/code&gt; and used hidden radio buttons. The script &lt;code&gt;src/_assets/js/themeswitch.js&lt;/code&gt; handles the theme changes by doing two things:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Add or remove the &lt;code&gt;dark&lt;/code&gt; or &lt;code&gt;light&lt;/code&gt; class to the main document element &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;documentElement&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt;(theme)
&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&quot;2&quot;&gt;&lt;li&gt;Save the theme choice in the browser local storage&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;localStorage&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;theme&lt;/span&gt; = theme;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When the user choses browser defaults and the theme value is “none”, the html element class is cleared as well as the local storage. But the “dark” class may be added back if the user his browser set in dark mode.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;documentElement&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;toggle&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;matchMedia&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;(prefers-color-scheme: dark)&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;matches&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also, &lt;code&gt;themeswitch.js&lt;/code&gt; primarly checks the local storage or the browser preferences on every page load to add or not the &lt;code&gt;dark&lt;/code&gt; class to the main document element.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;documentElement&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;classList&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;toggle&lt;/span&gt;(
  &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;,
  &lt;span class=&quot;hljs-variable language_&quot;&gt;localStorage&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;theme&lt;/span&gt; === &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt; || (!(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;theme&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable language_&quot;&gt;localStorage&lt;/span&gt;) &amp;amp;&amp;amp; &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;matchMedia&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;(prefers-color-scheme: dark)&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hljs-property&quot;&gt;matches&lt;/span&gt;)
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You may not want to use this manual switcher. In that case, just get rid of it in the footer, delete &lt;code&gt;themeswitch.js&lt;/code&gt; and don’t forget to also remove the &lt;code&gt;@custom-variant&lt;/code&gt; in &lt;code&gt;tailwind.css&lt;/code&gt; without which the natural dark mode will not work.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>RSS Feed</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/rss/"/>
    <updated>2025-10-15T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/rss/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;RSS&lt;/h2&gt;&lt;p&gt;Making the content from one website available to others is called syndication. There are several standard formats for this, and one of the most common is RSS, which stands for Really Simple Syndication. There are also other formats like Atom, which is widely used.&lt;/p&gt;&lt;h2&gt;11ty RSS Plugin&lt;/h2&gt;&lt;p&gt;The &lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;11ty RSS Plugin&lt;/a&gt; is a plugin that provides a range of utilities that are useful for generating an RSS or Atom feed using the Nunjucks templating syntax.&lt;/p&gt;&lt;p&gt;Huwindty comes with the RSS plugin and a feed layout that generates an Atom feed at the root of your site. On this demo site, it is available at &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/feed.xml&quot;&gt;aloxe.codeberg.page/huwindty/feed.xml&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;How does it work?&lt;/h2&gt;&lt;p&gt;The installation of this feed follows the 11ty documentation and uses the Nunjucks layout &lt;code&gt;feed.njk&lt;/code&gt; to shape the feed as desired:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&amp;lt;?xml version=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&amp;gt;
&lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;feed&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;http://www.w3.org/2005/Atom&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xml:base&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ meta.url }}&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.description }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;image&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.url }}{{ meta.image }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.url }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;image&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ meta.url }}{{ permalink }}&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;self&amp;quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ meta.url }}&amp;quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;updated&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ collections.documentation | getNewestCollectionItemDate | dateToRfc3339 }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;updated&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.url }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;author&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ meta.author.name }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;author&lt;/span&gt;&amp;gt;&lt;/span&gt;

{%- for post in collections.documentation | reverse %}
  {%- set absolutePostUrl =  meta.url+post.url %}
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;entry&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ post.data.title }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ absolutePostUrl }}&amp;quot;&lt;/span&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;updated&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ post.date | dateToRfc3339 }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;updated&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ absolutePostUrl }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xml:lang&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{{ meta.language }}&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;html&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;{{ post.templateContent | renderTransforms(post.data.page, meta.url) }}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;content&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;entry&lt;/span&gt;&amp;gt;&lt;/span&gt;
{%- endfor %}

&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;feed&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Define your site’s metadata&lt;/h3&gt;&lt;p&gt;You see that the code above used metadata that defines your site. It is set in the data folder under &lt;code&gt;_data/meta.json&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;hljs&quot; tabindex=&quot;0&quot;&gt;{
  &amp;quot;title&amp;quot;: &amp;quot;Huwindty 🌬️&amp;quot;,
  &amp;quot;url&amp;quot;: &amp;quot;https://aloxe.codeberg.page/huwindty&amp;quot;,
  &amp;quot;description&amp;quot;: &amp;quot;Huwindty enhanced template using 11ty.&amp;quot;,
  &amp;quot;language&amp;quot;: &amp;quot;en&amp;quot;,
  &amp;quot;image&amp;quot;: &amp;quot;/img/logo192.png&amp;quot;,
  &amp;quot;author&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;Alix Guillard&amp;quot;,
    &amp;quot;fediverse&amp;quot;: &amp;quot;@aloxe@mast.eu.org&amp;quot;
  },
&amp;quot;media_folder&amp;quot;: &amp;quot;src/static/img&amp;quot;,
&amp;quot;public_folder&amp;quot;: &amp;quot;/img&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Choose which pages will populate your feed&lt;/h3&gt;&lt;p&gt;The feed is using a collection. You can use the &lt;code&gt;collection.all&lt;/code&gt; to include all pages to your feed but you may also like to share your blog posts or a specific area of your site. In this case you need to create the specific collection.&lt;/p&gt;&lt;h4&gt;Create collection with tags&lt;/h4&gt;&lt;p&gt;As the &lt;a href=&quot;https://www.11ty.dev/docs/collections/&quot;&gt;11ty collection page&lt;/a&gt; states, you can create a collection of pages by adding a &lt;code&gt;tags&lt;/code&gt; key in the front matter of the chosen pages. They will then be part of the collection with the same name as your tags.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;tags: post
&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Create collection with the API&lt;/h4&gt;&lt;p&gt;You can also create the collection programatically by using the &lt;a href=&quot;https://www.11ty.dev/docs/collections-api/&quot;&gt;collection API&lt;/a&gt; and setting it in your eleventyConfig. As an explample, the default Huwindty feed gathers documentation pages that are defined in &lt;code&gt;eleventy.js&lt;/code&gt; from the path to the documentation folder.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// Collections &lt;/span&gt;
eleventyConfig.&lt;span class=&quot;hljs-title function_&quot;&gt;addCollection&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;documentation&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;collection&lt;/span&gt;) {
  &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; collection.&lt;span class=&quot;hljs-title function_&quot;&gt;getFilteredByGlob&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;./src/pages/documentation/**/*.md&amp;quot;&lt;/span&gt;);
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The collection API documentation shows various examples of generating a collection.&lt;/p&gt;&lt;h3&gt;The date&lt;/h3&gt;&lt;p&gt;The feed is loading pages in reverse order with the most recent page on top. You want to make sure you know on which date is your page last updated by adding a &lt;code&gt;date&lt;/code&gt; key in the page’s front matter. Otherewise eleventy will use the file date which may not be handy.&lt;/p&gt;&lt;p&gt;You can use &lt;a href=&quot;https://www.11ty.dev/docs/dates/&quot;&gt;different date format&lt;/a&gt; but I recommand using a simple &lt;code&gt;YYYY-MM-DD&lt;/code&gt; everywhere. The date is then converted to a format accepted by RSS readers thanks to the &lt;code&gt;dateToRfc3339&lt;/code&gt; nunjuncks filter.&lt;/p&gt;&lt;p class=&quot;note&quot;&gt;If you update a post and change the &lt;code&gt;date&lt;/code&gt; in the front matter, the feed will be updated accordingly and the post will rise up in your feed.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Markdown</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/markdown/"/>
    <updated>2025-10-15T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/markdown/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Markdown&lt;/h2&gt;&lt;p&gt;Markdown is a lightweight markup language that allows you to create formatted text using plain text syntax. It is easy to read and write and is often used with 11ty.&lt;/p&gt;&lt;p&gt;Pages using markdown are the same as html pages, they use the same front matter, but the content is written in markdown. The file extension is &lt;code&gt;.md&lt;/code&gt;.&lt;/p&gt;&lt;h2&gt;Markdown configuration&lt;/h2&gt;&lt;p&gt;In this starter, 11ty is parsing markdown with &lt;code&gt;markdown-it&lt;/code&gt; to generate the html pages. The configuration for &lt;code&gt;markdown-it&lt;/code&gt; is in &lt;code&gt;eleventy.js&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; mdit = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;markdown-it&amp;#x27;&lt;/span&gt;);
&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; mditAttrs = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;markdown-it-attrs&amp;#x27;&lt;/span&gt;);
&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; hljs = &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;highlight.js/lib/core&amp;#x27;&lt;/span&gt;);

&lt;span class=&quot;hljs-variable language_&quot;&gt;module&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;exports&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;eleventyConfig&lt;/span&gt;) {
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; mditOptions = {
    &lt;span class=&quot;hljs-attr&quot;&gt;html&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot;&gt;breaks&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot;&gt;linkify&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot;&gt;typographer&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;,
  }
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; mdLib = &lt;span class=&quot;hljs-title function_&quot;&gt;mdit&lt;/span&gt;(mditOptions).&lt;span class=&quot;hljs-title function_&quot;&gt;use&lt;/span&gt;(mditAttrs)
  &lt;span class=&quot;hljs-comment&quot;&gt;// Load any languages you need to highlight&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;// (...)&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;// highlight codeblocksaccording to language&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;// (...)&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;// generate responsive images from Markdown&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;// (...)&lt;/span&gt;
  eleventyConfig.&lt;span class=&quot;hljs-title function_&quot;&gt;setLibrary&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;md&amp;#x27;&lt;/span&gt;, mdLib)
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Plugins&lt;/h2&gt;&lt;p&gt;&lt;code&gt;markdown-it&lt;/code&gt; accepts &lt;a href=&quot;https://mdit-plugins.github.io/&quot;&gt;additional plugins&lt;/a&gt; that help markdown meet your needs.&lt;/p&gt;&lt;p&gt;The following plugins are included in the default configuration:&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-attrs&quot;&gt;markdown-it-attrs&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This plugin allows you to use attributes in markdown syntax. For example, &lt;code&gt;![image](image.png){.logo}&lt;/code&gt; will output &lt;code&gt;image.png&lt;/code&gt;, &lt;code&gt;alt=&amp;quot;image&amp;quot;&lt;/code&gt; and &lt;code&gt;class=&amp;quot;logo&amp;quot;&lt;/code&gt; in the html.&lt;/p&gt;&lt;p&gt;Some examples are available in &lt;a href=&quot;https://giuliachiola.dev/posts/add-html-classes-to-11ty-markdown-content/&quot;&gt;Add HTML classes to 11ty markdown content&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Extra styles in markdown are explained in detail in the &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/documentation/styles/&quot;&gt;style section&lt;/a&gt; of this documentation.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://www.npmjs.com/package/highlight.js&quot;&gt;highlight.js&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This plugin allows you to highlight the code in a code block according the language. For example, &lt;code&gt;&amp;amp;#32;```javascript&lt;/code&gt; will output &lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-javascript&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/code&gt; in the html.&lt;/p&gt;&lt;p&gt;The highlights can be themed, using a stand alone css in &lt;code&gt;src/_assets/public/css/highlightjs.css&lt;/code&gt;. It is a copy of &lt;code&gt;atom-one-dark.min.css&lt;/code&gt;. It is imported from &lt;code&gt;src/layout/includes/head.njk&lt;/code&gt; and you can decide to import it &lt;a href=&quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css&quot;&gt;from a CDN&lt;/a&gt; if you want.&lt;/p&gt;&lt;p&gt;Other themes are available. Check the way they look in the &lt;a href=&quot;https://highlightjs.org/examples&quot;&gt;highlight.js example page&lt;/a&gt; and download them from the CDN or directly from &lt;a href=&quot;https://github.com/highlightjs/highlight.js/tree/main/src/styles&quot;&gt;the highlight.js repository&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You can also define your own theme following &lt;a href=&quot;https://highlightjs.readthedocs.io/en/latest/theme-guide.html&quot;&gt;the guide&lt;/a&gt; from highlightjs.&lt;/p&gt;&lt;h4&gt;accessibility fix&lt;/h4&gt;&lt;p&gt;Code blocks in markdown are styles with a &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; nested in a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;. highlight.js applies the theme with styles on the &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; which always receives a &lt;code&gt;display:block;&lt;/code&gt;. Because of this, when the code in the block overflows, the scrollable region is &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; that could catch the focus.&lt;/p&gt;&lt;p&gt;It is important that scrollable region can be focusable to allow users without a mouse to scroll with the keyboard.&lt;/p&gt;&lt;p&gt;It is easy to fix this issue by removing &lt;code&gt;pre code.hljs{display:block;&lt;/code&gt; in highlightjs.css and adjust the styles to make it look good but it would need to be done each time the them is changed with a new css.&lt;/p&gt;&lt;p&gt;Instead, I chose to make &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; focusable by adding the attribute &lt;code&gt;tabindex=&amp;quot;0&amp;quot;&lt;/code&gt;. This is done in &lt;code&gt;eleventy.js&lt;/code&gt; with &lt;code&gt;mdLib.renderer.rules.fence&lt;/code&gt;, the markdown-it function that defines the html generated for code blocks.&lt;/p&gt;&lt;h2&gt;Pitfalls&lt;/h2&gt;&lt;h3&gt;nunjucks code in Markdown&lt;/h3&gt;&lt;p&gt;Markdown may be limited to achieve some of the custom rendering. To solve this you can include some nunjucks code inside markdown. You can read a few examples of this powerful solution in &lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/custom-markdown-components-in-11ty/&quot;&gt;Custom Markdown Components in 11ty&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;On the other end, this is not possible to directly add nunjucks code quotes in markdown code blocks. To make this possible, you need to change the template engine from nunjucks to markdown, adding &lt;code&gt;templateEngineOverride&lt;/code&gt; in the front matter of the page you want to add the nunjucks code.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;templateEngineOverride: md &lt;span class=&quot;hljs-comment&quot;&gt;# for when you have njk in code blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is explained in detail in &lt;a href=&quot;https://markllobrera.com/posts/eleventy-escaping-nunjucks-statements-in-markdown-code-blocks/&quot;&gt;Eleventy: Escaping Nunjucks Statements in Markdown Code Blocks&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Note that this option is not added in the default pages when they are created by the &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/documentation/cms/&quot;&gt;CMS&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Images&lt;/h3&gt;&lt;p&gt;Markdown is not known to be flexible with styling images, but you find a workaround for most of your wishes. There is an extensive blog post about the matter in &lt;a href=&quot;https://dzone.com/articles/how-to-style-images-with-markdown&quot;&gt;How to Style Images With Markdown&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Responsive images&lt;/h3&gt;&lt;p&gt;Markdown images are automatically rendered as responsive. A specific chapter on responsive images explains how this 11ty starter manages &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/documentation/images/&quot;&gt;responsive images&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Content Managment System</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/cms/"/>
    <updated>2025-08-27T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/cms/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Sveltia CMS&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/sveltia/sveltia-cms&quot;&gt;Sveltia CMS&lt;/a&gt; is a content management system (CMS) designed to provide a user-friendly interface to manage content for static site generators. It is firstly created to be hosted by Netifly. It offers a clean and accessible interface to create and edit pages that are still saved as files on the git repository of your project.&lt;/p&gt;&lt;p&gt;Sveltia CMS is a complete reboot of &lt;strong&gt;Netlify CMS&lt;/strong&gt; whose development was discontinued in 2022 and then rebranded in 2023 under the name &lt;a href=&quot;https://decapcms.org/&quot;&gt;Decap CMS&lt;/a&gt;. Since Sveltia CMS aims to offer all features of the original CMS, there is alost no difference between the two in terms of feature and configuration. For this reason, it is possible to follow the &lt;a href=&quot;https://decapcms.org/docs/basic-steps/&quot;&gt;Decap CMS documentation&lt;/a&gt; while using Sveltia CMS.&lt;/p&gt;&lt;p&gt;Sveltia CMS is a single-page app that is pulled from the page you decide to add it too. In this starter it is available in the typical &lt;a href=&quot;https://aloxe.github.io/huwindty/admin/&quot;&gt;/admin part the public site&lt;/a&gt;. Nevertheless, you will need to go through a few steps before you can take advantage of it.&lt;/p&gt;&lt;h2&gt;Authentication&lt;/h2&gt;&lt;p&gt;Because new content is saved as files on the git repository of your project. You need to have a user that has access to your git repository. For this you will need to create and OAuth Application and set up your git forge to authenticate. The steps described bellow are using OAuth and github.&lt;/p&gt;&lt;h3&gt;Create OAuth Application on github&lt;/h3&gt;&lt;p&gt;Go to the &lt;a href=&quot;https://github.com/settings/applications/new&quot;&gt;Github OAuth settings&lt;/a&gt; from &lt;em&gt;Settings&lt;/em&gt; &amp;gt; &lt;em&gt;Developer Settings&lt;/em&gt; &amp;gt; &lt;em&gt;OAuth Apps&lt;/em&gt; &amp;gt; &lt;em&gt;Generate New&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Fill &lt;em&gt;Homepage URL&lt;/em&gt; with the url of where you will install your external OAuth client. &lt;em&gt;Authorization callback URL&lt;/em&gt; will get the same url followed by ‘callback’ &lt;code&gt;https://example.com/callback&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Then hit on the button [Register application].&lt;/p&gt;&lt;p&gt;On the next step, you will have to create your Client Secret (CLIENT_SECRET) and save it in a secure file. Also save the Client ID (CLIENT_ID).&lt;/p&gt;&lt;h3&gt;Build an external OAuth client on your server&lt;/h3&gt;&lt;p&gt;In Netify, you can set up all you need to deploy and host your site. Netifly will manage your authentication and will let you maintain your site with Sveltia CMS.&lt;/p&gt;&lt;p&gt;If you want to deploy your site elsewhere, you will need an external OAuth client. Decap documentation has &lt;a href=&quot;https://decapcms.org/docs/external-oauth-clients/&quot;&gt;referenced a list&lt;/a&gt; of external apps you can install on your own server. This is the trickiest part of Huwindty as it will stand as a standalone app that your CMS with connect to for authentication purpose.&lt;/p&gt;&lt;p&gt;I chose two apps for this purpose, one is running on node and is served by nginx and the second is a PHP app served by Apache.&lt;/p&gt;&lt;h4&gt;Run netlify-cms-github-oauth-provider on nginx&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/vencax/netlify-cms-github-oauth-provider&quot;&gt;netlify-cms-github-oauth-provider&lt;/a&gt; is available on github and can run locally as well as on a server with nginx as a reverse proxy. The README is well details to run the installation.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;clone&lt;/span&gt; https://github.com/vencax/netlify-cms-github-oauth-provider
&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; netlify-cms-github-oauth-provider
npm install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The configuration can be set in an .env file but can also be part of the launch command line.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;NODE_ENV=production
ORIGINS=www.my_organisation.com,www.my_organisation_second.com
OAUTH_CLIENT_ID=f432a9casdff1e4b79c57
OAUTH_CLIENT_SECRET=pampadympapampadympapampadympa
REDIRECT_URL=https://your.server.com/callback
GIT_HOSTNAME=https://github.website.com
PORT=3111
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before you run the service, you need to set up the nginx for your OAuth domain to act as a reverse proxy.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;location / {
	proxy_pass http://localhost:3111/;
	proxy_http_version 1.1;
	proxy_set_header Upgrade &lt;span class=&quot;hljs-variable&quot;&gt;$http_upgrade&lt;/span&gt;;
	proxy_set_header Connection Upgrade;
	proxy_set_header Host &lt;span class=&quot;hljs-variable&quot;&gt;$host&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The README also explains how tho set the redirections for &lt;code&gt;auth&lt;/code&gt; and &lt;code&gt;callback&lt;/code&gt; in the nginx configuration.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt; location /auth {
    proxy_pass http://127.0.0.1:3111;
    proxy_pass_request_headers      on;
    proxy_set_header   X-Real-IP        &lt;span class=&quot;hljs-variable&quot;&gt;$remote_addr&lt;/span&gt;;
    proxy_set_header   X-Forwarded-For  &lt;span class=&quot;hljs-variable&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;;
    proxy_set_header Early-Data &lt;span class=&quot;hljs-variable&quot;&gt;$ssl_early_data&lt;/span&gt;;
}

location /callback {
    proxy_pass http://127.0.0.1:3111;
    proxy_pass_request_headers      on;
    proxy_set_header   X-Real-IP        &lt;span class=&quot;hljs-variable&quot;&gt;$remote_addr&lt;/span&gt;;
    proxy_set_header   X-Forwarded-For  &lt;span class=&quot;hljs-variable&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;;
    proxy_set_header Early-Data &lt;span class=&quot;hljs-variable&quot;&gt;$ssl_early_data&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After you run the service, you should be able to authenticate from your own server.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make sure the service always run on your server, there are a few additional steps that I won’t detail here. However you can look at this article that details a solution &lt;a href=&quot;https://hostingpile.com/tutorials/how-to-host-multiple-node-js-applications-on-a-single-vps-with-nginx-forever-and-crontab/&quot;&gt;with forever and crontab&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;Run netlify-cms-oauth-provider-php on Apache&lt;/h4&gt;&lt;p&gt;I chose the &lt;a href=&quot;https://github.com/mcdeck/netlify-cms-oauth-provider-php&quot;&gt;PHP Netlify CMS GitHub Oauth&lt;/a&gt; that comes with &lt;a href=&quot;https://www.van-porten.de/blog/2021/01/netlify-auth-provider/&quot;&gt;a blogpost&lt;/a&gt; explaining in detail how to set it up.&lt;/p&gt;&lt;p&gt;In short, you will have to clone the repo and install the dependencies:&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;clone&lt;/span&gt; https://github.com/mcdeck/netlify-cms-oauth-provider-php
&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; netlify-cms-oauth-provider-php
composer install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will then have to copy the &lt;code&gt;.env&lt;/code&gt; file into a new &lt;code&gt;.env.local&lt;/code&gt; where you will add the CLIENT_ID and CLIENT_SECRET and callback url from the OAuth Application that you previously created on github:&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;OAUTH_PROVIDER=github
...
OAUTH_CLIENT_ID=CLIENT_ID
OAUTH_CLIENT_SECRET=CLIENT_SECRET
REDIRECT_URI=https://oauth.example.com/callback
ORIGIN=https://host.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The line with &lt;code&gt;ORIGIN&lt;/code&gt; is the host url of your site. Do not include any path or trailing slash on &lt;code&gt;ORIGIN&lt;/code&gt; or the authentication flow will not redirect to your back-office&lt;/p&gt;&lt;p&gt;You will then have to upload everything from &lt;code&gt;netlify-cms-oauth-provider-php&lt;/code&gt; onto your server. Your server must handle https and php. The root index should point to the &lt;code&gt;public&lt;/code&gt; folder but all other folders should remain there.&lt;/p&gt;&lt;p&gt;When correctly installed, the index page of your Auth site should say ‘‘Hello’’ and offer a link to ‘‘Log in with Github’’. The current starter kit has a link to “&lt;a href=&quot;https://auth.xn--4lj4bfp6d.eu.org/auth&quot;&gt;My login with Github&lt;/a&gt;”.&lt;/p&gt;&lt;h3&gt;User management&lt;/h3&gt;&lt;p&gt;When you use github as authentication provider, users of your CMS will need an account on github and will use it to identify themselves. In order to access the repo, and be able to edit, they need to be given access to your website repository through &lt;em&gt;settings&lt;/em&gt; &amp;gt; &lt;em&gt;collaborators&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;All users will be visible from there so users can be managed on &lt;a href=&quot;https://github.com/aloxe/huwindty/settings/access&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Users can check that they keep access to the repository by editing files. They can also check that the authorisation can access their account. On their profile &amp;gt; &lt;em&gt;settings&lt;/em&gt; &amp;gt; *&lt;a href=&quot;https://github.com/settings/applications&quot;&gt;applications&lt;/a&gt;*.&lt;/p&gt;&lt;h2&gt;The back office configuration&lt;/h2&gt;&lt;p&gt;The back-office already installed with huwindty. You can find it under &lt;code&gt;_assets/public/admin&lt;/code&gt;. This folder contains two files: index.html and config.yml.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The index.html is the page that will load the CMS application.&lt;/li&gt;&lt;li&gt;config.yml is the config file. You can update it to set the behaviour of your CMS.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you prefer to use Decap CMS over Sveltia, simple uncomment the line in index.html, where the decap script is loaded and remove the one for Sveltia.&lt;/p&gt;&lt;h3&gt;Define backend&lt;/h3&gt;&lt;p&gt;In the &lt;code&gt;backend:&lt;/code&gt; section of the config, you will document all details for Svetlia CMS to access and update your git repository.&lt;/p&gt;&lt;p&gt;The name will be the forge system that you use. Currently, Svetlia supports github and gitlab, but the current starter uses github.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;  name: github &lt;span class=&quot;hljs-comment&quot;&gt;# current huwindty has been tested with github only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The repo will be the path to the git repository of your huwidty site on the chosen forge.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;  repo: aloxe/huwindty &lt;span class=&quot;hljs-comment&quot;&gt;# Path to your GitHub repository&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You need to specify the branch where the changes will be committed The branch has to exist on your repository otherwise the CMS will return an error.&lt;/p&gt;&lt;p&gt;If you choose your main branch, all changes that you save in the CMS will be pushed to the main branch and therefore, if &lt;a href=&quot;https://aloxe.github.io/huwindty/documentation/ci/&quot;&gt;the publication pipeline&lt;/a&gt; is in place, will be directly visible on your site.&lt;/p&gt;&lt;p&gt;Since Svetlia doesn’t yet handle content workflow, it is recommended to create a secondary branch for edition that can go through editorial workflow through a pull request.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;  branch: edit &lt;span class=&quot;hljs-comment&quot;&gt;# name of the branch where edits will be pushed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;note&quot;&gt;The content shown in the back office will be the one from the edition branch. If this branch contains many changes that are not merged into your main branch, the back end might be very different from the public site.&lt;/p&gt;&lt;p&gt;Finally, before you can start, you will need to update &lt;code&gt;base_url:&lt;/code&gt; with the url of the CMS OAuth provider you published as explained earlier.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;base_url: https://oauth.example.com &lt;span class=&quot;hljs-comment&quot;&gt;# Path to ext auth provider&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Media folders&lt;/h3&gt;&lt;p&gt;You may also change the &lt;code&gt;media_folder&lt;/code&gt; where all images and media will be uploaded to. The last part, with the &lt;code&gt;collections&lt;/code&gt;, defines what folders and pages are editable by the CMS as well as the fields that will be available in the CMS. Usually you will set here all variables that are present in the Front Matter of your pages.&lt;/p&gt;&lt;p&gt;In the current setup, I used &lt;code&gt;media_folder: &#39;&#39;&lt;/code&gt; and &lt;code&gt;public_folder: &#39;//&#39;&lt;/code&gt; to allow images to be saved in the same folder as the page.&lt;/p&gt;&lt;p&gt;Once the CMS is installed, you can go to your website admin section. (i.e. &lt;a href=&quot;https://aloxe.github.io/huwindty/admin/&quot;&gt;https://aloxe.github.io/huwindty/admin/&lt;/a&gt;), and once you are authenticated with your github account, you can start edit the pages that are in your config file.&lt;/p&gt;&lt;h3&gt;Editable content&lt;/h3&gt;&lt;p&gt;The editable content is defined in the &lt;code&gt;collections:&lt;/code&gt;. It allows you to list which Eleventy page in Eleventy will be editable, describe their properties and define which fields can be modified in the CMS back-officeinterface.&lt;/p&gt;&lt;p&gt;For example, the documentation pages of Huwindty are defined like this:&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;collections:
  - name: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;documentation&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Used in routes, e.g., /admin/collections/blog&lt;/span&gt;
    label: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Documentation&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Used in the UI&lt;/span&gt;
    folder: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;src/pages/documentation&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# The path to the folder where the documents are stored&lt;/span&gt;
    thumbnail: /img/vera.jpg
    columns: [title, &lt;span class=&quot;hljs-built_in&quot;&gt;date&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With media and public folder following the &lt;a href=&quot;https://decapcms.org/docs/collection-folder/#media-and-public-folder&quot;&gt;documentation of Decap CMS&lt;/a&gt;:&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;    media_folder: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# start with a slash&lt;/span&gt;
    public_folder: /documentation
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each page of this collection will have a &lt;code&gt;layout&lt;/code&gt; called “base” and &lt;code&gt;isMarkdown&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;. These will not appear in the CMS but will be set in the front matter. Then the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;headline&lt;/code&gt; can be modified as a string in the CMS.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;hljs language-bash&quot; tabindex=&quot;0&quot;&gt;    create: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Allow users to create new documents in this collection&lt;/span&gt;
    fields: &lt;span class=&quot;hljs-comment&quot;&gt;# All the fields for each document, usually in front matter + body&lt;/span&gt;
      - label: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Layout&amp;quot;&lt;/span&gt;
        name: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;layout&amp;quot;&lt;/span&gt;
        widget: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;
        default: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;base&amp;quot;&lt;/span&gt;
        preview: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
      - label: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;isMarkdown&amp;quot;&lt;/span&gt;
        name: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;isMarkdown&amp;quot;&lt;/span&gt;
        widget: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;
        default: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
        preview: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
      - label: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;
        name: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;
        widget: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt;
      - label: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;headline&amp;quot;&lt;/span&gt;
        name: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;headline&amp;quot;&lt;/span&gt;
        widget: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt;
        required: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;User management with github&lt;/h2&gt;&lt;p&gt;In your repository settings on Github, go to settings &amp;gt; collaborators and click on the button [Add people]. You will be able to add any github user as collaborator. Only people that you added will be able to edit your pages and you can revoke them at any time by removing them from the list.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Images</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/images/"/>
    <updated>2025-01-04T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/images/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Image location&lt;/h2&gt;&lt;p&gt;With the Huwindty starter, images are stored within the content (after all, images are content too). They can be added in any folder and their URL will always be relative to the &lt;code&gt;pages&lt;/code&gt; folder, which is the root folder for content.&lt;/p&gt;&lt;h3&gt;Example image&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-426.webp 426w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-460.webp 460w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-580.webp 580w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-768.webp 768w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-1200.webp 1200w&quot; sizes=&quot;(max-width: 1200px) 70vw, 1200px&quot;&gt;&lt;img decoding=&quot;async&quot; src=&quot;https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-426.jpeg&quot; alt=&quot;drooderfiets and yellow boat&quot; class=&quot;null&quot; width=&quot;1200&quot; height=&quot;732&quot; srcset=&quot;https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-426.jpeg 426w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-460.jpeg 460w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-580.jpeg 580w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-768.jpeg 768w, https://aloxe.codeberg.page/huwindty/img/MG-1bGbWW8-1200.jpeg 1200w&quot; sizes=&quot;(max-width: 1200px) 70vw, 1200px&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;For example, the image above (&lt;code&gt;boat.jpg&lt;/code&gt;) is located in the &lt;code&gt;/src/pages/documentation/&lt;/code&gt; folder and is used by a page in the same folder. The URL used to display it on the page will be &lt;code&gt;/documentation/boat.jpg&lt;/code&gt;. Always use an absolute URL for the image source (starting with a &lt;code&gt;/&lt;/code&gt;).&lt;/p&gt;&lt;h2&gt;Responsive images&lt;/h2&gt;&lt;p&gt;Web pages can be displayed on any screen, from a small phone to a large high-definition, expensive monitor. Displaying a 3000px-wide HD image on a phone is a waste of resources that slows down page rendering. Conversely, showing a 150px picture on a wide monitor might miss some details. Making images responsive is how you provide the appropriate picture to each screen.&lt;/p&gt;&lt;p&gt;The article &lt;a href=&quot;https://cloudfour.com/thinks/responsive-images-101-definitions/&quot;&gt;Responsive images 101&lt;/a&gt; covers everything you need to know about this topic when managing a website.&lt;/p&gt;&lt;h2&gt;Default choice&lt;/h2&gt;&lt;p&gt;The eleventy config provides a way to generate responsive images and store them in the correct location, as well as generating the correct responsive code to use them (see &lt;code&gt;.eleventy.js&lt;/code&gt;). In Huwindty, image sizes and formats are set using the following default settings and can be adjusted according to your layout and needs by changing the &lt;code&gt;Images&lt;/code&gt; enum at the beginning of &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Images&lt;/span&gt; = {
  &lt;span class=&quot;hljs-attr&quot;&gt;WIDTHS&lt;/span&gt;: [&lt;span class=&quot;hljs-number&quot;&gt;426&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;460&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;580&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;768&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1200&lt;/span&gt;], &lt;span class=&quot;hljs-comment&quot;&gt;// sizes of generated images&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;FORMATS&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;webp&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;jpeg&amp;#x27;&lt;/span&gt;], &lt;span class=&quot;hljs-comment&quot;&gt;// formats of generated images&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;SIZES&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;(max-width: 1200px) 70vw, 1200px&amp;#x27;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// size of image rendered&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Markdown pages are parsed with &lt;code&gt;mdLib&lt;/code&gt; and images are handled with the &lt;code&gt;mdLib.renderer.rules.image&lt;/code&gt; rule. Then the &lt;code&gt;eleventyImageTransformPlugin&lt;/code&gt; plugin takes care of rendering the responsive code as defined using &lt;code&gt;eleventy-img&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;It is even simpler in HTML pages, as the &lt;code&gt;eleventyImageTransformPlugin&lt;/code&gt; plugin takes all images in the code to make them responsive. Even images in the layout files are handled.&lt;/p&gt;&lt;p&gt;It is also possible to use the shortcode defined in &lt;code&gt;eleventyConfig.addShortcode(&amp;quot;Picture&amp;quot;…&lt;/code&gt;. This method allows you to define several options to display the image. Only the &lt;code&gt;alt&lt;/code&gt; attribute is compulsory, but you can also override the default width and formats of your image to fit the specific design of your HTML page.&lt;/p&gt;&lt;h2&gt;Responsive picture shortcode&lt;/h2&gt;&lt;p&gt;To get a step-by-step understanding of how the eleventy-img plugin is used to create a shortcode that generates the images and provides the correct code, you can read &lt;a href=&quot;https://dev.to/22mahmoud/how-to-optimize-and-lazyload-images-on-eleventy-11ty-206h&quot;&gt;How to optimize images on eleventy (11ty)&lt;/a&gt;, which has been freely adapted for Huwindty. You may want to add lazy loading and the blurry effect if you wish.&lt;/p&gt;&lt;p&gt;An example is available on the Huwindty home page&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;    {% Picture page, &amp;quot;vera-davidova.jpg&amp;quot;, &amp;quot;Photos of high grass dancing in the wind at the golden hour&amp;quot;, undefined, undefined, undefined, undefined %}
    &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 
    Picture attributes: 
    page, file name, alt text, class, widths, formats, sizes 
    --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The attributes are as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;page&lt;/strong&gt; provides the current path to generate the correct output path. Simply use &lt;code&gt;page&lt;/code&gt; after &lt;code&gt;Picture&lt;/code&gt;, and it will be fine.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;file name&lt;/strong&gt;: In this example, there is no path to the image file since it is in the same folder.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;alt text&lt;/strong&gt; is compulsory for various reasons. I also encourage you to write nice descriptive text that really helps visually impaired users understand your image.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;class&lt;/strong&gt; adds a CSS class to the image so you can change its position and dimensions. The specific class &lt;code&gt;lazy&lt;/code&gt; will also make the image lazy-load.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;widths&lt;/strong&gt; will override the default widths for which the output images will be generated. This is particularly useful if you change the image size using a CSS class; you will want to generate images of the same size.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;formats&lt;/strong&gt; will override the default formats.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;sizes&lt;/strong&gt; will override the default sizes to tell the browser how large the image will be before it is fully downloaded. The default is 100vw, but if you know your image will be displayed on half of the page, you may want to change this to 50vw.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Responsive Images in Markdown&lt;/h2&gt;&lt;p&gt;For Markdown, we implemented what is explained in &lt;a href=&quot;https://tomichen.com/blog/posts/20220416-responsive-images-in-markdown-with-eleventy-image/&quot;&gt;Responsive Images in Markdown with Eleventy Image&lt;/a&gt;, a nice step-by-step blog post explaining how to use markdown-it to parse normal image code in Markdown to generate responsive image HTML code using eleventy-img.&lt;/p&gt;&lt;p&gt;The image below is generated with the simple code&lt;/p&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;hljs language-markdown&quot; tabindex=&quot;0&quot;&gt;![&lt;span class=&quot;hljs-string&quot;&gt;drooderfiets and red circus&lt;/span&gt;](&lt;span class=&quot;hljs-link&quot;&gt;/documentation/circus.jpg&lt;/span&gt;){.lazy}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-426.webp 426w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-460.webp 460w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-580.webp 580w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-768.webp 768w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-1200.webp 1200w&quot; sizes=&quot;(max-width: 1200px) 70vw, 1200px&quot;&gt;&lt;img decoding=&quot;async&quot; src=&quot;https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-426.jpeg&quot; alt=&quot;drooderfiets and red circus&quot; class=&quot;lazy&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;900&quot; srcset=&quot;https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-426.jpeg 426w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-460.jpeg 460w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-580.jpeg 580w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-768.jpeg 768w, https://aloxe.codeberg.page/huwindty/img/lwQLM2MuNh-1200.jpeg 1200w&quot; sizes=&quot;(max-width: 1200px) 70vw, 1200px&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;When you inspect the generated code, you see following responsive HTML:&lt;/p&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;hljs language-html&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;picture&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;image/webp&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;srcset&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/documentation/images/circus-350w.webp 350w, /documentation/images/circus-700w.webp 700w, /documentation/images/circus-750w.webp 750w, /documentation/images/circus-1200w.webp 1200w, /documentation/images/circus-1500w.webp 1500w, /documentation/images/circus-2000w.webp 2000w&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;sizes&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;(max-width: 400px) 380px, (max-width: 470px) 450px, (max-width: 841px) 640px, (max-width: 1100px) 640px, 764px&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;alt&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;drooderfiets and red circus&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;loading&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;decoding&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;async&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/documentation/images/circus-350w.jpeg&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;width&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2000&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;height&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1500&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;srcset&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/documentation/images/circus-350w.jpeg 350w, /documentation/images/circus-700w.jpeg 700w, /documentation/images/circus-750w.jpeg 750w, /documentation/images/circus-1200w.jpeg 1200w, /documentation/images/circus-1500w.jpeg 1500w, /documentation/images/circus-2000w.jpeg 2000w&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;sizes&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;(max-width: 400px) 380px, (max-width: 470px) 450px, (max-width: 841px) 640px, (max-width: 1100px) 640px, 764px&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;picture&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Lazy loading&lt;/h2&gt;&lt;p&gt;Lazy loading images defers their loading on the page until they are actually needed, instead of loading these resources as soon as the page loads. This improves initial page load performance and enhances the user experience.&lt;/p&gt;&lt;p&gt;It is not recommended to lazy-load images that are visible on screen when the page loads (above the fold), but it is possible to defer images that are lower down the page. They will then be loaded as the user scrolls down.&lt;/p&gt;&lt;p&gt;Because of this, not all images can be lazy-loaded by default. Instead, content editors can intentionally request lazy loading by adding &lt;code&gt;&amp;quot;lazy&amp;quot;&lt;/code&gt; as a CSS class. The responsive image script will add &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; to the output code.&lt;/p&gt;&lt;p&gt;The markdown example above shows how to add this class to an image in Markdown.&lt;/p&gt;&lt;h2&gt;Non-responsive images and layout&lt;/h2&gt;&lt;p&gt;As mentioned earlier, images in layout files such as &lt;code&gt;head.njk&lt;/code&gt; are also handled and made responsive. Huwindty does not have images in its layout, but you can add images to them that will be displayed on all pages using the layout file. These images will also be automatically responsive.&lt;/p&gt;&lt;p&gt;If you want an image that keeps its width and format regardless of screen size, you will have to add the attribute &lt;code&gt;eleventy:ignore&lt;/code&gt;. Eleventy will then bypass this tag and &lt;code&gt;eleventyImageTransformPlugin&lt;/code&gt; will not make it responsive. This is quite useful for top-left logos, profile avatars or small icons.&lt;/p&gt;&lt;h2&gt;Images in CMS&lt;/h2&gt;&lt;p&gt;This starter comes with the simple &lt;a href=&quot;https://aloxe.codeberg.page/huwindty/documentation/cms/&quot;&gt;Svetlia CMS&lt;/a&gt; that allows you to add, remove and update pages and media. Images in Svetlia CMS can be added in two ways:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;in a dedicated media folder&lt;br&gt;&lt;em&gt;(All images are available for all pages)&lt;/em&gt;&lt;/li&gt;&lt;li&gt;in the folder of the current page&lt;br&gt;&lt;em&gt;(Images are not reusable in other pages)&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Because the CMS uses Markdown and that images in Markdown are automaticaly converted in responsive pictures, there is nothing else to do other than choose well your images, organise them, and never forget the alt text.&lt;/p&gt;&lt;h2&gt;Thumbnail&lt;/h2&gt;&lt;p&gt;The thumbnail of a page is defined in the front matter. For example the current page has:&lt;/p&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;hljs language-js&quot; tabindex=&quot;0&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;thumbnail&lt;/span&gt;: boat.&lt;span class=&quot;hljs-property&quot;&gt;jpg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This image is shown in the list of pages in the CMS interface, to help you netter spot the content you want to edit.&lt;/p&gt;&lt;p&gt;It is also used as the metadata image of the page. This is for example, the image that will be visible in the snipet when you share the url of a page on social medias.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Continuous Integration</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/ci/"/>
    <updated>2025-01-04T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/ci/</id>
      <content xml:lang="en" type="html">&lt;h2&gt;Github Continuous Integration&lt;/h2&gt;&lt;p&gt;This starter comes with 3 github pipelines that can be used for your project’s continuous integration.&lt;/p&gt;&lt;h3&gt;Deployment to github pages&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;pipeline:&lt;/strong&gt; pages.yml&lt;br&gt;&lt;strong&gt;prerequisites&lt;/strong&gt;: In your repository settings, you need to set github-pages as a new environment.&lt;/p&gt;&lt;p&gt;The pipeline is triggered on every update of the default branch. it will deploy the static site generated by 11ty (in _site) to github pages that will make it available at https://&amp;lt;your_account_name&amp;gt;.github.io/&amp;lt;your_repository_name&amp;gt;&lt;/p&gt;&lt;p&gt;If you choose this solution to publish your site, remember that the &lt;code&gt;url&lt;/code&gt; in the meta.json needs to be updated with &lt;code&gt;your_repository_name&lt;/code&gt;. Also make sure this name is saved in the env variables as BASE_HREF.&lt;/p&gt;&lt;p&gt;More on Github pages: https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site&lt;/p&gt;&lt;h3&gt;Deployment to codeberg pages&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;pipeline:&lt;/strong&gt; .woodpecker.yml&lt;br&gt;&lt;strong&gt;prerequisites&lt;/strong&gt;: Access to woodpecker, codeberg’s CI platform, with set up to access your repository and saved secrets. Your repository should also have a &lt;code&gt;pages&lt;/code&gt; branch.&lt;/p&gt;&lt;p&gt;The pipeline is triggered on every push on the main branch. It will generate the 11ty static site and commit it to the branch &lt;code&gt;pages&lt;/code&gt;. Fron there, codeberg will publish it to https://&amp;lt;your_account_name&amp;gt;.codeberg.org/&amp;lt;your_repository_name&amp;gt;&lt;/p&gt;&lt;p&gt;If you choose this solution to publish your site, remember that the &lt;code&gt;url&lt;/code&gt; in the meta.json needs to be updated with &lt;code&gt;your_repository_name&lt;/code&gt;. Also make sure this name is saved in the env variables as BASE_HREF.&lt;/p&gt;&lt;h4&gt;Steps&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://codeberg.org/Codeberg-e.V./requests/issues/new?template=ISSUE_TEMPLATE%2fWoodpecker-CI.yaml&quot;&gt;apply for codeberg CI access&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.codeberg.org/advanced/access-token/&quot;&gt;Generate an access token for your account&lt;/a&gt;&lt;/li&gt;&lt;li&gt;On &lt;a href=&quot;https://ci.codeberg.org/&quot;&gt;ci.codeberg.org&lt;/a&gt;, add a repository, click the gear and add secrets.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://woodpecker-ci.org/docs/usage/secrets&quot;&gt;woodpecker secrets&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;More on Codeberg CI:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://forgejo.org/docs/latest/user/&quot;&gt;Forgejo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.codeberg.org/codeberg-pages/&quot;&gt;Codeberg Pages&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://woodpecker-ci.org/docs/intro&quot;&gt;Woodpecker CI&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Deployment on a standalone server&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;pipeline:&lt;/strong&gt; test.yml&lt;br&gt;&lt;strong&gt;prerequisites&lt;/strong&gt;: You need to set up your own web server accessible via ssh.&lt;/p&gt;&lt;p&gt;The pipeline is triggered on every update of the branch called &lt;code&gt;test&lt;/code&gt; or manually in the apropriate github action page ‘Deploy 11ty test 🛠️’.&lt;/p&gt;&lt;p&gt;It will copy the static site generated by 11ty (in _site) to the server of your choice using ssh.&lt;/p&gt;&lt;p&gt;To do so, you will need to create an ssh key pair and copy the public key to &lt;code&gt;.ssh/authorized_keys&lt;/code&gt;. You will then need to save in your repository secrets all your server details:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;HOST: the name of your server&lt;/li&gt;&lt;li&gt;USERNAME: your username&lt;/li&gt;&lt;li&gt;KEY: the private ssh key you just created&lt;/li&gt;&lt;li&gt;PORT: the specific port used by your server ssh daemon (if you use the default, it will be 22)&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;note&quot;&gt;You can use duplicate the &lt;code&gt;test.yml&lt;/code&gt; file and set as many pipelines as you want for exemple if you have multiple environement on various servers (staging and production for example). Then you can change the &lt;code&gt;workflow_dispatch:&lt;/code&gt; section, the secrets as well as the path of your html root document after &lt;code&gt;target:&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Accessibility pipeline&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;pipeline:&lt;/strong&gt; axe.yml&lt;br&gt;&lt;strong&gt;prerequisites&lt;/strong&gt;: none&lt;/p&gt;&lt;p&gt;The Accessibility pipeline is triggered on every pull request, it will run &lt;strong&gt;Axe&lt;/strong&gt; on the generated site and return the number of accessibility violations found. If any violation is found, the action logs lists the broblem with explainations on the accessibility rule that is violated. Note that axe only knows the generated html so it cannot tell you which line of your code is wrong.&lt;/p&gt;&lt;p&gt;The current pipeline only tests the homepage accessibility.&lt;/p&gt;&lt;p&gt;Please note that only 20% to 50% of all accessibility issues can automatically be detected. Manual testing is always required.&lt;/p&gt;&lt;h3&gt;Lighthouse pipeline&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;pipeline:&lt;/strong&gt; lighthouse.yml&lt;br&gt;&lt;strong&gt;prerequisites&lt;/strong&gt;: none&lt;/p&gt;&lt;p&gt;Currently the lighthouse pipeline can only be launched manually. It returns errors that may not be fixable but may still provide useful information.&lt;/p&gt;&lt;p&gt;The pipeline will display the error for each test and a link to the lighthouse page that tells you what to do to fix it. If it is all green, you can merge your changes in.&lt;/p&gt;&lt;p&gt;The settings of lighthouse are done in &lt;code&gt;lighthouserc.js&lt;/code&gt; at the root of the project. It is possible to add assertions to focus on certain aspects of lighthouse measurements or allow more flexibility.&lt;/p&gt;&lt;p&gt;The current project tests three pages. It is possible to add more, but be aware that adding too many pages may cause the action to time out.&lt;/p&gt;&lt;p&gt;More on lighthouse-ci: https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/getting-started.md&lt;/p&gt;&lt;p&gt;You can also chech your live site on Lighthouse &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;directly on pagespeed.web.dev&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Documentation</title>
    <link href="https://aloxe.codeberg.page/huwindty/documentation/"/>
    <updated>2024-12-29T00:00:00Z</updated>
    <id>https://aloxe.codeberg.page/huwindty/documentation/</id>
      <content xml:lang="en" type="html"></content>
  </entry>

</feed>