<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Daily Dev Tips]]></title><description><![CDATA[Daily Development Tips for the Community]]></description><link>https://h.daily-dev-tips.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1629097194939/24y2YdUns.png</url><title>Daily Dev Tips</title><link>https://h.daily-dev-tips.com</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 06 Oct 2026 18:59:52 GMT</lastBuildDate><atom:link href="https://h.daily-dev-tips.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I wrote 1000 articles, what’s next?]]></title><description><![CDATA[Most of you know me for my consistency, a golden arrow in my blog series.
I've written 1000 articles in 1008 days!
Almost an article a day, and my honeymoon was the only holiday I ever took.
I'm super proud of this achievement; it has been a fantasti...]]></description><link>https://h.daily-dev-tips.com/i-wrote-1000-articles-whats-next</link><guid isPermaLink="true">https://h.daily-dev-tips.com/i-wrote-1000-articles-whats-next</guid><category><![CDATA[watercooler]]></category><category><![CDATA[General Advice]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[#DevRetro2022]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Thu, 22 Dec 2022 05:46:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671687927056/qP6lOtVoD.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most of you know me for my consistency, a golden arrow in my blog series.</p>
<p>I've written 1000 articles in 1008 days!
Almost an article a day, and my honeymoon was the only holiday I ever took.</p>
<p>I'm super proud of this achievement; it has been a fantastic journey.</p>
<p>But what's next?</p>
<p>And it took me a while to think about that.
Do I want to continue writing daily? Do I want to try out other things? What is the next big thing?</p>
<p>And before answering that, I need to open up about the fact that writing daily is super unique, and I loved it, but it was also quite draining towards the 1000th article.</p>
<p>And then something magical and exciting changed my whole thinking about everything.</p>
<p>We got pregnant!
So amazing, and I'm ready to become a dad.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671605496310/oFFC1-_o9.jpg" alt="Baby Bongers on the way" /></p>
<h2 id="heading-what-to-expect">What to expect</h2>
<p>So alright, what to expect from me in the future?
I will never stop creating content as I enjoy it so much, but I decided to move away from daily content.</p>
<p>There are a couple of aspects I want to try to find the next best thing:</p>
<ul>
<li>Youtube videos</li>
<li>Long-form articles</li>
<li>Ebooks</li>
</ul>
<p>Between those, I'll dedicate more time per content piece and might even go deeper into some of the ones I already created.</p>
<p>Besides that, I have a few hobby projects and ideas I want to execute, so keep an eye out for those.</p>
<h2 id="heading-what-about-the-site">What about the site?</h2>
<p>Well, I might drop an article irregularly as I see fit, but the truth is, I'm planning on selling the website.</p>
<p>It's been my baby for almost three years, and it has matured a lot to a point where I'd love to see someone take it over and keep providing unique content for new developers.</p>
<p>If that person is you, please do get in touch 🙏.</p>
<h2 id="heading-some-numbers">Some numbers</h2>
<p>Many of you probably came here to see some numbers, right?
What do 1000 articles represent?</p>
<p>And here are some of them:</p>
<ul>
<li>528704 words</li>
<li>1920 newsletter subscribers</li>
<li>160K+ page views every month</li>
<li>110+ #1 ranked google queries</li>
<li>an average of 100K impressions daily</li>
<li>5K clicks on search terms alone</li>
<li>And so much more</li>
</ul>
<p>I couldn't be happier.
In the beginning, I'd never thought that would even be possible, yet I achieved it.</p>
<p>And that's not because of my writing, but because of all you amazing people motivating me and reading the articles.</p>
<p>So from the bottom of my heart:</p>
<p>Thank you for joining me on this journey.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure community and more]]></title><description><![CDATA[It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool.
This shows in my previous explorations of Astro, Medusa, and now Vendure as well.
All these products thrive in a super open, welcoming, ...]]></description><link>https://h.daily-dev-tips.com/vendure-community-and-more</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-community-and-more</guid><category><![CDATA[community]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Wed, 21 Dec 2022 07:02:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671606093521/TLLCJWzXR.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool.</p>
<p>This shows in my previous explorations of <a target="_blank" href="https://daily-dev-tips.com/tags/astro/">Astro</a>, <a target="_blank" href="https://daily-dev-tips.com/tags/webshop/">Medusa</a>, and now Vendure as well.</p>
<p>All these products thrive in a super open, welcoming, and helpful community.
To me, this is super amazing as it helps you use the product to the fullest.</p>
<p>Let me sketch some examples of the Vendure community.</p>
<h2 id="heading-examples-of-the-community">Examples of the community</h2>
<p>First of all, Vendure has an excellent slack channel where you can pop in and ask any questions.
Anyone is super helpful to help you get to solve your issues.</p>
<p>I even got a DM from a core member stating they saw my articles on Vendure and asking why I was looking into their product.
I love it when creators like to get feedback on those things.</p>
<p>Secondly, there is a healthy amount of help available online, as in people writing about Vendure, creating examples, and even products.</p>
<p>An excellent example of the latter is <a target="_blank" href="https://pinelab.studio/">Pinelab</a>, where the owner Martijn creates open-source Vendure plugins. Vendure saw this effort and made Pinelab a silver Vendure partner.
Small acknowledgments like that show how much they respect their community and how much they want it to be healthy.</p>
<h2 id="heading-expectations">Expectations</h2>
<p>When it comes to communities, what would you be looking for?</p>
<p>As for me, it's mainly a matter of responsiveness, friendliness, and activeness.</p>
<p>To elaborate a bit on that, if there is no responsiveness, you will get frustrated and eventually give up on trying to solve the issue or question you might have.</p>
<p>The same with snarky comments or people being rude. It will deter you from being active in the community and again give up.</p>
<p>Or, in the last case, if there is nobody active actually to answer questions, it will naturally just die out.</p>
<p>These are my main three elements of a healthy community. My question to you is:
What's the most important thing for a community for you?</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Deploying Vendure]]></title><description><![CDATA[The cool part about Vendure is how easy it is to set up and how abstract each layer is.
Basically, we get the following elements:

External database
Server
Worker
Admin UI
Frontend

