<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jarod Peachey</title>
    <description>The latest articles on Forem by Jarod Peachey (@jarodpeachey).</description>
    <link>https://forem.com/jarodpeachey</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F254663%2F7f5ac336-1bde-4332-b953-c42a513945dc.jpg</url>
      <title>Forem: Jarod Peachey</title>
      <link>https://forem.com/jarodpeachey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jarodpeachey"/>
    <language>en</language>
    <item>
      <title>WordPress vs. Custom Website Design: Which is Better?</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Wed, 14 Apr 2021 15:41:14 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/wordpress-vs-custom-website-design-which-is-better-5ajf</link>
      <guid>https://forem.com/jarodpeachey/wordpress-vs-custom-website-design-which-is-better-5ajf</guid>
      <description>&lt;p&gt;WordPress is an amazing platform that makes building websites pretty simple for everyone. With themes, plugins, and customization, it's got lots of options for your website.&lt;/p&gt;

&lt;p&gt;However, when you start putting all those things together, it gets cluttered, hard to use and confusing.&lt;/p&gt;

&lt;p&gt;A custom built website is a great option to consider for your business. You can have anything you want on your website, without any of the bloat and clutter of WordPress.&lt;/p&gt;

&lt;p&gt;However, a custom website has some downsides as well. It's harder to make tiny, minor changes, and it might not be the best option for everyone.&lt;/p&gt;

&lt;p&gt;With that said, let's compare some of the benefits and downsides of WordPress and a custom website design.&lt;/p&gt;

&lt;p&gt;On to the comparison 👇&lt;/p&gt;

&lt;h2&gt;
  
  
  Website SEO
&lt;/h2&gt;

&lt;p&gt;SEO is arguably the most important part of a new website.&lt;/p&gt;

&lt;p&gt;Without it, no one will be able to find your website through Google search without digging through 100's of results.&lt;/p&gt;

&lt;p&gt;Wordpress comes out of the box with some simple SEO tools, but these are limited in their functionality.&lt;/p&gt;

&lt;p&gt;A custom website allows full control over the code, so the entire site can be constructed from top-to-bottom to be SEO-friendly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wordpress SEO
&lt;/h3&gt;

&lt;p&gt;Wordpress is a great option for some beginer SEO optimizations and tweaks. It's pretty simple to see your basic SEO metrics, but it's got some downsides as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  SEO Plugins
&lt;/h4&gt;

&lt;p&gt;Wordpress has many SEO plugins that allow you to optimize each blog post for SEO. One of these is &lt;a href="https://yoast.com"&gt;Yoast SEO&lt;/a&gt;, which is a plugin that shows up right below each post you write.&lt;/p&gt;

&lt;p&gt;This is a really cool feature because you can use a visual editor to understand your SEO better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wAMcNTCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kinsta.com/wp-content/uploads/2018/02/yoast-seo-taxonomies.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wAMcNTCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kinsta.com/wp-content/uploads/2018/02/yoast-seo-taxonomies.png" alt="How to Use Yoast SEO on WordPress [Complete Tutorial]"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yoast (and other tools) are a nice way to see a quick summary of all the SEO optimizations on your site.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hard to use
&lt;/h4&gt;

&lt;p&gt;While SEO plugins are great, it's often difficult to change your SEO info. With all the plugins, configuration options, and themes, it's common to find SEO settings in 3-5 different places on your site, making it hard to optimize everything you can.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom website SEO
&lt;/h3&gt;

&lt;p&gt;A custom website is also a great option for SEO for different reasons.&lt;/p&gt;

&lt;p&gt;A custom website makes it easier to control every part of the SEO, from structure to copy, blog posts to images.&lt;/p&gt;

&lt;h4&gt;
  
  
  Complete SEO control
&lt;/h4&gt;

&lt;p&gt;With a custom design, you'll get a website that's top-to-bottom optimized for SEO. &lt;/p&gt;

&lt;p&gt;When you get a custom website built, you'll be working with people who have the ability to change anything and everything you want on your website, something that is a lot harder to do with WordPress.&lt;/p&gt;

&lt;h4&gt;
  
  
  It takes longer to set up
&lt;/h4&gt;

&lt;p&gt;As is expected when comparing WordPress to anything else, a custom website will take longer to set up your SEO. Wordpress comes out-of-the-box with SEO optimizations.&lt;/p&gt;

&lt;p&gt;A custom website, while better in the long run, will take a little more time to set up and get ready for SEO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Website Design
&lt;/h2&gt;

&lt;p&gt;After you've got people coming to your site, your website needs to look good.&lt;/p&gt;

&lt;p&gt;You need to stand out as a business with a cohesive theme, copy style and feel to the website.&lt;/p&gt;

&lt;h3&gt;
  
  
  WordPress themes and design
&lt;/h3&gt;

&lt;p&gt;WordPress comes with 1,000s of custom themes and design to choose from. Tons of them are free as well, so you can get a site up and running with a pretty similar design to what you need.&lt;/p&gt;

&lt;p&gt;Most of the popular themes come with page builders, intuitive UI tools (most are drag-and-drop) that allow you to change the layout and design of your site with ease.&lt;/p&gt;

&lt;h4&gt;
  
  
  Theme compatibility
&lt;/h4&gt;

&lt;p&gt;As great as WordPress themes are, they've got one major downside: they don't all work with the same design and content.&lt;/p&gt;

&lt;p&gt;Because of the complexity of a website, when you create one using a certain theme, it requires specific set up.&lt;/p&gt;

&lt;p&gt;However, if you switch themes, your new theme might not have the same structure as the old one, resulting in a broken website that's hard to get back to normal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Auto updates + plugin conflicts
&lt;/h4&gt;

&lt;p&gt;Plugins and themes and are the backbone of WordPress, which is a good and bad thing.&lt;/p&gt;

&lt;p&gt;They're great for adding any kind of functionality to your website. There are tons of plugins to choose from, so you can always find what you're looking for.&lt;/p&gt;

&lt;p&gt;However, plugins and themes get updated. And with each new update comes some new code that's not compatible with every plugin on your website.&lt;/p&gt;

&lt;p&gt;Can you guess what happens?&lt;/p&gt;

&lt;p&gt;Yep. The website breaks again.&lt;/p&gt;

&lt;p&gt;And it's not the theme + plugin developers fault; it's hard to manually make sure your new updates work with all 50,000+ plugins and themes.&lt;/p&gt;

&lt;p&gt;Sadly, it's just something to deal with on a WordPress site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom website design
&lt;/h3&gt;

&lt;p&gt;Arguably, the best part about a website is the fact that you have COMLETE control over how your website looks. You don't have to struggle with plugins, themes or design.&lt;/p&gt;

&lt;h4&gt;
  
  
  Brand cohesiveness
&lt;/h4&gt;

&lt;p&gt;Since you have complete control over the design of your custom website, it's easy to make sure that your brand is properly represented by the website.&lt;/p&gt;

&lt;p&gt;With a custom design, you'll get your brand's colors, logo and font style throughout the entire site. The backgrounds, buttons, navigation and text will all have the same styles, so your website will be a professional place to represent your business.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ability to create a new design
&lt;/h4&gt;

&lt;p&gt;With a custom website, you're not limited to tweaking a WordPress theme that someone else built 2 years ago.&lt;/p&gt;

&lt;p&gt;You can create a design that's tailored 100% to your company. The possibilities are, quite literally, endless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Website performance
&lt;/h2&gt;

&lt;p&gt;A fast website is becoming more and more important to make your visitors happy, and to make Google happy with your business.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wordpress performance
&lt;/h3&gt;

&lt;p&gt;WordPress is by no means super slow. In fact, some of the fastest websites are highly-optimized WordPress sites.&lt;/p&gt;

&lt;p&gt;However, it's a bit difficult to make your WordPress site faster. You need to choose the right hosting, choose the right performance plugin, limit how many plugins you use, and choose the fastest theme.&lt;/p&gt;

&lt;p&gt;It's entirely possible, but there are some sacrifices along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom website performance
&lt;/h3&gt;

&lt;p&gt;With a custom website, there's no sacrifices.&lt;/p&gt;

&lt;p&gt;It's built fully to your standards and needs.&lt;/p&gt;

&lt;p&gt;So, if you say you want a fast website, you'll get a fast website.&lt;/p&gt;

&lt;p&gt;But the best part it, a fast custom website doesn't sacrifice design, usability or SEO.&lt;/p&gt;

&lt;p&gt;It's like the best of both (or all 4) worlds!&lt;/p&gt;

&lt;h2&gt;
  
  
  Which is best for you?
&lt;/h2&gt;

&lt;p&gt;As much as we like custom websites, they're not always the best option.&lt;/p&gt;

&lt;p&gt;WordPress is just super cool for a lot of things, and can be a great option for your new website.&lt;/p&gt;

&lt;h3&gt;
  
  
  WordPress is best for smaller personal sites
