Lukas TrummIdeas about web engineering2023-04-03T00:00:00Zhttps://lukastrumm.com/Lukas Trummlukas.trumm@gmail.comWorking with correct versions of tools in the JavaScript ecosystem2023-04-03T00:00:00Zhttps://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/<p>The ideal is to have the desired version of every tool at every situation during both development and deployment. Docker might be the answer for someone, but it might not be practical to use it all the time. Let’s analyze the situation.</p>
<p>There is an initiative called <a href="https://containers.dev/">devcontainers</a> to improve the practicality of the docker solution, but I’m not going to discuss that in this article.</p>
<h2 id="definitions" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#definitions">Definitions</a></h2>
<p>By <strong>tool,</strong> I mean the runtime (like <code>nodejs</code>), package manager (like <code>pnpm</code>), and others (<code>docker</code>, <code>git</code>, and other CLI tools).</p>
<p>By <strong>situation,</strong> I mean running your first command after <code>git clone</code>, running a command after switching <code>git branch</code>, or running a command in a <code>CI/CD</code> pipeline.</p>
<h3 id="there-are-several-levels-of-perfection" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#there-are-several-levels-of-perfection">There are several levels of perfection</a></h3>
<ol>
<li>Nothing. When something breaks, someone might fix it.</li>
<li>Documentation. <a href="http://readme.md/">README.md</a>. After following the docs carefully, a developer should be on the correct version of tools. Extra communication is necessary when updating versions.</li>
<li>Enforcement. There is configuration in place which forces certain tool versions and refuses to operate otherwise.</li>
<li>Automagic. The environment (either local or in CI) is set up in such a way, that it automatically uses (and installs before) correct versions of tools as configured. Might be harder to achieve without extra maintenance and documentation.</li>
</ol>
<p>Based on these options, I think there is no ideal solution.</p>
<p>For small or personal projects (1) may be enough.
For projects, that are not actively developed, (2) may be appropriate.
When issues with incorrect versions occurs, it is time to make some safeguards (3).
For larger teams or larger amount of projects per developer, it might be beneficial to invest into automation (4).</p>
<h2 id="how-to" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#how-to">How to</a></h2>
<p>A lot of the times it is enough to specify the major version. Like <code>node 18</code>, <code>yarn 1</code> etc. I personally run into most issues because of switching between projects that uses different major versions of tools.</p>
<h3 id="use-the-correct-version-in-ci%2Fcd" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#use-the-correct-version-in-ci%2Fcd">Use the correct version in CI/CD</a></h3>
<p>CI/CD needs to be configured in code, ideally in the same repo as the rest of the application code. That way, the definition of versions are closer between local and production environment. One might choose to use <code>docker</code> to make sure, that the whole environment is the same, but it is not always practical (might be slower for local development, might not fit the app architecture, might require unnecessary know-how).</p>
<h3 id="use-the-correct-version-of-the-runtime" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#use-the-correct-version-of-the-runtime">Use the correct version of the runtime</a></h3>
<p>I will focus on <code>nodejs</code> versions. One might soon need to deal with other runtimes like <code>deno</code> or <code>bun</code>, but leave that for another time.</p>
<p>To enforce a valid version you can use the <code>engines</code> field in <code>package.json</code>.</p>
<pre class="language-json"><code class="language-json"><span class="highlight-line"><span class="token property">"engines"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"node"</span><span class="token operator">:</span> <span class="token string">">=18"</span> <span class="token punctuation">}</span></span></code></pre>
<p>That will inform you about wrong version, but it does not do anything about it. What you want is a tool that installs and/or switches to the correct version whenever you switch directories on your command line.</p>
<p>First, you configure the desired version. Something like this (I use this with <code>fnm</code>, but different tools need different configuration):</p>
<pre class="language-bash"><code class="language-bash"><span class="highlight-line"><span class="token function">node</span> <span class="token parameter variable">--version</span> <span class="token operator">></span> .node-version</span></code></pre>
<p>And then setup a tool and your command line shell. Some options:</p>
<ul>
<li><a href="https://github.com/Schniz/fnm">fnm</a> is simple</li>
<li><a href="https://docs.volta.sh/">volta</a> can manage node, package manager and other tools from NPM</li>
<li><a href="https://asdf-vm.com/">asdf</a> is good when you need to handle more languages</li>
</ul>
<h3 id="use-the-correct-package-manager" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#use-the-correct-package-manager">Use the correct package manager</a></h3>
<p>You can go far with a set of shell aliases or functions. I have recently switched to using <a href="https://github.com/antfu/ni">@antfu/ni</a> and it is way better. You can stop warring about the package manager a given project is using from now.</p>
<h3 id="use-the-correct-version-of-the-package-manager" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#use-the-correct-version-of-the-package-manager">Use the correct version of the package manager</a></h3>
<p>This is more tricky, but using the <code>engines</code> field in <code>package.json</code> can enforce a version range.</p>
<pre class="language-json"><code class="language-json"><span class="highlight-line"><span class="token property">"engines"</span><span class="token operator">:</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">"node"</span><span class="token operator">:</span> <span class="token string">">=18"</span><span class="token punctuation">,</span></span><br /><span class="highlight-line"> <span class="token property">"pnpm"</span><span class="token operator">:</span> <span class="token string">">=7"</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre>
<p>Corepack (mentioned below) should improve this point in the future.</p>
<h3 id="use-the-correct-versions-of-formatting%2C-linting-and-building-tools" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#use-the-correct-versions-of-formatting%2C-linting-and-building-tools">Use the correct versions of formatting, linting and building tools</a></h3>
<p>Define them as <code>devDependencies</code> and use them via <code>scripts</code>. Like <code>nr build</code> from <code>@antfu/ni</code>.</p>
<p>Careful about running them ad hoc, there are a lot of details behind commands like <code>npm exec</code>, <code>npm x</code>, <code>npx</code> , <code>pnpm dlx</code>, <code>pnpm exec</code>, …</p>
<h2 id="alternatives-and-the-future" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#alternatives-and-the-future">Alternatives and the future</a></h2>
<h3 id="helper-npm-packages" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#helper-npm-packages">Helper NPM packages</a></h3>
<p>There are NPM packages that might help (e.g. <a href="https://github.com/pnpm/only-allow">only-allow</a>). The problem is that it might not work all the time (looking at GitHub issues…) and it is an extra dependency.</p>
<h3 id="package-manager-policies" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#package-manager-policies">Package manager policies</a></h3>
<p>If you are using <code>yarn</code> a lot, it might be worth looking it its version enforcement solution, which is <a href="https://classic.yarnpkg.com/en/docs/cli/policies/#toc-policies-set-version">documented here</a>.</p>
<h3 id="corepack" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#corepack">Corepack</a></h3>
<p><a href="https://nodejs.org/api/corepack.html">Corepack</a> probably will be the way to go—it will manage the versions of package managers for you, using <code>"packageManager"</code> field in <code>package.json</code>. It is still experimental and various tools might not work with it yet.</p>
<h2 id="conclusion" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/working-with-correct-versions-of-tools-in-the-javascript-ecosystem/#conclusion">Conclusion</a></h2>
<p>The JavaScript ecosystem is moving fast. If you want to be up to date you need tooling that help you keep your sanity. With tooling that I have described in this article, you can forget about some aspects of dependency management—and that is a good thing.</p>
77+ questions about a web project2023-02-08T00:00:00Zhttps://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/<p>You were asked to build a website? Does it seem it will be a larger one? It
might be the case it will actually not be a website but a webapp. It might need
a team to actually do it. Well, better prepare answers for these couple of
questions :-)</p>
<p></p><div class="table-of-contents"><div class="toc-heading">Table of content</div><ul><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#vision-and-requirements">Vision and requirements</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#communication">Communication</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#technical-environment">Technical environment</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#infrastructure">Infrastructure</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#users">Users</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#code">Code</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#runtime">Runtime</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#seo">SEO</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#performance%2C-ux%2C-a11y">Performance, UX, a11y</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#design">Design</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#legal">Legal</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#maintenance">Maintenance</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#marketing-and-sales">Marketing and sales</a></li><li><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#the-bottom-line">The bottom line</a></li></ul></div><p></p>
<h2 id="vision-and-requirements" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#vision-and-requirements">Vision and requirements</a></h2>
<ul>
<li>Is there a short document <strong>explaining why</strong> this piece of software should
exist and a concise description how it would accomplish that?</li>
<li>Do we have a place for <strong>collecting and prioritizing</strong> requirements?</li>
<li>Are <strong>non-functional requirements</strong> written somewhere?</li>
<li>Do we have a <strong>schedule</strong> or milestones which describes at least roughly what
will be done when?</li>
</ul>
<h2 id="communication" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#communication">Communication</a></h2>
<ul>
<li>Can you think of any <strong>expectations</strong> that are not described by current
requirements?</li>
<li>Will the <strong>customer collaborate</strong> with us on a regular basis?
<sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn1" id="fnref1">[1]</a></sup></li>
</ul>
<h2 id="technical-environment" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#technical-environment">Technical environment</a></h2>
<ul>
<li>Does anyone from the team have a specific <strong>know-how</strong> which is necessary /
effective to leverage for successful completion of the project?</li>
<li>Will there be a reasonable return of investment from <strong>learning</strong> and
implementing new technologies? Would it be easier to hire new people with such
skills?</li>
<li>Are there <strong>existing systems</strong> like CMSes or APIs that needs to be integrated?</li>
<li>Are there existing URL addresses or domains that needs to be <strong>redirected</strong> to
new ones once the new website will be released?</li>
</ul>
<h2 id="infrastructure" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#infrastructure">Infrastructure</a></h2>
<ul>
<li>Is there a possibility that currently running systems will be negatively
impacted after deploying this new application on target domain?</li>
<li>How will we <strong>host</strong> our website or application? Is it possible to change it
now or in the future?</li>
<li>What are the pros and cons of chosen hosting environment over some more
traditional choice?</li>
</ul>
<h2 id="users" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#users">Users</a></h2>
<ul>
<li>Do we have some existing <strong>analytics data</strong>?</li>
<li><strong>How many users</strong> do we expect first day, first month, first year?</li>
<li>Which <strong>browsers</strong> and their versions are going to be supported?</li>
<li>Would the project suffer from missing <strong>accessibility</strong> features? Is it a
subject of regulation?</li>
<li>Is it any good to provide users with a <strong>chatbot</strong> and is it worth the effort
and possible performance issues?</li>
<li>Are there any use cases for our website/application to be used <strong>without
JavaScript</strong> enabled?</li>
<li>Do our users need more language mutations and other <strong>internationalization</strong>
adaptations? Will we need to support a RTL language?</li>
<li>Will we need to build <strong>multiple variants</strong> of the software for different
users/customers?</li>
</ul>
<h2 id="code" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#code">Code</a></h2>
<ul>
<li>What is/will not be in a <strong>version control</strong> system? (like secrets, documents,
etc.)</li>
<li>Is there a <strong><code>README.md</code></strong> file which has enough information for any developer
to run the application, test it or prepare it for production?</li>
<li>Does every developer have an automatic way of <strong>formatting</strong> new code? (in
editor on save, precommit hook)</li>
<li>Is there a process in CI that checks common code <strong>style issues</strong> for every
change? (i.e. linting)</li>
<li>Is there a process in place that ensures that all code is <strong>checked for
quality</strong>? (code reviews, automated tests and checks)</li>
<li>Does every developer know when and how a code review is needed and when it is
appropriate to merge? <sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn2" id="fnref2">[2]</a></sup></li>
<li>Are there some automated <strong>checks for security</strong>? <sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn3" id="fnref3">[3]</a></sup></li>
<li>Is there a <strong>CI/CD</strong> pipeline that deploys every change? (continuous
deployment)</li>
<li>Is there a <strong>preview environment</strong> for every change and is it practical to
have them?</li>
<li>Do we have know-how when and how to use unit <strong>testing</strong>, integration testing
or end-to-end testing?</li>
<li>Do we use the right programming <strong>language</strong> for the job?</li>
<li>Which <strong>framework</strong> do we use, what it solves and what problems it does not
solve?</li>
<li>Is there a way to <strong>generate</strong> some boring boilerplate code?</li>
<li>Do we have a set of <strong>testing data</strong>?</li>
<li>Can we develop against this data set without even running the database?</li>
<li>Will there be only one <strong>version of the software</strong> at a time? Or will we have
to support multiple versions with following maintenance?</li>
</ul>
<h2 id="runtime" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#runtime">Runtime</a></h2>
<ul>
<li>Does the web app handle <strong>redeployments</strong> of static assets seamlessly?</li>
<li>How will the web app handle a breaking <strong>change in backend APIs</strong> while an old
version of frontend code is still running on the client side?</li>
<li>How is the cache on the <strong>CDN</strong> level invalidated?</li>
<li>Do we send correct <strong>security headers</strong>?</li>
<li>Do we send correct <strong>cache</strong> headers for HTML, data requests and assets?</li>
</ul>
<h2 id="seo" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#seo">SEO</a></h2>
<ul>
<li>Does every page have its <strong>canonical URL</strong>? <sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn4" id="fnref4">[4]</a></sup></li>
<li>Does our canonical URLs end with or without a slash? Do all redirects, sitemap
items and links target this canonical URL?</li>
<li>Do our domain default to <strong>www</strong> prefix?</li>
<li>Do we need more control over Google results, and will we use Google search
console? Will we use structured data?</li>
<li>Which website <strong>analytics</strong> solution will be used? Will we try to project for
missing data (blocked by users or usage before consent) and how?</li>
<li>Do we have a complete <strong>sitemap</strong>?</li>
<li>Do we have a <strong>robots.txt</strong>? Does it contain only necessary records?</li>
<li>Do we have a page on the site for every frequent <strong>search term</strong>?</li>
<li>How are we managing <strong>third party scripts</strong>? Do we need Google Tag Manager?
How much will be the performance influenced by third party scripts?</li>
<li>Does the application respond with correct <strong>response codes</strong>? An unknown URL
should be 404 etc.</li>
</ul>
<h2 id="performance%2C-ux%2C-a11y" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#performance%2C-ux%2C-a11y">Performance, UX, a11y</a></h2>
<ul>
<li>Is it OK to display <strong>loading spinners</strong> for 10 seconds on a 3G network before
displaying the content?</li>
<li>Will we have to do <strong>image preprocessing</strong>? Will it be a hosted solution? Do
we care about resolutions and formats of those shipped images?</li>
<li>Is it useful to measure <strong>Core web vitals</strong> regularly/automatically?</li>
<li>Will we use <strong>progressive enhancement</strong> techniques? Does our team have
knowledge to do so?</li>
<li>Are we going to optimize the amount of <strong>generated CSS</strong>? How?</li>
<li>Can be the desired set of fonts optimized in order to prevent <em>Flash of
unstyled fonts</em> for most users?</li>
<li>Which level of <strong>accessibility</strong> will be our target? Do we have someone who
understands accessibility on this level?</li>
<li>Do we have a plan for hallway <strong>usability testing</strong>?
<sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn5" id="fnref5">[5]</a></sup></li>
</ul>
<h2 id="design" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#design">Design</a></h2>
<ul>
<li>How does our <strong>design process</strong> look like? How are responsibilities
distributed among designers, developers, marketers, product or UX people?</li>
<li>Do we need our own <strong>design system</strong>?</li>
<li>Which <strong>tools and techniques</strong> we will use (preprocessing, postprocessing,
feature detection, polyfills, CSS structure and layering, scoping, reset, RTL
support…)?</li>
<li>How will we approach responsive design? <strong>Mobile or desktop first</strong>, strict
set of media queries or more fluid techniques, leverage container queries?</li>
<li>Which <strong>set of icons</strong> we will use? Will it play well with our framework of
choice?</li>
<li>Do we have a live web with our <strong>style guide</strong>?</li>
</ul>
<h2 id="legal" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#legal">Legal</a></h2>
<ul>
<li>Is it necessary to have a <strong>cookie consent</strong> on the website?</li>
<li>In case we need a cookie consent would it be beneficial to use a third party
solution? Will we use the analytics from that solution for something?</li>
<li>Do we need to implement something extra in order to comply with <strong>privacy
laws</strong> like GDPR?</li>
</ul>
<h2 id="maintenance" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#maintenance">Maintenance</a></h2>
<ul>
<li>Where will we <strong>track tasks and bugs</strong>?</li>
<li>How can our <strong>customers report</strong> bugs?</li>
<li>Do we have an automated system for <strong>reporting runtime errors</strong>?</li>
<li>How are our production systems <strong>backuped</strong>? When was the last time we have
done a restoration from those backups?</li>
<li>How often there is a change in some data or source code? For how long will our
system handle the increasing frequency of change?</li>
<li>Which types of changes would our <strong>architecture</strong> allow easily and which would
be hard?</li>
<li>Do we have a place for writing down <strong>maintenance procedures</strong>? (E.g. updating
dependencies, data schema migration, adding redirects, etc.)</li>
<li>Who manages credentials and how? Do we need to use an external service for
them? Do we need to rotate them?</li>
<li>Is there a single place (like a URL) which anybody from the team can visit and
see important links or other useful information about the project? (I call
this a <strong>project signpost</strong>)</li>
<li>Do we need to track special events in the system, like <strong>conversions</strong>?</li>
<li>Do we have a way to automatically check for links that accidentally targets
<strong>PAGE NOT FOUND</strong>?</li>
<li>Does our <strong>monitoring, logging</strong> and tracking solution solve real problems?</li>
</ul>
<h2 id="marketing-and-sales" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#marketing-and-sales">Marketing and sales</a></h2>
<ul>
<li>How does marketing or sales strategy correspond to a <strong>release date</strong> of our
product?</li>
<li>Do we focus enough on <strong>feedback</strong> from users, developers, investors?</li>
</ul>
<h2 id="the-bottom-line" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#the-bottom-line">The bottom line</a></h2>
<p>This is not an exhaustive list, although I was trying to be complete—based on
my experience. BUT keep in mind that it is also critical to <strong>maximize the
amount of work that does not need to be done!</strong> <sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fn6" id="fnref6">[6]</a></sup></p>
<h4 class="footnotes-title">Notes</h4>
<section class="footnotes">
<ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>From <a href="https://agilemanifesto.org/">Agile manifesto</a>:
Customer collaboration over contract negotiation <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>One nice strategy for this is called <a href="https://martinfowler.com/articles/ship-show-ask.html">Ship / Show /
Ask</a> <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>For example GitHub has tools for automated checks of
<a href="https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates">dependencies</a>
and <a href="https://github.com/github/codeql-action">static code analysis</a> <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>There are quite a few rules for canonical URLs so it is best
to consult <a href="https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls">Google search
documentation</a> <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p>Hallway usability testing is mentioned for example
in the famous <a href="https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/">Joel’s
test</a> <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref5" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn6" class="footnote-item"><p>Again a quote from <a href="https://agilemanifesto.org/">Agile
manifesto</a> <a href="https://lukastrumm.com/blog/2023/77+-questions-about-a-web-project/#fnref6" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Multi-branch, multi-language website story2022-12-30T00:00:00Zhttps://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/<p>At the beginning of 2021, which is already almost two years ago, my team and I
have started working on a rather large website. The requirements were
interesting… and as it usually happens they have changed quite significantly
during implementation.</p>
<p>I am going to tell a story about one project where I learned a lot of things.
The project was not a failure, we managed to deliver the solution and it runs in
production, but I will focus on what went wrong.</p>
<h2 id="what-we-got" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#what-we-got">What we got</a></h2>
<p>The initial requirements for the set of websites were roughly these:</p>
<ul>
<li>You will be provided with custom designs for components and pages, the result
should match perfectly</li>
<li>The company has a set of branches and every branch will need its own website,
possibly in multiple languages (!)</li>
<li>Most of the content but not all (!) will be the same</li>
<li>The design must be the same for every website and editors should have very
little room for diverging from the original design</li>
<li>All (!) content should be editable by editors, ideally in a WYSIWYG way,
stored in a CMS</li>
</ul>
<h2 id="what-we-had" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#what-we-had">What we had</a></h2>
<p>A small team and a lot to explain. The deadline can’t be in two months, please.</p>
<p>So we started with prototyping right away. We set first milestone for us to make
a decision about framework, tools and the CMS in 14 days. The first bets looked
promising and we quickly converged to these technologies:</p>
<ul>
<li>Storyblok as a headless CMS</li>
<li>Nuxt 2 as the framework</li>
<li>Bootstrap for its styling internals</li>
<li>Gitlab for pipelines</li>
<li>Azure for hosting</li>
</ul>
<p>Let’s briefly discuss every building block.</p>
<h3 id="cms" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#cms">CMS</a></h3>
<p>Storyblok has very nice compromise between structured and visual editing of the
content. The documentation and integration with VueJS ecosystem were great. We
also liked other features like multi-language support, the flexibility of the
content structure, fast CDN based content delivery and built in image
processing.</p>
<h3 id="nuxt" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#nuxt">Nuxt</a></h3>
<p>Most of our team’s frontend experience were with VueJS, so Nuxt was a natural
choice. The initial requirements looked suitable for a static site builder or a
Jamstack like solution, but we knew it might be challenged in the future and
Nuxt will be ready for that. And it was challenged, but more about that later.</p>
<h3 id="bootstrap-and-sass" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#bootstrap-and-sass">Bootstrap and SASS</a></h3>
<p>The styling looked like a big portion of the whole project. The choice to use
Bootstrap and Sass were again based on our experience. We used only some parts
of the Bootstrap internals and Sass utilities. It led us to a quick start.</p>
<h3 id="gitlab" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#gitlab">Gitlab</a></h3>
<p>Gitlab pipelines became a central part of our solution since we focused on
static generation. While there is nothing bad about Gitlab pipelines
specifically it became the weakest point of the entire system because it was
overused. Data fetching, caching, monorepo tooling and any other logic can be
solved much easier in an application than in a build pipeline.</p>
<h3 id="azure" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#azure">Azure</a></h3>
<p>It was a requirement to use Azure, but unfortunately I don’t remember how it
happened. We spent unreasonable amount of time configuring Azure CDNs and
deployment. Something like a Netlify site would be done 10 times faster.</p>
<h2 id="what-went-wrong" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#what-went-wrong">What went wrong</a></h2>
<p>Let me start from the end. Unfortunately, the contract between companies ended
unexpectedly, and we were not able to pay the technical debt back as we
developers would like to do. Sometimes we have to say ‘It is good enough.’</p>
<p>First challenge was the know-how. I was quite new to a team/tech leader role,
while other colleagues were even new to software development. At the same time
our customer didn’t have a good understanding about the scope of the project.
For example communication with other branches of the company took a long time.
For a long time there was nobody who understands requirements well. These
challenges led to very poor estimations. The go-live deadline was postponed
several months.</p>
<h3 id="cms-1" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#cms-1">CMS</a></h3>
<p>One of the big ideas that we wanted to implement was to have a set of
components, that would hold the same concept for business people, for the CMS,
as well as for developers. Good example would be a Steps component, which
represents a series of steps one have to follow in order to achieve something.
Every step has a number, a title and a description. A concept that can work for
designers, developers and editors. Although we have strived to communicate it
well and show it live in a styleguide to everyone, it was still difficult to
achieve consistency. Storyblok, our CMS of choice, have a concept of a
component. But it is all about discipline to avoid having 4 different Steps
components in the CMS mapping to 3 different components in code. And then
someone needs a 6-step component where so far every aspect of the design of this
component was based on the fact that it can only have a maximum of 5 steps.</p>
<p>I would say that we could do two things to improve this situation. One is to
have a set of shared principles not only between a designer and a developer but
also between business people and editors. Reminds me of Domain driven design and
ubiquitous language. Apparently it can be helpful even in the field of building
websites.</p>
<p>The other thing is automation. We could implement an automated check for
component mapping accross the system, the APIs are waiting to be used…</p>
<p>The last part is documentation. While Storyblok has mostly great docs, there
were some missing guidance for building a large, complex website with multiple
languages.</p>
<p>We have also struggled with one late requirement from the client—to use
Storyblok for writing blog posts, that are enhanced with custom components. At
the time of building the site it was not really possible to have both clean
editing experience and using our own Vue components to build the articles. The
issue is that editors typically support either editing content in fixed page
structure, completely free form page building or writing mostly text, links and
maybe some images (think of CKEditor). We needed something in between where it
would still be acceptable for non-technical editors to create consistent and
rich blog posts.</p>
<h3 id="seo%2C-performance%2C-css" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#seo%2C-performance%2C-css">SEO, performance, CSS</a></h3>
<p>One problematic part was that our client, despite our effort, was reluctant to
give as any input about how performant the site should be and how much we should
focus on SEO. Making a website performant and SEO friendly takes time and has to
be planned. It is important to set some expectations up front, otherwise there
might be some unpleasant surprises. And there were, since we had to prioritize
other things than performance and SEO to meet deadlines.</p>
<p>The performance part was a bit problematic because of Nuxt. At version 2 it was
a great framework for applications, but the frontend had too much Javascript
even in full static generation mode.</p>
<p>Search functionality was another half-baked feature that we have shipped. The
decision was to have at least some search and don’t spend much time with it
rather than involving 3rd party service or a sophisticated backend. This decision
was made based on an idea that visitors come from Google anyway. So the internal
search was based on build in Nuxt/content package, which has a client side
search. Yeah, it means downloading an index in json, which has several
megabytes. A poor man’s solution that worked OK in some situations.</p>
<p>The SEO is a lot of little things that are easier to manage if someone plan to
do them up front. Correct HTTP status codes in all special cases, canonical
urls, handcrafted metadata, etc. etc. We had to go back and improve all of
these in later stages of the project when we got enough agreement and
necessary information.</p>
<p>Styling went mostly well, but there was one area, that we have underestimated.
We have produced unnecessarily big CSS bundles because we were not careful
enough with generating helper classes. When we noticed the problem it was too
late to purge all the redundant styles easily. It was about the time when the
tooling for Tailwind started to be great, it’s a pity… We might have been ok,
if we had handcrafted all the CSS. Even with a huge help from VueJS with scoped
styles, it is hard to keep it on the right track when several new developers
start committing at the same time.</p>
<h3 id="updating-a-static-site" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#updating-a-static-site">Updating a static site</a></h3>
<p>A big misconception we had was about frequency of updates. What first looked
like a mostly static site turned out not to be so.</p>
<p>Static site generation meant (at least for Nuxt at that time) a full rebuild of
the whole site for every code or data change. It might not be a concern running
a 5-minute build couple times a day. But as the pipeline grows the build and
deploy no longer takes 5 minutes but may take 15. And a couple of websites times
a couple of code, data and CMS changes results in too much work the pipelines
has to do in one day. And resulted in unexpected slowdowns in delivery.</p>
<p>Nuxt can be switched to SSR mode with minimal code changes. Unfortunately
because of our infrastructure and for historical reasons we were not able to use
it during the time we had.</p>
<p>Frequent redeployments have another issue. The CDN, caching and Javascript in
the browser has to be setup in such a way so that new deployments are
transparent for the user of the website and does not cause missing assets or
other errors. At the same time it should reasonably cache everything it can to
speed up page load time. The Nuxt SSG site is served as HTML for the initial
page load but is immediately enhanced with Javascript and becomes a single page
application. At the time we had issues making this SPA to be refreshed if a
deployment happened while a user was browsing the website. We had to write some
rather hacky code to improve the situation (involving a forced full page
reload).</p>
<h2 id="what-was-a-success" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#what-was-a-success">What was a success</a></h2>
<p>As far as I know the site was down maybe once because of some DNS issues, but
never because of infrastructure or code bug. Nothing can beat a web statically
hosted from a CDN.</p>
<p>We have managed to implement very nice design system. That is mostly designer’s
credit because she shared with us a set of principles and design tokens that we
have followed all the time. We have created a set of sass variables, utility
classes and base components as building blocks for everything else. That worked
great.</p>
<p>Another great experience was the integration with Storyblok. Its API was flexible
and fast and most of the tasks were straight forward. For example, we needed to
be notified when there was a change published in a subset of the site and that
was convenient with their webhooks.</p>
<h2 id="what-is-the-future" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/multi-branch-multi-language-website-story/#what-is-the-future">What is the future</a></h2>
<p>Rich Harris called it Transitional web apps in one of his
<a href="https://www.youtube.com/watch?v=860d8usGC0o">presentations</a>. The idea is to
extract the best characteristics of multipage architecture and single page apps
into one solution that is, well, transitional. We have used Vue framework which
helped more junior members of our team to quickly became productive. On the
other hand a good old PHP based solution would be better from several
perspectives. A framework implementing the ideas of Transitional web apps could
be very helpful for a project like this. From improving general know-how,
delivering better performance and SEO, to simplifying deployment. The future is
bright I guess…</p>
How I work2022-12-16T00:00:00Zhttps://lukastrumm.com/blog/2022/how-i-work/<p>I feel like it is time to write down some specifics about how I work. This is no
longer changing every year, so it might be useful as a reference for future
collaborations. Also it works for me, so I am going to change it only if
something significant will cross my way.</p>
<p>This is documenting how I have worked in the last several years and what I value
at work. It might be more like a living document more than a blog post.</p>
<ul>
<li>I work from home. I value occasional in person meetings.</li>
<li>I usually work between 6:30 and 15:30 CET, averaging 7 work hours per day.</li>
<li>I go for a run every day, typically before lunchtime.</li>
<li>I work on my personal skills or side projects almost every day, before or
after my work hours depending on when my children needs me more.</li>
<li>Rest of my time is primarily for my family, I do not work in the evening if
not necessary.</li>
<li>During a year I have 30 days on average when I do not work (vacation, sick
days; not including national holidays).</li>
<li>Every week I reserve several time blocks for deep work and weekly review.</li>
<li>I need to know the ‘Why?’ in order to feel comfortable at work. Why is this
piece of technology used here? Why we need to do this before that? How does it
work? And why does it work like this? You can expect these questions from me.</li>
<li>I keep things organized. Creating order out of chaos energizes me, the
opposite is killing me.</li>
<li>I value documentation. I document my progress, my results, my failures. I like
when others write documentation too.</li>
<li>I value simplicity, openness, transparency, honesty and reliability.</li>
<li>Work is serious, the life is more.</li>
</ul>
<h2 id="software-development" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/how-i-work/#software-development">Software development</a></h2>
<ul>
<li>I use Linux (Pop_OS).</li>
<li>I use command line whenever it is suitable.</li>
<li>I love web technologies.</li>
<li>I program in Neovim.</li>
<li>My config and other projects are <a href="https://github.com/lttr/">open on Github</a>.</li>
<li>When applicable I prefer continuous integration as a <a href="https://martinfowler.com/articles/ship-show-ask.html">collaboration
scheme</a>.</li>
</ul>
<h2 id="notes" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2022/how-i-work/#notes">Notes</a></h2>
<p>I’ve written a note about similar topic earlier. It was about <a href="https://lukastrumm.com/notes/key-values">key values at
work</a>.</p>
Reusable components2021-02-15T00:00:00Zhttps://lukastrumm.com/blog/2021/reusable-components/<p>In this article I am trying to summarize a couple of techniques that are
typically used for building reusable components. The idea came to me from a
course on VueJS by Michael Thiessen. I am writing the examples in simple
javascript functions and not in any framework code.</p>
<style>
button {
padding: 0.3rem 0.5rem;
border-radius: 4px;
}
@media (prefers-color-scheme: dark) {
button {
color: var(--text-color);
background: var(--body-back-color);
border-color: var(--primary-color);
}
}
</style>
<p>Video course <a href="https://michaelnthiessen.com/reusable-components">Reusable components by Michael Thiessen</a> is another take on
some basic features of VueJS. Michael is explaining the concepts that one need
to create a reusable component and specific VueJS features only happen to be the
implementation.</p>
<p>I’m going to summarize every technique (Michael calls them <em>levels of
reusability</em>), but I’ll only use simple javascript functions as examples, since
the ideas are not framework dependant.</p>
<h2 id="templating" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#templating">Templating</a></h2>
<p>Is about reusing the same markup. Copy pasting a piece of markup might be a good
starting point. And it might be enough—not everyting needs to be absolutely
DRY and componentized.</p>
<pre class="klipse-fallback language-js"><code class="language-javascript"><span class="highlight-line"><span class="token keyword">const</span> buttonTemplate <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button>😊 </button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button>😊 Foo</button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
const buttonTemplate = `<button>😊 </button>`
function MyButtonComponent() {
return `<button>😊 Foo</button>`
}
MyButtonComponent()
</code></pre><h3 id="result" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#result">Result</a></h3>
<div id="b1"></div>
<script>
function MyButtonComponent() {
return `<button>😊 Foo</button>`
}
document.getElementById('b1').innerHTML = MyButtonComponent()
</script>
<br />
<h2 id="configuration" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#configuration">Configuration</a></h2>
<p>Is parametrized template. This is the core of any templating language. Also this
is how a so called dumb component looks like.</p>
<pre class="klipse-fallback language-js"><code class="language-javascript"><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> text <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button>😊 <em></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>text<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></em></button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"><span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">'My Emphasised Button'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
function MyButtonComponent({ text }) {
return `<button>😊 <em>${text}</em></button>`
}
MyButtonComponent({ text: 'My Emphasised Button' })
</code></pre><h3 id="result-1" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#result-1">Result</a></h3>
<div id="b2"></div>
<script>
function MyButtonComponent({ text }) {
return `<button>😊 <em>${text}</em></button>`
}
document.getElementById('b2').innerHTML = MyButtonComponent({ text: 'My Emphasised Button' })
</script>
<br />
<h2 id="adaptability" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#adaptability">Adaptability</a></h2>
<p>A component is adaptable, when it can be used for different purposes. And it is
typically the case when the component accepts <em>slots</em> for external content.</p>
<pre class="klipse-fallback language-js"><code class="language-javascript"><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token parameter">content</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>content<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"><span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token string">'<strong>My Strong Button 🙍</strong>'</span><span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
function MyButtonComponent(content) {
return `<button>${content}</button>`
}
MyButtonComponent('<strong>My Strong Button 🙍</strong>')
</code></pre><h3 id="result-2" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#result-2">Result</a></h3>
<div id="b3"></div>
<script>
function MyButtonComponent(content) {
return `<button>${content}</button>`
}
document.getElementById('b3').innerHTML = MyButtonComponent('<strong>My Strong Button 🙍</strong>')
</script>
<br />
<h2 id="inversion" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#inversion">Inversion</a></h2>
<p>Only the child component in this example knows a special algorithm to compute
something, while only the parent component knows how to present the information
in text. Passing a funciton as a component property is known as <em>render props</em>.</p>
<pre class="klipse-fallback language-js"><code class="language-javascript"><span class="highlight-line"><span class="token comment">// Child component</span></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token parameter">contentFunction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token function-variable function">computeLevelFromContent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">content</span><span class="token punctuation">)</span> <span class="token operator">=></span> content<span class="token punctuation">.</span>length</span><br /><span class="highlight-line"> <span class="token keyword">const</span> level <span class="token operator">=</span> <span class="token function">computeLevelFromContent</span><span class="token punctuation">(</span><span class="token function">contentFunction</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> content <span class="token operator">=</span> <span class="token function">contentFunction</span><span class="token punctuation">(</span>level<span class="token punctuation">)</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>content<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token comment">// Parent component</span></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">Parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">level</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">My Powerful Button (level: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>level<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"><span class="token function">Parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
// Child component
function MyButtonComponent(contentFunction) {
const computeLevelFromContent = (content) => content.length
const level = computeLevelFromContent(contentFunction(''))
const content = contentFunction(level)
return `<button>${content}</button>`
}
// Parent component
function Parent() {
return MyButtonComponent((level) => `My Powerful Button (level: ${level})`)
}
Parent()
</code></pre><h3 id="result-3" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#result-3">Result</a></h3>
<div id="b4"></div>
<script>
function MyButtonComponent(contentFunction) {
const computeLevelFromContent = (content) => content.length
const level = computeLevelFromContent(contentFunction(''))
const content = contentFunction(level)
return `<button>${content}</button>`
}
document.getElementById('b4').innerHTML
= MyButtonComponent((level) => `My Powerful Button (level: ${level})`)
</script>
<br />
<h2 id="extension" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#extension">Extension</a></h2>
<p>Extensible component is like an adaptable component in this context but with an
<em>extension point</em>. One can provide custom content for this extension point or
use the default. There might be multiple extension points, which would be
implemented as <em>named scoped slots</em> in VueJS for example.</p>
<pre class="klipse-fallback language-js"><code class="language-javascript"><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> buttonText <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>buttonText<span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token function-variable function">buttonText</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">level</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">My Powerful Button (level: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>level<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> <span class="token function-variable function">computeLevelFromContent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">content</span><span class="token punctuation">)</span> <span class="token operator">=></span> content<span class="token punctuation">.</span>length</span><br /><span class="highlight-line"> <span class="token keyword">const</span> level <span class="token operator">=</span> <span class="token function">computeLevelFromContent</span><span class="token punctuation">(</span><span class="token function">buttonText</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span><br /><span class="highlight-line"> <span class="token keyword">const</span> content <span class="token operator">=</span> <span class="token function">buttonText</span><span class="token punctuation">(</span>level<span class="token punctuation">)</span></span><br /><span class="highlight-line"> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><button></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>content<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></button></span><span class="token template-punctuation string">`</span></span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token keyword">function</span> <span class="token function">Parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><br /> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">MyButtonComponent</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /><span class="highlight-line"> <span class="token function-variable function">buttonText</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">level</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>level<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> My Extended Button 😉</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span></span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"><span class="token function">Parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
function MyButtonComponent({ buttonText } = {}) {
if (!buttonText) {
buttonText = (level) => `My Powerful Button (level: ${level})`
}
const computeLevelFromContent = (content) => content.length
const level = computeLevelFromContent(buttonText(''))
const content = buttonText(level)
return `<button>${content}</button>`
}
function Parent() {
return `${MyButtonComponent()} ${MyButtonComponent({
buttonText: (level) => `${level} My Extended Button 😉`,
})}`
}
Parent()
</code></pre><h3 id="result-4" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#result-4">Result</a></h3>
<div id="b5"></div>
<script>
function MyButtonComponent({ buttonText } = {}) {
if (!buttonText) {
buttonText = (level) => `My Powerful Button (level: ${level})`
}
const computeLevelFromContent = (content) => content.length
const level = computeLevelFromContent(buttonText(''))
const content = buttonText(level)
return `<button>${content}</button>`
}
document.getElementById('b5').innerHTML
= `${MyButtonComponent()} ${MyButtonComponent({
buttonText: (level) => `Level ${level}: My Extended Button 😉`,
})}`
</script>
<br />
<h2 id="nesting" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2021/reusable-components/#nesting">Nesting</a></h2>
<p>When we nest components while using previous techniques we end up passing
content from parent components down into nested child components. Slots inside
slots. Maximum adaptability but also maximum cognitive overhead.</p>
<p>In Vue placing a slot that is passed into another component’s slot is not that
bad, but I’m not going to write a convoluted vanilla javascript example. This
piece of Vue template shows a slot that a parent component can use to pass
content down into AdaptableComponent and use all its props.</p>
<p>One interesting aspect of this is that we can decide where we want the content
to come from and where in the hierarchy the default content will be placed.</p>
<pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>AdaptableComponent</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span> <span class="token attr-name">#default</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>scope<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span> <span class="token attr-name">v-bind</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>scope<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>AdaptableComponent</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span></span></code></pre>
You need grit for css grid2020-12-29T00:00:00Zhttps://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/<p>CSS grid is an awesome piece of browser technology. The other side is that the concepts are not super intuitive and there is some work to be done before you can appreciate it. Endurance and passion is needed. Courage. Grit. Especially with those grid lines…</p>
<p>First you need at least a little bit of experience with css grid, because I will dive deep into it rather quickly. Let’s draw a picture.</p>
<style>
.grid-picture-default {
display: grid;
grid-template-rows:
[start] 1fr 30px
[center] repeat(3, 30px) 1fr
[end];
grid-template-columns:
[start] 1fr 30px
[center] repeat(3, 30px) 1fr
[end];
background-color: var(--base03);
width: 300px;
height: 300px;
}
.grid-picture-default .a {
grid-area: start / 2 / center / auto;
background-color: var(--yellow);
}
.grid-picture-default .b {
grid-area: 2 / center / auto / end;
background-color: var(--blue);
}
.grid-picture-default .c {
grid-area: center / center / end / auto;
background-color: var(--red);
}
.grid-picture-default .d {
grid-area: center / 1 / center / center;
background-color: var(--green);
}
</style>
<figure>
<div class="grid-picture-default">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
<figcaption>
This picture was created using css grid with named grid lines and grid-area property
</figcaption>
</figure>
<p>Firefox has been a go to tool to visualize what is going on with css grid. Recently Chrome Dev tools added support too, and it can even show grid line names!</p>
<figure><img src="https://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/css-grid-chrome-devtools.png" alt="" /><figcaption>Previous picture under Chrome Dev tools grid analyzer</figcaption></figure>
<p>Suddenly you can see what is going on. There are six columns and six rows in this grid. There are lines around those columns and rows and some of them have name. These names can help with defining css properties—otherwise it can be very difficult to understand the code. I’m going to build the same picture with several approaches to show you the differencies.</p>
<h2 id="grid-line-numbers" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/#grid-line-numbers">Grid line numbers</a></h2>
<p>Rows and columns are called tracks in css grid. Every track is bounded by lines. Therefore you can target specific locations in grid using line numbers. Grid area is a set of fields occupied by an element. You define the element’s area using <code>grid-area</code> property like this:</p>
<pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">.item</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> <start-row>/<start-column>/<end-row>/<end-column><span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre>
<p>The first approach is to use the line numbers. The <code>auto</code> keyword means default value. A negative number means some number of lines from the end.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.grid-picture-one</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 1fr <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--base03<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-one .a</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> 1 / 2 / 4 / auto<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--yellow<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-one .b</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> 2 / 3 / auto / 7<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--blue<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-one .c</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> 3 / 3 / -1 / auto<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--red<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-one .d</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> 3 / 1 / 3 / 3<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--green<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid-picture-one<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>b<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>c<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.grid-picture-one {
display: grid;
grid-template-rows: 1fr repeat(4, 30px) 1fr;
grid-template-columns: 1fr repeat(4, 30px) 1fr;
background-color: var(--base03);
width: 300px;
height: 300px;
}
.grid-picture-one .a {
grid-area: 1 / 2 / 4 / auto;
background-color: var(--yellow);
}
.grid-picture-one .b {
grid-area: 2 / 3 / auto / 7;
background-color: var(--blue);
}
.grid-picture-one .c {
grid-area: 3 / 3 / -1 / auto;
background-color: var(--red);
}
.grid-picture-one .d {
grid-area: 3 / 1 / 3 / 3;
background-color: var(--green);
}
</style>
<div class="grid-picture-one">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
</code></pre><h2 id="grid-line-names" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/#grid-line-names">Grid line names</a></h2>
<p>You can use line names instead of line number. Line names are those words in [square brackets]. Here is how I have build the initial example.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.grid-picture-two</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span></span><br /><mark class="highlight-line highlight-line-active"> [start] 1fr 30px</mark><br /><mark class="highlight-line highlight-line-active"> [center] <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr</mark><br /><mark class="highlight-line highlight-line-active"> [end]<span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span></span><br /><mark class="highlight-line highlight-line-active"> [start] 1fr 30px</mark><br /><mark class="highlight-line highlight-line-active"> [center] <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr</mark><br /><mark class="highlight-line highlight-line-active"> [end]<span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--base03<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-two .a</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> start / 2 / center / auto<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--yellow<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-two .b</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> 2 / center / auto / end<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--blue<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-two .c</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> center / center / end / auto<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--red<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-two .d</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> center / 1 / center / center<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--green<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid-picture-two<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>b<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>c<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.grid-picture-two {
display: grid;
grid-template-rows:
[start] 1fr 30px
[center] repeat(3, 30px) 1fr
[end];
grid-template-columns:
[start] 1fr 30px
[center] repeat(3, 30px) 1fr
[end];
background-color: var(--base03);
width: 300px;
height: 300px;
}
.grid-picture-two .a {
grid-area: start / 2 / center / auto;
background-color: var(--yellow);
}
.grid-picture-two .b {
grid-area: 2 / center / auto / end;
background-color: var(--blue);
}
.grid-picture-two .c {
grid-area: center / center / end / auto;
background-color: var(--red);
}
.grid-picture-two .d {
grid-area: center / 1 / center / center;
background-color: var(--green);
}
</style>
<div class="grid-picture-two">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
</code></pre><h2 id="named-grid-areas" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/#named-grid-areas">Named grid areas</a></h2>
<p>Another approach is to define the areas all at once using <code>grid-template-areas</code> property.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.grid-picture-three</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 1fr <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span> 1fr<span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token property">grid-template-areas</span><span class="token punctuation">:</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'. a . . . .'</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'. a b b b b'</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'d d c . . .'</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'. . c . . .'</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'. . c . . .'</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token string">'. . c . . .'</span><span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--base03<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-three .a</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> a<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--yellow<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-three .b</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> b<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--blue<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-three .c</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> c<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--red<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-three .d</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> d<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--green<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid-picture-three<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>b<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>c<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.grid-picture-three {
display: grid;
grid-template-rows: 1fr repeat(4, 30px) 1fr;
grid-template-columns: 1fr repeat(4, 30px) 1fr;
grid-template-areas:
'. a . . . .'
'. a b b b b'
'd d c . . .'
'. . c . . .'
'. . c . . .'
'. . c . . .';
background-color: var(--base03);
width: 300px;
height: 300px;
}
.grid-picture-three .a {
grid-area: a;
background-color: var(--yellow);
}
.grid-picture-three .b {
grid-area: b;
background-color: var(--blue);
}
.grid-picture-three .c {
grid-area: c;
background-color: var(--red);
}
.grid-picture-three .d {
grid-area: d;
background-color: var(--green);
}
</style>
<div class="grid-picture-three">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
</code></pre><p>Or you can do the same with special <code>-start</code> and <code>-end</code> grid line names suffixes. But in this case, it is a mess.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.grid-picture-four</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-rows</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> [a-start] 1fr</span><br /><span class="highlight-line"> [b-start] 30px</span><br /><span class="highlight-line"> [a-end b-end c-start d-start] 30px</span><br /><span class="highlight-line"> [d-end] 30px</span><br /><span class="highlight-line"> 30px</span><br /><span class="highlight-line"> 1fr</span><br /><span class="highlight-line"> [c-end]<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span></span><br /><span class="highlight-line"> [d-start] 1fr</span><br /><span class="highlight-line"> [a-start] 30px</span><br /><span class="highlight-line"> [a-end b-start c-start d-end] 30px</span><br /><span class="highlight-line"> [c-end] 30px</span><br /><span class="highlight-line"> 30px</span><br /><span class="highlight-line"> 1fr</span><br /><span class="highlight-line"> [b-end]<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--base03<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-four .a</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> a<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--yellow<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-four .b</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> b<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--blue<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-four .c</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> c<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--red<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.grid-picture-four .d</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">grid-area</span><span class="token punctuation">:</span> d<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--green<span class="token punctuation">)</span><span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid-picture-four<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>b<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>c<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.grid-picture-four {
display: grid;
grid-template-rows:
[a-start] 1fr
[b-start] 30px
[a-end b-end c-start d-start] 30px
[d-end] 30px
30px
1fr
[c-end];
grid-template-columns:
[d-start] 1fr
[a-start] 30px
[a-end b-start c-start d-end] 30px
[c-end] 30px
30px
1fr
[b-end];
background-color: var(--base03);
width: 300px;
height: 300px;
}
.grid-picture-four .a {
grid-area: a;
background-color: var(--yellow);
}
.grid-picture-four .b {
grid-area: b;
background-color: var(--blue);
}
.grid-picture-four .c {
grid-area: c;
background-color: var(--red);
}
.grid-picture-four .d {
grid-area: d;
background-color: var(--green);
}
</style>
<div class="grid-picture-four">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
</code></pre><h2 id="conclusions" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/you-need-grit-for-css-grid/#conclusions">Conclusions</a></h2>
<ul>
<li>grid areas are only shortcuts for a set of grid lines that bound the area</li>
<li><code>grid-template-areas</code> might be the most readable approach for placing elements on specific areas in grid</li>
<li>for more dynamic or bigger grids it might be useful to use line numbers or named lines but the readability goes away rather quickly</li>
</ul>
Power management on Ubuntu and Pop!_OS2020-12-16T00:00:00Zhttps://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/<p>Is it possible to hibernate a Linux machine? What is the difference between sleep, suspend, stand-by and hibernation? Why isn’t my machine waking up after pressing keys on my keyboard?</p>
<figure><img src="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/will-it-sleep.png" alt="" /><figcaption>What is going to happen?</figcaption></figure>
<p>I can finally answer these questions after a long time wondering why something does not work. Let me explain some of the concepts first.</p>
<h2 id="power-management-concepts" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#power-management-concepts">Power management concepts</a></h2>
<p><em>These concepts are general but what I’m describing here might be specific for Ubuntu based Linux systems.</em></p>
<h3 id="sleep-and-suspend" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#sleep-and-suspend">Sleep and suspend</a></h3>
<p>These terms are used interchangeably. The state of your machine is saved to RAM and the computer puts as much as it can to some low power consumption mode. Energy is still consumed and there is a risk of losing unsaved work in case energy is no longer available (e.g. empty battery). The advantage is, that suspending and waking up is fast (couple of seconds in my experience).</p>
<h3 id="hibernate" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#hibernate">Hibernate</a></h3>
<p>When a computer hibernates it saves its state to hard drive and then shuts down. Someone might call it <em>suspend to disk</em>. When it wakes up it restores its state from hard drive into memory. You need space on your hard drive in other to save the state.</p>
<p>Hibernation has most issues, probably because it is dependant on the combination of hardware and operating system. You might not need hibernation—sleep might save enough energy and power off might be fast enough.</p>
<p>Update: Hibernation might be useful. A hibernated system does not consume power
and hibernation protects from some class of possible attacks when the drive is
encrypted as mentioned in <a href="https://support.system76.com/articles/enable-hibernation">this article from System76</a>.</p>
<h3 id="power-off" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#power-off">Power off</a></h3>
<p>Is a normal process of properly shutting down a computer. <em>Halting</em> a computer might be slightly different. As I understand it <em>powering off</em> is a more complete process.</p>
<h3 id="lock-screen" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#lock-screen">Lock screen</a></h3>
<p>When you manually lock your computer or when you are away for some time it provides you with a prompt for password—your computer is locked. The same happens when the computer is waking up.</p>
<h3 id="log-out" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#log-out">Log out</a></h3>
<p>Shuts down your running applications (it might not stop all of the background processes) and effectively locks the screen.</p>
<h3 id="idle-time" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#idle-time">Idle time</a></h3>
<p>Is a time when the computer evaluates that it is doing nothing. From the practical point of view the computer can be configured to do something useful after some specific time of beiing idle and it might lock the screen or suspend itself.</p>
<h3 id="standby-and-awake" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#standby-and-awake">Standby and awake</a></h3>
<p>I believe you can’t directly force your computer to go into those states, those are probably internal. In <em>awake</em> state all components are running, while in <em>standby</em> state harddisks and other peripherials might be turned off.</p>
<h2 id="shutting-down" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#shutting-down">Shutting down</a></h2>
<p>Or rather sleeping down because at least for me, suspending is way more convenient (read: faster) way of ending my work. I usually hit a dedicated key on my keyboard (a cheep Cherry keyboard). Another way is to let your machine sleep after a specific time. In Gnome settings there is an item called Automatic suspend (Settings ➙ Power), where you can set it up. Wierdly enough you need Gnome Tweaks to set the suspend action after closing a lid of your notebook (it is in General section there).</p>
<h2 id="waking-up" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#waking-up">Waking up</a></h2>
<p>A reasonable way to wake up your computer is to hit some key on a keyboard. It might sound simple, but there are issues with external keyboards for notebooks or wireless keyboards. In my case I have checked <a href="https://askubuntu.com/">askUbuntu</a> and my BIOS settings and found a disabled option. Now I can wake up my notebook (from sleep) using keyboard (not mouse—but I like it) which is connected via USB dongle.</p>
<h2 id="sources" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/power-management-on-ubuntu-and-pop_os/#sources">Sources</a></h2>
<ul>
<li><a href="https://askubuntu.com/questions/369760/what-are-the-differences-between-sleep-standby-suspend-and-hibernate-in-ubuntu">https://askubuntu.com/questions/369760/what-are-the-differences-between-sleep-standby-suspend-and-hibernate-in-ubuntu</a></li>
<li><a href="https://askubuntu.com/questions/848698/wake-up-from-suspend-using-wireless-usb-keyboard-or-mouse-for-any-linux-distro/1155666#1155666">https://askubuntu.com/questions/848698/wake-up-from-suspend-using-wireless-usb-keyboard-or-mouse-for-any-linux-distro/1155666#1155666</a></li>
<li><a href="https://help.ubuntu.com/stable/ubuntu-help/power-suspend.html.en">https://help.ubuntu.com/stable/ubuntu-help/power-suspend.html.en</a></li>
<li><a href="https://help.ubuntu.com/stable/ubuntu-help/shell-exit.html.en#suspend">https://help.ubuntu.com/stable/ubuntu-help/shell-exit.html.en#suspend</a></li>
<li><a href="https://wiki.ubuntu.com/PowerManagement">https://wiki.ubuntu.com/PowerManagement</a></li>
<li><a href="https://help.ubuntu.com/stable/ubuntu-help/session-screenlocks.html.en">https://help.ubuntu.com/stable/ubuntu-help/session-screenlocks.html.en</a></li>
<li><a href="https://support.system76.com/articles/enable-hibernation">https://support.system76.com/articles/enable-hibernation</a></li>
</ul>
Flexbox zombies2020-11-14T00:00:00Zhttps://lukastrumm.com/blog/2020/flexbox-zombies/<p>Recently I have finished the Flexbox zombies game. The way the author forces you to deliberately practice a skill is great.</p>
<p><a href="https://flexboxzombies.com/">Flexbox zombies</a> is an online course that teaches you the <code>display: flex</code> css property. It presents quite a boring topic—placing items on a screen—in a very atractive way.</p>
<p>Even if you think you know css flexbox I would still recommend it, because it is interesting how it is presented directly inside a browser and everything is interactive. And you will probably find out you don’t know everything. I have found a couple of new facts and following are some notes about it.</p>
<h2 id="start-with-display%3A-flex" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#start-with-display%3A-flex">Start with display: flex</a></h2>
<p>The number of times one have to write <code>display: flex</code> in the course is overwhelming, but at the end, it was worth it. As the author said—it is about deliberate practice.</p>
<p>Lets define a class with <code>display: flex</code> and a couple of other properties.</p>
<style>
.flex-container {
display: flex;
width: 300px;
height: 100px;
background: rebeccapurple;
}
.flex-item {
color: white;
background: darkcyan;
}
</style>
<pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">.flex-container</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background</span><span class="token punctuation">:</span> rebeccapurple<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token selector">.flex-item</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background</span><span class="token punctuation">:</span> darkcyan<span class="token punctuation">;</span></span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre>
<h2 id="flexible-width" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#flexible-width">Flexible width</a></h2>
<p>Width is flexible—who would guess?</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.my-box</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">min-width</span><span class="token punctuation">:</span> 150px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">max-width</span><span class="token punctuation">:</span> 250px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">flex-basis</span><span class="token punctuation">:</span> 225px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.item-1</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-shrink</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.item-2</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-grow</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Fits the content<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item my-box<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Flex-basis wide<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item my-box item-1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>No need to shrink<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item my-box item-2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Grow stops at 250px<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.my-box {
width: 200px;
min-width: 150px;
max-width: 250px;
flex-basis: 225px;
}
.item-1 {
flex-shrink: 1;
}
.item-2 {
flex-grow: 1;
}
</style>
<div class="flex-container">
<div class="flex-item">Fits the content</div>
</div>
<div class="flex-container">
<div class="flex-item my-box">Flex-basis wide</div>
</div>
<div class="flex-container">
<div class="flex-item my-box item-1">No need to shrink</div>
</div>
<div class="flex-container">
<div class="flex-item my-box item-2">Grow stops at 250px</div>
</div>
</code></pre><h2 id="flex-shorthand" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#flex-shorthand">Flex shorthand</a></h2>
<p>Shorthand property <code>flex</code> combines <code>flex-grow</code>, <code>flex-shrink</code> and <code>flex-basis</code>. When you omit the last one, <code>flex-basis</code> became <code>0</code> instead of <code>auto</code>.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.flex-basis-auto</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-basis</span><span class="token punctuation">:</span> initial<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.flex-basis-zero</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex</span><span class="token punctuation">:</span> 0 0<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item flex-basis-auto<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Flex-basis auto<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item flex-basis-zero<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Flex-basis 0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.flex-basis-auto {
flex-basis: initial;
}
.flex-basis-zero {
flex: 0 0;
}
</style>
<div class="flex-container">
<div class="flex-item flex-basis-auto">Flex-basis auto</div>
</div>
<div class="flex-container">
<div class="flex-item flex-basis-zero">Flex-basis 0</div>
</div>
</code></pre><h2 id="align-content" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#align-content">Align content</a></h2>
<p>In the following example the <code>align-content</code> property pushes all the items to the vertical center of the container while <code>align-items</code> to the center of their lines.</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.content-aligned</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token property">align-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.items-aligned</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /> <span class="token selector">.content-aligned > *,<br /> .items-aligned > *</span> <span class="token punctuation">{</span><br /><span class="highlight-line"> <span class="token property">flex-basis</span><span class="token punctuation">:</span> 140px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container content-aligned<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> darkcyan</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> darkgreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> cadetblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span> <span class="token punctuation">/></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container items-aligned<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> purple</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> darkcyan</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> darkgreen</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">background</span><span class="token punctuation">:</span> cadetblue</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Item 3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.content-aligned {
flex-wrap: wrap;
align-content: center;
}
.items-aligned {
flex-wrap: wrap;
align-items: center;
}
.content-aligned > *,
.items-aligned > * {
flex-basis: 140px;
text-align: center;
}
</style>
<div class="flex-container content-aligned">
<div class="flex-item" style="background: darkcyan">Item 1</div>
<div class="flex-item" style="background: darkgreen">Item 2</div>
<div class="flex-item" style="background: cadetblue">Item 3</div>
</div>
<br />
<div class="flex-container items-aligned" style="background: purple">
<div class="flex-item" style="background: darkcyan">Item 1</div>
<div class="flex-item" style="background: darkgreen">Item 2</div>
<div class="flex-item" style="background: cadetblue">Item 3</div>
</div>
</code></pre><h2 id="new-properties" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#new-properties">New properties</a></h2>
<p>There are new properties available in some browsers that are not mentioned in the Flexbox zombies course.</p>
<p>One is <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gap"><code>gap</code></a>:</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.flex-with-gap</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">gap</span><span class="token punctuation">:</span> 20px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container flex-with-gap<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.flex-with-gap {
gap: 20px;
}
</style>
<div class="flex-container flex-with-gap">
<div class="flex-item">Item 1</div>
<div class="flex-item">Item 2</div>
<div class="flex-item">Item 3</div>
</div>
</code></pre><p>Another one is <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/place-content"><code>place-content</code></a> a shorthand for <code>justify-content</code> and <code>align-content</code>:</p>
<pre class="klipse-fallback language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.flex-centered</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">place-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token selector">.flex-centered > *</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-container flex-centered<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex-item<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.flex-centered {
flex-wrap: wrap;
place-content: center;
}
.flex-centered > * {
width: 120px;
}
</style>
<div class="flex-container flex-centered">
<div class="flex-item">Item 1</div>
<div class="flex-item">Item 2</div>
<div class="flex-item">Item 3</div>
</div>
</code></pre><h2 id="conclusion" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/flexbox-zombies/#conclusion">Conclusion</a></h2>
<p>The Flexbox zombies is a great course and great game at the same time. That’s rare!</p>
<p>I don’t remember if the course mentioned a very useful value of <code>justify-content</code>: <code>space-evenly</code>. Other than that it is very thorough. I highly recommend this style of learning!</p>
My Getting things done in 20202020-04-23T00:00:00Zhttps://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/<p>For my personal time management I like to use a variant of the Getting Things
Done methodology. The nice thing about this GTD thing is that you can use only
small parts of the whole methodology and still benefit from it.</p>
<p>I am using some sort of GTD system for about 10 years now. I have tried a couple
of time management methodologies and used systems for both paper and digital
variants.</p>
<p>My current system is probably very close to ZTD (Zen To Done)<sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/#fn1" id="fnref1">[1]</a></sup>. When you
are doing something for a long time you usually stick with its core features and
fundamentals. And that is what the ZTD is to the GTD.</p>
<h2 id="the-core-tool" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/#the-core-tool">The core tool</a></h2>
<p>I have been using Wunderlist for several years, but it is going to be discontinued. Microsoft ToDo is its successor, but the feature set and design is a little bit different and I don’t quite like it.</p>
<p>Recently I found <a href="https://ticktick.com/">TickTick</a>. It is also a multiplatform todo
app. It has the advantage that you can customize the menu—namely remove the unnecessary items. It is important when you are looking for a tool, that is simple but has certain features. Primarily I need an Inbox and a couple of specific lists.</p>
<figure><img src="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/gtd-inbox.png" alt="" /><figcaption>Here is an example of how the Inbox screen looks like in my TickTick.</figcaption></figure>
<p>Other than that I like the option to create subtasks (for items in Projects list) and the ability to show and hide completed tasks.</p>
<figure><img src="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/gtd-projects.png" alt="" /><figcaption>The Projects list is a list of bigger or longer tasks where I track a series of my todos. When this is not enough or when there is more people involved I use a Trello board.</figcaption></figure>
<h2 id="information-archive" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/#information-archive">Information archive</a></h2>
<p>Another important part of the GTD methodology is some sort of system for storing information. This topic is worth a separate article or maybe a book. To stick with description of the current state of my GTD system I’m only going to say: This website is becoming my information archive and I love it.</p>
<p>The advantages I am currently seeing:</p>
<ul>
<li>Writing is simple (in Markdown; a note can be generated with short command line alias)</li>
<li>Reading is simple (the result is a website)</li>
<li>Search is simple (my own search from command line or maybe google it)</li>
<li>Backup and history is built in (everything is in git)</li>
<li>The output can be plain text or a very interactive thing (because the result is a website)</li>
<li>Everything is instantly shareable (send a link)</li>
<li>There is a possibility to integrate other sources of my information (e.g. list of <a href="https://lukastrumm.com/reading/">books I have read from Goodreads.com</a>)</li>
</ul>
<h2 id="additional-tools" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/#additional-tools">Additional tools</a></h2>
<p>I keep various lists in separate app. Those lists are focused more on thinging and helping remember things, not doing things. I use <a href="https://simplenote.com/">Simplenote</a>. It is truly simple but still have some nice features like history and seamless synchronization. My favorite lists are:</p>
<ul>
<li>Things I want to buy (it should be on this list for some time before I
actually buy it)</li>
<li>Possible articles or blog posts</li>
<li>Inspirational people</li>
<li>Habits I am currently working on</li>
<li>Things I should get rid of (sell it)</li>
</ul>
<p>For more complex projects I use <a href="https://trello.com/">Trello</a>. It is useful for
projects where there are multiple tasks in various levels of completeness.</p>
<p>When I need to collect a lot of links, images and other web content I use
<a href="https://keep.google.com/">Google Keep</a> (I have used Evernote before, but it is
unnecessarily complex for me).</p>
<h4 class="footnotes-title">Notes</h4>
<section class="footnotes">
<ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>Leo Babauta is the author of the <a href="https://www.goodreads.com/book/show/6056601-zen-to-done">ZTD book</a>. He focuses on simplicity and minimalism. <a href="https://lukastrumm.com/blog/2020/my-getting-things-done-in-2020/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Markdown capabilities in Eleventy2020-01-30T00:00:00Zhttps://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/<p>Let’s try what markdown offers in context of Eleventy static site generator.</p>
<p>Markdown in Eleventy is parsed by <a href="https://github.com/markdown-it/markdown-it">markdown-it</a>. It can be extended by a number of <a href="https://www.npmjs.com/search?q=keywords:markdown-it-plugin">plugins</a>.</p>
<p>The first example is a table of content—it is a list that consists of headings on level 2. The plugin for this is <a href="https://www.npmjs.com/package/markdown-it-table-of-contents"><code>markdown-it-table-of-contents</code></a>.</p>
<p></p><div class="table-of-contents"><div class="toc-heading">Table of content</div><ul><li><a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#this-is-a-heading-h2">This is a heading h2</a></li><li><a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#text">Text</a></li><li><a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#extras">Extras</a></li><li><a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#my-custom-plugins">My custom plugins</a></li></ul></div><p></p>
<h2 id="this-is-a-heading-h2" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#this-is-a-heading-h2">This is a heading h2</a></h2>
<h3 id="this-is-a-heading-h3" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#this-is-a-heading-h3">This is a heading h3</a></h3>
<h4>This is a heading h4</h4>
<h5>This is a heading h5</h5>
<h2 id="text" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#text">Text</a></h2>
<p>Paragraphs in markdown have to be divided by a blank line.</p>
<!-- prettier-ignore -->
<p>This paragraph contains
multiple lines in source code,
<s>because I like it more this way</s>.</p>
<p>Default markdown behavior is not inserting <code><br></code> on places of newlines. This is the behavior of html, too. It is better because there is less ambiguity in source code and you can let your formatter do it’s work.</p>
<h3 id="text-elements" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#text-elements">Text elements</a></h3>
<p><strong>bold</strong> <em>italic</em> <s>strikethrough</s> <code>code</code></p>
<blockquote>
<p>Quote</p>
</blockquote>
<pre class="language-js"><code class="language-js"><span class="highlight-line"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token string">'more code'</span></span></code></pre>
<p><em>(Code block with language specified as <code>js</code>.)</em></p>
<h3 id="lists" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#lists">Lists</a></h3>
<ul>
<li>First
<ul>
<li>Alpha</li>
<li>Beta</li>
</ul>
</li>
<li>Second</li>
</ul>
<ol>
<li>First
<ul>
<li>Alpha</li>
<li>Beta</li>
</ul>
</li>
<li>Second</li>
</ol>
<h3 id="automatic-conversions" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#automatic-conversions">Automatic conversions</a></h3>
<p>Links like <a href="http://example.com/">example.com</a> are automatically converted.</p>
<p>You can use two hyphens to produce an n-dash, e.g. 9–12. Or three hyphens—to create <a href="https://www.thepunctuationguide.com/em-dash.html">m-dash</a>.</p>
<p>“Quotation marks” and ellipsis is supported too…</p>
<p>Arrows: rain ➙ wet</p>
<h2 id="extras" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#extras">Extras</a></h2>
<p>Extra markdown functionality is provided either by embedded or external
<code>markdown-it</code> plugins.</p>
<h3 id="tables" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#tables">Tables</a></h3>
<table>
<thead>
<tr>
<th>Memory</th>
<th>Latency (ns)</th>
</tr>
</thead>
<tbody>
<tr>
<td>L1 cache</td>
<td>0.5</td>
</tr>
<tr>
<td>L2 cache</td>
<td>7</td>
</tr>
<tr>
<td>Main memory</td>
<td>100</td>
</tr>
</tbody>
</table>
<p>Source: <a href="https://gist.github.com/jboner/2841832">Latency Numbers Every Programmer Should Know</a></p>
<h3 id="footnotes" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#footnotes">Footnotes</a></h3>
<p>You can specify references to footnotes by writing something like this inside markdown: <sup class="footnote-ref"><a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#fn1" id="fnref1">[1]</a></sup></p>
<pre class="language-text"><code class="language-text"><span class="highlight-line">[^markdown-capabilities]</span></code></pre>
<p>And somewhere after that:</p>
<pre class="language-text"><code class="language-text"><span class="highlight-line">[^markdown-capabilities]: [markdown capabilities](https://github.com/markdown-it/markdown-it#syntax-extensions)</span></code></pre>
<h3 id="anchors" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#anchors">Anchors</a></h3>
<p>Hover over a heading, click the <code>#</code> sign and use targeted url…</p>
<h3 id="figures" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#figures">Figures</a></h3>
<p>Look, this is a <code><figure></code> with caption.</p>
<figure><img src="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/dependencies.png" alt="" /><figcaption>Box with title App depend on a bunch of Libs</figcaption></figure>
<h2 id="my-custom-plugins" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#my-custom-plugins">My custom plugins</a></h2>
<p>You can write your own plugin for <code>markdown-it</code>—it is one function.</p>
<h3 id="code-blocks-with-title" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#code-blocks-with-title">Code blocks with title</a></h3>
<p>This line</p>
<pre class="language-text"><code class="language-text"><span class="highlight-line">```html [Elaborate html document]</span><br /><span class="highlight-line">...html code...</span></code></pre>
<p>produces</p>
<pre class="language-html"><h2 class="title">Elaborate html document</h2><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Page<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></span></code></pre>
<h3 id="mermaid" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#mermaid">Mermaid</a></h3>
<figure>
<pre class="mermaid" style="
min-height: 320px;
visibility: hidden;
">
graph TD;
linkStyle default interpolate basis;
F[Feature]:::violet --> E(enable?):::blue;
E -- no --> OFF;
E -- yes --> P(permissions):::blue;
P -- unauthorized --> OFF:::red;
P -- authorized --> ON:::green;
</pre>
<figcaption> <code>Role</code> based <b>toggling</b></figcaption>
</figure><h3 id="executable-code-blocks" tabindex="-1"><a class="header-anchor" href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#executable-code-blocks">Executable code blocks</a></h3>
<p>Using <a href="https://github.com/viebel/klipse">klipse</a>.</p>
<pre class="klipse-fallback language-js"><code class="language-js"><span class="highlight-line"><span class="token keyword">const</span> t <span class="token operator">=</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>timing</span><br /><span class="highlight-line"><span class="token keyword">const</span> duration <span class="token operator">=</span> t<span class="token punctuation">.</span>domContentLoadedEventEnd <span class="token operator">-</span> t<span class="token punctuation">.</span>navigationStart</span><br /><span class="highlight-line"><span class="token punctuation">;</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">DOM loaded after </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>duration<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ms</span><span class="token template-punctuation string">`</span></span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
const t = window.performance.timing
const duration = t.domContentLoadedEventEnd - t.navigationStart
;`DOM loaded after ${duration} ms`
</code></pre><pre class="klipse-fallback language-html"><h2 class="title">HTML and CSS</h2><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /><span class="highlight-line"> <span class="token selector">.my-text</span> <span class="token punctuation">{</span></span><br /><mark class="highlight-line highlight-line-active"> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span></mark><br /><mark class="highlight-line highlight-line-active"> <span class="token property">text-overflow</span><span class="token punctuation">:</span> ellipsis<span class="token punctuation">;</span></mark><br /><span class="highlight-line"> <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token punctuation">}</span></span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Once upon a time, there was a man<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span></code></pre>
<pre class="klipse-actual language-html" data-editor-type="html"><code class="klipse-eval-html language-html">
<style>
.my-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 120px;
}
</style>
<p class="my-text">Once upon a time, there was a man</p>
</code></pre><pre class="klipse-fallback language-js"><code class="language-js"><span class="highlight-line"><span class="token keyword">const</span> array <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span></span><br /><span class="highlight-line"><span class="token keyword">let</span> sum1 <span class="token operator">=</span> array<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> curr</span><span class="token punctuation">)</span> <span class="token operator">=></span> acc <span class="token operator">+</span> curr<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span></span><br /><del class="highlight-line highlight-line-remove"><span class="token keyword">let</span> sum2 <span class="token operator">=</span> <span class="token number">0</span></del><br /><ins class="highlight-line highlight-line-add"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> n <span class="token keyword">of</span> array<span class="token punctuation">)</span> <span class="token punctuation">{</span></ins><br /><ins class="highlight-line highlight-line-add"> sum2 <span class="token operator">+=</span> n</ins><br /><ins class="highlight-line highlight-line-add"><span class="token punctuation">}</span></ins><br /><span class="highlight-line"></span><br /><span class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>sum1<span class="token punctuation">)</span></span><br /><span class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>sum2<span class="token punctuation">)</span></span></code></pre>
<pre class="klipse-actual language-js" data-editor-type="code-mirror"><code class="klipse-eval-js language-js">
const array = [1, 2, 3]
let sum1 = array.reduce((acc, curr) => acc + curr, 0)
let sum2 = 0
for (const n of array) {
sum2 += n
}
console.log(sum1)
console.log(sum2)
</code></pre><h4 class="footnotes-title">Notes</h4>
<section class="footnotes">
<ol class="footnotes-list"><li id="fn1" class="footnote-item"><p><a href="https://github.com/markdown-it/markdown-it#syntax-extensions">markdown capabilities</a> <a href="https://lukastrumm.com/blog/2020/markdown-capabilities-in-eleventy/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>