While this is amazing, it also brings a bit of complexity when it co...]]></description><link>https://h.daily-dev-tips.com/deploying-vendure</link><guid isPermaLink="true">https://h.daily-dev-tips.com/deploying-vendure</guid><category><![CDATA[vendure]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Tue, 20 Dec 2022 07:11:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671520244604/oW1IRD87I.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The cool part about Vendure is how easy it is to set up and how abstract each layer is.
Basically, we get the following elements:</p>
<ul>
<li>External database</li>
<li>Server</li>
<li>Worker</li>
<li>Admin UI</li>
<li>Frontend</li>
</ul>
<p>While this is amazing, it also brings a bit of complexity when it comes to hosting your Vendure shop.</p>
<p>At the time of writing, I'm still doing some research, and it seems Michael from Vendure is also working on an excellent guide for hosting. (Which I'll add here once it's done).</p>
<p>For my testing purpose, I decided to try out hosting to see what's possible and go with the following setup.</p>
<ul>
<li><a target="_blank" href="https://daily-dev-tips.com/posts/hosting-a-discord-bot-on-railway/">RailwayApp</a> for the database, server, worker, and admin UI</li>
<li><a target="_blank" href="https://daily-dev-tips.com/posts/hosting-a-static-blog-on-netlify/">Netlify</a> for the storefront</li>
</ul>
<p>I wouldn't change the front end, as Netlify works fine. However, Vercel or Cloudflare would work equally well.</p>
<p>As for the backend side, Railway works, but it's a bit slow on their free tier. (Still experimenting with a nice setup there).</p>
<h2 id="heading-setting-up-the-backend">Setting up the backend</h2>
<p>I'll still show you how to host Vendure for free but with limited resources for this guide.
You should be able to apply this process to another provider or potentially upgrade the railway subscription.</p>
<p>Create a new <a target="_blank" href="https://railway.app/">Railway account</a> or login into your existing one, creating a new project.</p>
<p>The first thing I added was a PostgreSQL database. I then manually connected to it with <a target="_blank" href="https://daily-dev-tips.com/posts/top-5-mysql-clients-for-mac/#1-tableplus">TablePlus</a> and imported the database I had locally.</p>
<p>You'll see the database connection string we'll need in a bit on the connection screen, so copy that to a safe spot.</p>
<p>The next thing we need to do is add a new service, a project, from GitHub. (Assuming you pushed your project to GitHub).
In Railway, you'll be able to right-click on the canvas and select the new service option.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671428796417/khHH3oM34.png" alt="New service" /></p>
<p>Once you add the service, it should automatically add the Postgres variables.
Add optional variables you have set in your <code>.env</code> file.
You'll need to add the database options here, as Vendure uses an indirect connection.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671428982652/TDOl7J3X6.png" alt="Variables" /></p>
<p>Then we'll also need to define what command it should run in the settings.
And in the case of Vendure, we can set it to <code>yarn run build</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671429062584/mrCUu_G5A.png" alt="Build command" /></p>
<p>It should then auto-build your application every single time you push new changes.</p>
<blockquote>
<p>Note: I sometimes found you need to trigger re-deploy as it would timeout the first deployment manually.</p>
</blockquote>
<p>Once it's running, you should already have access to your admin UI!</p>
<p>The URL should be something like this: <code>https://your-name.up.railway.app/admin</code>.</p>
<h2 id="heading-hosting-the-storefront">Hosting the storefront</h2>
<p>Depending on which storefront option you choose, we have multiple options.
I chose Remix, so I found Netlify super easy.</p>
<p>Log in to Netlify and choose the project from your GitHub repos.
It will automatically recognize it's a Remix project and set all the configurations for us.</p>
<p>All we need to do here is set an environment variable for the <code>VENDURE_API_URL</code>. This should point to your Railway environment.</p>
<p>Then go ahead and deploy it, and it should be up and running.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Overwriting email templates]]></title><description><![CDATA[The previous article looked at customizing Vendure on a data and process level.
In this article, we'll look at customizing emails, as they are often a big part of a webshop system.
We'll be looking at two different layers of customization for customi...]]></description><link>https://h.daily-dev-tips.com/vendure-overwriting-email-templates</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-overwriting-email-templates</guid><category><![CDATA[vendure]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Mon, 19 Dec 2022 06:08:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671430042775/bDVk3DCjL.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The previous article looked at <a target="_blank" href="https://daily-dev-tips.com/posts/customizing-vendure/">customizing Vendure</a> on a data and process level.
In this article, we'll look at customizing emails, as they are often a big part of a webshop system.</p>
<p>We'll be looking at two different layers of customization for customizing these emails.</p>
<ol>
<li>Globals</li>
<li>New email flows</li>
</ol>
<h2 id="heading-changing-email-globals">Changing email globals</h2>
<p>We'll first have to add the email plugin, which we'll use to modify things.</p>
<pre><code class="lang-bash">npm install @vendure/email-plugin
</code></pre>
<p>Now we can open our <code>vendure-config.ts</code> file and load the plugin.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config: VendureConfig = {
  <span class="hljs-attr">plugins</span>: [
    EmailPlugin.init({
      <span class="hljs-attr">handlers</span>: defaultEmailHandlers,
      <span class="hljs-attr">templatePath</span>: path.join(__dirname, <span class="hljs-string">'../static/email/templates'</span>),
      <span class="hljs-attr">globalTemplateVars</span>: {
        <span class="hljs-attr">fromAddress</span>: <span class="hljs-string">'"example" &lt;noreply@example.com`&gt;'</span>,
      },
      <span class="hljs-attr">transport</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">'smtp'</span>,
        <span class="hljs-attr">host</span>: <span class="hljs-string">'smtp.example.com'</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-number">587</span>,
        <span class="hljs-attr">auth</span>: {
          <span class="hljs-attr">user</span>: <span class="hljs-string">'username'</span>,
          <span class="hljs-attr">pass</span>: <span class="hljs-string">'password'</span>,
        },
      },
    }),
  ],
};
</code></pre>
<p>From this config, you can change quite a few variables. For a complete list, check out the <a target="_blank" href="https://www.vendure.io/docs/typescript-api/email-plugin/">official documentation</a>.</p>
<p>This config can change almost everything that has to do with the existing templates.
You can change the copy and format of each email by modifying them in <code>static/email/templates</code>.</p>
<h2 id="heading-new-email-flows">New email flows</h2>
<p>At one stage, I needed to support a brand-new email flow.
By default, this was the email being sent on payment to give you an order confirmation, but I needed it to be sent pre-payment as payment instructions were manual for this shop.</p>
<p>So to add a new flow, we can create custom email event handlers on specific actions in our system.</p>
<p>This is the example of the order placed handler.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> orderPlacedHandler = <span class="hljs-keyword">new</span> EmailEventListener(<span class="hljs-string">'order-placed'</span>)
    .on(OrderPlacedEvent)
    .loadData(<span class="hljs-keyword">async</span> ({ event, injector }) =&gt; {
        transformOrderLineAssetUrls(event.ctx, event.order, injector);
        <span class="hljs-keyword">const</span> shippingLines = <span class="hljs-keyword">await</span> hydrateShippingLines(event.ctx, event.order, injector);
        <span class="hljs-keyword">return</span> { shippingLines };
    })
    .setRecipient(<span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> event.order.customer!.emailAddress)
    .setSubject(<span class="hljs-string">`Order confirmation for #{{ order.code }}`</span>)
    .setFrom(<span class="hljs-string">`{{ fromAddress }}`</span>)
    .setTemplateVars(<span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> ({ <span class="hljs-attr">order</span>: event.order, <span class="hljs-attr">shippingLines</span>: event.data.shippingLines }));
</code></pre>
<p>And to use it, we return this handler in our config.</p>
<pre><code class="lang-js">EmailPlugin.init({
        ...
    handlers: [orderPlacedHandler],
}),
</code></pre>
<p>When creating this new template, ensure that you add a new physical email in your template folder.
In this case, <code>static/email/templates/order-placed/body.hbs</code>.</p>
<blockquote>
<p>Note: You can also subscribe to your own <a target="_blank" href="https://daily-dev-tips.com/posts/customizing-vendure/#customizing-the-order-process">custom events</a>.</p>
</blockquote>
<p>Pretty cool, as it's straightforward to create and customize email flows within Vendure.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Customizing vendure]]></title><description><![CDATA[Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case.
In this article, I'll take a high-level look at some elements we can customize within...]]></description><link>https://h.daily-dev-tips.com/customizing-vendure</link><guid isPermaLink="true">https://h.daily-dev-tips.com/customizing-vendure</guid><category><![CDATA[vendure]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sun, 18 Dec 2022 05:50:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671342604223/wbU1qTMpy.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case.</p>
<p>In this article, I'll take a high-level look at some elements we can customize within Vendure.</p>
<p>The cool part is that it mainly works via changing the one <code>vendure-config.ts</code> file.</p>
<h2 id="heading-customizing-models">Customizing models</h2>
<p>The first thing one might want to do is add custom fields to any of the existing Entities.
I'm surprised by how easy this process is and how slick everything works.</p>
<p>Open your <code>vendure-config.ts</code> file and add or modify the <code>customFields</code> section.
In my case, I'll add a custom field to the product entity. You can give it any name you'd like.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config: VendureConfig = {
  <span class="hljs-attr">customFields</span>: {
    <span class="hljs-attr">Product</span>: [{ <span class="hljs-attr">name</span>: <span class="hljs-string">'myCustomField'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'string'</span> }],
  },
};
</code></pre>
<p>Since this will introduce a database change, we'll need to generate a new migration.
Don't worry. Vendure will take care of all the heavy lifting.</p>
<pre><code class="lang-bash">npm run migration:generate customField
</code></pre>
<p>And now, we can run our server, and everything will work.
If we visit a product, we should see the custom field.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671257802939/mmxKD_mmd.png" alt="Custom field in Vendure" /></p>
<h2 id="heading-customizing-the-order-process">Customizing the order process</h2>
<p>Besides customizing the fields, you might want to add additional steps in the order process.</p>
<p>For instance, you might want to validate some aspects of the order or the customer.
This could be customer should be a valid tax-related customer, or an order above a certain weight can't be shipped.</p>
<p>So let's take the first example as the <a target="_blank" href="https://www.vendure.io/docs/developer-guide/customizing-the-order-process/">Vendure docs</a> describe this best.</p>
<p>Currently, we would have the following state:</p>
<pre><code class="lang-text">AddingItems &gt; ArrangingPayment
</code></pre>
<p>We want it to be:</p>
<pre><code class="lang-text">AddingItems &gt; ValidateCustomer &gt; ArrangingPayment
</code></pre>
<p>The first thing we need to do is define a new state. This is a physical text and doesn't do anything yet.</p>
<p>Let's create a new file to separate things: <code>validate-customer.ts</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { CustomOrderProcess } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vendure/core'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> validateCustomer: CustomOrderProcess&lt;<span class="hljs-string">'ValidateCustomer'</span>&gt; = {
  <span class="hljs-attr">transitions</span>: {
    <span class="hljs-attr">AddingItems</span>: {
      <span class="hljs-attr">to</span>: [<span class="hljs-string">'ValidateCustomer'</span>],
      merge strategy: <span class="hljs-string">'replace'</span>,
    },
    <span class="hljs-attr">ValidateCustomer</span>: {
      <span class="hljs-attr">to</span>: [<span class="hljs-string">'ArrangingPayment'</span>, <span class="hljs-string">'AddingItems'</span>],
    },
  },
};
</code></pre>
<p>As you can see, this tells what transitions are valid to make.
We can then open our <code>vendure-config.ts</code> and load our new process.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config: VendureConfig = {
  <span class="hljs-attr">orderOptions</span>: {
    <span class="hljs-attr">process</span>: [validateCustomer],
  },
};
</code></pre>
<p>Now let's make sure this intercepts something. Go back to the <code>validate-customer.ts</code> file and add the following function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> validateCustomer: CustomOrderProcess&lt;<span class="hljs-string">'ValidateCustomer'</span>&gt; = {
  <span class="hljs-comment">// Transitions go here</span>

  <span class="hljs-comment">// The logic for enforcing our validation goes here</span>
  <span class="hljs-keyword">async</span> onTransitionStart(fromState, toState, data) {
    <span class="hljs-keyword">if</span> (fromState === <span class="hljs-string">'ValidateCustomer'</span> &amp;&amp; toState === <span class="hljs-string">'ArrangingPayment'</span>) {
      <span class="hljs-keyword">const</span> isValid = <span class="hljs-keyword">await</span> validateTheActualCustomer(data.order.customer);
      <span class="hljs-keyword">if</span> (!isValid) {
        <span class="hljs-comment">// Returning a string is interpreted as an error message.</span>
        <span class="hljs-comment">// The state transition will fail.</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">`The customer is not valid`</span>;
      }
    }
  },
};
</code></pre>
<p>This is simply a mockup, and you should create the actual validation function to evaluate the customer on specific fields.
If we return a string, it's handled as an error state, and the transition won't happen.</p>
<h2 id="heading-generic-modifiers">Generic modifiers</h2>
<p>The above two are very common modifiers, but Vendure comes packed with more.</p>
<p>For instance, I needed to modify the stock level output in one of my shops.
By default, it only shows things as "low stock" and never the actual number.
On my webshop, it was needed to show the exact stock at hand.</p>
<p>To achieve that, we can open the <code>vendure-config.ts</code> and create a new function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyStockDisplayStrategy</span> <span class="hljs-title">implements</span> <span class="hljs-title">StockDisplayStrategy</span> </span>{
  getStockLevel(
    ctx: RequestContext,
    <span class="hljs-attr">productVariant</span>: ProductVariant,
    <span class="hljs-attr">saleableStockLevel</span>: number
  ): string {
    <span class="hljs-keyword">return</span> saleableStockLevel.toString();
  }
}
</code></pre>
<p>This is a function to extend the default stock display strategy. In my case, I return the physical stock level as a string.
To ensure Vendure uses this value, we can modify the config to load that.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config: VendureConfig = {
  <span class="hljs-attr">catalogOptions</span>: {
    <span class="hljs-attr">stockDisplayStrategy</span>: <span class="hljs-keyword">new</span> MyStockDisplayStrategy(),
  },
};
</code></pre>
<p>And now, the stock levels on the site will show the exact amount you have left in stock.</p>
<p>This is just one example, Vendure comes packed with small little hooks that we can use to customize our webshop and system.
I love that they made it easy and hassle-free to adjust the system to your needs.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Setting up facets]]></title><description><![CDATA[As mentioned in my very first article about Vendure, one of the most important things for me was the concept of facets.
In my use case, I needed custom elements for each product that the end users could filter.
For example, the beer shop I'm working ...]]></description><link>https://h.daily-dev-tips.com/vendure-setting-up-facets</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-setting-up-facets</guid><category><![CDATA[vendure]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sat, 17 Dec 2022 05:20:24 GMT</pubDate><content:encoded><![CDATA[<p>As mentioned in my very <a target="_blank" href="https://daily-dev-tips.com/posts/vendure-headless-commerce-part1/">first article about Vendure</a>, one of the most important things for me was the concept of facets.</p>
<p>In my use case, I needed custom elements for each product that the end users could filter.</p>
<p>For example, the beer shop I'm working on needs to have quite a lot of global fields:</p>
<ul>
<li>Brewery</li>
<li>Type of brew</li>
<li>Alcohol percentage</li>
<li>And so on</li>
</ul>
<p>Luckily for us, Vendure supported this out of the box, and in this article, I'll show you how to set it up.</p>
<blockquote>
<p>Note: This involves more graphical interaction over development.</p>
</blockquote>
<h2 id="heading-manually-creating-facets">Manually creating facets</h2>
<p>You can spool up your Vendure server and visit the admin UI at <a target="_blank" href="http://localhost:3000/admin/">http://localhost:3000/admin/</a>.</p>
<p>Move to Facets in the left sidebar menu; if you opt for the demo products, you'll see some already created facets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671168095489/HULP_exVU.png" alt="Facets in Vendure" /></p>
<p>In the top right, you'll have the option to create new facets containing a name and optional code.
Once you've chosen a name, you'll be able to add facet values. These are all the unique values for that facet.</p>
<p>I've created a Test facet with <code>foo</code> and <code>bar</code> values in the example below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671168263067/AgAK26snY.png" alt="New facet" /></p>
<p>This is all great and well, but it doesn't do much. So we must move to one of our products to leverage these facets.</p>
<p>When you open a product, you should see on the right side there is a button to add facets.
The important part to note here is that it searches based on the values, not the name.</p>
<p>I'm trying to add the <code>Foo</code> value in this case.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671168402723/-GXXiDyi8.png" alt="New facet to product" /></p>
<h2 id="heading-importing-facets">Importing facets</h2>
<p>As mentioned in the <a target="_blank" href="https://daily-dev-tips.com/posts/vendure-importing-data/">Vendure import article</a>, we can use an import to manage many products.</p>
<p>It's good to note that this also supports the import of facets!</p>
<p>How it works is that you define <code>variantFacets</code> as a column, and inside, you can column deliminate all the values like so:</p>
<pre><code class="lang-text">test:Foo|test:Bar
</code></pre>
<p>This would add both the <code>Foo</code> and the <code>Bar</code> value.
The <code>test</code> part is the code of the facet that we created.</p>
<p>This is super helpful in creating an excellent structured database with all my products organized with custom facets.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Assets to an S3 bucket]]></title><description><![CDATA[As my webshop serves a lot of images, I wanted to leverage a good CDN and quickly found a neat integration with S3 available for Vendure.
In this article, I'll show you how you can connect and leverage an S3 bucket as your asset storage.
Setting up A...]]></description><link>https://h.daily-dev-tips.com/vendure-assets-to-an-s3-bucket</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-assets-to-an-s3-bucket</guid><category><![CDATA[vendure]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Amazon S3]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Fri, 16 Dec 2022 05:45:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671169462788/Wt6krkTt1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As my webshop serves a lot of images, I wanted to leverage a good CDN and quickly found a neat integration with S3 available for Vendure.</p>
<p>In this article, I'll show you how you can connect and leverage an S3 bucket as your asset storage.</p>
<h2 id="heading-setting-up-amazon">Setting up Amazon</h2>
<p>The first thing you'll need is an AWS account, which can be tedious. (Mainly quite long)</p>
<p>Head over to AWS and create your account.</p>
<p><a target="_blank" href="https://aws.amazon.com/console/">Create AWS account</a></p>
<p>Once you are set up and ready to go, it's time to create a new bucket.
The steps for creating a bucket are extensive and might change over time, so it's best to follow <a target="_blank" href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html">Amazon's docs on this</a>.</p>
<p>Eventually, your bucket should be ready like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671082563917/i2CZgABnC.png" alt="S3 Bucket" /></p>
<p>You'll also need to add new access credentials.
Head to AWS's <code>IAM</code> section and create a new user.</p>
<p>You can give it a name that represents the tool you will use and also choose to make it an Access key.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671083005468/h27c5_cqp.png" alt="IAM Role" /></p>
<p>On the next screen, you'll need to attach the permissions. In our case, we can choose to connect them manually.
Search for <code>AmazonS3FullAccess</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671083099475/jRU16zQvi.png" alt="Attach policies" /></p>
<p>You can press next until you get to the actual keys in the next couple of steps.
Copy the key and secret to a secure place.</p>
<h2 id="heading-setting-the-bucket-as-storage">Setting the bucket as storage</h2>
<p>Now it's time to add some code.
First of all, we need to install the <code>aws-sdk</code> package.</p>
<pre><code class="lang-bash">npm install aws-sdk
</code></pre>
<p>I save my secrets in a <code>.ENV</code> file for maximum protection, so go ahead and add the following two keys.</p>
<pre><code class="lang-bash">AWS_ACCESS_KEY_ID={YOUR_KEY}
AWS_SECRET_ACCESS_KEY={YOUR_SECRET}
</code></pre>
<p>Next, we need to modify the <code>vendure-config.ts</code> file to use a new asset plugin.</p>
<p>Start by importing the S3 one.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
  AssetServerPlugin,
  configureS3AssetStorage,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@vendure/asset-server-plugin'</span>;