&lt;/h3&gt;

&lt;p&gt;If you want a simple website, blog or something else small, WordPress is by far the best option.&lt;/p&gt;

&lt;p&gt;Here's a few of the benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's easy to set up a minimal website&lt;/li&gt;
&lt;li&gt;It's cheaper&lt;/li&gt;
&lt;li&gt;1000s of themes to choose from&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WordPress was orignally built as a blogging platform, which is why it's one of the best options for a new blog (funny how that works).&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom websites are best for, well, fully custom designs
&lt;/h3&gt;

&lt;p&gt;While WordPress is great for some things, it just gets cluttered, hard-to-use and clunky as you start trying to get a super-customized theme, high-performance and great SEO.&lt;/p&gt;

&lt;p&gt;With a custom website, you don't have to settle for someone else's website design.&lt;/p&gt;

&lt;p&gt;You literally get your own design, that is unique to you and your business.&lt;/p&gt;

&lt;p&gt;Plus, you don't have to sacrifice anything. Here's a few of the benefits of a custom site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster. Like, blazing fast.&lt;/li&gt;
&lt;li&gt;Total SEO control. We're talking images, text, headings, and structure.&lt;/li&gt;
&lt;li&gt;Custom design unique to you&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, I hope after some super-intense study (just kidding, you don't need to study much), you've found your answer as to whether or not a custom website is better than WordPress for you.&lt;/p&gt;

&lt;p&gt;If you HAVE decided that a brand-spanking new custom website sounds like a great fit for you, shoot us an email at &lt;a href="mailto:jarod@jellydevelopment.com"&gt;jarod@jellydevelopment.com&lt;/a&gt; (you'll get a personal reply within 1 24 hours).&lt;/p&gt;

&lt;p&gt;Thanks for reading, and best of luck with your new website 🔥&lt;/p&gt;

</description>
      <category>wordpress</category>
    </item>
    <item>
      <title>Building a Twitter theme Chrome extension</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Sat, 02 Jan 2021 15:28:33 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/building-a-twitter-theme-chrome-extension-3fid</link>
      <guid>https://forem.com/jarodpeachey/building-a-twitter-theme-chrome-extension-3fid</guid>
      <description>&lt;p&gt;Chrome extensions are awesome.&lt;/p&gt;

&lt;p&gt;And Twitter is awesome.&lt;/p&gt;

&lt;p&gt;But I didn't really like the Twitter UI. I always found it a little cluttered, and hard to read.&lt;/p&gt;

&lt;p&gt;Since I had always wanted to build a Chrome extension, I decided to jump right in and build a Twitter theme extension!&lt;/p&gt;

&lt;p&gt;Let's get into it.&lt;/p&gt;

&lt;p&gt;(Oh, you can get the extension at &lt;a href="https://get-glitter.netlify.app"&gt;https://get-glitter.netlify.app&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Functionality
&lt;/h2&gt;

&lt;p&gt;The main thing I wanted it to do was customize the theme of Twitter.&lt;/p&gt;

&lt;p&gt;To avoid complexity starting out, I simply used the &lt;code&gt;override.css&lt;/code&gt; file to add some custom styles to things like the navbar, cards and more.&lt;/p&gt;

&lt;p&gt;It was a bit tough, because Twitter uses dynamically generated classnames, so I had to use nested CSS selectors.&lt;/p&gt;

&lt;p&gt;For example, here's a pretty large single element selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[aria-labelledby='modal-header']
&amp;gt; div:first-child
&amp;gt; div:first-child
&amp;gt; div:nth-child(2)
&amp;gt; div:first-child
&amp;gt; div:first-child
&amp;gt; div:first-child
&amp;gt; div:first-child
&amp;gt; div:nth-child(3)
[role='button']:hover {
    cursor: pointer  !important;
    background-color: var(--primarycolor) !important;
    filter: brightness(1.2) !important;
    color: var(--buttontextcolor) !important;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the longest part, because I kept accidently overriding styles I didn't want to.&lt;/p&gt;

&lt;p&gt;Anyway, I came up with a few themes based on CSS variables. The basic theme looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    name:  'theme-light',
    title:  'Default',
    category:  'Light',
    primarycolor:  '#1DA1F2',
    backgroundcolor:  '#f1f1f1',
    hovercolor:  '#f7f7f7',
    cardbackground:  '#ffffff',
    accentcolor:  '#f1f1f1',
    bordercolor:  '#bbbbbb',
    textcolor:  '#222222',
    cardborderradius:  '8px',
    cardbordercolor:  '#000000',
    cardborderwidth:  '0',
    cardshadow:
'rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px',
    buttonborderradius:  '6px',
    buttontextcolor:  '#ffffff',
    inputtextcolor:  '#111111',
    inputbackground:  '#ffffff',
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I included the obvious colors, backgrounds, etc; but I also included a category and a theme name. This was to make sure I could seperate themes by category later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing themes
&lt;/h3&gt;

&lt;p&gt;The most important part of this was being able to store the themes.&lt;/p&gt;

&lt;p&gt;To do this, I created a &lt;code&gt;loadThemes.js&lt;/code&gt; file, which was a simple script to loop through each theme in the &lt;code&gt;themes&lt;/code&gt; array and set a cookie for Twitter with that theme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;themes.forEach((theme) =&amp;gt; {
  chrome.cookies.get(
  { url:  'https://twitter.com', name:  theme.name },
  function (cookie) {
    if (
      cookie &amp;amp;&amp;amp;
      cookie.value &amp;amp;&amp;amp;
      cookie.value !== '{}' &amp;amp;&amp;amp;
      cookie.value !== '' &amp;amp;&amp;amp;
      JSON.parse(cookie.value) !== {}
    ) {
    } else {
      chrome.cookies.set(
        {
          url:  'https://twitter.com',
          name:  theme.name,
          value:  JSON.stringify(theme),
          expirationDate:  new  Date().getTime() + 10 * 365 * 24 * 60 * 60,
        },
          function () {},
        );
        window.location.reload();
      }
    },
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I had a few cookies with the themes in them, which I could access later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching themes
&lt;/h3&gt;

&lt;p&gt;After I built the UI for switching themes (a simple grid with the themes laid out) I had to actually implement the theme switching.&lt;/p&gt;

&lt;p&gt;To do this, I added a click event listener to each theme in the UI.&lt;/p&gt;

&lt;p&gt;I then accessed the &lt;code&gt;id&lt;/code&gt; attribute on that element, which would be the same as the theme cookie name.&lt;/p&gt;

&lt;p&gt;I could use that to access the cookie, and call a function to update the CSS custom properties on Twitter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;themePreset.addEventListener("click", (e) =&amp;gt; {
  changeTheme(e.target.id);
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;changeTheme&lt;/code&gt; function is pretty large, but here's the basic idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept theme name parameter&lt;/li&gt;
&lt;li&gt;Get cookie with the name of the &lt;code&gt;themeName&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;Parse the cookie to get the &lt;code&gt;theme&lt;/code&gt; object&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;chrome.tabs.getSelected&lt;/code&gt; to pass some code for Twitter to run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the code I passed to Twitter to run (abridged):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.documentElement.style.setProperty(
    '--primarycolor',
    '${newTheme.primarycolor}',
);
document.documentElement.style.setProperty(
    '--backgroundcolor',
    '${newTheme.backgroundcolor}',
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then used &lt;code&gt;chrome.tabs.executeScript(tab.id, { code:  code });&lt;/code&gt; to execute the script, and now the CSS custom properties were changed.&lt;/p&gt;

&lt;p&gt;Twitter looks different now! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding custom themes
&lt;/h2&gt;

&lt;p&gt;I got a little carried away at this point, and decided to add custom themes and edit ability.&lt;/p&gt;

&lt;p&gt;In hindsight, that was both dumb and cool.&lt;/p&gt;

&lt;p&gt;Anyways, I did that by simply adding more cookies to Twitter, with each cookie storing the theme data.&lt;/p&gt;

&lt;p&gt;Every time the extension loaded, I accessed the theme cookies and created new elements for them, so you could switch between the themes you created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the extension
&lt;/h2&gt;

&lt;p&gt;Thanks for reading this far! You can find the extension at &lt;a href="https://get-glitter.netlify.app"&gt;https://get-glitter.netlify.app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

&lt;p&gt;p.s If you want, you can follow me on &lt;a href="https://twitter.com/jarodpeachey"&gt;Twitter&lt;/a&gt; for more cool stuff like this!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build a Todo List App with VueJS</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Fri, 11 Sep 2020 18:54:50 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/build-a-todo-list-app-with-vuejs-2hm2</link>
      <guid>https://forem.com/jarodpeachey/build-a-todo-list-app-with-vuejs-2hm2</guid>
      <description>&lt;p&gt;VueJS is a modern Javascript framework that makes it easy to handle data flow, simply by including attributes in your HTML tags.&lt;/p&gt;

&lt;p&gt;In this guide, we'll be building a simple todo list app to get up and running with VueJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and Installation
&lt;/h2&gt;

&lt;p&gt;There are two ways to setup Vue: through a NodeJS project, or by including a script inside of your HTML file. Since we're just starting out, we'll use a script inside of our index.html file.&lt;/p&gt;

&lt;p&gt;We can set up our index.html file like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE  html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Todooey - A Simple Todo List App&amp;lt;/title&amp;gt;
    &amp;lt;link rel="stylesheet" href="style.css"&amp;gt;
    &amp;lt;script src="https://unpkg.com/vue"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id="app"&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to use Vue in our app, we need to create a  new instance of Vue. We can do this using another &lt;code&gt;script&lt;/code&gt; tag before the closing &lt;code&gt;body&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we're able to use Vue in our app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Our App
&lt;/h2&gt;

&lt;p&gt;Before we add the functionality to our app with Vue, we'll create the basic HTML/CSS structure with static content.&lt;/p&gt;

&lt;p&gt;Inside of our HTML file, we'll create the Add Todo input, as well as the Todo list and each item&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container"&amp;gt;
  &amp;lt;h1 class=""&amp;gt;My Todo List&amp;lt;/h1&amp;gt;
  &amp;lt;div class="card"&amp;gt;
    &amp;lt;div class="flex"&amp;gt;
      &amp;lt;input placeholder="Add new todo" /&amp;gt;
        &amp;lt;button&amp;gt;Add&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class="card"&amp;gt;
    &amp;lt;div class="card-inner"&amp;gt;
      &amp;lt;h2&amp;gt;Todo&amp;lt;/h2&amp;gt;
      &amp;lt;ul class="list"&amp;gt;
        &amp;lt;li class="list-item"&amp;gt;
          &amp;lt;div class="list-item-toggle"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span&amp;gt;Wash the car&amp;lt;/span&amp;gt;
          &amp;lt;div class="list-item-delete"&amp;gt;X&amp;lt;/div&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, we'll add some basic styling to our app inside our &lt;code&gt;style.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html,
body {
  margin: 0;
  padding: 0;
  background: #faffff;
  font-size: 16px;
}

* {
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
        Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  color: #3d4855;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin-top: 0;
}

.container {
  padding: 24px 0;
  max-width: 700px;
  width: 100%;
  margin: 0 auto;
}

.card {
  border-radius: 4px;
  box-shadow: 1px 1px 40px -10px #31505f30, 0px 1px 2px 0px #31505f30;
  background: white;
  margin-bottom: 24px;
}

.card-inner {
  padding: 16px 24px;
}

.flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

input {
  border-radius: 4px;
  background: transparent;
  border: none;
  width: 100%;
  padding: 14px;
  font-size: 16px;
  border: 1px solid transparent;
  height: 100%;
  display: block;
  outline: none;
}

button {
  background: #4fc08d;
  padding: 10px 22px;
  border: none;
  color: white;
  border-radius: 4px;
  margin: 8px;
  font-size: 16px;
  cursor: pointer;
  box-shadow: 1px 1px 15px -2px #212c4430;
  transition: 0.15s;
}

button:hover {
  background: #42aa7b;
}

button:disabled {
  background: #e8e8e8;
  color: #555;
  box-shadow: none;
}

.list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.list-item {
  padding: 12px 16px 12px 16px;
  border: 1px solid #e8e8e8;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  margin-bottom: 6px;
  border-radius: 4px;
}

.list-item:first-child {
  border-top: 1px solid #e8e8e8;
}

.list-item-toggle {
  border: 1px solid #e8e8e8;
  border-radius: 999px;
  height: 21px;
  width: 21px;
  margin-right: 16px;
}

.list-item-delete {
  margin-left: auto;
  color: tomato;
  margin-top: -2px;
  font-weight: bold;
  text-decoration: none !important;
}

.list-item.completed {
  border: 1px solid #4fc08d;
}

.list-item.completed span {
  text-decoration: line-through;
}

.list-item.completed .list-item-toggle {
  background: #4fc08d;
  border: #4fc08d;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Vue to Add Functionality
&lt;/h2&gt;

&lt;p&gt;Great! Now that our app is styled, we can begin using Vue to create a dynamic todo list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Displaying Our Todo List
&lt;/h3&gt;

&lt;p&gt;To display our todo list, we'll take advantage of Vue's 2-way data flow. Inside of our &lt;code&gt;script&lt;/code&gt; tag, we'll use Vue's &lt;code&gt;data&lt;/code&gt; object to create an array that will contain all our todo items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
    data: {
      items: [
         {
           id: 1,
           name: 'Clean the fridge'
         },
         {
           id: 2,
           name: 'Walk the dogs'
         },
      ]
    }
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Each todo item has a name and an ID, which will be used for removing items from the list later on.&lt;/p&gt;

&lt;p&gt;Now that we have our data, we can display it in our list using the &lt;code&gt;v-for&lt;/code&gt; attribute, which is basically a &lt;code&gt;forEach&lt;/code&gt; loop that Vue uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ul class="list"&amp;gt;
  &amp;lt;li class="list-item" v-for="item in reversedItems"&amp;gt;
    ...
    &amp;lt;span&amp;gt;{{ item.name }}&amp;lt;/span&amp;gt;
    ...
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;v-for&lt;/code&gt; attribute allows us to acces the &lt;code&gt;item&lt;/code&gt; property. We can display the name by using the double handlebars syntax: &lt;code&gt;{{ item.name }}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Todo Items
&lt;/h3&gt;

&lt;p&gt;Now that our items display properly, we can work on adding new items to the list. Using Vue's &lt;code&gt;methods&lt;/code&gt; property, we can create a method that adds a new todo to the list.&lt;/p&gt;

&lt;p&gt;First, let's create a new property inside our &lt;code&gt;data&lt;/code&gt; object, called &lt;code&gt;newItem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
    data: {
      newItem: '',
      items: [...]
    }
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will be the value that we enter into the Add Todo input.&lt;/p&gt;

&lt;p&gt;In order to make sure that what we type in our input updates the &lt;code&gt;newItem&lt;/code&gt; value, we can take advantage of Vue's 2-way data flow, using the &lt;code&gt;v-model&lt;/code&gt; attribute. This means that whatever value we enter into the input will be persisted to the &lt;code&gt;data&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input v-model="newItem" placeholder="Add new todo"  /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we now have our &lt;code&gt;newItem&lt;/code&gt; value stored, we can create a method to add that item to the list.&lt;/p&gt;

&lt;p&gt;Beneath the &lt;code&gt;data&lt;/code&gt; object, we'll create a new &lt;code&gt;methods&lt;/code&gt; object with a function, &lt;code&gt;addItem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
    data: {...},
    methods: {
      addItem: function() {
        this.items.push({
          id: this.items.length + 1,
          name: this.newItem,
          completed: false,
        });
        this.newItem = '';
      },
    },
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Basically, when this function is called, we're taking the &lt;code&gt;newItem&lt;/code&gt; value and pushing it to the &lt;code&gt;items&lt;/code&gt; array. The, we're clearing out the &lt;code&gt;newItem&lt;/code&gt; value, which clears our Add Todo input.&lt;/p&gt;

&lt;p&gt;Now, all we need to do is call the function when we click the Add button. We can use the &lt;code&gt;v-on&lt;/code&gt; attribute, or the &lt;code&gt;@&lt;/code&gt; symbol for short.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button @click="addItem"&amp;gt;Add&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, Vue will know to call the &lt;code&gt;addItem&lt;/code&gt; function when this button is clicked.&lt;/p&gt;

&lt;p&gt;As something a little extra, we can also disable the button is there is no value in the input, using the &lt;code&gt;:disabled&lt;/code&gt; attribute. This tells Vue to apply the disabled attribute only if the expression inside the qoutes is true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button @click="addItem" :disabled="newItem.length === 0"&amp;gt;Add&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Marking Items as Complete
&lt;/h3&gt;

&lt;p&gt;The final thing that we need to do is add the ability to mark our items as complete.&lt;/p&gt;

&lt;p&gt;To do this, we'll add a new property to each item in our array: the &lt;code&gt;completed&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
new Vue({
  el: '#app',
  data: {
    items: [{
      id: 1,
      name: 'Clean the fridge',
      completed: true,
    },
    {
      id: 2,
      name: 'Walk the dogs',
      completed: false,
    }]
  }
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Vue once again provides us with an attribute to dynamically change the class of an element, based on data in the Vue instance.&lt;/p&gt;

&lt;p&gt;So, we can go to our list item and add the &lt;code&gt;:class&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li class="list-item" :class="{completed: item.completed}" v-for="item in reversedItems"&amp;gt;
  ...
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This tells Vue that it should apply the &lt;code&gt;completed&lt;/code&gt; class to the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; only if the item is completed (which we can tell by accessing the &lt;code&gt;item.completed&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Now, our completed items should have a green outline. However, we still need to be able to mark them complete if they are not.&lt;/p&gt;

&lt;p&gt;To do this, we'll create another method, called &lt;code&gt;toggleComplete&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
    data: {...},
    methods: {
      addItem: function() {...},
      toggleComplete: function (item) {
        item.completed = !item.completed;
      }
    },
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once we have our method, we can call it using the &lt;code&gt;@click&lt;/code&gt; attribute that Vue provides.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li class="list-item" :class="{completed: item.completed}" v-for="item in reversedItems"&amp;gt;
  &amp;lt;div class="list-item-toggle" @click="toggleComplete(item)"&amp;gt;&amp;lt;/div&amp;gt;
  ...
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once again, we can pass in the &lt;code&gt;item&lt;/code&gt; object as a prop to the function, because Vue allows us to access it via the &lt;code&gt;v-for&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Now, we can toggle each todo item between complete and uncomplete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting Todo Items
&lt;/h3&gt;

&lt;p&gt;The final thing we need to do is allow ourselves to delete todo items. Once again, we'll use a method to accomplish this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  new Vue( {
    el: '#app',
    data: {...},
    methods: {
      addItem: function() {...},
      toggleComplete: function (item) {...},
      removeItem: function (itemID) {
        this.items = this.items.filter((item) =&amp;gt; newItem.id!== itemID);
      } 
    },
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this function, we're accessing the &lt;code&gt;itemID&lt;/code&gt; prop (which is passed from the delete element) and setting the &lt;code&gt;items&lt;/code&gt; property to a new array, without the item we just deleted.&lt;/p&gt;

&lt;p&gt;Now, we can call the function from our delete element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li class="list-item" :class="{completed: item.completed}" v-for="item in reversedItems"&amp;gt;
  ...
  &amp;lt;div class="list-item-delete" @click="removeItem(item.id)"&amp;gt;X&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Tada! Now, we can succesfully delete our todo items!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;So that's it! We've just build a functioning todo application using Vue. We learned how to call methods, access data and update data, all without any JS DOM manipulation.&lt;/p&gt;

&lt;p&gt;You can find the full code for this app on  &lt;a href="https://github.com/jarodpeachey/vue-todo-list"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you liked this tutorial, I'd appreciate it if you could  &lt;a href="https://www.buymeacoffee.com/jarodpeachey"&gt;buy me a coffee&lt;/a&gt;! Or, follow me on &lt;a href="https://twitter.com/jarodpeachey"&gt;Twitter&lt;/a&gt; ✌.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>html</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a Reusable Grid System in React</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Thu, 16 Jul 2020 18:55:36 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/creating-a-reusable-grid-system-in-react-2p47</link>
      <guid>https://forem.com/jarodpeachey/creating-a-reusable-grid-system-in-react-2p47</guid>
      <description>&lt;p&gt;The grid system is arguably the most valuable layout tool for building websites. Without it, responsive layouts would be, well, NOT responsive.&lt;/p&gt;

&lt;p&gt;I use React a lot, so I decided to create a grid system that I could reuse in my React apps. It started as a personal tool, but as I got more use out of it, I decided to release it for other devs to use.&lt;/p&gt;

&lt;p&gt;So I did. It's called React Tiny Grid, and it's a 12-column grid system that's pretty handy. You can find it &lt;a href="https://react-tiny-grid.netlify.app"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But today, we're going to rebuild it step-by-step, so you can follow along and see how it's built.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We'll be using styled-components to style our grid system. Let's install that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --save styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we've got our dependencies installed, we'll create our two files: one for the Row component, and one for the Column component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ touch Row.js Column.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Grid Functionality
&lt;/h2&gt;

&lt;p&gt;To start, we'll create a basic flex wrapper that makes all the column items the same width, and wraps them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Row Component
&lt;/h3&gt;

&lt;p&gt;Inside of our Row.js file, we'll outline the basic row component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import  React  from  'react';
import  styled, { css } from  'styled-components';
import { Column } from  './Column';

export const Row = ({children}) =&amp;gt; {
  return (
    &amp;lt;Wrapper&amp;gt;
      {React.Children.toArray(children).map((item) =&amp;gt; {
        return (
          item &amp;amp;&amp;amp; (
            &amp;lt;Column&amp;gt;
              {item.props.children}
            &amp;lt;/Column&amp;gt;
          )
        );
      })}
    &amp;lt;/Wrapper&amp;gt;
  );
};

const  Wrapper = styled.div`
  @media (min-width: 769px) {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    margin: 0 -8px 0 -8px
  }
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's break this down.&lt;/p&gt;

&lt;p&gt;For the basic functionality, we're mapping through the &lt;code&gt;children&lt;/code&gt; of this component, and making those each a Column (we'll style those later).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{React.Children.toArray(children).map((item) =&amp;gt; {
  return (
    item &amp;amp;&amp;amp; (
      &amp;lt;Column&amp;gt;
        {item.props.children}
      &amp;lt;/Column&amp;gt;
    )
  );
})}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To add the grid functionality, we simply make the &lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; a flex element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  Wrapper = styled.div`
  @media (min-width: 769px) {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    margin: 0 -8px 0 -8px;
  }
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We 'activate' the grid system once the screen size is wider than 769px. Then, we set the display to flex.&lt;/p&gt;

&lt;p&gt;We also add the negative margin to account for the spacing of the columns (styled later).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;margin: 0 -8px 0 -8px;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the Column Component
&lt;/h3&gt;

&lt;p&gt;Now that we have our Row component, we need to style the Column component.&lt;/p&gt;

&lt;p&gt;Inside of our Column.js file, we'll create the basic column markup and styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import  React  from  'react';
import  styled, { css } from  'styled-components';

export const Column = ({children}) =&amp;gt; {
  return (
    &amp;lt;Wrapper&amp;gt;{children}&amp;lt;/Wrapper&amp;gt;
  );
};

const Wrapper = styled.div`
  flex: 1 1 0;
  width: 100%;
  padding: 8px;
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All we have to do for now is give the Column the ability to resize equally with it's siblings. This is accomplished using the &lt;code&gt;flex&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flex: 1 1 0;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We also added 8px of padding to each column. If you recall, that's the amount of negative margin we added to the &lt;code&gt;Row&lt;/code&gt; component. This is to make sure the edges of the columns meet the edges of their parent container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supporting Custom Breakpoints
&lt;/h2&gt;

&lt;p&gt;So far, we've got an automatic grid system! The columns are all resized, and are full-width on mobile.&lt;/p&gt;

&lt;p&gt;But a REAL grid system supports custom breakpoints. So let's do that now.&lt;/p&gt;

&lt;p&gt;Inside of our &lt;code&gt;Row.js&lt;/code&gt; file, we'll accept a &lt;code&gt;breakpoints&lt;/code&gt; prop, with a default value of 769.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const Row = ({children, breakpoints = [769]}) =&amp;gt; {
  ...
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we can use this breakpoints array to decide when to active the grid. To do this, we pass the first item in the &lt;code&gt;breakpoints&lt;/code&gt; array to the &lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const Row = ({children}) =&amp;gt; {
  return (
    &amp;lt;Wrapper breakpoint={breakpoints[0]}&amp;gt;
      ...
    &amp;lt;/Wrapper&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, we replace the 769px media query with a template literal, which are supported by styled-components. This allows us to use our breakpoint value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  Wrapper = styled.div`
  @media (min-width: ${props =&amp;gt; props.breakpoint}px) {
    ...
  }
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we can pass in a custom breakpoint to our &lt;code&gt;Row&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Row breakpoints={[960]} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But you know what would be cool?&lt;/p&gt;

&lt;p&gt;Custom column widths. For each breakpoint 🤯&lt;/p&gt;

&lt;p&gt;Let's do that now!&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Widths
&lt;/h3&gt;

&lt;p&gt;Back inside of our &lt;code&gt;Column.js&lt;/code&gt; file, we need to accept two new props: first, a &lt;code&gt;breakpoints&lt;/code&gt; array, which will be passed down from the parent &lt;code&gt;Row&lt;/code&gt; component. Second, a &lt;code&gt;widths&lt;/code&gt; array, which will contain an array of numbers defining how many columns to take up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const Column = ({children, breapoints, widths = ['auto']}) =&amp;gt; {
  ...
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: we used a default value of auto for the widths: this will allow the column to take up whatever space is available, in case we forget to pass in a widths prop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we're setting up the grid system to support up to three custom breakpoints and widths. However, we need to make sure that we have a default value for each of these three, in case we forget to pass in a value.&lt;/p&gt;

&lt;p&gt;At the top of our &lt;code&gt;Column&lt;/code&gt; component, we'll add these variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  breakpointOne = breakpoints[0];
const  breakpointTwo = breakpoints.length &amp;gt;= 1 ? breakpoints[1] : null;
const  breakpointThree = breakpoints.length &amp;gt;= 2 ? breakpoints[2] : null;

const  widthOne = widths[0];
const  widthTwo = widths.length &amp;gt;= 1 ? widths[1] : null;
const  widthThree = widths.length &amp;gt;= 2 ? widths[2] : null;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Basically, what we're doing is checking if there are 3 width values. If not, we set the third value to the previous width item. That way, our grid won't break!&lt;/p&gt;

&lt;p&gt;Now, we need to pass in these values as props to the column &lt;code&gt;&amp;lt;Wrapper&amp;gt;&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const Column = ({children, breakpoints, widths = ['auto']}) =&amp;gt; {
  return (
    &amp;lt;Wrapper
      breakpointOne={breakpointOne}
      breakpointTwo={breakpointTwo}
      breakpointThree={breakpointThree}
      widthOne={widthOne}
      widthTwo={widthTwo}
      widthThree={widthThree}
    &amp;gt;
      {children}
    &amp;lt;/Wrapper&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will allow us to change the width of the column based on specific breakpoints.&lt;/p&gt;

&lt;p&gt;Inside our &lt;code&gt;Wrapper&lt;/code&gt; styled-component, let's add media queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Wrapper = styled.div`
  flex: 1 1 0;
  width: 100%;
  padding: 8px;

  // ACTIVE BETWEEN BREAKPOINT ONE AND TWO (OR 9999PX)
  @media(min-width: ${props =&amp;gt; props.breakpointOne}px) and
  (max-width: ${props =&amp;gt; props.breakpointTwo | 9999}px) {
    width: ${props =&amp;gt; props.widthOne !== 'auto'
      ? `${(props.widthOne / 12) * 100}%`
      : null};
    flex: ${(props) =&amp;gt; (props.widthOne !== 'auto' ? 'none !important' : null)};
  }

  // ACTIVE BETWEEN BREAKPOINT TWO AND THREE (OR 9999PX)
  @media(min-width: ${props =&amp;gt; props.breakpointTwo}px) and
  (max-width: ${props =&amp;gt; props.breakpointThree | 9999}px) {
    width: ${props =&amp;gt; props.widthTwo !== 'auto'
      ? `${(props.widthTwo / 12) * 100}%`
      : null};
    flex: ${(props) =&amp;gt; (props.widthTwo !== 'auto' ? 'none !important' : null)};
  }

  // ACTIVE BETWEEN BREAKPOINT THREE AND UP
  @media(min-width: ${props =&amp;gt; props.breakpointThree}px) {
    width: ${props =&amp;gt; props.widthThree !== 'auto'
      ? `${(props.widthThree / 12) * 100}%`
      : null};
    flex: ${(props) =&amp;gt; (props.widthThree !== 'auto' ? 'none !important' : null)};
  }
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok. That's a lot to look at.&lt;/p&gt;

&lt;p&gt;The first thing we make sure to do is add a &lt;code&gt;max-width&lt;/code&gt; to the media query. This is to make sure the &lt;code&gt;flex&lt;/code&gt; property does NOT get reset if the width value is 'auto'.&lt;/p&gt;

&lt;p&gt;The main thing we have to take note of is the function used to calculate the width of the column. Since we use a 12-column grid, we get this value by taking the width (a value from 1-12) and dividing it by 12. We multiply THAT number by 100 to get the percentage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;width: ${props =&amp;gt; props.widthThree !== 'auto' ? `${(props.widthThree / 12) * 100}%` : null};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We also add a ternary operator to make sure the width is still 100% if the column width is auto by setting the width value to null.&lt;/p&gt;

&lt;p&gt;Now, the final thing we need to do is pass the breakpoints from the &lt;code&gt;Row&lt;/code&gt; component to the &lt;code&gt;Column&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Inside of our &lt;code&gt;Row.js&lt;/code&gt; file, we'll update the return statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (
  {React.Children.toArray(children).map((item) =&amp;gt; {
    return (
      item &amp;amp;&amp;amp; (
        &amp;lt;Column
          breakpoints={breakpoints}
          {...item.props}
        &amp;gt;
          {item.props.children}
        &amp;lt;/Column&amp;gt;
      )
    );
  })}
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And viola! Now, we're able to use custom breakpoints and widths for our grid system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Row breakpoints={[576]}&amp;gt;   
 &amp;lt;Column widths={[4]} /&amp;gt;  
 &amp;lt;Column widths={[8]} /&amp;gt;  
 &amp;lt;Column widths={[3]} /&amp;gt;  
 &amp;lt;Column widths={[9]} /&amp;gt;  
 &amp;lt;Column widths={[7]} /&amp;gt;  
 &amp;lt;Column widths={[5]} /&amp;gt;  
&amp;lt;/Row&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So now, we have a fully-functioning React grid system. If you want even more functionality, like custom spacing, offsets, and more, check out &lt;a href="https://react-tiny-grid.netlify.app"&gt;React Tiny Grid&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find the full code for this grid system on &lt;a href="https://github.com/jarodpeachey/react-tiny-grid/tree/master/packages/core/src"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you liked this tutorial and found React Tiny Grid useful, I'd appreciate it if you could &lt;a href="https://www.buymeacoffee.com/jarodpeachey"&gt;buy me a coffee&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;If you've got any questions or improvements for the grid system, you can comment that down below.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>FaunaDB in 5 Minutes</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Tue, 19 May 2020 13:05:40 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/faunadb-in-5-minutes-42h5</link>
      <guid>https://forem.com/jarodpeachey/faunadb-in-5-minutes-42h5</guid>
      <description>&lt;p&gt;Originally posted on &lt;strong&gt;&lt;a href="https://fiveminutedev.com"&gt;Five Minute Developer&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The serverless ecosystem is growing more than ever before, and there are a lot of new tools built around it.  In this post, we'll be overviewing FaunaDB, a serverless database built for scalability and ease of use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Fauna?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fauna.com/"&gt;FaunaDB&lt;/a&gt; is a global cloud database created to integrate with the JAMstack and modern serverless architecture. According to their site, FaunaDB "transforms the traditional DBMS into a Data API that gives you all the capabilities of an old-guard database, without sacrificing flexibility, scale, and performance".&lt;/p&gt;

&lt;p&gt;That's a pretty cool sentence.&lt;/p&gt;

&lt;p&gt;FaunaDB also allows you to query your data how you want. It supports relational data, document-based data, and graph-based data. It's got a ton of cool features, which we'll list below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fauna + GraphQL
&lt;/h3&gt;

&lt;p&gt;FaunaDB recently added &lt;a href="https://docs.fauna.com/fauna/current/start/graphql"&gt;support for GraphQL&lt;/a&gt;, which allows you to create custom schemas and access your data using GraphQL. Fauna allows access to a GraphQL endpoint for each database you create, which allows for easy access to your data.&lt;/p&gt;

&lt;p&gt;It's great for integrating with SSGs like Gatsby and Hugo. It also integrates perfectly with Apollo.&lt;/p&gt;

&lt;h3&gt;
  
  
  FQL
&lt;/h3&gt;

&lt;p&gt;For more advanced functionality, Fauna also comes with the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/"&gt;Fauna Query Language&lt;/a&gt; (FQL). FQL is a function-based querying language, built for advanced data manipulation. FQL comes with at least 50 built-in functions that you can use depending on your needs.&lt;/p&gt;

&lt;p&gt;An FQL statement looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query(
  Create(
    Collection('posts'),
    {
      data: {
        title: "New Post",
        author: "Jarod Peachey",
        date: "10/08/2019"
      },
    },
  )
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Executing this FQL statement will create a new document in the &lt;code&gt;posts&lt;/code&gt; collection, which we can access through one of the many other FQL functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functions
&lt;/h3&gt;

&lt;p&gt;FaunaDB allows you to create reusable queries in FQL using &lt;code&gt;functions&lt;/code&gt;. This is useful for, well, repeating queries without writing more code.&lt;/p&gt;

&lt;p&gt;A function is defined like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateFunction({
  name: "create_post",
  body: Query(
    Lambda(
      "data",
      Create(
        Collection('posts'),
          {
            data: {
            title: Select("title", Var("data")),
            author: Select("author", Var("data")),
            date: Select("date", Var("data"))
          },
        },
      )
    )
  )
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first argument to the CreateFunction query is the name. For this example, we named it "create_post".&lt;/p&gt;

&lt;p&gt;The second argument is the query to run when the function is called. This is placed inside of a Lambda() function, which lets us access the data passed to the function call.&lt;/p&gt;

&lt;p&gt;To call this function, simply execute this query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call(Function("create_post"), {
  title: "New Post",
  author: "Jarod Peachey",
  date: "10/08/2019"
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Indexes
&lt;/h3&gt;

&lt;p&gt;Fauna also allows you to create &lt;code&gt;indexes&lt;/code&gt;, which let you retrieve data based on specific attributes, rather than the document &lt;code&gt;ref&lt;/code&gt; (or id). You can use &lt;a href="https://docs.fauna.com/fauna/current/api/fql/indexes"&gt;indexes&lt;/a&gt; to get a single post or multiple posts.&lt;/p&gt;

&lt;p&gt;For example, the simplest index gets all the documents in a single collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query(
  CreateIndex({
    name: "all_posts",
    source: Collection("posts")
  })
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This allows you to access all posts, via a call to the index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Match(Index('all_posts'))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;FaunaDB is growing in popularity, so there are plenty of examples to choose from, as well as Fauna's own &lt;a href="https://docs.fauna.com/fauna/current/index.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/build-a-100-serverless-rest-api-with-firebase-functions-faunadb/"&gt;Serverless REST API with Fauna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/instant-graphql-backend-using-faunadb/"&gt;GraphQL Backend with Security Using FaunaDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My personal favorite tutorial is &lt;a href="https://css-tricks.com/rethinking-twitter-as-a-serverless-app/"&gt;Rethinking Twitter as a Serverless App&lt;/a&gt; on &lt;a href="https://css-tricks.com"&gt;CSS Tricks&lt;/a&gt;. It was immensely helpful when I started using FaunaDB, and I highly recommend reading it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In my opinion, FaunaDB is one of the front-runners in the serverless world, and it's an amazing platform. I would definitely recommend using it for your next project requiring a database.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>react</category>
      <category>database</category>
    </item>
    <item>
      <title>Creating a Countdown using React Hooks</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Wed, 29 Apr 2020 16:32:30 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/creating-a-countdown-using-react-hooks-58k</link>
      <guid>https://forem.com/jarodpeachey/creating-a-countdown-using-react-hooks-58k</guid>
      <description>&lt;p&gt;React Hooks are an amazing way of managing state, context, refs and just about everything else in React. They're very versatile, and if you use them right, you can really power-up your website.&lt;/p&gt;

&lt;p&gt;In this tutorial, we're going to create a basic countdown using two hooks: &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Hooks
&lt;/h2&gt;

&lt;p&gt;The two hooks we're using are two of the most used React hooks. At least, I use them more than I do the others, so I'm assuming the same can be said about other developers.&lt;/p&gt;

&lt;p&gt;Maybe not.&lt;/p&gt;

&lt;p&gt;Anyway, here's what each of the hooks does:&lt;/p&gt;

&lt;h3&gt;
  
  
  The useState Hook
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useState&lt;/code&gt; hook is the equivalent to the &lt;code&gt;state&lt;/code&gt; object in React class-based components. It manages the state, and allows you to update that state object.&lt;/p&gt;

&lt;p&gt;The hook takes in two defenitions: the name of the state item, and the name of the function that updates that state item.&lt;/p&gt;

&lt;p&gt;The simplest implmentation of this hook is creating a single state object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [state, setState] = useState({});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, you can also create a seperate state item for everything you want&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [valueOne, setValueOne] = useState(1);
const [valueTwo, setValueTwo] = useState(2);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll be using both methods in our countdown component.&lt;/p&gt;

&lt;h3&gt;
  
  
  The useEffect Hook
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook is, in a way, the jack-of-all-trades hook in React. You can use it to update state if something happens, trigger a re-render based off of a state value, or any other number of things.&lt;/p&gt;

&lt;p&gt;The basic implementation of this hook is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    // Code in here
}, [])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook takes 2 parameters: the callback function and the value to watch.&lt;/p&gt;

&lt;p&gt;The second argument can be either an empty array, or a particular value. If it's an empty array, it runs the callback function once. If it's got a value in it, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    // Code in here
}, [value])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It will run whenever &lt;code&gt;value&lt;/code&gt; changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Countdown
&lt;/h2&gt;

&lt;p&gt;OK. Now that we've got a basic understanding of the hooks we'll be using, we can start creating the basic component layout.&lt;/p&gt;

&lt;p&gt;First, we'll create a new file called &lt;code&gt;countdown.js&lt;/code&gt;. Inside that file, we'll create the functional component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {useState, useEffect} = React;

const Countdown = () =&amp;gt; {
  const [countdownDate, setCountdownDate] = useState(new Date('12/25/2020').getTime());
  const [state, setState] = useState({
    days: 0,
    hours: 0,
    minutes: 0,
    seconds: 0,
  });

  useEffect(() =&amp;gt; {
    setInterval(() =&amp;gt; updateCountdown(), 1000);
  }, []);

  const updateCountdown = () =&amp;gt; {
    // TODO: Code to calculate how long between the countdown date and the current time
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div className='countdown-wrapper'&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;{state.days || '0'}&amp;lt;/div&amp;gt;
          &amp;lt;small className="time-text"&amp;gt;Days&amp;lt;/small&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;:&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;{state.hours || '00'}&amp;lt;/div&amp;gt;
          &amp;lt;small className="time-text"&amp;gt;Hours&amp;lt;/small&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;:&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;{state.minutes || '00'}&amp;lt;/div&amp;gt;
          &amp;lt;small className="time-text"&amp;gt;Minutes&amp;lt;/small&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;:&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className='time-section'&amp;gt;
          &amp;lt;div className='time'&amp;gt;{state.seconds || '00'}&amp;lt;/div&amp;gt;
          &amp;lt;small className="time-text"&amp;gt;Seconds&amp;lt;/small&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Countdown;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;OK. So what's going on here?&lt;/p&gt;

&lt;p&gt;The first thing we do inside our new component is create new state values using the &lt;code&gt;useState&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [countdownDate, setCountdownDate] = useState(new Date('12/25/2020').getTime());
const [state, setState] = useState({
  days: 0,
  hours: 0,
  minutes: 0,
  seconds: 0,
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first hook creates the countdown date, which I have set to Christmas.&lt;/p&gt;

&lt;p&gt;The second hook stores our data for the remaining days, hours, minutes and seconds until the countdown date (again, Christmas). These are each set to 0, and will be updated every second.&lt;/p&gt;

&lt;p&gt;Which brings us to the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  setInterval(() =&amp;gt; setNewTime(), 1000);
}, []);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Inside the callback function, we're setting up an interval that will run every second. Each time it runs, it calls our &lt;code&gt;updateCountdown&lt;/code&gt; function (which we haven't created yet. We'll get to that).&lt;/p&gt;

&lt;p&gt;The rest of the component is the "html" for the countdown. The main thing to note is where we access the state value for days, hours, minutes and seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className='time'&amp;gt;{state.hours || '00'}&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Updating the Countdown
&lt;/h2&gt;

&lt;p&gt;The final thing to do is add the logic that updates the countdown inside the &lt;code&gt;updateCountdown&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const updateCountdown = () =&amp;gt; {
  if (countdownDate) {
    // Get the current time
    const currentTime = new Date().getTime();

    // Get the time remaining until the countdown date
    const distanceToDate = countdownDate - currentTime;

    // Calculate days, hours, minutes and seconds remaining
    let days = Math.floor(distanceToDate / (1000 * 60 * 60 * 24));
    let hours = Math.floor(
      (distanceToDate % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
    );
    let minutes = Math.floor(
      (distanceToDate % (1000 * 60 * 60)) / (1000 * 60),
    );
    let seconds = Math.floor((distanceToDate % (1000 * 60)) / 1000);

    // For visual appeal, add a zero to each number that's only one digit
    const numbersToAddZeroTo = [1, 2, 3, 4, 5, 6, 7, 8, 9];

    if (numbersToAddZeroTo.includes(hours)) {
      hours = `0${hours}`;
    } else if (numbersToAddZeroTo.includes(minutes)) {
      minutes = `0${minutes}`;
    } else if (numbersToAddZeroTo.includes(seconds)) {
      seconds = `0${seconds}`;
    }

    // Set the state to each new time
    setState({ days: days, hours: hours, minutes, seconds });
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Basically, we're accessing the new time and subtracting that from the countdown date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Get the current time
    const currentTime = new Date().getTime();

    // Get the time remaining until the countdown date
    const distanceToDate = countdownDate - currentTime;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This gives us the time remaining, and we do some fancy math stuff to calculate the days and hours left.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fancy math stuff ---------------------------------------------------&lt;/em&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let days = Math.floor(distanceToDate / (1000 * 60 * 60 * 24));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After we calculate the days and such remaining, we set the state to equal the values we just calculated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setState({ days: days, hours: hours, minutes, seconds });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Every time we set the state, React triggers a re-render of the content that changed.&lt;/p&gt;

&lt;p&gt;Guess what that means?&lt;/p&gt;

&lt;p&gt;Yep! Our countdown now updates every 1 second and displays the new time remaining 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So that's how you use React Hooks to create a simple countdown component. You can find a working demo on &lt;a href="https://codepen.io/Jarodwp/pen/ExVmVOV"&gt;Codepen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you liked this article, you can check me out on &lt;a href="%5Bhttps://twitter.com/JarodPeachey%5D(https://twitter.com/JarodPeachey)"&gt;Twitter&lt;/a&gt;, or visit my &lt;a href="https://jarodpeachey.netlify.com"&gt;website&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;Thanks for reading! 👋&lt;/p&gt;

</description>
      <category>react</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Simple Slide-Out Mobile Menu with React Hooks</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Sun, 26 Apr 2020 12:15:00 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/simple-slide-out-mobile-menu-with-react-hooks-6b4</link>
      <guid>https://forem.com/jarodpeachey/simple-slide-out-mobile-menu-with-react-hooks-6b4</guid>
      <description>&lt;p&gt;If you're a front-end developer, I can almost guarantee that you've worked with a mobile menu at some point in your career. If you have, you know first-hand that, sometimes, crafting mobile menus can be a little difficult.&lt;/p&gt;

&lt;p&gt;Just this month, I was working on a website of mine, and I came across one of these issues. I wanted to create a mobile menu with a few simple requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It slides out from under the header&lt;/li&gt;
&lt;li&gt;That's it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Seriously, it's not like I wanted to add 18 different animations, transitions, and effects. I just wanted to make the menu slide out from underneath the header. Simple, right?&lt;/p&gt;

&lt;p&gt;Nope. &lt;/p&gt;

&lt;p&gt;As I found out, it wasn't as simple as setting the z-index of the menu to be less than that of the header. And trust me, I set the z-index to &lt;code&gt;999999&lt;/code&gt; just to see what would happen (spoiler: nothing).&lt;/p&gt;

&lt;p&gt;After browsing through Stackoverflow, Github, and other forums for way too long, I eventually found a solution. The solution made perfect sense after I found it, but I'm writing this post anyway so others can easily find it as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Structure
&lt;/h2&gt;

&lt;p&gt;For this tutorial, I'm using React with styled-components.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because that's what I built it with.&lt;/p&gt;

&lt;p&gt;Anyway, I'm going to go through this assuming you already have your app set up, with a header and all that good stuff.&lt;/p&gt;

&lt;p&gt;If you don't, go ahead and set up a basic React project.&lt;/p&gt;

&lt;p&gt;OK. If you don't already have one, create a &lt;code&gt;header.js&lt;/code&gt; file. I don't care where.&lt;/p&gt;

&lt;p&gt;To start, we're going to create a functional component and structure the header and mobile menu.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;header.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import  React, { useState } from  'react';

export const  Header = () =&amp;gt; {
  return (
    &amp;lt;Wrapper&amp;gt;
      &amp;lt;HeaderWrapper id='header'&amp;gt;
        &amp;lt;Container&amp;gt;
          &amp;lt;Title&amp;gt;Menu Demo&amp;lt;/Title&amp;gt;
          &amp;lt;MenuToggle&amp;gt;
            &amp;lt;RotateContainer&amp;gt;
              &amp;lt;span  /&amp;gt;
              &amp;lt;span  /&amp;gt;
              &amp;lt;span  /&amp;gt;
            &amp;lt;/RotateContainer&amp;gt;
          &amp;lt;/MenuToggle&amp;gt;
        &amp;lt;/Container&amp;gt;
      &amp;lt;/HeaderWrapper&amp;gt;
      &amp;lt;MenuWrapper&amp;gt;
        &amp;lt;Menu&amp;gt;
          &amp;lt;MenuItem href='/'&amp;gt;Home&amp;lt;/MenuItem&amp;gt;
          &amp;lt;MenuItem href='/'&amp;gt;About&amp;lt;/MenuItem&amp;gt;
          &amp;lt;MenuItem href='/'&amp;gt;Contact&amp;lt;/MenuItem&amp;gt;
        &amp;lt;/Menu&amp;gt;
      &amp;lt;/MenuWrapper&amp;gt;
    &amp;lt;/Wrapper&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we're using styled-components, each component is named accordingly.&lt;/p&gt;

&lt;p&gt;Oh, and remember when I said I spent forever messing with the &lt;code&gt;z-index&lt;/code&gt; of the menu, and it didn't work?&lt;/p&gt;

&lt;p&gt;That's because the mobile menu must be a &lt;em&gt;sibling&lt;/em&gt; of the header, &lt;strong&gt;not&lt;/strong&gt; a child. It doesn't work if it a child element.&lt;/p&gt;

&lt;p&gt;Anyways. After we have the basic structure, we need to style each item.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styling the menu
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Styling the Wrapper&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This isn't very exciting, to be honest. It's got three lines of CSS in it.&lt;/p&gt;

&lt;p&gt;But, still very important.&lt;/p&gt;

&lt;p&gt;Place this styled-component at the bottom of your &lt;code&gt;header.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  Wrapper = styled.div`
  * {
    box-sizing: border-box;
  }
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;box-sizing&lt;/code&gt; rule is needed to size elements with margin and padding properly. However, you most likely won't need this, as your root CSS file probably sets the same rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling the Header Wrapper&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The header wrapper is also optional. If you already have a header on your website (very important, you probably should), then you can keep your current styling.&lt;/p&gt;

&lt;p&gt;If not, add a new &lt;code&gt;HeaderWrapper&lt;/code&gt; styled-component to your file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  HeaderWrapper = styled.header`
  padding: 18px 0;
  color: white;
  position: fixed;
  background: tomato;
  left: 0;
  top: 0;
  right: 0;
  bottom: auto;
  z-index: 999;
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There's one specific line of CSS that is very important: &lt;code&gt;z-index: 999;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To display the header over the top of the menu, you need to make sure the header component has a z-index higher than the mobile menu.&lt;/p&gt;

&lt;p&gt;Moving on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling the Menu Toggle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I took a little detour on the mobile menu toggle and added some pleasing transitions, using &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;At the bottom of your file, add two new styled-components: one for the toggle, and one to handle the rotation of the toggle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  MenuToggle = styled.div`
  z-index: 9999;
  width: 30px;
  height: 30px;
  transform: rotate(0deg);
  transition: all 0.25s ease-in;
  cursor: pointer;
  margin-left: auto;
  span {
    display: block;
    position: absolute;
    height: 4px;
    width: 100%;
    background: white;
    border-radius: 9px;
    opacity: 1;
    left: 0;
    transform: rotate(0deg);
    transition: ${(props) =&amp;gt;
    props.open ? 'all 0.25s ease-in' : 'all 0.25s ease-out'};
  } 
  span:nth-child(1) {
    top: ${(props) =&amp;gt; (props.open ? 'calc(50% - 2px)' : '10%')};
    transform-origin: left center;
  }
  span:nth-child(2) {
    top: ${(props) =&amp;gt; (props.open ? 0 : 'calc(50% - 2px)')};
    left: ${(props) =&amp;gt; (props.open ? 'calc(50% - 2px)' : null)};
    width: ${(props) =&amp;gt; (props.open ? '4px' : null)};
    height: ${(props) =&amp;gt; (props.open ? '100%' : null)};
    transform-origin: left center;
  }
  span:nth-child(3) {
    top: calc(90% - 4px);
    transform-origin: left center;
    width: ${(props) =&amp;gt; (props.open ? 0 : null)};
    opacity: ${(props) =&amp;gt; (props.open ? 0 : 1)};
  }
`;

const  RotateContainer = styled.div`
  height: 100%;
  width: 100%;
  transition: ${(props) =&amp;gt; props.open ? 'all 0.25s ease-in-out' : 'all 0.25s ease-in-out'};
  transform: ${(props) =&amp;gt; (props.open ? 'rotate(-45deg)' : 'none')};
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To summarize that, we're adding three &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tags inside the &lt;code&gt;MenuToggle&lt;/code&gt; component. The &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tags are rotated depending on whether the menu is open or not.&lt;/p&gt;

&lt;p&gt;You may notice the variables inside the styled-components: &lt;code&gt;width: ${(props) =&amp;gt; (props.open ? 0 : null)};&lt;/code&gt; These are what decide whether or not to show the mobile menu, rotate the toggle, or apply other menu-related styling. We'll be adding that functionality later on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling the Menu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't worry, this is the last one, I promise.&lt;/p&gt;

&lt;p&gt;The menu styling also depends entirely on your preference, but, once again, there are some important lines of CSS that you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  MenuWrapper = styled.div`
  position: fixed;
  overflow: hidden;
  top: ${(props) =&amp;gt; (props.open ? '0' : '-100%')};
  left: 0;
  z-index: 0;
  margin-top: 66px;
  width: 100%;
  transition: ${(props) =&amp;gt;
  props.open ? 'all 0.25s ease-out' : 'all 0.6s ease-out'};
  box-shadow: 0px 4px 20px -5px #e8e8e8;
  padding: 12px;
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you have your own styling, simply add in these 5 lines (the very important ones):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;position: fixed;
overflow: hidden;
top: ${(props) =&amp;gt; (props.open ? '0' : '-100%')};
left: 0;
z-index: 0;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding the functionality
&lt;/h2&gt;

&lt;p&gt;Great! So far, we have nothing useful. We've got a menu that doesn't close, which is probably not the best thing for your website. Luckily, we're not done yet.&lt;/p&gt;

&lt;p&gt;To open and close the menu, we need to set an &lt;code&gt;open&lt;/code&gt; state that tells each component whether or not the menu is open.&lt;/p&gt;

&lt;p&gt;To do this, we're using the React &lt;code&gt;useState()&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;Inside your functional component, add the state, as well as a toggle function that will set the menu to open or closed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Header = () =&amp;gt; {
  const [open, setOpen] = useState(false);

  const  toggleMenu = () =&amp;gt; {
    setOpen(!open);
  };

  ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have our &lt;code&gt;open&lt;/code&gt; state, we need to call the &lt;code&gt;toggleMenu()&lt;/code&gt; function when we click on the menu toggle.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;&amp;lt;MenuToggle&amp;gt;&lt;/code&gt; component to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;MenuToggle onClick={toggleFunction} open={open}&amp;gt;
  &amp;lt;RotateContainer open={open}&amp;gt;
    &amp;lt;span  /&amp;gt;
    &amp;lt;span  /&amp;gt;
    &amp;lt;span  /&amp;gt;
  &amp;lt;/RotateContainer&amp;gt;
&amp;lt;/MenuToggle&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, when you click on the menu toggle, it should switch from a hamburger menu to an X. The menu doesn't show up yet, because we haven't hooked it up to the &lt;code&gt;open&lt;/code&gt; state yet.&lt;/p&gt;

&lt;p&gt;Let's do that now.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;&amp;lt;MenuWrapper&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Menu&amp;gt;&lt;/code&gt; components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;MenuWrapper open={open}&amp;gt;
  &amp;lt;Menu open={open}&amp;gt;
    &amp;lt;MenuItem href='/'&amp;gt;Home&amp;lt;/MenuItem&amp;gt;
    &amp;lt;MenuItem href='/'&amp;gt;About&amp;lt;/MenuItem&amp;gt;
    &amp;lt;MenuItem href='/'&amp;gt;Contact&amp;lt;/MenuItem&amp;gt;
  &amp;lt;/Menu&amp;gt;
&amp;lt;/MenuWrapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And OPEN SESAME! A mobile menu now appears when you click the hamburger menu 🎉 (guess what happens when you click the X)&lt;/p&gt;

&lt;p&gt;So, we now have a functioning mobile menu that slides out from underneath the header, as well as a menu toggle that looks pretty sweet!&lt;/p&gt;

&lt;p&gt;If you liked this article, please leave a like.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>javascript</category>
      <category>design</category>
    </item>
    <item>
      <title>Adding Comments to a Static Website</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Wed, 15 Apr 2020 18:55:05 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/adding-comments-to-a-static-website-4h8k</link>
      <guid>https://forem.com/jarodpeachey/adding-comments-to-a-static-website-4h8k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Static websites aren't static anymore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This has become pretty obvious with the rise of serverless architecture, the headless CMS and the JAMstack. Static websites are created by sourcing content from an API, and generating a static website using static site generator.&lt;/p&gt;

&lt;p&gt;However, the JAMstack method still has some drawbacks, specifically when dealing with &lt;em&gt;dynamic&lt;/em&gt; functionality. In today's day and age, it's very rare that a website not need some kind of dynamic aspect to it.&lt;/p&gt;

&lt;p&gt;One of the most popular dynamic aspects of a website is, without a doubt, comments. However, it's not as easy to add comments to a static site as it is a website with a traditional server.&lt;/p&gt;

&lt;p&gt;That's why I decided to develop a tool that could allow anyone to add comments to their static blog or website with as little hassle as possible.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://github.com/jarodpeachey/triangle-comments"&gt;Triangle Comments&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Triangle?
&lt;/h3&gt;

&lt;p&gt;Triangle Comments is a tool that provides drop-in commenting to be used on any static site, anywhere on that site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Triangle?
&lt;/h3&gt;

&lt;p&gt;I created Triangle not to be the first method to add comments on a static site but to offer more than other options. Triangle is unique in that it can be both static AND dynamic.&lt;/p&gt;

&lt;p&gt;What does that mean?&lt;/p&gt;

&lt;p&gt;Well, Triangle collects data from a Netlify form and sends the data to GraphQL. That data is used by the &lt;code&gt;Comments&lt;/code&gt; component offered by Triangle. Your static site generator then builds the HTML, and the comments will be included in that HTML.&lt;/p&gt;

&lt;p&gt;But what if someone adds a new comment, and you want it to show up right away?&lt;/p&gt;

&lt;p&gt;Triangle makes a call to the API where your comments are stored and gets the latest comments. The beautiful part is: this API call doesn't bog down your site at all. Because of the comments in the GraphQL server from your most recent build, the entire site (plus all but the new comments) shows up on page before the new comments are called.&lt;/p&gt;

&lt;p&gt;Once the new comments are retrieved, the &lt;code&gt;Comments&lt;/code&gt; component is updated to include the latest comment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let me know what you think!
&lt;/h3&gt;

&lt;p&gt;This is still in beta version, but I'd love for you to test it out, and see what you think! I'm constantly improving it and would love your feedback regarding improvements or features you'd like to see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.toCheck%20it%20out%20here!"&gt;https://github.com/jarodpeachey/triangle-comments&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>gatsby</category>
      <category>npm</category>
    </item>
    <item>
      <title>Your Dream Product</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Tue, 21 Jan 2020 00:54:46 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/your-dream-product-29m7</link>
      <guid>https://forem.com/jarodpeachey/your-dream-product-29m7</guid>
      <description>&lt;p&gt;Everyone loves a good shortcut, hack or automation in their lives. Whether it's coding, health, social or personal life, there's always room for another app to make something easier.&lt;/p&gt;

&lt;p&gt;So that's what I'm here to ask you about: an app that would make a specific aspect of your life so much better!&lt;/p&gt;

&lt;p&gt;What are some apps that would be awesome to have in your life, but aren't available right now? Doesn't matter if it seems impossible, just write them down in the comments!&lt;/p&gt;

&lt;p&gt;Thanks in advance for your reply!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Community of Developers</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Sat, 30 Nov 2019 13:46:24 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/community-of-developers-4n30</link>
      <guid>https://forem.com/jarodpeachey/community-of-developers-4n30</guid>
      <description>&lt;p&gt;Obviously, Dev.to is a community of programmers, developers and designers. It's truly an awesome place. I love the community posts, listings, discussions and more.&lt;/p&gt;

&lt;p&gt;That's why I always look for developer websites to discuss, learn and grow on. Recently, I found Webwide.io through - wait for it - Dev.to. It's an awesome forum site for developers and designers to  ask questions about problems, share articles, and just chat about life!&lt;/p&gt;

&lt;p&gt;(No, I am not affiliated with them. It's just an awesome site!)&lt;/p&gt;

&lt;p&gt;You can check it out down below!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webwide.io/?ref=1270"&gt;https://webwide.io/?ref=1270&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Convince me: Why should I use Python?</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Fri, 25 Oct 2019 12:25:38 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/convince-me-why-should-i-use-python-5bnh</link>
      <guid>https://forem.com/jarodpeachey/convince-me-why-should-i-use-python-5bnh</guid>
      <description>

</description>
    </item>
    <item>
      <title>Website Review From Fellow Developers</title>
      <dc:creator>Jarod Peachey</dc:creator>
      <pubDate>Wed, 23 Oct 2019 17:09:17 +0000</pubDate>
      <link>https://forem.com/jarodpeachey/website-review-community-project-5h3</link>
      <guid>https://forem.com/jarodpeachey/website-review-community-project-5h3</guid>
      <description>&lt;p&gt;Hey Dev.to community! It's awesome to join this community/website. I found it looking for a solution to an issue I was having, and sure enough, there was an answer!&lt;/p&gt;

&lt;p&gt;Anyways, I want to start something cool: a website/app review thread. &lt;/p&gt;

&lt;p&gt;If you have a personal project, company website, or other app/web app that you'd love to get feedback on, post it down in the comments! Tell us a little bit about your project, and what you would like feedback on!&lt;/p&gt;

&lt;p&gt;Once you've done that, go through the comments and find 1-2 other sites to review and give feedback on.&lt;/p&gt;

&lt;p&gt;Let's use our knowledge to help each other!&lt;/p&gt;

&lt;p&gt;I'll start us off: here's my portfolio site built using Gatsby and hosted on Netlify. I'd appreciate if you could tell me what you think of the design/user experience!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jarodpeachey.netlify.com"&gt;https://jarodpeachey.netlify.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's your turn!&lt;/p&gt;

</description>
      <category>design</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
