{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Aileen Rae","description":"The latest articles on DEV Community by Aileen Rae (@aileenr).","link":"https:\/\/dev.to\/aileenr","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F419187%2F1c9625b9-5209-471a-80c8-3d399b8b189f.jpeg","title":"DEV Community: Aileen Rae","link":"https:\/\/dev.to\/aileenr"},"language":"en","item":[{"title":"Bookmarks: February 2023","pubDate":"Sun, 12 Mar 2023 17:16:26 +0000","link":"https:\/\/dev.to\/aileenr\/bookmarks-february-2023-1027","guid":"https:\/\/dev.to\/aileenr\/bookmarks-february-2023-1027","description":"<p>Who cares if it's March when I'm publishing this! Here are some web articles that stuck with me last month.<\/p>\n\n<h2>\n  \n  \n  Tech and Web\n<\/h2>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/www.refactoringui.com\/previews\/building-your-color-palette\">Building your colour palette - Refactoring UI<\/a>\n<\/h3>\n\n<p>Building attractive interfaces is a large component of my love for building on the web, but I am not a designer. I have a decent enough eye for seeing what's <em>wrong<\/em> in a web layout and for accurately implementing a design spec. But I trip up when it comes to creating, and one of the biggest hurdles for me is <strong>colour<\/strong>.<\/p>\n\n<p>I've tried so many colour palette generators and generated some beautiful colour schemes, but I can never get them to actually <em>work<\/em>. This article on Refactoring UI illustrates exactly why - it's impossible. A web interface colour palette is much more intricate, and much more full of grey than you would expect.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Wp3ciAbU--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/a95vjwfa38yr0ecl8cet.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Wp3ciAbU--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/a95vjwfa38yr0ecl8cet.png\" alt=\"A colour palette in action\" width=\"880\" height=\"285\"><\/a><\/p>\n\n<p>Using image examples, it shows you how each colour in your palette needs to have different shades, and how these would be implemented in common UI components. I will be referencing this often for future side projects.<\/p>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/fossheim.io\/writing\/posts\/excluding-non-binary-people-by-design\/\">Exluding non-binary people by design: How sign-up forms can lead to discrimination - Sarah L. Fossheim<\/a>\n<\/h3>\n\n<p>An excellent exploration of how designing digital systems has to have inclusiveness baked in from the start.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--nyIHqYm9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/jfyuuie7vypnl07gxvq4.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--nyIHqYm9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/jfyuuie7vypnl07gxvq4.png\" alt=\"A screenshot of Google's input for entering a non-binary gender\" width=\"880\" height=\"952\"><\/a><\/p>\n\n<blockquote>\n<p>This is why data isn\u2019t neutral or objective, but influenced by those who collect it, and later possibly further compromised by the biases of those that use it.<\/p>\n<\/blockquote>\n\n<p>I also highly recommend the follow-up article: <a href=\"https:\/\/fossheim.io\/writing\/posts\/trans-inclusive-design-tools\/\">Getting started with trans inclusive design<\/a>.<\/p>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/www.matuzo.at\/blog\/2023\/single-page-applications-criticism\/\">Why I'm not the biggest fan of Single Page Applications - Manuel Matuzovic<\/a>\n<\/h3>\n\n<p>In a world where SPA vs MPA has become somewhat of a flame-war, this measured take is a refreshing read.<\/p>\n\n<p>As someone who started her web development career working with SPA frameworks, I'm ashamed even this surface-level article highlighted holes in my accessibility logic. This very website does not consistently shift focus to the beginning of the DOM on SPA-navigation.<\/p>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/simonwillison.net\/2023\/Feb\/15\/bing\/\">Bing: \u201cI will not harm you unless you harm me first\u201d - Simon Willison<\/a>\n<\/h3>\n\n<p>A wild ride of a read \ud83d\ude02<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--VJUBSPqu--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/3b1pf6f6cbsk8jg7v9jz.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--VJUBSPqu--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/3b1pf6f6cbsk8jg7v9jz.png\" alt=\"A screenshot from AI-powered Bing\" width=\"869\" height=\"346\"><\/a><\/p>\n\n<h2>\n  \n  \n  Career\n<\/h2>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/charity.wtf\/2017\/05\/11\/the-engineer-manager-pendulum\/\">The engineer-manager pendulum - Charity.wtf<\/a>\n<\/h3>\n\n<p>There's this pervasive idea in software engineering that once you reach a certain level of seniority you have to choose: do you want to continue to be an individual contributor (IC) or a manager? Just google \"IC vs engineering manager\" and be overwhelmed by the sheer number of discussion pieces.<\/p>\n\n<p>I think a lot of people resist this dichotomy. In my current company, we have a tech lead role which is meant to be a split of engineering manager and IC engineer duties. Our job ad says 25% of a tech lead's time is spent writing code. In reality though, the management responsibilities are always higher priority than any IC work.<\/p>\n\n<p>The engineer-manager pendulum article has an explanation for this:<\/p>\n\n<blockquote>\n<p>Management is highly interruptive, and great engineering \u2014 where you\u2019re learning things \u2014 requires blocking out interruptions. You can\u2019t do these two opposite things at once.\u00a0As a manager,\u00a0it is your job to be available for your team, to be interrupted. It is your job to <em>choose<\/em> to hand off\u00a0the challenging assignments, so that your engineers can get better at engineering.<\/p>\n<\/blockquote>\n\n<p>The alternative? Focus on either IC or management one at a time, but go back and forth between the two: the pendulum. Charity articulates why this works far better than I can so go read it!<\/p>\n\n","category":["design","webdev","personal"]},{"title":"Bookmarks: January 2023","pubDate":"Sat, 04 Feb 2023 15:33:56 +0000","link":"https:\/\/dev.to\/aileenr\/bookmarks-january-2023-3j4h","guid":"https:\/\/dev.to\/aileenr\/bookmarks-january-2023-3j4h","description":"<p>Please enjoy some curated links to online content I have enjoyed this past month. \ud83d\ude0a<\/p>\n\n<h2>\n  \n  \n  Tech and Web\n<\/h2>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/jvns.ca\/blog\/2022\/12\/08\/a-debugging-manifesto\" rel=\"noopener noreferrer\">A Debugging Manifesto - Julia Evans<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztpkfcqmep9z6h4cozqa.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztpkfcqmep9z6h4cozqa.png\" alt=\"An image panel from Julia Evan's \" width=\"683\" height=\"382\"><\/a><br>\nA friendly approach to reframing software bugfixing as a learning activity.<\/p>\n\n<blockquote>\n<p>If something is breaking, it\u2019s often because there\u2019s something wrong in my mental model<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/pepelsbey.dev\/articles\/skewed-highlight\/\" rel=\"noopener noreferrer\">A CSS challenge: skewed highlight - Vadim Makeev<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9d1m9kg7mfsrwd6o5qox.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9d1m9kg7mfsrwd6o5qox.png\" alt=\"A CSS skewed highlight effect by Vadim Makeev.\" width=\"800\" height=\"384\"><\/a><br>\nA really nice highlighter effect with modern CSS. It achieves the slant using gradients, rather than separate elements or pseudo-elements. It also leverages a little-known CSS property for getting the effect to work across line breaks.<\/p>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/www.joshwcomeau.com\/career\/clever-code-considered-harmful\/\" rel=\"noopener noreferrer\">Clever Code Considered Harmful - Josh W. Comeau<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhp11fa4dkwfvpubpnj5o.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhp11fa4dkwfvpubpnj5o.png\" alt=\"A screenshot of complex, unreadable haskell codefrom Josh W. Comeau's blog.\" width=\"800\" height=\"263\"><\/a><br>\nA well-articulated case against complex and overly \"clever\" code. The most compelling takeaways for me are:<\/p>\n\n<ul>\n<li>consider whether your code can be understood by a junior dev,<\/li>\n<li>when complexity is necessary, encapsulate it to prevent it bleeding all over your codebase. <\/li>\n<\/ul>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/unicornicons.com\/icons\" rel=\"noopener noreferrer\">Unicorn Icons - Kushmeen<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flg88yu08cv7pqg1x704o.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flg88yu08cv7pqg1x704o.gif\" alt=\"An GIF of gorgeous animated icons by Kushmeen.\" width=\"961\" height=\"536\"><\/a><br>\n\ud83d\udc4f\ud83c\udffb I love these. And I immediately want to start a project where I can use them.<\/p>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/iamkate.com\/data\/12-bit-rainbow\/\" rel=\"noopener noreferrer\">The 12-Bit Rainbow Palette - Kate Rose Morley<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpttx45n0jnz7wdl9xu0.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpttx45n0jnz7wdl9xu0.png\" alt=\"A well-designed 12-colour rainbow palette by Kate Rose Morley\" width=\"670\" height=\"84\"><\/a><br>\nThis pleases me a lot. In fact, I have half-formed plans to implement a similar rainbow palette on this here blog. Stay tuned.<\/p>\n\n<h2>\n  \n  \n  Career\n<\/h2>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/www.jvt.me\/posts\/2022\/09\/21\/year-later-salary-history\/\" rel=\"noopener noreferrer\">Lessons learned since posting my salary history publicly - Jamie Tanna<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs53pzzyqt566lfvrao5f.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs53pzzyqt566lfvrao5f.png\" alt=\"A screenshot of Jamie Tanna's published salary history.\" width=\"800\" height=\"377\"><\/a><br>\nThis is really interesting to consider, and something I would love to do later in my career. Being a woman in tech means I'm statistically likely to be underpaid for the work I do, and that's some heavy baggage to carry. I appreciate this transparency and I hope it can become a norm in the industry.<\/p>\n\n<h2>\n  \n  \n  Miscellaneous\n<\/h2>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/www.youtube.com\/watch?v=kqItMybTKTo\" rel=\"noopener noreferrer\">How to Do Laundry When You're Depressed - KC Davis<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkbvl6xo4s063nobf54q.jpg\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkbvl6xo4s063nobf54q.jpg\" alt=\"A TED talk video thumbnail of KC Davis.\" width=\"800\" height=\"450\"><\/a><br>\nA poignant TED talk on the burden of daily caretaking tasks. It's focussed on shifting your self talk from one of punishment to one of compassion. As someone with a chronic health condition that can affect my functioning, this was tearful and healing.<\/p>\n\n<blockquote>\n<p>Care tasks are morally neutral.<\/p>\n\n<p>Anything worth doing is worth doing half-assed.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  <a href=\"https:\/\/neal.fun\/wonders-of-street-view\/\" rel=\"noopener noreferrer\">Wonders of Street View - neal.fun<\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gtkzngovh2c1lyp9g0l.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gtkzngovh2c1lyp9g0l.png\" alt=\"A Google Street View screenshot of a skier jumping over two other people high in a snowy mountainscape.\" width=\"800\" height=\"493\"><\/a><br>\nA sometimes hilarious, sometimes awe-inspiring collection of the weird and wonderful snapshots that can be found on Google Street View.<\/p>\n\n","category":["bookmarks","personal"]},{"title":"Checking and unchecking a checkbox with JavaScript: a quick lesson on HTML IDL attributes","pubDate":"Fri, 06 Jan 2023 13:26:55 +0000","link":"https:\/\/dev.to\/aileenr\/checking-and-unchecking-a-checkbox-with-javascript-a-quick-lesson-on-html-idl-attributes-nf8","guid":"https:\/\/dev.to\/aileenr\/checking-and-unchecking-a-checkbox-with-javascript-a-quick-lesson-on-html-idl-attributes-nf8","description":"<p>I feel like an idiot for this amount of time I spent on this one today at work.<\/p>\n\n<p><strong>TL:DR;<\/strong> What you're looking for is:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ &lt;input type=\"checkbox\" id=\"your-checkbox-id\" \/&gt;<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">yourCheckbox<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">your-checkbox-id<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n\n<span class=\"c1\">\/\/ check the checkbox<\/span>\n<span class=\"nx\">yourCheckbox<\/span><span class=\"p\">.<\/span><span class=\"nx\">checked<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">true<\/span><span class=\"p\">;<\/span>\n\n<span class=\"c1\">\/\/ uncheck the checkbox<\/span>\n<span class=\"nx\">yourCheckbox<\/span><span class=\"p\">.<\/span><span class=\"nx\">checked<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">false<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>So what was I doing wrong today? Let's take a look at the Codepen below.<\/p>\n\n<p><iframe height=\"600\" src=\"https:\/\/codepen.io\/aileen-r\/embed\/abjmNwP?height=600&amp;default-tab=result&amp;embed-version=2\">\n<\/iframe>\n<\/p>\n\n<h2>\n  \n  \n  \u274c Using the setAttribute method\n<\/h2>\n\n<p>I had a list of checkboxes, with one \"select all\" checkbox at the top. When the \"select all\" checkbox is checked, I wanted to check all the underlying checkboxes.<\/p>\n\n<p>I tried setting the <code>checked<\/code> attribute on the input elements. My code looked something like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">selectAllCheckbox<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">select-all<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">childCheckboxes<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">querySelectorAll<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">.child-checkbox<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">toggleSelectAllCheckbox<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">areAllChecked<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[...<\/span><span class=\"nx\">childCheckboxes<\/span><span class=\"p\">].<\/span><span class=\"nf\">every<\/span><span class=\"p\">(<\/span><span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">c<\/span><span class=\"p\">.<\/span><span class=\"nf\">hasAttribute<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">checked<\/span><span class=\"dl\">'<\/span><span class=\"p\">));<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">areAllChecked<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ uncheck all if every checkbox is checked<\/span>\n    <span class=\"nx\">childCheckboxes<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">c<\/span><span class=\"p\">.<\/span><span class=\"nf\">removeAttribute<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">checked<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">}<\/span>\n  <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ otherwise, check all<\/span>\n    <span class=\"nx\">childCheckboxes<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">c<\/span><span class=\"p\">.<\/span><span class=\"nf\">setAttribute<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">checked<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"dl\">''<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">selectAllCheckbox<\/span><span class=\"p\">.<\/span><span class=\"nf\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">click<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">toggleSelectAllCheckbox<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This seems alright at first glance. If you toggle the \"select all\" checkbox it works.<\/p>\n\n<p>However, if you toggle any of the child checkboxes <em>then<\/em> toggle \"select all\", it ignores the children you just toggled. Try it out in the Codepen example above. This won't do.<\/p>\n\n<h2>\n  \n  \n  \u2705 Setting the \"checked\" property\n<\/h2>\n\n<p>Eventually, I figured out using the <code>setAttribute()<\/code> and <code>removeAttribute()<\/code> methods was where I was going wrong. Instead, I needed to access and set the <code>checked<\/code> property directly, like so:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">selectAllCheckbox<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">getElementById<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">select-all<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">childCheckboxes<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">querySelectorAll<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">.child-checkbox<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">toggleSelectAllCheckbox<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">areAllChecked<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[...<\/span><span class=\"nx\">childCheckboxes<\/span><span class=\"p\">].<\/span><span class=\"nf\">every<\/span><span class=\"p\">(<\/span><span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">c<\/span><span class=\"p\">.<\/span><span class=\"nx\">checked<\/span> <span class=\"o\">===<\/span> <span class=\"kc\">true<\/span><span class=\"p\">)<\/span>\n  <span class=\"nx\">childCheckboxes<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">c<\/span><span class=\"p\">.<\/span><span class=\"nx\">checked<\/span> <span class=\"o\">=<\/span> <span class=\"o\">!<\/span><span class=\"nx\">areAllChecked<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">})<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">selectAllCheckbox<\/span><span class=\"p\">.<\/span><span class=\"nf\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">click<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">toggleSelectAllCheckbox<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There is some extra work to make sure the \"select all\" checkbox updates when toggling the children, but you can check out the <a href=\"https:\/\/codepen.io\/aileen-r\/pen\/abjmNwP\" rel=\"noopener noreferrer\">Codepen<\/a> for that.<\/p>\n\n<h2>\n  \n  \n  Why was I wrong?\n<\/h2>\n\n<p>When it comes to setting attributes on HTML elements, I had always assumed <code>element.setAttribute('attribute', value)<\/code> was roughly interchangeable with <code>element.attribute = value<\/code>. But there is a subtle difference.<\/p>\n\n<p>HTML attributes have two sides, the <strong>content attribute<\/strong> and the <strong>IDL attribute<\/strong>.<\/p>\n\n<p>The <strong>content attribute<\/strong> is what is written in HTML. It is also accessed via the methods <code>element.hasAttribute()<\/code>, <code>element.getAttribute()<\/code>, <code>element.setAttribute()<\/code>, and <code>element.removeAttribute()<\/code>.<\/p>\n\n<p>For example, if I have <code>&lt;input type=\"checkbox\" id=\"your-checkbox-id\" \/&gt;<\/code>, <code>checkboxElement.hasAttribute('checked')<\/code> will be false.<\/p>\n\n<p>If I then set <code>checkboxElement.setAttribute('checked')<\/code> and use a devtools inspector, my HTML will now be <code>&lt;input type=\"checkbox\" id=\"your-checkbox-id\" checked \/&gt;<\/code>.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7pf3vebgvm1kfirg05i.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7pf3vebgvm1kfirg05i.png\" alt=\"Screenshot of a checkbox element in Firefox devtools inspector.\" width=\"585\" height=\"85\"><\/a><\/p>\n\n<p>The <strong>IDL attribute<\/strong> is a JavaScript property. If I log my element to the console with <code>console.log('checkboxElement')<\/code>, I can drill into it like any JavaScript object and see all the properites. These are the IDL attributes.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgcvkrb1pb1zos9hg3rc.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgcvkrb1pb1zos9hg3rc.png\" alt=\"Screenshot of a checkbox element logged to the Firefox developer console. A list of properties, including \" width=\"492\" height=\"357\"><\/a><\/p>\n\n<p>The IDL attribute will use the underlying content attribute. <code>element.setAttribute(\"attribute\", value)<\/code> and <code>element.attribute = value<\/code> are interchangable...most of the time.<\/p>\n\n<p>The catch with checkboxes is that, for the <code>checked<\/code> IDL attribute, the underlying content attribute is <em>not<\/em> <code>checked<\/code>. It doesn't have one.<\/p>\n\n<p>The content attribute <code>checked<\/code> for inputs with <code>type=\"checkbox\"<\/code> instead corresponds to the <code>defaultChecked<\/code> IDL attribute. Even though <code>element.setAttribute(\"checked\")<\/code> <em>sort of<\/em> works for programatically checking a checkbox (at least in the browsers I tried), it's not supposed to.<\/p>\n\n<p>Use the <code>checked<\/code> content attribute if you want the checkbox checked by default at page load (or when the element is first painted).<\/p>\n\n<p>If you want to mutate the checkbox with JavaScript, use the <code>checked<\/code> IDL attribute: <code>element.checked = true<\/code>.<\/p>\n\n<h2>\n  \n  \n  Sources\n<\/h2>\n\n<p>MDN: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/input\/checkbox\" rel=\"noopener noreferrer\">&lt;input type=\"checkbox\"&gt;<\/a>, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/IDL\" rel=\"noopener noreferrer\">IDL glossary entry<\/a>.<\/p>\n\n","category":["javascript","html","codesnippets","todayilearned"]},{"title":"Fixing overflow: scroll padding in Firefox","pubDate":"Mon, 01 Aug 2022 19:27:16 +0000","link":"https:\/\/dev.to\/aileenr\/fixing-overflow-scroll-padding-in-firefox-1ipo","guid":"https:\/\/dev.to\/aileenr\/fixing-overflow-scroll-padding-in-firefox-1ipo","description":"<h2>\n  \n  \n  The preamble and the problem\n<\/h2>\n\n<p><em>(You can skip my opening context and jump to the workaround.)<\/em><\/p>\n\n<p>I recently ran into a problem with padding in scrolling elements while working on an exercise in <a href=\"https:\/\/www.joshwcomeau.com\/\" rel=\"noopener noreferrer\">Josh Comeau<\/a>'s fantastic <a href=\"https:\/\/css-for-js.dev\/\" rel=\"noopener noreferrer\">CSS for JavaScript Developers<\/a> course.<\/p>\n\n<p>More specifically, I was trying to implement this scrolling container of buttons:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgidnenrqoy9hobmuuwbj.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgidnenrqoy9hobmuuwbj.gif\" alt=\"An animated close-up of a web page element for picking \"><\/a><\/p>\n\n<p>The row of buttons is allowed to occupy the full width of the container, but there is some padding on the left when scrolled to the left edge and some padding on the right when scrolled to the right edge. How do we get this padding?<\/p>\n\n<p>You might guess that adding <code>padding-left<\/code> and <code>padding-right<\/code> properties to the scrolling container would solve this problem, something like this:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2p5lj4z1cjfr0zia1ux.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2p5lj4z1cjfr0zia1ux.png\" alt=\"Screenshot of the .scroll-container element scrolled to its leftmost edge. The Dev Tools overlay shows a padding-left is applied and the child elements of the .scroll-container are some distance away from the left edge of the container, respecting the padding.\"><\/a><\/p>\n\n<p>This would fix it...almost. The padding on the scrolling container behaves nicely in WebKit browsers, but we run into a problem when we try this in Firefox.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxaj615xm2pseoy8z32gv.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxaj615xm2pseoy8z32gv.gif\" alt=\"An animated gif of the .scroll-container element scrolled to its leftmost edge. The padding-left is visible. The cursor is shown scrolling the element to the right, but there is no visible padding-right.\"><\/a><\/p>\n\n<p>If we use Dev Tools to inspect the scrolling container, we can see that, yup, there is definitely <code>padding-right<\/code>. But, unlike other browsers, Firefox does not consider this padding to be part of the scrollable space.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1294z0y5noazlnxed821.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1294z0y5noazlnxed821.png\" alt=\"Screenshot of the .scroll-container element scrolled to its rightmost edge. Although the Dev Tools overlay shows a padding-right is applied, the child elements of the .scroll-container do not respect this padding and are flush with the right edge of the container.\"><\/a><\/p>\n\n<p>Ah, don't you just love browser compatibility issues?<\/p>\n\n<p>(\u2139 For the curious, the <a href=\"https:\/\/w3c.org\" rel=\"noopener noreferrer\">W3C<\/a> discussion went back-and-forth on the desired behaviour here. Ultimately they have decided that the WebKit implementation is correct. The bug tracker for Firefox has <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1700858\" rel=\"noopener noreferrer\">an open issue logged<\/a> where you can view the latest updates on the eventual fix.)<\/p>\n\n<h2>\n  \n  \n  Workaround for overflow:scroll padding in Firefox\n<\/h2>\n\n<p>As is often the case with CSS, there are a few workaround solutions. I chose to remove the <code>padding-right<\/code> from the scrolling container and add that space as margin to the last child element inside instead.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"nc\">.scroll-container<\/span> <span class=\"o\">&gt;<\/span> <span class=\"o\">*<\/span><span class=\"nd\">:last-child<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">margin-right<\/span><span class=\"p\">:<\/span> <span class=\"m\">32px<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Breaking this down:<\/p>\n\n<ul>\n<li>\n<code>.scroll-container<\/code> is self-explanatory. This is the scrolling element.<\/li>\n<li>\n<code>*<\/code> is the universal selector in CSS. It matches all elements. <\/li>\n<li>\n<code>:last-child<\/code> is a pseudo-class selector. It acts as a modifier, meaning <code>*:last-child<\/code> selects all elements that are the <em>last<\/em> child of their parent element.<\/li>\n<li>\n<code>&gt;<\/code> is the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Child_combinator\" rel=\"noopener noreferrer\">child combinator<\/a>. My rule only applies to <code>*:last-child<\/code> <strong>if<\/strong> it is a direct child of <code>.scroll-container<\/code>. This ensures we don't accidentally apply unwanted margin to grandchildren elements or beyond.<\/li>\n<\/ul>\n\n<p>(\u26a0 The universal <code>*<\/code> selector can be unweildy. If you know what the last child in your scrolling container is, I recommend replacing this with a more specific selector.)<\/p>\n\n<p>You can see this in action in the Codepen demo below.<\/p>\n\n<p><iframe height=\"600\" src=\"https:\/\/codepen.io\/aileen-r\/embed\/XWEjxWg?height=600&amp;default-tab=result&amp;embed-version=2\">\n<\/iframe>\n<\/p>\n\n","category":["css","webdev","html","todayilearned"]},{"title":"Pok\u00e9mon as HTML list bullets using SASS functions","pubDate":"Mon, 25 Jul 2022 18:21:49 +0000","link":"https:\/\/dev.to\/aileenr\/pokemon-as-html-list-bullets-using-sass-functions-39ib","guid":"https:\/\/dev.to\/aileenr\/pokemon-as-html-list-bullets-using-sass-functions-39ib","description":"<p>\u2139 <em>This is a chatty post describing my step-by-step development process. You can skip to the end result here.<\/em><\/p>\n\n<p>Earlier this year, one of <a href=\"https:\/\/codepen.io\/\" rel=\"noopener noreferrer\">CodePen<\/a>'s weekly challenges was all about <a href=\"https:\/\/codepen.io\/challenges\/2022\/april\/1\" rel=\"noopener noreferrer\">list styles<\/a>. If you have not already, I highly recommend <a href=\"https:\/\/codepen.io\/challenges\" rel=\"noopener noreferrer\">subscribing to Codepen's weekly challenges<\/a>. They're a great inspiration for little frontend dev exercises.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskw6b2uaexctqutx3cyk.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskw6b2uaexctqutx3cyk.png\" alt=\"Screenshot of the Codepen List Styles Challenge page.\"><\/a><\/p>\n\n<p>Back to list styles - I was immediately feeling inspired to code up something frivolous and fun. I decided I wanted to replace the traditional numbers of an <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/ol\" rel=\"noopener noreferrer\">ordered list<\/a> with images that esoterically represent numbers. Specifically, I decided to use Pok\u00e9mon in <a href=\"https:\/\/bulbapedia.bulbagarden.net\/wiki\/List_of_Pok%C3%A9mon_by_National_Pok%C3%A9dex_number\" rel=\"noopener noreferrer\">Pok\u00e9dex order<\/a>.<\/p>\n\n<p>Yes, I am a Pok\u00e9mon nerd, but so are a lot of developers in the community. There are a lot of great Pok\u00e9mon resources for dev side projects such as <a href=\"https:\/\/pokeapi.co\/\" rel=\"noopener noreferrer\">Pok\u00e9API<\/a>. For this little project, I chose <a href=\"https:\/\/msikma.github.io\/pokesprite\/\" rel=\"noopener noreferrer\">Pok\u00e9Sprite<\/a> sprite images to be my ordered list bullets.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtiwixgwzg79v0cf3c2q.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtiwixgwzg79v0cf3c2q.png\" alt=\"Screenshot of the Codepen List Styles Challenge page.\"><\/a><\/p>\n\n<h2>\n  \n  \n  How I built it\n<\/h2>\n\n<h3>\n  \n  \n  Step 1: Incrementing numbers in CSS rules\n<\/h3>\n\n<p>I started thinking abstractly about what I needed the CSS to do. Replacing a single list number marker with an image would require the following CSS:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"image_url_here\")<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In order to have a different image for each list item, I needed a different rule for each child using the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/:nth-of-type\" rel=\"noopener noreferrer\">nth-of-type CSS pseudo-class<\/a>.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"err\">1<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"image_001\")<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"err\">2<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"image_002\")<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"err\">3<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"image_003\")<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c\">\/* etc etc *\/<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Copy-pasting this for each list item would quickly become tedious. There are now <a href=\"https:\/\/bulbapedia.bulbagarden.net\/wiki\/List_of_Pok%C3%A9mon_by_National_Pok%C3%A9dex_number\" rel=\"noopener noreferrer\">nearly 1,000 Pok\u00e9mon<\/a>. No way: I wanted a programmatic solution.<\/p>\n\n<p>At this point I wanted to style this with vanilla CSS if possible, so I began playing with the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/counter\" rel=\"noopener noreferrer\">counter() CSS function<\/a> to programatically generate the numbers. Something like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"nt\">counter-increment<\/span><span class=\"o\">:<\/span> <span class=\"nt\">idx<\/span><span class=\"o\">;<\/span>\n\n<span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"nt\">idx<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"image_{idx}\")<\/span><span class=\"p\">;<\/span> <span class=\"c\">\/* This is invalid \ud83d\ude21 *\/<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>But, after several attempts and furious googling on how to put the counter value in an image URL, I found <a href=\"https:\/\/stackoverflow.com\/questions\/68157908\/can-i-insert-css-counter-in-content-url-of-pseudo-before-element\" rel=\"noopener noreferrer\">this (unecessarily downvoted) Stack Overflow question<\/a>:<\/p>\n\n<blockquote>\n<p>Can I insert css counter in content url?<\/p>\n<\/blockquote>\n\n<p>The answer is <strong>no<\/strong>. Bummer. \ud83d\ude1e<\/p>\n\n<p>On the plus side, the answer to that Stack Overflow question provided the solution: a <a href=\"https:\/\/sass-lang.com\/documentation\/at-rules\/control\/for\" rel=\"noopener noreferrer\">SASS @for loop<\/a>.<\/p>\n\n<p>With that I had the CSS plumbing ready for my Pok\u00e9mon sprite image URLs:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight scss\"><code><span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">@for<\/span> <span class=\"nv\">$i<\/span> <span class=\"ow\">from<\/span> <span class=\"m\">1<\/span> <span class=\"ow\">through<\/span> <span class=\"m\">908<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">&amp;<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"sx\">.png\")<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Step 2: Preparing the image files\n<\/h3>\n\n<p>Now the only thing missing was the Pok\u00e9mon image files themselves. I downloaded <a href=\"https:\/\/github.com\/msikma\/pokesprite\/tree\/master\/pokemon-gen7x\/regular\" rel=\"noopener noreferrer\">this collection of sprites<\/a> from Pok\u00e9Sprites and quickly noticed I had made a breaking assumption: the files were named after the Pok\u00e9mon rather than their dex number, e.g. <code>bulbasaur.png<\/code>.<\/p>\n\n<p>Not to worry though, Pok\u00e9Sprite also comes with <a href=\"https:\/\/github.com\/msikma\/pokesprite\/blob\/master\/data\/pokemon.json\" rel=\"noopener noreferrer\">a structured JSON data file<\/a> through which I could map the filename to the dex number. I got cracking on writing a script I could run to rename the hundreds of files for me. I'm not a Node expert so after a lot of googling about Node FS, I ended up with this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ extractOrderedListOfPokemon.mjs<\/span>\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">input<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/pokemon.json<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">fs<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">fs<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">dirPath<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/by-nat-dex-number<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">data<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">input<\/span><span class=\"p\">.<\/span><span class=\"k\">default<\/span><span class=\"p\">;<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">filesToDelete<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">errCallback<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">err<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">ERROR: <\/span><span class=\"dl\">'<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">err<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">dir<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">fs<\/span><span class=\"p\">.<\/span><span class=\"nx\">promises<\/span><span class=\"p\">.<\/span><span class=\"nf\">opendir<\/span><span class=\"p\">(<\/span><span class=\"nx\">dirPath<\/span><span class=\"p\">);<\/span>\n<span class=\"k\">for<\/span> <span class=\"k\">await <\/span><span class=\"p\">(<\/span><span class=\"kd\">const<\/span> <span class=\"nx\">dirent<\/span> <span class=\"k\">of<\/span> <span class=\"nx\">dir<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">filename<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">dirent<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span><span class=\"p\">;<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">pokemonSlug<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">filename<\/span><span class=\"p\">.<\/span><span class=\"nf\">replace<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.png<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"\"<\/span><span class=\"p\">);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">dexNumber<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">Object<\/span><span class=\"p\">.<\/span><span class=\"nf\">values<\/span><span class=\"p\">(<\/span><span class=\"nx\">data<\/span><span class=\"p\">).<\/span><span class=\"nf\">find<\/span><span class=\"p\">(<\/span><span class=\"nx\">pokemon<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">pokemon<\/span><span class=\"p\">.<\/span><span class=\"nx\">slug<\/span><span class=\"p\">.<\/span><span class=\"nx\">eng<\/span> <span class=\"o\">===<\/span> <span class=\"nx\">pokemonSlug<\/span><span class=\"p\">)?.<\/span><span class=\"nx\">idx<\/span><span class=\"p\">;<\/span>\n\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">dexNumber<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">fs<\/span><span class=\"p\">.<\/span><span class=\"nf\">rename<\/span><span class=\"p\">(<\/span><span class=\"s2\">`<\/span><span class=\"p\">${<\/span><span class=\"nx\">dirPath<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">filename<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">,<\/span> <span class=\"s2\">`<\/span><span class=\"p\">${<\/span><span class=\"nx\">dirPath<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">dexNumber<\/span><span class=\"p\">}<\/span><span class=\"s2\">.png`<\/span><span class=\"p\">,<\/span> <span class=\"nx\">errCallback<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">filesToDelete<\/span><span class=\"p\">.<\/span><span class=\"nf\">push<\/span><span class=\"p\">(<\/span><span class=\"s2\">`<\/span><span class=\"p\">${<\/span><span class=\"nx\">dirPath<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">filename<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">filesToDelete<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">file<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">fs<\/span><span class=\"p\">.<\/span><span class=\"nf\">unlink<\/span><span class=\"p\">(<\/span><span class=\"nx\">file<\/span><span class=\"p\">,<\/span> <span class=\"nx\">errCallback<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">});<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I ran this as a node script in my terminal. After learning I needed the <code>--experimental-json-modules<\/code> option for the <code>.json<\/code> import to work, I had the files I needed named as <code>001.png<\/code>, <code>002.png<\/code> etc, all the way up to <code>908.png<\/code>. I uploaded them all to an AWS S3 bucket for hosting.<\/p>\n\n<h3>\n  \n  \n  Step 3: A SASS zerofill function\n<\/h3>\n\n<p>All I thought was left to do was to plug my image URLs into my code like so:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight scss\"><code><span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">@for<\/span> <span class=\"nv\">$i<\/span> <span class=\"ow\">from<\/span> <span class=\"m\">1<\/span> <span class=\"ow\">through<\/span> <span class=\"m\">908<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">&amp;<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"https:\/\/my-s3-bucket-domain.com\/<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"sx\">.png\")<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>except:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c04i25v9is426ctah8z.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c04i25v9is426ctah8z.png\" alt=\"An HTML list with Pok\u00e9mon icons as bullets, but there are no images before the 100th list item.\"><\/a><\/p>\n\n<p>Oops, my image urls are <em>zerofilled<\/em>, or padded with zeroes at the start so that each filename is the same length of characters. My CSS code is looking for <code>1.png<\/code> when it needs <code>001.png<\/code>.<\/p>\n\n<p>Once again, <a href=\"https:\/\/stackoverflow.com\/a\/20122879\/16315892\" rel=\"noopener noreferrer\">Stack Overflow had my solution<\/a>, and I adapted my code to:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight scss\"><code><span class=\"k\">@function<\/span> <span class=\"nf\">zerofill<\/span><span class=\"p\">(<\/span><span class=\"nv\">$i<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">@return<\/span> <span class=\"si\">#{<\/span><span class=\"nf\">str-slice<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"000\"<\/span><span class=\"o\">,<\/span> <span class=\"m\">0<\/span><span class=\"o\">,<\/span> <span class=\"m\">3<\/span> <span class=\"o\">-<\/span> <span class=\"nf\">str-length<\/span><span class=\"p\">(<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"p\">))<\/span><span class=\"si\">}#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nt\">ol<\/span> <span class=\"nt\">li<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">@for<\/span> <span class=\"nv\">$i<\/span> <span class=\"ow\">from<\/span> <span class=\"m\">1<\/span> <span class=\"ow\">through<\/span> <span class=\"m\">908<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">&amp;<\/span><span class=\"nd\">:nth-of-type<\/span><span class=\"o\">(<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"o\">)<\/span><span class=\"nd\">::marker<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nv\">$i<\/span><span class=\"p\">:<\/span> <span class=\"nf\">zerofill<\/span><span class=\"p\">(<\/span><span class=\"nv\">$i<\/span><span class=\"p\">);<\/span>\n      <span class=\"nl\">content<\/span><span class=\"p\">:<\/span> <span class=\"sx\">url(\"https:\/\/my-s3-bucket-domain.com\/<\/span><span class=\"si\">#{<\/span><span class=\"nv\">$i<\/span><span class=\"si\">}<\/span><span class=\"sx\">.png\")<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  The result\n<\/h3>\n\n<p>And ta-da, \ud83c\udf89 my Pok\u00e9mon ordered list!<\/p>\n\n<p><iframe height=\"600\" src=\"https:\/\/codepen.io\/aileen-r\/embed\/zYpjLyg?height=600&amp;default-tab=result&amp;embed-version=2\">\n<\/iframe>\n<\/p>\n\n<p>\u26a0 If you're a Safari or iOS user, unfortunately you won't see the Pok\u00e9mon bullets. At the time of writing, Safari has limited support for the <code>::marker<\/code> pseudo-element. You can check out <a href=\"https:\/\/bugs.webkit.org\/show_bug.cgi?id=204163\" rel=\"noopener noreferrer\">the bug ticket<\/a> for more details.<\/p>\n\n","category":["sass","css","html","pok\u00e9mon"]},{"title":"GitHub Actions: Fixing the 'Permission Denied' error for shell scripts","pubDate":"Mon, 04 Apr 2022 18:40:35 +0000","link":"https:\/\/dev.to\/aileenr\/github-actions-fixing-the-permission-denied-error-for-shell-scripts-4gbl","guid":"https:\/\/dev.to\/aileenr\/github-actions-fixing-the-permission-denied-error-for-shell-scripts-4gbl","description":"<p>Ever encountered this frustratingly vague \"Permission denied\" error when trying to run a bash script in an GitHub action workflow? \ud83d\ude21<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4viqu90rqe3mrrg222g.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4viqu90rqe3mrrg222g.png\" alt=\"Screenshot from GitHub's 'Actions' tab showing a build error: 'Permission denied' when trying to run a shell script\"><\/a><\/p>\n\n<p>\"Permission denied\" means that your script file does not have the \"execute\" permission set. On Mac and Linux you can use the <code>chmod<\/code> command to make script files executable, but Windows does not support this.<\/p>\n\n<h2>\n  \n  \n  How to fix it\n<\/h2>\n\n<p>Luckily, Git offers a command that works with Windows. Run:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>git update-index <span class=\"nt\">--chmod<\/span><span class=\"o\">=<\/span>+x your_script.sh\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>locally to make the bash script executable. Once you commit and push the change to your GitHub repository the script will be allowed to run in your GitHub action. \ud83c\udf89<\/p>\n\n<p><strong>NB:<\/strong> you will need to run this command then commit and push the change to GitHub for any bash script you create or rename on a Windows machine in order for it to run in a GitHub action.<\/p>\n\n<h2>\n  \n  \n  How to run a bash script in a GitHub action\n<\/h2>\n\n<p><em><strong>That's great Aileen, but how do I even add a script to a GitHub action?<\/strong><\/em><\/p>\n\n<p>Here is an example action which runs a <code>your_script.sh<\/code> script on commit to the <code>main<\/code> branch of your repository.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># https:\/\/gist.github.com\/aileen-r\/f74e680fb47ebc8b29a9f1cc452a5da9<\/span>\n\n<span class=\"c1\"># This is a basic workflow to help you get started with Actions<\/span>\n\n<span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Run a shell script<\/span>\n\n<span class=\"c1\"># Controls when the workflow will run<\/span>\n<span class=\"na\">on<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># Triggers the workflow on push but only for the main branch<\/span>\n  <span class=\"na\">push<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">branches<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span> <span class=\"nv\">main<\/span> <span class=\"pi\">]<\/span>\n\n<span class=\"c1\"># A workflow run is made up of one or more jobs that can run sequentially or in parallel<\/span>\n<span class=\"na\">jobs<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># This workflow contains a single job called \"build\"<\/span>\n  <span class=\"na\">build<\/span><span class=\"pi\">:<\/span>\n    <span class=\"c1\"># The type of runner that the job will run on<\/span>\n    <span class=\"na\">runs-on<\/span><span class=\"pi\">:<\/span> <span class=\"s\">ubuntu-latest<\/span>\n\n    <span class=\"c1\"># Steps represent a sequence of tasks that will be executed as part of the job<\/span>\n    <span class=\"na\">steps<\/span><span class=\"pi\">:<\/span>\n      <span class=\"c1\"># Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">uses<\/span><span class=\"pi\">:<\/span> <span class=\"s\">actions\/checkout@v2<\/span>\n\n      <span class=\"c1\"># Runs a single command using the runners shell<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Run shell script<\/span>\n        <span class=\"na\">run<\/span><span class=\"pi\">:<\/span> <span class=\"s\">.\/your_script.sh<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>If you're new to GitHub actions, GitHub has <a href=\"https:\/\/docs.github.com\/en\/actions\/quickstart\" rel=\"noopener noreferrer\">an excellent quickstart guide<\/a>.<\/p>\n\n","category":["github","devops","ci","bash"]},{"title":"Sticky Section Headers","pubDate":"Sun, 10 Oct 2021 18:43:58 +0000","link":"https:\/\/dev.to\/aileenr\/sticky-section-headers-506k","guid":"https:\/\/dev.to\/aileenr\/sticky-section-headers-506k","description":"<p>Hi folks! I threw together a Codepen to demo using <code>position: sticky<\/code> to \"stick\" section headers to the side of the screen while scrolling long blocks of content.<\/p>\n\n<p><iframe height=\"600\" src=\"https:\/\/codepen.io\/aileen-r\/embed\/Yzxzvag?height=600&amp;default-tab=result&amp;embed-version=2\">\n<\/iframe>\n<\/p>\n\n<p>This layout pattern could be used for a list of blog posts, comments on a single blog post, or for keeping share buttons in view on long article pages. It could also be used for an instant messaging layout to \"stick\" a user's profile picture next to their message.<\/p>\n\n<p>On mobile screen sizes, the headers stack vertically but stay sticky at the top of the screen.<\/p>\n\n<h2>\n  \n  \n  Resources Used\n<\/h2>\n\n<ul>\n<li>\n<a href=\"https:\/\/www.happyhues.co\/palettes\/15\">Happy Hues<\/a> for the colour palette.<\/li>\n<li>\n<a href=\"https:\/\/fontawesome.com\/\">Font Awesome<\/a> for social icons.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  References\n<\/h2>\n\n<ul>\n<li>This CSS Tricks article on <a href=\"https:\/\/css-tricks.com\/linearly-scale-font-size-with-css-clamp-based-on-the-viewport\/\">scaling font-size based on the viewport<\/a>.<\/li>\n<li>More generally, I've been doing the amazing <a href=\"https:\/\/css-for-js.dev\/\">CSS for JavaScript Developers course<\/a> which has been inspiring me to learn CSS in-depth as a language, rather than as a collection of hacks and tricks.<\/li>\n<\/ul>\n\n","category":["css","showdev","html","webdev"]},{"title":"Let's Build a HTML and CSS Landing Page with Parcel","pubDate":"Fri, 06 Aug 2021 13:47:53 +0000","link":"https:\/\/dev.to\/aileenr\/blazing-fast-frontend-development-with-parcel-21dc","guid":"https:\/\/dev.to\/aileenr\/blazing-fast-frontend-development-with-parcel-21dc","description":"<p>Ever wanted to dive straight into building a simple HTML page without having to faff around with build configuration?<\/p>\n\n<p>Sure, there are amazing online tools like <a href=\"https:\/\/codepen.io\/\" rel=\"noopener noreferrer\">Codepen<\/a>, but I'm talking something you can run locally with hot reloading, something you can easily build and deploy with minimum setup.<\/p>\n\n<p>I wanted just that, and that's when I learned about <a href=\"https:\/\/parceljs.org\/\" rel=\"noopener noreferrer\">Parcel.js<\/a>. The \"blazing fast, zero configuration web application bundler\".<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6unpi6qrohqmv29wrq54.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6unpi6qrohqmv29wrq54.png\" alt=\"Parcel landing page\"><\/a><\/p>\n\n<p>Unlike <a href=\"https:\/\/webpack.js.org\/\" rel=\"noopener noreferrer\">Webpack<\/a>, a bundler which offers maximal configurability, Parcel prefers a <strong>minimal config approach<\/strong>. It handles most imports out-of-the box, with no need to manually install plugins.<\/p>\n\n<p>If that sounds good and you want some free project templates to start from already, I've got you covered. \ud83d\ude09 They're at the bottom of this article. Curious to learn more? Let's build a landing page together to see how it works.<\/p>\n\n<ul>\n<li>\nLet's build a landing page\n\n<ul>\n<li>Hello World page<\/li>\n<li>Add SASS styles<\/li>\n<li>Separating HTML into partials with posthtml-include<\/li>\n<li>I want to use TypeScript!<\/li>\n<li>Installing extra dependencies &amp; finishing the landing page<\/li>\n<li>Cross-Browser Support<\/li>\n<li>Deploying our landing page<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>Some downsides<\/li>\n\n<li>Takeaways<\/li>\n\n<li>One-click deploy starter templates<\/li>\n\n<\/ul>\n\n<h2>\n  \n  \n  Let's build a landing page\n<\/h2>\n\n<p>We're going to build and deploy <a href=\"https:\/\/www.codewell.cc\/challenges\/608d9565747bad001532bd64\" rel=\"noopener noreferrer\">this landing page designed by Codewell<\/a>.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff03x6tgwh0mht38p9ph9.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff03x6tgwh0mht38p9ph9.png\" alt=\"Landing page design by Codewell\"><\/a><\/p>\n\n<p>We'll be using <a href=\"https:\/\/sass-lang.com\/\" rel=\"noopener noreferrer\">SASS<\/a> and <a href=\"https:\/\/posthtml.org\/#\/\" rel=\"noopener noreferrer\">posthtml<\/a>, which can be used with Parcel with minimal configuration. Finally we're using <a href=\"https:\/\/www.netlify.com\/\" rel=\"noopener noreferrer\">Netlify<\/a> to deploy our landing page for free.<\/p>\n\n<h3>\n  \n  \n  Hello World page\n<\/h3>\n\n<p>First, we'll get a simple \"hello world\" up and running with Parcel. You'll need the <a href=\"https:\/\/docs.npmjs.com\/cli\" rel=\"noopener noreferrer\">npm CLI<\/a> installed for this.<\/p>\n\n<ol>\n<li>\n<p>Create a directory to host the project and make it your current directory.<br>\n<\/p>\n<pre class=\"highlight shell\"><code><span class=\"nv\">$ <\/span><span class=\"nb\">mkdir <\/span>commune-waitlist-page\n<span class=\"nv\">$ <\/span><span class=\"nb\">cd <\/span>commune-waitlist-page\n<\/code><\/pre>\n\n<\/li>\n<li><p>Run <code>npm init<\/code> and follow the prompts (defaults are fine).<\/p><\/li>\n<li><p>Open the directory in your favourite code editor. You should have a <code>package.json<\/code> file. Remove the <code>\"main\": \"index.js\",<\/code> line, since Parcel will not need it.<\/p><\/li>\n<li>\n<p>Next let's add our main HTML and JS files. Create a <code>src<\/code> directory and create two files named <code>index.html<\/code> and <code>index.js<\/code>, with the following content:<br>\n<code>index.html<\/code>:<br>\n<\/p>\n<pre class=\"highlight html\"><code><span class=\"cp\">&lt;!DOCTYPE html&gt;<\/span>\n<span class=\"nt\">&lt;html<\/span> <span class=\"na\">lang=<\/span><span class=\"s\">\"en\"<\/span><span class=\"nt\">&gt;<\/span>\n  <span class=\"nt\">&lt;head&gt;<\/span>\n    <span class=\"nt\">&lt;meta<\/span> <span class=\"na\">charset=<\/span><span class=\"s\">\"UTF-8\"<\/span> <span class=\"nt\">\/&gt;<\/span>\n    <span class=\"nt\">&lt;meta<\/span> <span class=\"na\">http-equiv=<\/span><span class=\"s\">\"X-UA-Compatible\"<\/span> <span class=\"na\">content=<\/span><span class=\"s\">\"IE=edge\"<\/span> <span class=\"nt\">\/&gt;<\/span>\n    <span class=\"nt\">&lt;meta<\/span> <span class=\"na\">name=<\/span><span class=\"s\">\"viewport\"<\/span> <span class=\"na\">content=<\/span><span class=\"s\">\"width=device-width, initial-scale=1.0\"<\/span> <span class=\"nt\">\/&gt;<\/span>\n    <span class=\"nt\">&lt;title&gt;<\/span>Commune Waitlist Page<span class=\"nt\">&lt;\/title&gt;<\/span>\n  <span class=\"nt\">&lt;\/head&gt;<\/span>\n  <span class=\"nt\">&lt;body&gt;<\/span>\n    <span class=\"nt\">&lt;h1&gt;<\/span>Commune<span class=\"nt\">&lt;\/h1&gt;<\/span>\n    <span class=\"nt\">&lt;script <\/span><span class=\"na\">type=<\/span><span class=\"s\">\"module\"<\/span> <span class=\"na\">src=<\/span><span class=\"s\">\".\/index.js\"<\/span><span class=\"nt\">&gt;&lt;\/script&gt;<\/span>\n  <span class=\"nt\">&lt;\/body&gt;<\/span>\n<span class=\"nt\">&lt;\/html&gt;<\/span>\n<\/code><\/pre>\n\n\n<p><code>index.js<\/code>:<br>\n<\/p>\n<pre class=\"highlight javascript\"><code><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">log<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">Hello world! \ud83d\udc4b<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n\n<p>Your directory should now look something like this:<br>\n<a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8nbz3yganhfdizcuh3z.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8nbz3yganhfdizcuh3z.png\" alt=\"Project directory structure. A \"><\/a><\/p>\n<\/li>\n<li>\n<p>Finally, let's add Parcel! Run<br>\n<\/p>\n<pre class=\"highlight shell\"><code><span class=\"nv\">$ <\/span>npm <span class=\"nb\">install<\/span> <span class=\"nt\">-D<\/span> parcel@next\n<\/code><\/pre>\n\n\n<p>to save Parcel v2 as a dev dependency. Then add the following to the \"scripts\" property in <code>package.json<\/code>:<br>\n<\/p>\n<pre class=\"highlight json\"><code><span class=\"nl\">\"start\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"parcel serve .\/src\/index.html\"<\/span><span class=\"err\">,<\/span><span class=\"w\">\n<\/span><span class=\"nl\">\"build\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"parcel build .\/src\/index.html\"<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/li>\n<li><p>Run <code>npm start<\/code> and open <a href=\"http:\/\/localhost:1234\" rel=\"noopener noreferrer\">http:\/\/localhost:1234<\/a> in your browser to see your Hello World app running locally!<\/p><\/li>\n<\/ol>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0u7uce4tbgzcgbq5ffk.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0u7uce4tbgzcgbq5ffk.png\" alt=\"Screenshot of Hello World app running in Firefox browser.\"><\/a><\/p>\n\n<p>Unlike other bundlers, Parcel uses an HTML file as its entry point, as you can see in the <code>parcel serve<\/code> and <code>parcel build<\/code> commands we added to <code>package.json<\/code>. Parcel detects any JavaScript or CSS dependencies directly from the entry HTML file then bundles it appropriately.<\/p>\n\n<h3>\n  \n  \n  Add SASS styles\n<\/h3>\n\n<p>Being able to use SASS for my stylesheet is one of my biggest motivations for using a bundler for a simple frontend app like this. Parcel makes adding SASS a breeze.<\/p>\n\n<ol>\n<li>\n<p>In the <code>src<\/code> directory, create a file called <code>styles.scss<\/code>. For the sake of this demo, I am using it to create two SASS variables and set them as the <code>color<\/code> and <code>background-color<\/code> of the page:<br>\n<\/p>\n<pre class=\"highlight scss\"><code><span class=\"c1\">\/\/ styles.scss<\/span>\n<span class=\"nv\">$background-color<\/span><span class=\"p\">:<\/span> <span class=\"mh\">#F6F9FE<\/span><span class=\"p\">;<\/span>\n<span class=\"nv\">$color<\/span><span class=\"p\">:<\/span> <span class=\"mh\">#353252<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nt\">body<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nl\">background-color<\/span><span class=\"p\">:<\/span> <span class=\"nv\">$background-color<\/span><span class=\"p\">;<\/span>\n    <span class=\"nl\">color<\/span><span class=\"p\">:<\/span> <span class=\"nv\">$color<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/li>\n<li>\n<p>Add the following line to your <code>index.html<\/code> file:<br>\n<\/p>\n<pre class=\"highlight html\"><code><span class=\"nt\">&lt;link<\/span> <span class=\"na\">rel=<\/span><span class=\"s\">\"stylesheet\"<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\".\/styles.scss\"<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/code><\/pre>\n\n\n\n\n<p>then switch back to the browser to see your style changes.<\/p>\n<\/li>\n<\/ol>\n\n<p>That's it! \u2728 No plugins to install, no config files to add, nothing. SASS just <em>works<\/em>.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmy9gkwh9oilfucn34i6j.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmy9gkwh9oilfucn34i6j.png\" alt=\"Screenshot of Hello World app running in Firefox browser, now with some added styles.\"><\/a><\/p>\n\n<p>Behind the scenes - as soon as you hit \"save\" on <code>index.html<\/code> - Parcel read the file and saw it referenced a <code>.scss<\/code> file. It then went and installed the appropriate SASS plugin for you and rebuilt for hot reload. In fact, if you inspect your <code>package.json<\/code> file you'll see Parcel has added the <code>@parcel\/transformer-sass<\/code> plugin to your dev dependencies for you.<\/p>\n\n<h3>\n  \n  \n  Separating HTML into partials with posthtml-include\n<\/h3>\n\n<p>Our <code>index.html<\/code> file is small at the moment, but it's going to get pretty long as we build the landing page. It becomes tedious scrolling up and down a long HTML file to make edits.<\/p>\n\n<p>One way to avoid that is to split our HTML into separate partial <code>.html<\/code> files. Parcel offers a plugin for <a href=\"https:\/\/v2.parceljs.org\/languages\/html\/#posthtml\" rel=\"noopener noreferrer\">posthtml<\/a>, which lets us do this. It requires a small config file.<\/p>\n\n<p>Let's try this by adding a partial for the navigation bar on the landing page.<\/p>\n\n<ol>\n<li>\n<p>At the root of your project directory (where <code>package.json<\/code> lives), create a new file called <code>.posthtmlrc<\/code> containing the following:<br>\n<\/p>\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"plugins\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"posthtml-include\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n            <\/span><span class=\"nl\">\"root\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\".\/src\"<\/span><span class=\"w\">\n        <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/li>\n<li>\n<p>In the <code>src<\/code> directory, create a new directory called <code>partials<\/code>. In <code>partials<\/code>, create a new file called <code>nav.html<\/code> with the following content:<br>\n<\/p>\n<pre class=\"highlight html\"><code><span class=\"nt\">&lt;nav&gt;<\/span>\n  <span class=\"nt\">&lt;ul&gt;<\/span>\n    <span class=\"nt\">&lt;li&gt;&lt;a<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\"#\"<\/span><span class=\"nt\">&gt;<\/span>Features<span class=\"nt\">&lt;\/a&gt;&lt;\/li&gt;<\/span>\n    <span class=\"nt\">&lt;li&gt;&lt;a<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\"#\"<\/span><span class=\"nt\">&gt;<\/span>Affiliates<span class=\"nt\">&lt;\/a&gt;&lt;\/li&gt;<\/span>\n    <span class=\"nt\">&lt;li&gt;&lt;a<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\"#\"<\/span><span class=\"nt\">&gt;<\/span>Pricing<span class=\"nt\">&lt;\/a&gt;&lt;\/li&gt;<\/span>\n    <span class=\"nt\">&lt;li&gt;&lt;a<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\"#\"<\/span><span class=\"nt\">&gt;<\/span>Communities<span class=\"nt\">&lt;\/a&gt;&lt;\/li&gt;<\/span>\n    <span class=\"nt\">&lt;li&gt;&lt;a<\/span> <span class=\"na\">href=<\/span><span class=\"s\">\"#\"<\/span><span class=\"nt\">&gt;<\/span>Join Waitlist<span class=\"nt\">&lt;\/a&gt;&lt;\/li&gt;<\/span>\n  <span class=\"nt\">&lt;\/ul&gt;<\/span>\n<span class=\"nt\">&lt;\/nav&gt;<\/span>\n\n<\/code><\/pre>\n\n<\/li>\n<li>\n<p>Then, replace the <code>&lt;h1&gt;Commune&lt;\/h1&gt;<\/code> line in <code>index.html<\/code> with the following:<br>\n<\/p>\n<pre class=\"highlight html\"><code><span class=\"nt\">&lt;header&gt;<\/span>\n  <span class=\"nt\">&lt;h1&gt;<\/span>Commune<span class=\"nt\">&lt;\/h1&gt;<\/span>\n  <span class=\"nt\">&lt;include<\/span> <span class=\"na\">src=<\/span><span class=\"s\">\"partials\/nav.html\"<\/span><span class=\"nt\">&gt;&lt;\/include&gt;<\/span>\n<span class=\"nt\">&lt;\/header&gt;<\/span>\n<\/code><\/pre>\n\n<\/li>\n<li><p>If npm throws an <code>EPERM<\/code> error, cancel the process with Ctrl+C and run <code>npm start<\/code> again.<\/p><\/li>\n<\/ol>\n\n<p>Once again, that's it! \u2728 If you inspect your <code>package.json<\/code> file you will see that Parcel has installed the necessary package for you: <code>posthtml-include<\/code> in this instance.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forcpyhe54eaunrjyu9ec.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forcpyhe54eaunrjyu9ec.png\" alt=\"Screenshot of Hello World app running in Firefox browser with navigation links added.\"><\/a><\/p>\n\n<h3>\n  \n  \n  I want to use TypeScript!\n<\/h3>\n\n<p>I'm not on the TypeScript train yet, but I hear you! Parcel has you covered. Here's a contrived example to prove it.<\/p>\n\n<ol>\n<li><p>First, let's rename our <code>index.js<\/code> file to <code>index.ts<\/code> and update the reference in <code>index.html<\/code> accordingly. You may need to restart the app.<\/p><\/li>\n<li>\n<p>It works! But let's add some TypeScript-specific code to convince ourselves. Replace the contents of <code>index.ts<\/code> with:<br>\n<\/p>\n<pre class=\"highlight typescript\"><code><span class=\"kd\">function<\/span> <span class=\"nf\">consoleLogWithEmoji<\/span><span class=\"p\">(<\/span><span class=\"nx\">message<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">,<\/span> <span class=\"nx\">emoji<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">):<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">message<\/span> <span class=\"o\">+<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\"> <\/span><span class=\"dl\">\"<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">emoji<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nf\">consoleLogWithEmoji<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">Hello world!<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">\ud83d\udc4b<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/li>\n<\/ol>\n\n<p>Easy-peasy! Unfortunately though, Parcel doesn't perform TypeScript type checking out-the-box. Further TypeScript details are outwith the scope of this article, but you can learn <a href=\"https:\/\/v2.parceljs.org\/languages\/typescript\/#type-checking\" rel=\"noopener noreferrer\">how to configure type-checking in the Parcel documentation<\/a>.<\/p>\n\n<h3>\n  \n  \n  Installing extra dependencies &amp; finishing the landing page\n<\/h3>\n\n<p>I won't waste your time walking through every piece of HTML and CSS I added to build the landing page. If you'd like to see the changes I made you can see the <a href=\"https:\/\/github.com\/aileen-r\/commune-waitlist-page\/pull\/1\" rel=\"noopener noreferrer\">diff on GitHub here<\/a>.<\/p>\n\n<p>With Parcel we can install npm packages just like we can with other bundlers. As a finishing touch, I'm going to add some light animation using the <a href=\"https:\/\/michalsnik.github.io\/aos\/\" rel=\"noopener noreferrer\">animate on scroll<\/a> library.<\/p>\n\n<p>To use animate on scroll, run<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npm <span class=\"nb\">install <\/span>aos <span class=\"nt\">--save<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>in the project root directory. Next we add<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">AOS<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">aos<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">aos\/dist\/aos.css<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nx\">AOS<\/span><span class=\"p\">.<\/span><span class=\"nf\">init<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>to our<code>index.js<\/code> file. You can also add additional configuration options to the <code>AOS.init()<\/code> call. See the <a href=\"https:\/\/github.com\/michalsnik\/aos\/tree\/v2\" rel=\"noopener noreferrer\">AOS docs<\/a> for details.<\/p>\n\n<p>Now we can add <code>data-aos=\"animation_name\"<\/code> to any element you want to animate in. I added <code>data-aos=\"fade\"<\/code> to the page wrapper div, then some other fade in animations after a short delay.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdw9q3060yy9oqk8xf76.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdw9q3060yy9oqk8xf76.gif\" alt=\"Landing page animated with Animate on scroll library\"><\/a><\/p>\n\n<p>It's done! \ud83c\udf89 One last thing before we can build for production...<\/p>\n\n<h3>\n  \n  \n  Cross-Browser Support\n<\/h3>\n\n<p>Before we deploy our app, let's add some basic cross-browser support. Parcel doesn't transpile any code out-of-the-box, but we can add support for some older browsers with <a href=\"https:\/\/parceljs.org\/getting-started\/webapp\/#declaring-browser-targets\" rel=\"noopener noreferrer\">browserslist<\/a>.<\/p>\n\n<p>Simply add<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"nl\">\"browserslist\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n    <\/span><span class=\"s2\">\"defaults\"<\/span><span class=\"w\">\n<\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>to <code>package.json<\/code> to configure browserslist's recommended cross-browser support. You can check out the <a href=\"https:\/\/github.com\/browserslist\/browserslist\" rel=\"noopener noreferrer\">browserslist repo<\/a> for more configuration options.<\/p>\n\n<p>Now let's get this thing deployed!<\/p>\n\n<h3>\n  \n  \n  Deploying our landing page\n<\/h3>\n\n<p>We're going to use <a href=\"https:\/\/www.netlify.com\/\" rel=\"noopener noreferrer\">Netlify<\/a> to deploy our landing page. I love using Netlify to host my frontend projects because it connects directly to <a href=\"https:\/\/github.com\/\" rel=\"noopener noreferrer\">GitHub<\/a>, it's super quick and easy to set up, and it's free!<\/p>\n\n<p>If you're not already using GitHub to host your code there's <a href=\"https:\/\/docs.github.com\/en\/github\/importing-your-projects-to-github\/importing-source-code-to-github\/adding-an-existing-project-to-github-using-the-command-line\" rel=\"noopener noreferrer\">a guide for pushing your code to a GitHub repository here<\/a>.<\/p>\n\n<p>To deploy the code from GitHub to Netlify:<\/p>\n\n<ol>\n<li><p>Login or sign-up to <a href=\"https:\/\/app.netlify.com\" rel=\"noopener noreferrer\">Netlify<\/a>.<\/p><\/li>\n<li><p>On the overview page, click \"New site from Git\".<br>\n<a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqv0l108699yudnvu2v1y.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqv0l108699yudnvu2v1y.png\" alt=\"Netlify overview page\"><\/a><\/p><\/li>\n<li><p>Choose \"GitHub\" as your Git provider. There is also the option to choose GitLab or BitBucket.<br>\n<a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tbrhf30q25tmm1xktkl.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tbrhf30q25tmm1xktkl.png\" alt=\"Connect Netlify to GitHub\"><\/a><\/p><\/li>\n<li><p>On the next page of the wizard, select the GitHub repository for your project.<\/p><\/li>\n<li>\n<p>All the default site settings are correct for us, but let's quickly break the build settings down:  <\/p>\n\n<ul>\n<li>\n<strong>Base directory<\/strong> - This is the directory where you run npm commands like <code>npm start<\/code> and <code>npm run build<\/code>. For us, this is the root directory so this should be blank.<\/li>\n<li>\n<strong>Build command<\/strong> - The command for creating a production build. This is <code>npm run build<\/code>, which we added to <code>package.json<\/code> back when we first built a Hello World page.\n<pre>\"build\": \"parcel build .\/src\/index.html\"<\/pre>\n<\/li>\n<li>\n<strong>Publish directoy<\/strong> - This is the name of the directory that is outputted from <code>npm run build<\/code>. For us this is <code>dist<\/code>, which is the default from Parcel.\n<img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq2gancx7g2kt0ubns7t.png\" alt=\"Netlify build settings for a Parcel app\">\n<\/li>\n<\/ul>\n<\/li>\n<li><p>Click \"Deploy site\".<\/p><\/li>\n<li><p>Netlify will create a randomly generated URL for you like <em>elegant-elion-c301a1.netlify.app<\/em>. You can edit this by clicking \"Site settings\" then \"Change site name\".<\/p><\/li>\n<li><p>Once the last production deploy has a green \"Published\" badge next to it, your website is live! It will re-deploy any time you push code changes to the default branch of your GitHub repository.<br>\n<a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff07om5qlgqgvv89vbo53.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff07om5qlgqgvv89vbo53.png\" alt=\"Commune waitlist page deployed to Netlify\"><\/a><\/p><\/li>\n<\/ol>\n\n<p>And it's done! My landing page now lives at <a href=\"https:\/\/commune-waitlist-page-aileen-r.netlify.app\/\" rel=\"noopener noreferrer\">https:\/\/commune-waitlist-page-aileen-r.netlify.app\/<\/a> \ud83d\ude80 <\/p>\n\n<h2>\n  \n  \n  Some downsides\n<\/h2>\n\n<p>My overall experience of using Parcel was a happy one, since I could get up and running super quickly. That being said I did hit a couple of snags along the way.<\/p>\n\n<p>Hot reload sometimes fails to recompile and you have to manually kill the app then rerun <code>npm start<\/code>. I noticed this when:<\/p>\n\n<ol>\n<li>Saving a SASS file with a syntax error, like a missing semi-colon. Fixing the error and re-saving doesn't force a recompile like I would expect. This is obviously only an issue when using SASS.<\/li>\n<li>Making an edit to an HTML file. About 50% of the time it would throw an <code>EPERM<\/code> permissions error since it was trying to rename a file that was currently in-use by the running process (<code>npm start<\/code>). It's possible this error only occurs when using posthtml-include, but I haven't investigated further.\n<img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r4kj98877f5pn5yn134.png\" alt=\"EPERM error after editing an HTML file.\">\n<\/li>\n<\/ol>\n\n<p>While this is a bit of a nuisance, the app startup time is quick so it never interrupted my flow.<\/p>\n\n<p>Another hurdle I ran into was cross-browser support. While everything worked smoothly for semi-modern browsers, Internet Explorer 11 support was a different issue. First there is <a href=\"https:\/\/github.com\/parcel-bundler\/parcel\/issues\/2364\" rel=\"noopener noreferrer\">an issue running dev server in IE11<\/a>, and you have to manually install polyfills yourself. I chose to ignore IE11 support since <a href=\"https:\/\/blogs.windows.com\/windowsexperience\/2021\/05\/19\/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge\/\" rel=\"noopener noreferrer\">Microsoft is finally retiring the browser in 2022<\/a>. If you need to continue to support IE...well, may the force be with you.<\/p>\n\n<p>It's worth noting that I've been using v2 of Parcel, which at the time of writing is still at its first release candidate build.<\/p>\n\n<h2>\n  \n  \n  Takeaways\n<\/h2>\n\n<p>Parcel is great for small projects. I've specifically found it to be perfect for setting up <a href=\"https:\/\/github.com\/aileen-r\/group-array-elements-interview-question\" rel=\"noopener noreferrer\">technical test solutions<\/a> while job hunting as it makes it easy to add Jest for unit testing without using a JS framework starter kit like Create React App.<\/p>\n\n<p>If I found myself needing more configurability, I would probably still pick Webpack first.<\/p>\n\n<p>One thing Parcel offers which I didn't try is using it for <a href=\"https:\/\/v2.parceljs.org\/recipes\/react\/\" rel=\"noopener noreferrer\">React<\/a> or <a href=\"https:\/\/v2.parceljs.org\/languages\/vue\/\" rel=\"noopener noreferrer\">VueJS<\/a> apps. Personally I think the starter projects generated by <a href=\"https:\/\/create-react-app.dev\/\" rel=\"noopener noreferrer\">Create React App<\/a> and <a href=\"https:\/\/cli.vuejs.org\/guide\/creating-a-project.html\" rel=\"noopener noreferrer\">Vue CLI<\/a> are easy enough to get started with, so I don't see a need to try and use Parcel. If anyone has used Parcel for React or Vue I'd love to hear your experience with it in the comments.<\/p>\n\n<h2>\n  \n  \n  One-click deploy starter templates\n<\/h2>\n\n<p>If reading a tutorial isn't your thing and you want to dive headfirst into code, I've prepared some starter templates for you. Each has a \"deploy to Netlify\" button which creates your own copy of the repository and deploys it to Netlify for free with one click!<\/p>\n\n<ul>\n<li><a href=\"https:\/\/github.com\/aileen-r\/parcel-html-css-js-starter-template\" rel=\"noopener noreferrer\">HTML, CSS, and JavaScript starter template with Parcel<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/aileen-r\/parcel-html-sass-js-starter-template\" rel=\"noopener noreferrer\">HTML, SASS, and JavaScript starter template with Parcel<\/a><\/li>\n<\/ul>\n\n<p>If you find any of the templates useful please let me know. Thanks for reading!<\/p>\n\n","category":["html","javascript","parcel","sass"]},{"title":"How to spoof your timezone in Google Chrome","pubDate":"Sat, 06 Mar 2021 17:48:16 +0000","link":"https:\/\/dev.to\/aileenr\/how-to-spoof-your-timezone-in-google-chrome-48ch","guid":"https:\/\/dev.to\/aileenr\/how-to-spoof-your-timezone-in-google-chrome-48ch","description":"<p>Today I learned: you can spoof your timezone in Google Chrome <strong>without<\/strong> needing to change your system settings.<\/p>\n\n<p>I was implementing user timezone preferences for a CMS product when I learned about this, much to my relief. I had been anticipating having to change my system settings over and over again as I tested how my datetime formatting behaved in different timezones.<\/p>\n\n<p>So how do you do it?<\/p>\n\n<ol>\n<li>Open DevTools in Chrome (F12).<\/li>\n<li>If not already shown, open the Console drawer (esc).<\/li>\n<li>Click the three, vertically-aligned dots at the top-left of the console drawer (<code>\u22ee<\/code>).<\/li>\n<li>In the dropdown menu, select <strong>Sensors<\/strong>.\n<img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe79bud0ywvwtdqk25mxa.jpg\" alt=\"Google Chrome Sensors tab\">\n<\/li>\n<li>In the new Sensors tab, you can change your location to one of the presets, or choose \"Other...\" to manually enter a timezone.\n<img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5onffvy8m6oo2zol4dok.jpg\" alt=\"Google Chrome Sensors Geolocation option\">\n<\/li>\n<\/ol>\n\n<p>If you're viewing this in Chrome, try it out now and take a look at the current time displayed in the Codepen below.<\/p>\n\n<p><iframe height=\"600\" src=\"https:\/\/codepen.io\/aileen-r\/embed\/GRNXMvB?height=600&amp;default-tab=result&amp;embed-version=2\">\n<\/iframe>\n<\/p>\n\n","category":["todayilearned","chrome","tips","timezones"]},{"title":"TIL: You can watch for nested properties changing in React's useEffect() hook","pubDate":"Wed, 17 Feb 2021 18:58:36 +0000","link":"https:\/\/dev.to\/aileenr\/til-you-can-watch-for-nested-properties-changing-in-react-s-useeffect-hook-26nj","guid":"https:\/\/dev.to\/aileenr\/til-you-can-watch-for-nested-properties-changing-in-react-s-useeffect-hook-26nj","description":"<p>Today I learned: you can watch for nested properties changing in React's <code>useEffect()<\/code> hook by using dot notation in the dependency array, like so:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"c1\">\/\/ hook runs whenever someValue.someNestedValue is updated<\/span>\n<span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span><span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ do something<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">someValue<\/span><span class=\"p\">.<\/span><span class=\"nx\">someNestedValue<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<p>React's <code>useEffect()<\/code> hook lets you perform a <em>side-effect<\/em> in a functional component. That is, whenever the component updates, whatever code you put in the <code>useEffect()<\/code> hook executes.<\/p>\n\n<p>By default, the hook runs on <strong>every<\/strong> component update, which for performance reasons we should avoid:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span><span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ I run when ANYTHING updates<\/span>\n<span class=\"p\">})<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>But, we can optionally pass a <strong>dependency array<\/strong> as a second argument to tell React to only re-run the hook when the specified dependencies update:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span><span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ I only run when someValue updates<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">someValue<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>But what about if you have nested data, say an object containing form data, e.g.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">values<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Aileen<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">age<\/span><span class=\"p\">:<\/span> <span class=\"mi\">26<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">city<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Edinburgh<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">favoriteFood<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">pizza \ud83c\udf55<\/span><span class=\"dl\">'<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>What if I want to trigger a side-effect when the user updates just their age, and not when any other value changes?<\/p>\n\n<p>It seems obvious in hindsight, but you can watch for nested values changing simply by referencing the nested property with dot notation:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span><span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">ageChangeSideEffect<\/span><span class=\"p\">(<\/span><span class=\"nx\">values<\/span><span class=\"p\">.<\/span><span class=\"nx\">age<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">values<\/span><span class=\"p\">.<\/span><span class=\"nx\">age<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Additionally, we can trigger the <code>useEffect()<\/code> hook for deeper nested objects if necessary:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span><span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ do something<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">someValue<\/span><span class=\"p\">.<\/span><span class=\"nx\">someNestedValue<\/span><span class=\"p\">.<\/span><span class=\"nx\">someDeeplyNestedValue<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n","category":["todayilearned","react","javascript","beginners"]}]}}