</code></pre>
<p>And inside the config, add a new plugin.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config: VendureConfig = {
    # Your other config here
    <span class="hljs-attr">plugins</span>: [
        AssetServerPlugin.init({
            <span class="hljs-attr">route</span>: <span class="hljs-string">'assets'</span>,
            <span class="hljs-attr">storageStrategyFactory</span>: configureS3AssetStorage({
                <span class="hljs-attr">bucket</span>: <span class="hljs-string">'vendure'</span>,
                <span class="hljs-attr">credentials</span>: {
                    <span class="hljs-attr">accessKeyId</span>: process.env.AWS_ACCESS_KEY_ID,
                    <span class="hljs-attr">secretAccessKey</span>: process.env.AWS_SECRET_ACCESS_KEY,
                },
            }),
        }),
    ],
};
</code></pre>
<p>It's essential to change the bucket name to your bucket.</p>
<p>And now, any assets you upload via the admin UI or the import will be stored in the S3 bucket!</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Importing data]]></title><description><![CDATA[Product imports are an essential element that I found great when working with Vendure.
It was super important to me to be able to import products and their data.
Many people might have the exact needs as they often already have a webshop or system to...]]></description><link>https://h.daily-dev-tips.com/vendure-importing-data</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-importing-data</guid><category><![CDATA[vendure]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Thu, 15 Dec 2022 06:33:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671085962042/BtGOpBxLJ.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Product imports are an essential element that I found great when working with Vendure.
It was super important to me to be able to import products and their data.</p>
<p>Many people might have the exact needs as they often already have a webshop or system to keep track of these things.</p>
<p>In this article, we'll look at how we can use the data import feature of Vendure.</p>
<h2 id="heading-importing-products">Importing products</h2>
<p>When importing products, Vendure accepts a flat <code>.csv</code> format, and it can hold products, assets, variants, and even custom fields.
These elements will be created during the import, which is excellent.</p>
<p>You can find an example of the CSV format on the <a target="_blank" href="https://www.vendure.io/docs/developer-guide/importing-product-data/#product-import-format">Vendure docs</a></p>
<p>The are multiple ways of doing the import, and I decided I wanted to be able to run it manually, so I created my script for it.</p>
<p>I called the script <code>populate-server.ts</code>.
It's important to note that this uses the Vendure core <code>populate</code> function, which takes two parameters, the first being the initial data and the second your import.</p>
<p>My complete file looks like this.</p>
<pre><code class="lang-js"><span class="hljs-comment">// populate-server.ts</span>
<span class="hljs-keyword">import</span> { bootstrap } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vendure/core'</span>;
<span class="hljs-keyword">import</span> { populate } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vendure/core/cli'</span>;
<span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;

<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">'./src/vendure-config'</span>;
<span class="hljs-keyword">import</span> { initialData } <span class="hljs-keyword">from</span> <span class="hljs-string">'./my-initial-data'</span>;

<span class="hljs-keyword">const</span> productsCsvFile = path.join(__dirname, <span class="hljs-string">'import.csv'</span>);

populate(<span class="hljs-function">() =&gt;</span> bootstrap(config), initialData, productsCsvFile)
  .then(<span class="hljs-function">(<span class="hljs-params">app</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> app.close();
  })
  .then(
    <span class="hljs-function">() =&gt;</span> process.exit(<span class="hljs-number">0</span>),
    <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(err);
      process.exit(<span class="hljs-number">1</span>);
    }
  );
</code></pre>
<p>Let's go ahead and also create this <code>my-initial-data.ts</code> file.
This file can be used to set up the admin section of your Vendure server.</p>
<p>In my case, I limited quite a bit of the setup, and my file looks like this.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { InitialData, LanguageCode } <span class="hljs-keyword">from</span> <span class="hljs-string">'@vendure/core'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> initialData: InitialData = {
  <span class="hljs-attr">paymentMethods</span>: [],
  <span class="hljs-attr">defaultLanguage</span>: LanguageCode.en,
  <span class="hljs-attr">countries</span>: [],
  <span class="hljs-attr">defaultZone</span>: <span class="hljs-string">'SA'</span>,
  <span class="hljs-attr">taxRates</span>: [],
  <span class="hljs-attr">shippingMethods</span>: [],
  <span class="hljs-attr">collections</span>: [],
};
</code></pre>
<p>You can find the complete object you can construct on the <a target="_blank" href="https://www.vendure.io/docs/developer-guide/importing-product-data/#initial-data">Vendure docs</a>.</p>
<blockquote>
<p>Note: Every time you run your import, these will be executed, so running it more than once will result in duplicates.</p>
</blockquote>
<p>To run the actual import, we can use the following command:</p>
<pre><code class="lang-bash">yarn ts-node populate-server.ts
</code></pre>
<p>Depending on the number of products, it can take some time to finish.</p>
<p>I often ran the script for testing purposes to get the proper import set.
You might have to play around with your CSV format if importing many custom fields this way.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Storefronts]]></title><description><![CDATA[When setting up a commerce website, you'll likely need a storefront. This will be what the end users will use to order your products.
In the case of Vendure, we are open to creating our own, but luckily for us, they have some fantastic starters alrea...]]></description><link>https://h.daily-dev-tips.com/vendure-storefronts</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-storefronts</guid><category><![CDATA[vendure]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webshop]]></category><category><![CDATA[ecommerce]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Wed, 14 Dec 2022 06:09:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670998138912/PiZkxb3DJ.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When setting up a commerce website, you'll likely need a storefront. This will be what the end users will use to order your products.</p>
<p>In the case of Vendure, we are open to creating our own, but luckily for us, they have some fantastic starters already set up.</p>
<p>At the time of writing, they have official starters for:</p>
<ul>
<li>Remix</li>
<li>Vue Storefront</li>
<li>Next.js</li>
<li>Angular</li>
</ul>
<p>Since I started a <a target="_blank" href="https://daily-dev-tips.com/tags/remix/">series on Remix</a>, I have been eager to try that.</p>
<h2 id="heading-installing-the-remix-storefront">Installing the Remix Storefront</h2>
<p>To install the Storefront, we can clone the <a target="_blank" href="https://github.com/vendure-ecommerce/storefront-remix-starter">Git repo</a> and install it.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git@github.com:vendure-ecommerce/storefront-remix-starter.git

<span class="hljs-built_in">cd</span> storefront-remix-starter

npm install
</code></pre>
<p>Then, create a <code>.env</code> file in the root and point it to our local Vendure server.</p>
<pre><code class="lang-js">VENDURE_API_URL=http:<span class="hljs-comment">//localhost:3001/shop-api</span>
</code></pre>
<p>Now go ahead and run the Storefront with: <code>npm run dev</code>.</p>
<blockquote>
<p>Note: Make sure your Vendure server is running.</p>
</blockquote>
<p>And visit the Storefront on <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670909460542/tTALBNZ5F.png" alt="Remix Storefront example" /></p>
<p>Play around with it and try to order some products. You'll see it's blazing fast!</p>
<h2 id="heading-other-options">Other options</h2>
<p>As mentioned, you can use some other supported Storefronts, which you can find on the <a target="_blank" href="https://www.vendure.io/integration/">Vendure website</a>.</p>
<p>And if you want to use something together, you can take inspiration from any of the existing integrations and create your own new integration.</p>
<p>Since, in the end, they query the API and have no concrete direct implementations in place.</p>
<p>I'm super stoked to see this freedom of front-end in a (headless) commerce system being so well demoed out.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure - Quick setup]]></title><description><![CDATA[In the previous article, we talked about Vendure, what it is, and why I find it an exciting commerce solution.
In this article, we'll get started and see how easy it is to set up.

Note: For these articles, I mainly use Vendure's documentation, which...]]></description><link>https://h.daily-dev-tips.com/vendure-quick-setup</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-quick-setup</guid><category><![CDATA[vendure]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Tue, 13 Dec 2022 06:30:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670912986466/W0ps9P4wv.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous article, we talked about <a target="_blank" href="https://daily-dev-tips.com/posts/vendure-headless-commerce-part1/">Vendure</a>, what it is, and why I find it an exciting commerce solution.</p>
<p>In this article, we'll get started and see how easy it is to set up.</p>
<blockquote>
<p>Note: For these articles, I mainly use <a target="_blank" href="https://www.vendure.io/docs">Vendure's documentation</a>, which is comprehensive.</p>
</blockquote>
<h2 id="heading-vendure-quick-start">Vendure quick start</h2>
<p>The easiest way to start with Vendure is to run their create command. This will set up everything you need to get started.</p>
<p>Out of the box, we get:</p>
<ul>
<li>Admin GraphQL API</li>
<li>Shop GraphQL API</li>
<li>Admin UI</li>
</ul>
<p>All you need to have is node (with npx) npm 5.2 and higher installed.
With that, you can run the following command.</p>
<pre><code class="lang-bash">npx @vendure/create my-app
</code></pre>
<p>Where <code>my-app</code> is the actual name of your application.</p>
<p>In the installation process, you'll be asked which type of database you want to proceed with. You can pick whichever one works best for your system.
It will also give you the option to populate with sample data.</p>
<p>To get started quickly, the SQLite option is very nice to get started with.</p>
<p>Once the script is done, you can navigate to your folder and run the application.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-app
yarn dev
</code></pre>
<p>It will spool up all your available resources. Once healthy, you should see the following in your terminal.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670822276977/Ls13S6HZ2M.png" alt="Vendure server running" /></p>
<h2 id="heading-exploring-the-apis">Exploring the APIs</h2>
<p>As mentioned, we get access to the Vendure APIs, split into two categories.</p>
<p>An admin API and a Shop API.
Administrators can use the admin API to manage products, orders, and more.
The shop API is public-facing and can be used for our eventual storefront, mobile app, etc.</p>
<p>Let's take a quick look at how we can reach them.
For the following examples, I'm using <a target="_blank" href="https://daily-dev-tips.com/posts/testing-api-calls-in-insomnia/">Insomnia</a>, but any API tool will work.</p>
<p>Let's start with the shop API. To access it, we can use the following URL <code>http://localhost:3000/shop-api</code>.</p>
<p>The API uses GraphQL as its layer of communication.
For instance, we can use the following graphQL query to get a list of products.</p>
<pre><code>query products {
  products {
    items {
      name
    }
  }
}
</code></pre><p>Which results in a list of all our product names:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670822788620/dIXHaGXdS.png" alt="Insomnia shop API result" /></p>
<p>Another fantastic element of Vendure is that it gets shipped with a GraphQL explorer built in, so we can visit the API URL and query from there.
Visit <code>http://localhost:3000/shop-api</code> and execute your queries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670823041640/Y0GgsYB9t.png" alt="Vendure GraphQL playground" /></p>
<p>The same goes for the admin API. However, we should use the following URL <code>http://localhost:3000/admin-api</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670824635692/m9sGRpGgE.png" alt="Vendure Admin API" /></p>
<h2 id="heading-exploring-the-admin-ui">Exploring the admin UI</h2>
<p>Besides these fantastic APIs, we also get access to a default admin UI.
Visit the following URL: <code>http://localhost:3000/admin/</code>, and you can explore the admin interface.</p>
<p>It's an excellent place to start exploring how things are linked together.
If you choose the population of data, you'll even be able to see some advanced linking and facets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670824768606/vr0hC3CAI.png" alt="Admin UI" /></p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Vendure headless commerce - part 1]]></title><description><![CDATA[A while ago, we started looking at Medusa as an alternative for a WooCommerce webshop, I'm still busy with this project, but in the meantime began looking at Vendure too.
At first, the website was a little bit of a letdown, and Medusa seemed to do a ...]]></description><link>https://h.daily-dev-tips.com/vendure-headless-commerce-part-1</link><guid isPermaLink="true">https://h.daily-dev-tips.com/vendure-headless-commerce-part-1</guid><category><![CDATA[ecommerce]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Mon, 12 Dec 2022 06:16:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670825719813/4K3vOKxpC.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while ago, we started looking at <a target="_blank" href="https://daily-dev-tips.com/posts/trying-out-a-medusa-webshop/">Medusa</a> as an alternative for a WooCommerce webshop, I'm still busy with this project, but in the meantime began looking at Vendure too.</p>
<p>At first, the website was a little bit of a letdown, and Medusa seemed to do a more appealing job at marketing itself.
However, I quickly came back to this after giving it a try.</p>
<p>A big shoutout to the Vendure team, as they have been super helpful with all my requests and taking the time to help me set up.</p>
<p>In a couple of articles, we'll be looking at Vendure and how we can set up a headless commerce system and link it to some storefronts.</p>
<h2 id="heading-what-exactly-is-headless-commerce">What exactly is headless commerce?</h2>
<p>You might be wondering, what is this headless commerce system?</p>
<p>It's an e-commerce system, but it's not tied to any specific frontend solution.
In the case of Vendure, it's focused on developers who love the modern web, and we see familiar names such as TypeScript, GraphQL, and NodeJS.</p>
<p>We get an out-of-the-box solid system that we can extend and modify to work with our other systems.</p>
<p>This benefit is that a developer can choose whatever frontend stack they want to work in, giving a lot of freedom.
We can quickly hook up multiple solutions and languages to work with, even on the admin side.</p>
<h2 id="heading-what-makes-vendure-so-great">What makes Vendure so great?</h2>
<p>I started looking at Vendure because of how flexible their setup was. We get a lot of hooks we can use and a pretty large open-source community that is super helpful.</p>
<p>One of my main selling points was that they provide product variants with facets.
I was particularly struggling with this on Medusa, and it worked great out of the box from Vendure.</p>
<p>The other real benefit was the number of storefronts we could hook into. I liked the Remix storefront a lot as I was exploring Remix in general (so this is very biased).</p>
<p>It also comes with many great options that need little to no modifications to make things change, and more in future articles.</p>
<h2 id="heading-what-to-expect">What to expect</h2>
<p>You might be interested in this process, so let's discuss what to expect from the following articles.</p>
<ul>
<li>We'll set up the system with the admin interface</li>
<li>We'll create a storefront</li>
<li>Importing data</li>
<li>Setting up products and facets</li>
<li>Attaching a CDN</li>
<li>Customizing Vendure</li>
<li>Deploying</li>
</ul>
<p>If you are keen on any of the above topics, subscribe to my newsletter and get the latest articles as they are launched.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Conditional wrapping in React]]></title><description><![CDATA[This is something you do not always need, but I wrote this article for those looking for it.
Sometimes we might have a generic element, a specific component that renders inside a modal.
When a specific flag is set, the component should get a parent w...]]></description><link>https://h.daily-dev-tips.com/conditional-wrapping-in-react</link><guid isPermaLink="true">https://h.daily-dev-tips.com/conditional-wrapping-in-react</guid><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sun, 11 Dec 2022 05:54:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670738027749/5UpK-hITF.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is something you do not always need, but I wrote this article for those looking for it.</p>
<p>Sometimes we might have a generic element, a specific component that renders inside a modal.
When a specific flag is set, the component should get a parent wrapper to display it in a different variant.</p>
<p>We could use an if...else statement, but it looks messy.</p>
<h2 id="heading-conditional-wrapping-in-react">Conditional wrapping in React</h2>
<p>Let's say we got specific service cards to make it a bit easier to follow. In some cases, they explain a service, but in others, they need to link to a detail page.</p>
<p>The component might look like this.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ServiceCard = <span class="hljs-function">(<span class="hljs-params">{ title, description, image, url }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{title}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};
</code></pre>
<p>As mentioned, what happens if we need to wrap this whole thing in a link element when the URL exists?
We could use the if...else loop.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ServiceCard = <span class="hljs-function">(<span class="hljs-params">{ title, description, image, url }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
      {url ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{url}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{title}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{title}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/section&gt;
  );
};
</code></pre>
<p>But this shows duplicate code, so it's a bit silly. If we need to style each element, we must modify it in two places.</p>
<p>So how can we better wrap this conditionally?</p>
<p>We can create a generic component that handles this for us, the component will be named <code>ConditionalWrapper</code>, and it will take a condition, the wrapper, and the children it should wrap.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ConditionalWrapper = <span class="hljs-function">(<span class="hljs-params">{ condition, wrapper, children }</span>) =&gt;</span>
  condition ? wrapper(children) : children;
</code></pre>
<p>With that in place, we can use it on our existing component to clean it up.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ServiceCard = <span class="hljs-function">(<span class="hljs-params">{title, description, image, url}</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ConditionalWrapper</span>
                <span class="hljs-attr">condition</span>=<span class="hljs-string">{url}</span>
                <span class="hljs-attr">wrapper</span>=<span class="hljs-string">{children</span> =&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{url}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>}
            &gt;
                <span class="hljs-tag">&lt;&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{title}</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ConditionalWrapper</span>&gt;</span></span>
        &lt;/section&gt;
    )
}
</code></pre>
<p>And now, if we use our component, depending on whether we pass the URL. It will render with or without the href. And the best part is that we have no duplication in our elements.</p>
<p>For example, the following use case:</p>
<pre><code class="lang-js">&lt;ServiceCard title=<span class="hljs-string">'test'</span> description=<span class="hljs-string">'foo bar'</span> img=<span class="hljs-string">'img1.jpg'</span> /&gt;
</code></pre>
<p>It would return the following HTML output:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>foo bar<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"img1.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"test"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>We will get the following output if we put the URL in the element.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"url"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>foo bar<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"img1.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"test"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Pretty cool, right?</p>
<p>The main magic, of course, happens in the ConditionalWrapper component and, to be precise, the wrapper argument.</p>
<p>Since we pass the children (which is a React default prop), we can see that the use case of our function as in <code>wrapper={children =&gt; &lt;a href={url}&gt;{children}&lt;/a&gt;}</code> states.</p>
<ul>
<li>If the condition is met</li>
<li>Wrap the children in this specific element</li>
</ul>
<p>There will only be a handful of times when you might need this function, but it can be a huge lifesaver.</p>
<p>Note: big thanks to <a target="_blank" href="https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2">Olivier</a> for the original idea!</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Modifying an SVG path with CSS]]></title><description><![CDATA[In the previous article, we learned that we could animate a CSS path, which led me to discover something even more mind-blowing!
We can modify the CSS path! (only supported in Chromium browsers).
Let's check this out and see how it works.
Modifying S...]]></description><link>https://h.daily-dev-tips.com/modifying-an-svg-path-with-css</link><guid isPermaLink="true">https://h.daily-dev-tips.com/modifying-an-svg-path-with-css</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[SVG]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sat, 10 Dec 2022 05:32:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670650162398/eNquo9OHe.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a target="_blank" href="https://daily-dev-tips.com/posts/animate-an-svg-path-with-css/">previous article</a>, we learned that we could animate a CSS path, which led me to discover something even more mind-blowing!</p>
<p>We can modify the CSS path! (only supported in Chromium browsers).</p>
<p>Let's check this out and see how it works.</p>
<h2 id="heading-modifying-svg-path-with-css">Modifying SVG path with CSS</h2>
<p>To start, we'll need an essential SVG element again. I started with this curved line.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 7 9"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M1,3 C1,6 6,6 6,3"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>Which would result in something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669874220096/iPBShXlfO.png" alt="SVG Path" /></p>
<p>So how can we modify the path now?
And you'll be surprised, but it's accessible with CSS like this.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">svg</span><span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-tag">path</span> {
  <span class="hljs-attribute">d</span>: <span class="hljs-built_in">path</span>(<span class="hljs-string">'M1,6 C1,3 6,3 6,6'</span>);
}
</code></pre>
<p>It looks familiar, right? We can modify the path there. In my instance, I changed it to become the opposite angle of the curve, so it turned upside down.</p>
<p>I also added a transition effect on the path so it will animate smoothly.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">svg</span> <span class="hljs-selector-tag">path</span> {
  <span class="hljs-attribute">fill</span>: transparent;
  <span class="hljs-attribute">stroke</span>: indigo;
  <span class="hljs-attribute">stroke-linecap</span>: round;
  <span class="hljs-attribute">stroke-linejoin</span>: round;
  <span class="hljs-attribute">transition</span>: <span class="hljs-number">0.2s</span>;
}
</code></pre>
<p>And now we're able to hover it and see the path change!
This blew my mind and is so cool.</p>
<p>You can see its effect here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669874548554/T_toH11sx.gif" alt="SVG animation on hover" /></p>
<p>Or if you are on Chromium, check it out on <a target="_blank" href="https://codepen.io/rebelchris/pen/vYrzqwe">this CodePen</a>.</p>
<p>Let's hope this gets better browser support, as it's fantastic to have this ability.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Animate an SVG path with CSS]]></title><description><![CDATA[A while ago, I found this super cool effect that animated an SVG path as it was drawn on the canvas.
It turns out it's pretty easy to create this with CSS, so let's see how it's done.
Animating an SVG path with CSS
The first part was to create an SVG...]]></description><link>https://h.daily-dev-tips.com/animate-an-svg-path-with-css</link><guid isPermaLink="true">https://h.daily-dev-tips.com/animate-an-svg-path-with-css</guid><category><![CDATA[CSS]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Fri, 09 Dec 2022 05:32:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670563824934/SkiSFXHW-.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while ago, I found this super cool effect that animated an SVG path as it was drawn on the canvas.</p>
<p>It turns out it's pretty easy to create this with CSS, so let's see how it's done.</p>
<h2 id="heading-animating-an-svg-path-with-css">Animating an SVG path with CSS</h2>
<p>The first part was to create an SVG line, and I used sketch to draw a triangle-looking element.
You can draw anything you want or even use <a target="_blank" href="https://editor.method.ac/">online free tools</a>.</p>
<p>Once your shape is complete, add it to your HTML. For reference, here is my one.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
  <span class="hljs-attr">width</span>=<span class="hljs-string">"291px"</span>
  <span class="hljs-attr">height</span>=<span class="hljs-string">"260px"</span>
  <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 291 260"</span>
  <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span>
  <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
  <span class="hljs-attr">xmlns:xlink</span>=<span class="hljs-string">"http://www.w3.org/1999/xlink"</span>
&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Path<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"Page-1"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"none"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span> <span class="hljs-attr">fill-rule</span>=<span class="hljs-string">"evenodd"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
      <span class="hljs-attr">d</span>=<span class="hljs-string">"M273.097656,120.507813 C201.899566,163.577543 130.777516,213.94793 50.8398438,240.160156 C36.9248074,244.723012 17.4914196,262.184399 8.2265625,250.84375 C-1.53762975,238.89189 20.198756,222.272258 24.0078125,207.316406 C27.3670238,194.126823 28.5689142,180.441602 29.6132812,166.871094 C30.9603726,149.366986 31.1766739,131.782428 31.171875,114.226563 C31.1623478,79.3735161 8.15793288,37.1795952 29.5703125,9.6796875 C43.1473611,-7.75730878 67.7544299,32.013528 87.5742187,41.7890625 C105.639606,50.6992894 124.365537,58.2317755 143.085938,65.6679688 C150.003672,68.4158594 157.202901,70.4330349 164.40625,72.3085938 C177.173796,75.6329203 190.335014,77.4306133 202.960938,81.2578125 C220.824973,86.6728004 237.747783,94.999359 255.734375,99.9921875 C266.927708,103.099302 278.679688,103.638021 290.152344,105.460938"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"Path"</span>
      <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#979797"</span>
      <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"10"</span>
    &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>Now we can move to animate it, and since I'm only using one SVG, I added the code to the main SVG element.</p>
<p>The first thing we want to do is set the stroke dash array, and its offset.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">svg</span> {
  <span class="hljs-attribute">stroke-dasharray</span>: <span class="hljs-number">1000</span>;
  <span class="hljs-attribute">stroke-dashoffset</span>: <span class="hljs-number">1000</span>;
  <span class="hljs-attribute">pointer-events</span>: none;
}
</code></pre>
<p>The dash array refers to the width of the dash and the offset to the starting point. 1000 is bigger than our actual line so it will be split into 1000 pieces.</p>
<p>Then we want to add an animation that removes the offset over time.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">svg</span> {
  <span class="hljs-attribute">animation</span>: animateDash <span class="hljs-number">2s</span> linear forwards infinite;
}
</code></pre>
<p>Then we can create the animation to remove the offset, as mentioned.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> animateDash {
  <span class="hljs-selector-tag">to</span> {
    <span class="hljs-attribute">stroke-dashoffset</span>: <span class="hljs-number">0</span>;
  }
}
</code></pre>
<p>And that's it. Our animation will now run to show the drawing of the line.</p>
<p>You can even play with this and change the array and offset sizes, which will impact how your animation runs, and you can even make it appear as a dashed border animation.</p>
<p>For reference, you can see the result in this CodePen.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/rebelchris/pen/KKexgBM">https://codepen.io/rebelchris/pen/KKexgBM</a></div>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Working with data attributes in CSS]]></title><description><![CDATA[We previously looked at using data attributes in JavaScript. These data attributes are a fantastic way to store little bits of information on an element without using custom attributes.
However, we can also use them to style some aspects with specifi...]]></description><link>https://h.daily-dev-tips.com/working-with-data-attributes-in-css</link><guid isPermaLink="true">https://h.daily-dev-tips.com/working-with-data-attributes-in-css</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Thu, 08 Dec 2022 05:39:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670477866416/tNd7T7e6F.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We previously looked at using <a target="_blank" href="https://daily-dev-tips.com/posts/vanilla-javascript-data-attributes/">data attributes in JavaScript</a>. These data attributes are a fantastic way to store little bits of information on an element without using custom attributes.</p>
<p>However, we can also use them to style some aspects with specific attribute sets.</p>
<h2 id="heading-css-attributes-in-css">CSS attributes in CSS</h2>
<p>To paint a simple picture, let's create elements that hold a specific value like this.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">data-rating</span>=<span class="hljs-string">"1"</span>&gt;</span>Rating<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">data-rating</span>=<span class="hljs-string">"5"</span>&gt;</span>Rating<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>As you can see, our rating is only set as the custom attribute.</p>
<p>Let's first look at how we can style this object, which is very easy by simply using its name.</p>
<pre><code class="lang-css"><span class="hljs-selector-attr">[data-rating]</span> {
  <span class="hljs-attribute">color</span>: indigo;
}
</code></pre>
<p>With this, the rating text will be purple.</p>
<p>We can also make it more specific and add styling for particular values.</p>
<pre><code class="lang-css"><span class="hljs-selector-attr">[data-rating=<span class="hljs-string">'1'</span>]</span> {
  <span class="hljs-attribute">color</span>: red;
}
<span class="hljs-selector-attr">[data-rating=<span class="hljs-string">'5'</span>]</span> {
  <span class="hljs-attribute">color</span>: indigo;
}
</code></pre>
<p>And to top it off, we can inject the value with CSS!</p>
<pre><code class="lang-css"><span class="hljs-selector-attr">[data-rating]</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-built_in">attr</span>(data-rating);
}
</code></pre>
<p>Which would result in the rating being added after our text.</p>
<p>You can play with these data attributes on the following CodePen.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/rebelchris/pen/rNKrdGa">https://codepen.io/rebelchris/pen/rNKrdGa</a></div>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Too much, and yet not enough]]></title><description><![CDATA[If you have been an avid reader of this blog, you might have noticed I like exploring different aspects of web development.
I don't like to niche down or restrict myself to one specific topic.
This might be because of my ADD nature or simply because ...]]></description><link>https://h.daily-dev-tips.com/too-much-and-yet-not-enough</link><guid isPermaLink="true">https://h.daily-dev-tips.com/too-much-and-yet-not-enough</guid><category><![CDATA[General Advice]]></category><category><![CDATA[watercooler]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Wed, 07 Dec 2022 05:15:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670390068041/pT7aR_yYN.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have been an avid reader of this blog, you might have noticed I like exploring different aspects of web development.</p>
<p>I don't like to niche down or restrict myself to one specific topic.
This might be because of my ADD nature or simply because I enjoy exploring all the different topics.</p>
<p>But today, I was deciding on what to write about. And from my list of open topics, I felt like there was too much to pick from.
Did I want to pick yet another completely new topic?</p>
<p>But then again, the topics I already wrote about seemed worn out. I touched on all the most important topics. Going into detail would mean writing long-form articles.</p>
<p>(This is something I'd love to do, but I don't have the energy for now)</p>
<h2 id="heading-the-power-of-broadcasting">The power of broadcasting</h2>
<p>I'm a big believer in broadcasting. It's something I've enjoyed throughout my life.</p>
<p>When I was young, I couldn't stick to one sport, I wanted to try them all out, and my parent was happy enough to let me.</p>
<p>Sometimes I would stick to a sport for a year or longer, but often I didn't enjoy them as much as hoped.</p>
<p>I think this was the nature of my personality. Just not someone who can do things for an extended period with no genuine interest in that particular thing.</p>
<p>And for me, this came with a fast amount of power. By always broadcasting my interest, I got to experience things I loved, but maybe more importantly, find the things I didn't like.</p>
<h2 id="heading-how-this-can-apply-to-you">How this can apply to you</h2>
<p>So you might be wondering, ok, incredible life story, but what is it to me?</p>
<p>And as mentioned, I'm a firm believer in finding one's passion and genuinely experiencing what you enjoy most, so if you are reading this and unsure if you are doing the thing you love the most. Perhaps you should try to experience some other aspects of that thing.</p>
<p>Don't drop everything at once, but on the weekend, try out an alternative language, try out accessibility if you never did, try out data-science, or even backend development.</p>
<p>You might enjoy that even more than what you're doing now.</p>
<p>I hope this article will inspire some people to at least give it a think and perhaps experience to find the thing they love the most.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Using CSS counters]]></title><description><![CDATA[A while ago, we looked at custom numbered list styling, but we can use the concept of CSS counters to turn any element into a counter.
So what exactly are these CSS counters? We can look at them as variables maintained by CSS. CSS rules can increase ...]]></description><link>https://h.daily-dev-tips.com/using-css-counters</link><guid isPermaLink="true">https://h.daily-dev-tips.com/using-css-counters</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Tue, 06 Dec 2022 06:04:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670306537925/omZY6Lgg_.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while ago, we looked at <a target="_blank" href="https://daily-dev-tips.com/posts/css-custom-numbered-list-styling/">custom numbered list styling</a>, but we can use the concept of CSS counters to turn any element into a counter.</p>
<p>So what exactly are these CSS counters? We can look at them as variables maintained by CSS. CSS rules can increase the values, which will track how many times they are used.</p>
<h2 id="heading-using-css-counters">Using CSS counters</h2>
<p>To use these counters, we must first create them with the counter-reset function. Wherever you call this reset from, it will reset the count for that counter (identified by its name).</p>
<p>Let's set up a counter on our body and count for each <code>p</code> element.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">counter-reset</span>: paragraph;
}

<span class="hljs-selector-tag">p</span><span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">counter-increment</span>: paragraph;
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'Paragraph '</span> <span class="hljs-built_in">counter</span>(paragraph) <span class="hljs-string">': '</span>;
}
</code></pre>
<p>If we now create the following HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>We end up with this result.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669537433562/CrYHcAulv.png" alt="CSS Counter" /></p>
<p>We can define these counters as we wish and reset them as we go.</p>
<h2 id="heading-custom-reset">Custom reset</h2>
<p>Let's take a look at custom resets.
For instance, we have <code>h2</code> elements as our main counter, and for each paragraph, inside of it, we want to showcase a different counter.
For the demo, we'll even combine the counter output.</p>
<p>Let's take the following HTML structure.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>First heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Second heading<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>We could then easily create an index for each section like this.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">counter-reset</span>: heading;
}
<span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">counter-reset</span>: paragraph;
}
<span class="hljs-selector-tag">h2</span><span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">counter-increment</span>: heading;
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'Section '</span> <span class="hljs-built_in">counter</span>(heading) <span class="hljs-string">': '</span>;
}
<span class="hljs-selector-tag">p</span><span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">counter-increment</span>: paragraph;
  <span class="hljs-attribute">content</span>: <span class="hljs-built_in">counter</span>(heading) <span class="hljs-string">'.'</span> <span class="hljs-built_in">counter</span>(paragraph) <span class="hljs-string">' '</span>;
}
</code></pre>
<p>Which would result in the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669537895892/PjJnU2kuS.png" alt="Multiple counters in CSS" /></p>
<p>Pretty cool, right, It might be for sporadic use cases, but one day, you might need CSS counters.</p>
<p>You can also check them out on this <a target="_blank" href="https://codepen.io/rebelchris/pen/poKKdBg">CodePen</a>.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[A look at HSL colors]]></title><description><![CDATA[For this article, I want to explore HSL colors, which I never really used before but want to explore.
HSL stands for hue, saturation, and lightness, where the following values can be used.

hue: is 360 degrees on the color wheel, so it goes from 0 to...]]></description><link>https://h.daily-dev-tips.com/a-look-at-hsl-colors</link><guid isPermaLink="true">https://h.daily-dev-tips.com/a-look-at-hsl-colors</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Mon, 05 Dec 2022 05:11:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670217010537/XCv_Yj7wg.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For this article, I want to explore HSL colors, which I never really used before but want to explore.</p>
<p>HSL stands for <code>hue</code>, <code>saturation</code>, and <code>lightness</code>, where the following values can be used.</p>
<ul>
<li><code>hue</code>: is 360 degrees on the color wheel, so it goes from 0 to 360.</li>
<li><code>saturation</code>: is a percentage from 0% to 100% where 100 equals the full color.</li>
<li><code>lightness</code>: is also a percentage where 0% is black, and 100% is white.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669440716019/mCya0LfzO.png" alt="HSL color wheel" /></p>
<h2 id="heading-using-hsl-colors-in-css">Using HSL colors in CSS</h2>
<p>We can write the following syntax to use this color variant in CSS.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">120</span>, <span class="hljs-number">50%</span>, <span class="hljs-number">50%</span>);
}
</code></pre>
<p>Which will give us a green background.</p>
<p>A compelling element to using HSL is that it's super easy to use the same level of tints across the board.</p>
<p>Let's say you are developing a theme with full-color versions and a lighter tint for secondary elements.</p>
<p>With HSL you can ensure that you use the same tints no matter which color you pick.</p>
<p>For example, let's set up a header with a secondary body.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"primary"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"secondary logo"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"secondary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"secondary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"secondary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"secondary"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"primary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"primary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"primary"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">l</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>This would give us an actual example. Let's start by making all the primary elements black and the secondary white. We would end up with the following layout.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.primary</span> {
  <span class="hljs-attribute">background-color</span>: black;
}
<span class="hljs-selector-class">.secondary</span> {
  <span class="hljs-attribute">background-color</span>: white;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669441815661/zM9U8rCqo.png" alt="Layout option defined" /></p>
<p>However, we don't want it just black and white and want a theme switched even. It will become challenging to get all the available themes in the right shades, right?</p>
<p>Well, not with HSL!</p>
<p>Let's define some HSL variables we can easily reuse.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--primary-h</span>: <span class="hljs-number">4</span>;
  <span class="hljs-attribute">--primary-s</span>: <span class="hljs-number">73%</span>;
}
</code></pre>
<p>I've decided to make the hue and saturation the same, and it will be the lightness we play with to make the variants of the color.</p>
<p>In the above example, we use four as the hue, which is a red color.</p>
<p>Now we can add it to our primary and secondary colors to see what happens.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.primary</span> {
  <span class="hljs-attribute">--primary-l</span>: <span class="hljs-number">54%</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(var(--primary-h), <span class="hljs-built_in">var</span>(--primary-s), <span class="hljs-built_in">var</span>(--primary-l));
}
<span class="hljs-selector-class">.secondary</span> {
  <span class="hljs-attribute">--primary-l</span>: <span class="hljs-number">93%</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(var(--primary-h), <span class="hljs-built_in">var</span>(--primary-s), <span class="hljs-built_in">var</span>(--primary-l));
}
</code></pre>
<p>As you can see, the primary is about as true to the color, whereas the secondary is more to the white side.</p>
<p>It will result in the following image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669442035947/_93CFec97.png" alt="HSL color theme" /></p>
<p>And what's cool is that we can change the root <code>--primary-h</code> value to adjust the theme.</p>
<p>Let's try and set it to <code>304</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--primary-h</span>: <span class="hljs-number">304</span>;
}
</code></pre>
<p>And now, let's see what our app would look like.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669442155409/70kys1NSP.png" alt="Different hue theme" /></p>
<p>As you can see, the vibe of the theme is the same, we just swapped the hue, so it still feels familiar.</p>
<p>You can also play with this example on this <a target="_blank" href="https://codepen.io/rebelchris/pen/YzvLmYm">CodePen</a>.</p>
<h2 id="heading-testing-hsl-out">Testing HSL out</h2>
<p>Let's create a super quick demo to try out all HSL variants.</p>
<p>I've created three sliders in HTML, respective of the values for the HSL.
Then I've added these as variables in our CSS like this.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--primary-h</span>: <span class="hljs-number">4</span>;
  <span class="hljs-attribute">--primary-s</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">--primary-l</span>: <span class="hljs-number">50%</span>;
}
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(var(--primary-h), <span class="hljs-built_in">var</span>(--primary-s), <span class="hljs-built_in">var</span>(--primary-l));
}
</code></pre>
<p>And added some magic CSS to listen to all the changes on the sliders so we can adjust the values.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> hue = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#hue'</span>);
<span class="hljs-keyword">const</span> saturation = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#saturation'</span>);
<span class="hljs-keyword">const</span> lightness = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#lightness'</span>);

hue.addEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">document</span>.documentElement.style.setProperty(<span class="hljs-string">'--primary-h'</span>, <span class="hljs-built_in">this</span>.value);
});
saturation.addEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">document</span>.documentElement.style.setProperty(<span class="hljs-string">'--primary-s'</span>, <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.value}</span>%`</span>);
});
lightness.addEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">document</span>.documentElement.style.setProperty(<span class="hljs-string">'--primary-l'</span>, <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.value}</span>%`</span>);
});
</code></pre>
<p>With this in place, you'll be able to play around with the values to see what happens.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/rebelchris/pen/gOKzVBr">https://codepen.io/rebelchris/pen/gOKzVBr</a></div>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Submit button outside the form]]></title><description><![CDATA[The other day I had quite a weird scenario where we had a form inside a specific section, but the submit button was at the bottom.
At first, I tried to re-configure the HTML so that the button would be part of the form element. However, that quickly ...]]></description><link>https://h.daily-dev-tips.com/submit-button-outside-the-form</link><guid isPermaLink="true">https://h.daily-dev-tips.com/submit-button-outside-the-form</guid><category><![CDATA[HTML5]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sun, 04 Dec 2022 06:13:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670134351860/Pz-vlxEcD.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The other day I had quite a weird scenario where we had a form inside a specific section, but the submit button was at the bottom.</p>
<p>At first, I tried to re-configure the HTML so that the button would be part of the form element. However, that quickly became an HTML soup.</p>
<p>So I decided to research other options and learned (after many years of being a developer) that you can place submit buttons outside a form!</p>
<p>Let's take a look at that.</p>
<h2 id="heading-submit-button-outside-a-form">Submit button outside a form</h2>
<p>To achieve this, we should use the following markup.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"newsletterForm"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">form</span>=<span class="hljs-string">"newsletterForm"</span>&gt;</span>Submit!<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>As you can see, the button is not part of the form, yet this will work.</p>
<p>This is because we used the <code>form</code> attribute on our button. In it, we define which form this button belongs to.</p>
<p>You can also try it out in <a target="_blank" href="https://codepen.io/rebelchris/pen/MWXGoGj">this CodePen</a>.</p>
<blockquote>
<p>Note: You will see a "Not Found" page, as our form doesn't go anywhere.</p>
</blockquote>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item><item><title><![CDATA[Removing all vowels with JavaScript]]></title><description><![CDATA[Today we'll look at a nifty solution to remove all vowels in a string using JavaScript.
The idea is that we get a string and have to return the string without the letters aeiou.
JavaScript remove all vowels
Let's dive right into the solution.
const i...]]></description><link>https://h.daily-dev-tips.com/removing-all-vowels-with-javascript</link><guid isPermaLink="true">https://h.daily-dev-tips.com/removing-all-vowels-with-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Chris Bongers]]></dc:creator><pubDate>Sat, 03 Dec 2022 11:08:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670065658715/iD28oc84p.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today we'll look at a nifty solution to remove all vowels in a string using JavaScript.</p>
<p>The idea is that we get a string and have to return the string without the letters <code>aeiou</code>.</p>
<h2 id="heading-javascript-remove-all-vowels">JavaScript remove all vowels</h2>
<p>Let's dive right into the solution.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> input = <span class="hljs-string">'daily dev tips'</span>;

<span class="hljs-keyword">const</span> removeVowels = input.replace(<span class="hljs-regexp">/[aeiou]/gi</span>, <span class="hljs-string">''</span>);

<span class="hljs-built_in">console</span>.log(removeVowels);

<span class="hljs-comment">// 'dly dv tps'</span>
</code></pre>
<p>It works!
And yep that's all the code we need, but let's take a closer look at how it works.</p>
<p>The first part is to use the JavaScript replace function to replace a specific match.
The first part is the match, for which we'll use a regular expression. And the second part is the replacement.</p>
<p>We could, say, replace the letter <code>i</code> with an empty string like this.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> removeVowels = input.replace(<span class="hljs-string">'i'</span>, <span class="hljs-string">''</span>);

<span class="hljs-built_in">console</span>.log(removeVowels);

<span class="hljs-comment">// 'daly dev tips'</span>
</code></pre>
<p>However, you'll notice it only replaced the first occurrence. And, of course, we can only target one letter at a time.
So this is where our regular expression comes in.</p>
<p>We start the regular expression by wrapping it in the <code>/ /</code> backslashes.
Then we open a pattern matcher with the <code>[]</code> brackets. And in between, we specify which letters should be matched.
The last part is to use <code>gi</code> at the end, which stands for <code>global ignore</code>.</p>
<ul>
<li><code>global</code> meaning to apply it to each occurrence, not just the first one</li>
<li><code>ignore</code> means to perform a case-insensitive search</li>
</ul>
<p>And that's it. I hope you learned something about removing vowels with JavaScript.</p>
<h3 id="heading-thank-you-for-reading-and-lets-connect">Thank you for reading, and let's connect!</h3>
<p>Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on <a target="_blank" href="https://www.facebook.com/DailyDevTipsBlog">Facebook</a> or <a target="_blank" href="https://twitter.com/DailyDevTips1">Twitter</a></p>
]]></content:encoded></item></channel></rss>