<?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[Tanner Wiltshire’s Blog]]></title><description><![CDATA[Tanner Wiltshire’s Blog]]></description><link>https://blog.tannerwiltshire.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 15:13:44 GMT</lastBuildDate><atom:link href="https://blog.tannerwiltshire.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Today I learned how flex-shrink can mess up your width]]></title><description><![CDATA[I've been working on a fantasy pool app using Next JS and Tailwind CSS. I needed an episode selector component, and I figured it would take me about two minutes to write one. I was mostly right, but it took me a whole bunch of troubleshooting to get ...]]></description><link>https://blog.tannerwiltshire.com/today-i-learned-how-flex-shrink-can-mess-up-your-width</link><guid isPermaLink="true">https://blog.tannerwiltshire.com/today-i-learned-how-flex-shrink-can-mess-up-your-width</guid><category><![CDATA[CSS]]></category><category><![CDATA[flexbox]]></category><dc:creator><![CDATA[Tanner Wiltshire]]></dc:creator><pubDate>Tue, 28 Dec 2021 23:56:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/SXihyA4oEJs/upload/v1640629367301/rgPcVQ-5m.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been working on a fantasy pool app using Next JS and Tailwind CSS. I needed an episode selector component, and I figured it would take me about two minutes to write one. I was mostly right, but it took me a whole bunch of troubleshooting to get to what I was looking for. Basically, I wanted a horizontal scrolling bar with a button for each episode like so:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640630057920/fL0nc-49S.png" alt="My vision for the episode selector component" /></p>
<p>So I wrote it out like so, with the following result:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> EpisodeSelector = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-full flex overflow-x-scroll py-2"</span>&gt;</span>
      {episodes.map((episode) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{episode}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-24 p-1 mr-4 last:mr-0"</span>
        &gt;</span>
          Episode {episode}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
  );
};
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640630191581/-pZYGOC59.png" alt="Actual result for the episode selector component" /></p>
<p>I added the border for troubleshooting purposes. I wanted the word Episode and the episode number on the same line, but for some reason they were separate. No matter what I did with the width of the divs they never changed. I knew it was something to do with flexbox because when I took it off the parent <code>div</code> the issue disappeared.</p>
<p>After over an hour of troubleshooting, I realized that you can set some properties on flex items to control their size. Not sure how this managed to become a gap in my knowledge, but there it was. </p>
<p>I played around with <code>flex-basis</code> hoping it would allow me to set the initial size and have them adhere to that. No change. <code>flex-grow</code> made no sense because the items seemed to be shrinking in width, not growing. Lo and behold, the <code>flex-shrink</code> property allows flex items to shrink as necessary! I tried setting <code>flex</code> to none; problem solved! With that fixed, the items adhered to the width that I specified, allowing the word episode and the corresponding number to sit on the same line like I wanted in the first place. </p>
<p>The best part: after all that, I decided on a different look for the episode selector anyway! Here’s to constantly finding more problems to solve to keep learning and eliminating knowledge gaps!</p>
]]></content:encoded></item><item><title><![CDATA[My Top 5 things of 2021]]></title><description><![CDATA[2021.
Though it wasn't always the easiest year, it definitely had some great highlights. Here's a list of some of the things that brought me joy this year.
5: Breville Cafe Roma Espresso Machine

Happiness is a latte with perfect micro foam. Admitted...]]></description><link>https://blog.tannerwiltshire.com/my-top-5-things-of-2021</link><guid isPermaLink="true">https://blog.tannerwiltshire.com/my-top-5-things-of-2021</guid><dc:creator><![CDATA[Tanner Wiltshire]]></dc:creator><pubDate>Tue, 21 Dec 2021 15:57:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/K5IS7QLSm7U/upload/v1640057129230/gxI2j5arP.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-2021">2021.</h1>
<p>Though it wasn't always the easiest year, it definitely had some great highlights. Here's a list of some of the things that brought me joy this year.</p>
<h2 id="heading-5-breville-cafe-roma-espresso-machine">5: Breville Cafe Roma Espresso Machine</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640094656965/sBS7Ec8JX.jpeg" alt="Brevile Cafe Roma brewing a double espresso" /></p>
<p>Happiness is a latte with perfect micro foam. Admittedly, this one might owe its spot on the list to a bit of recency bias given that we just got it the week of Black Friday. Both myself and my wife are ex-baristas, and we've always talked about having an espresso machine one day. This one was a great deal at Canadian Tire and we had a bunch of Canadian Tire money, so we treated ourselves. </p>
<p>It also unexpectedly saved me a bunch of money. It became too difficult to justify $7 for a latte at Starbucks when I know that I can make a better one for a third of the cost at home. A final bonus: Starbucks discontinued their eggnog latte this year, so I was able to make my own and enjoy them daily if I want.</p>
<h2 id="heading-4-magic-the-gathering-arena-on-mobile">4: Magic: The Gathering Arena on Mobile</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640095015043/M2EdU8Xqe.jpeg" alt="Magic: The Gathering Arena poster" /></p>
<p>This one is less about the game itself and more about what it was a catalyst for. I had one friend at work who played the game before Arena came out, but a free-to-play digital client for the game made it much easier and faster for others to learn. I now have a small community of friends who all play and discuss the game in person and in our Discord server. We have even begun organizing some in-person <a target="_blank" href="https://magic.wizards.com/en/game-info/gameplay/formats/booster-draft">booster drafts</a> when it is safe to do so. I look forward to how our small group grows and evolves.</p>
<p>The mobile launch of the game made it that much easier to play a quick game or get advice on a deck. It increased the frequency of conversations, which usually lead to conversations about things other than magic. In this way I've developed a handful of friendships I otherwise might not have.</p>
<h2 id="heading-3-my-tattoo">3: My Tattoo</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640097724785/Bdic4Qial.jpeg" alt="My tattoo: &quot;Despite the overwhelming odds tomorrow came&quot;" /></p>
<p>I've wanted a tattoo since I was fourteen. Due to the permanence of the consequences, I never wanted to rush the decision. Whenever I thought of something that I thought might make a good tattoo, I thought about whether I'd be okay with seeing it on my body at 80 years old. If I thought yes, then I'd sit on the idea for a year or so before revisiting it. If I still thought it would be okay at that point then I would consider it. </p>
<p>I had many ideas for tattoos over the years. This was the first one that, when I revisited it, I still thought it was a pretty good one. Since it was the first time that had happened, I sat on it for another year or so just to be sure. When it came back around, I was sure. </p>
<p>The lyric is from <a target="_blank" href="https://www.youtube.com/watch?v=L_veE_yBZ6M">"Tragedy + Time" by Rise Against</a>. It came out on their 2014 album "The Black Market", and every time I've heard it since then this lyric gives me chills. I suffer from Anxiety and Depression, and I find that the words are a reminder that no matter what happens or how bad anything gets, life goes on. </p>
<p>So it took quite a while (16 years), but I figure it made a pretty awesome 30th birthday present.</p>
<h2 id="heading-2-covid-19-vaccines">2: COVID-19 Vaccines</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640099285187/5wX-vW9Ez.jpeg" alt="Gloved hands filling vaccine syringe" /></p>
<p>Okay, okay, the vaccine itself didn't bring me any joy. It actually brought me uncontrollable shivers all night after my second dose to the point that I didn't go to work the next day because my entire body was aching.</p>
<p>What it did bring me was the opportunity to see my friends and family again in person. Being able to go hang out with friends and have a couple beers in the pool did wonders for my mental health. I was able to go to my sister's wedding (not what they dreamed of, but at least they were able to have some people in attendance). We were finally able to have people over at our new house for dinner and to meet...</p>
<h2 id="heading-1-my-daughter-riley">1: My daughter Riley</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1640099401203/XsdZJZO-d.jpeg" alt="IMG_5408.jpeg" /></p>
<p>This kid is the single greatest achievement in my life, bar none. Her smile is my favourite thing in the world. It isn't always easy (it's usually hard), but somehow her smiles and laughter make everything worth it. I love watching her explore and learn. She loves watching everything and everyone. She hasn't started crawling yet, but I know once she gets moving we will have to keep a very close eye on her, since her curiosity knows no bounds. I can't wait to see what the next year brings for her!</p>
]]></content:encoded></item><item><title><![CDATA[Today I learned what getStaticProps and getServerSideProps do]]></title><description><![CDATA[I've been using React for a couple years, and Next.js for a little over a year though for much more straightforward projects.
I'm used to using the useState and useEffect hooks in React. Normally, I'd set my state variables in a side effect, and then...]]></description><link>https://blog.tannerwiltshire.com/today-i-learned-what-getstaticprops-and-getserversideprops-do</link><guid isPermaLink="true">https://blog.tannerwiltshire.com/today-i-learned-what-getstaticprops-and-getserversideprops-do</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[problem solving skills]]></category><dc:creator><![CDATA[Tanner Wiltshire]]></dc:creator><pubDate>Wed, 15 Dec 2021 03:17:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/qDY9ahp0Mto/upload/v1639538444121/vUzvCOHh3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been using React for a couple years, and Next.js for a little over a year though for much more straightforward projects.</p>
<p>I'm used to using the <code>useState</code> and <code>useEffect</code> hooks in React. Normally, I'd set my state variables in a side effect, and then use render the page using information from the state variables. So imagine my frustration when I was trying to do the same thing in Next only to get constant errors about my state variables being undefined!</p>
<p>I was trying to display a table using data from a json file. I initially supplied that data to a state variable:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { survivors <span class="hljs-keyword">as</span> survivorsList } <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/survivors'</span>;
<span class="hljs-keyword">import</span> { players <span class="hljs-keyword">as</span> playersList } <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/players'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ playersList, survivorsList }</span>) </span>{
  <span class="hljs-keyword">const</span> [players, setPlayers] = useState([]);
  <span class="hljs-keyword">const</span> [survivors, setSurvivors] = useState([]);

  <span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
    setPlayers(playersList);
    setSurvivors(survivorsList);
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    getData();
  }, [playersList, survivorsList]);
</code></pre>
<p>Then I created the table rows by looping over the players array and using the appropriate data. I was rewarded with <code>TypeError: can't access property "map", players is undefined</code>.</p>
<p>What was happening without my understanding was that Next was pre-rendering the page. On the initial render my state variables were indeed undefined, and after the render my side effect fired and populated them with the data. The problem is that when the page relies on some of that data to render the pre-render that Next was doing fails, providing the error message that my variable was undefined.</p>
<p>A quick google search into why Next was rendering before my side effect led me to the page of the Next.js docs about Pages and Pre-rendering. What I learned was that unlike React which runs the <code>useEffect</code> before rendering, Next generates HTML for each page in advance for performance and SEO reasons. In order to pre-render a page that relies on some data, you have to pass the data to the page as props.</p>
<p>You do this using one of two functions: <code>getStaticProps</code> or <code>getServerSideProps</code>.</p>
<p><code>getStaticProps</code> is used for static generation. Next generates the HTML once at build time, and this HTML is supplied for every request. <code>getServerSideProps</code> is used for server-side rendering. Here, Next generates HTML on each request. This is useful if the page shows frequently updated data.</p>
<p>After playing around with the functions I managed to get my page to render using the supplied data, using <code>getStaticProps</code>. Now I know when I eventually start using data that I'll have to fetch from a server, I'll have to change it to <code>getServerSideProps</code> in order to pre-render the page with the current data.</p>
]]></content:encoded></item><item><title><![CDATA[I solved a complicated problem (or How to make a multicolor mana selector)]]></title><description><![CDATA[I’ve been working on a companion app for a trading card game called Magic: The Gathering, or MTG for short (check it out if you want). In the game, two or more players spend resources called mana to cast spells trying to reduce their opponents’ life ...]]></description><link>https://blog.tannerwiltshire.com/i-solved-a-complicated-problem-or-how-to-make-a-multicolor-mana-selector</link><guid isPermaLink="true">https://blog.tannerwiltshire.com/i-solved-a-complicated-problem-or-how-to-make-a-multicolor-mana-selector</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[problem solving skills]]></category><dc:creator><![CDATA[Tanner Wiltshire]]></dc:creator><pubDate>Tue, 07 Dec 2021 22:28:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/4Ennrbj1svk/upload/v1638916079844/fqiNzomcq.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’ve been working on a companion app for a trading card game called Magic: The Gathering, or MTG for short (<a target="_blank" href="http://mtgasniffer.tannerwiltshire.com">check it out</a> if you want). In the game, two or more players spend resources called mana to cast spells trying to reduce their opponents’ life total from 20 to 0. The app displays possibilities for cards an opponent could play, based on an amount of mana entered by the user. To understand the problem, we’ll start with some context.</p>
<p>There are 5 colors of mana, each represented in shorthand by a single letter: white (W), blue (U), black (B), red (R), and green (G). There is also a sixth type of mana called colorless (or C), though it doesn’t come up very commonly. Cards that can produce mana are called mana sources, and can typically produce one mana of one or more colors per turn cycle (from the start of a player’s turn until the start of their next turn).</p>
<p>Most spells can only be played during the “Main Phase” of your turn, but some can be played at any time during any player’s turn. These spells are referred to as being “instant speed”, and they are the spells we are interested in for this app.</p>
<p>Each spell has a mana cost, which indicates how much and what colors of mana are required to cast it. Generic mana costs are the most common. They are simply represented by a number, and can be paid with any of the 5 colors of mana, or colorless. The colored mana is denoted by mana symbols on cards, and by the letters listed above wrapped in curly braces for text. For example, a cost of 1{R} requires 2 total mana, one of which must be red, and a cost of 3{U}{B} requires 5 total mana, one of which must be blue, and one which must be black.</p>
<p>The app allows the user to enter mana of any one of the 5 colors, or of any color (the gold symbol shown below), or colorless. The mana filter is created by looping over a state object, returning a <code>ManaButton</code> component for each color.</p>
<pre><code class="lang-javascript">mana: {
  <span class="hljs-attr">W</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">U</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">B</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">R</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">G</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">M</span>: <span class="hljs-number">0</span>, <span class="hljs-comment">// M represents sources that produce any color of mana</span>
  <span class="hljs-attr">C</span>: <span class="hljs-number">0</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638909440661/9Gk67Qh3d.png" alt="Standard mana selection menu." /></p>
<p><br /></p>
<p>When the user adds any amount of mana, the app goes through the selected set of cards, comparing the cards required amounts of each color of mana with the available amounts entered by the user. If the required amount of each color of mana is available and the total cost of the card is less than or equal to the total available mana, then the card is added to the list of cards to be displayed.</p>
<p>This covers most situations you’d come across. However, what if your opponent has a land that can produce both blue and black mana? This was the challenge I was faced with: add a way for the user to create a new mana source button with colors that they select, and have the app display cards appropriately.</p>
<p>This problem can be broken into three parts:</p>
<ol>
<li>Select colors and create a new mana source button.</li>
<li>Allow custom multicolor mana sources to be used for any of their defined colors.</li>
<li>Allow custom multicolor mana sources to be used only as many times as the user indicates are available (ie. a source that creates blue or black should only count for 1 mana and not 2).</li>
</ol>
<h3 id="heading-select-colors-and-create-a-new-mana-source-button">Select colors and create a new mana source button</h3>
<p>The easiest part of this problem was the UI. I knew I wanted to have some kind of circular menu that presented the 5 colors where the user could select 2-4 colors, and then confirm or cancel.</p>
<p>I looked at a few different open source libraries for creating circular menus, and I landed on <a target="_blank" href="https://github.com/innFactory/react-planet">react-planet</a> as it was more flexible and visually pretty much what I wanted.</p>
<p>I created a state object within my multicolorMenu component called colors, and listed the 5 main colors that I'd need to make buttons for.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [colors, setColors] = useState({
  <span class="hljs-attr">W</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'W'</span>, <span class="hljs-attr">symbol</span>: W, <span class="hljs-attr">selected</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">sortOrder</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">U</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'U'</span>, <span class="hljs-attr">symbol</span>: U, <span class="hljs-attr">selected</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">sortOrder</span>: <span class="hljs-number">2</span> },
  <span class="hljs-attr">B</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'B'</span>, <span class="hljs-attr">symbol</span>: B, <span class="hljs-attr">selected</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">sortOrder</span>: <span class="hljs-number">3</span> },
  <span class="hljs-attr">R</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'R'</span>, <span class="hljs-attr">symbol</span>: R, <span class="hljs-attr">selected</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">sortOrder</span>: <span class="hljs-number">4</span> },
  <span class="hljs-attr">G</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'G'</span>, <span class="hljs-attr">symbol</span>: G, <span class="hljs-attr">selected</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">sortOrder</span>: <span class="hljs-number">5</span> },
});
</code></pre>
<p>Using Object.entries(), I mapped over the colors object and created buttons for each one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638909337390/SCytcROfc6.png" alt="Multicolor mana selection menu" /></p>
<p>A few things happen when one of the buttons is clicked. First, the selected value for that color is changed to true so that I can conditionally display a checkmark over the button indicating that it's selected. Second, the color object is added to a <code>colorsForNewManaSource</code> array in state, and then the array is sorted by each object's <code>sortOrder</code> value. This is important later on.</p>
<p>Once the user has selected between 2 and 4 colors, the menu's close button switches to a confirm button with a checkmark. The menu won't allow a user to confirm with a single color or all 5 colors selected because they are already available in the standard mana filter. When the user confirms the selections, the <code>value</code> of each object in the <code>colorsForNewManaSource</code> array are joined together into a single string. Remember how the color objects were sorted by their <code>sortOrder</code> properties? This is important because it creates consistency in the naming convention, so when we pass the name to the ManaButton component, it can find the symbol svg with the same name exported from the symbols.js file. The name is then used to create a new source in the app's main mana state.</p>
<pre><code class="lang-js">mana: {
  <span class="hljs-attr">W</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">U</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">B</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">R</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">G</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">M</span>: <span class="hljs-number">0</span>, <span class="hljs-comment">// M represents sources that produce any color of mana</span>
  <span class="hljs-attr">C</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">WU</span>: <span class="hljs-number">0</span>
}
</code></pre>
<p>Here's the final result, with the app rendering after the change to the mana state:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638909261699/iWszJn7OF.gif" alt="Animated image depicting the use of the multicolor mana selection menu to create a new mana button." /></p>
<h3 id="heading-allow-custom-multicolor-mana-sources-to-be-used-for-any-of-their-defined-colors">Allow custom multicolor mana sources to be used for any of their defined colors</h3>
<p>Now that the user can create a button for a new multicolor mana source, I needed to make it do something. To start, I needed the new mana source to be able to allow cards of any of its colors to be displayed, so I needed to figure out how to identify what the colors are in the first place.</p>
<p>For my first pass at this, I tried to use the name of the color (the string value we created when confirming the source) by just using the string <code>split()</code> method. In the interest of not repeating my code, I needed to use the same method that I did for the rest of the mana sources. However, this method fails when it reaches the any color mana (M), since it is represented by a single letter.</p>
<p>I decided to refactor the mana state. Instead of the value for each property being simply a number representing the available amount of that color, I changed it to an object so that I could add an array of colors that it could produce.</p>
<pre><code class="lang-js">mana: {
      <span class="hljs-attr">W</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'W'</span>] },
      <span class="hljs-attr">U</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'U'</span>] },
      <span class="hljs-attr">B</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'B'</span>] },
      <span class="hljs-attr">R</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'R'</span>] },
      <span class="hljs-attr">G</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'G'</span>] },
      <span class="hljs-attr">M</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'W'</span>, <span class="hljs-string">'U'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'R'</span>, <span class="hljs-string">'G'</span>] },
      <span class="hljs-attr">C</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [] },
    }
</code></pre>
<p>Now when a new source is created, the colors value for that object is created by using the <code>split()</code> method on the source's name. So the new source added to the mana state looks like this:</p>
<pre><code class="lang-js">WU: { <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">colors</span>: [<span class="hljs-string">'W'</span>, <span class="hljs-string">'U'</span>]},
</code></pre>
<p>This required a change to the function that compares casting cost to available mana. Before, I was able to loop over the mana and directly compare each source to the required color since it was just a numerical value. Now I had to check for each source if it produced the current color it was checking for, and only compare the available amount if it did produce that color.</p>
<h3 id="heading-allow-a-multicolor-source-to-be-used-only-as-many-times-as-are-available-as-indicated-by-the-user">Allow a multicolor source to be used only as many times as are available as indicated by the user</h3>
<p>I ran into an issue where multicolor sources were allowing cards that cost more mana than was available through the filter. For example, I had 1 mana from a source providing blue or red, and a card costing 1 blue <em>and</em> 1 red was being displayed. After a lot of troubleshooting, including learning a lot about how to use the debugger in the browser, I discovered the issue. When the function checked for the availability of multiple colors, it did not indicate if a source had already been used, so it was using the full available mana for each color of a card. So using the above example, when the function checked if there was 1 blue mana, it found that there was. Then when it moved on to red, it found that there was also 1 red mana available, because there was no indication that it had already been used to provide the required blue mana.</p>
<p>So I needed a solution. I also wanted to prioritize using sources that produced fewer colors since they are less flexible. If I had 1 blue from an only blue source and 1 blue/red mana, and the same card costing 1 blue and 1 red, I didn't want to inadvertantly use up the blue/red mana on the required blue mana and have an extra blue mana and no red mana available.</p>
<p>I solved both issues at once. I made a temporary copy of the current mana state as an array that I could manipulate throughout the checking of an individual card without affecting the actual mana. Next, the array was by the number of colors each source could produce. In this way, the order was guaranteed to be the same every time, and I'd avoid any issues using the mana inefficiently.</p>
<p>Time to change the compare function one more time. Now I loop over each color of required mana, and for each required color loop over the mana state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (currentColor <span class="hljs-keyword">in</span> requiredMana) {
  mana.forEach(<span class="hljs-function">(<span class="hljs-params">source</span>) =&gt;</span> {
    <span class="hljs-comment">// End the loop if the source has no mana available, or if the required color has been fulfilled.</span>
    <span class="hljs-keyword">if</span> (source.value === <span class="hljs-number">0</span> || requiredMana[currentColor] === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">if</span> (source.colors.includes(currentColor)) {
      <span class="hljs-comment">/*  If there is more mana available than required for the current color,
       subtract the required amount from the mana source. Otherwise, subtract the
       available mana from the required amount. */</span>
      <span class="hljs-keyword">if</span> (source.value &gt;= requiredMana[currentColor]) {
        source.value -= requiredMana[currentColor];
        <span class="hljs-keyword">if</span> (source.value &lt; <span class="hljs-number">0</span>) {
          source.value = <span class="hljs-number">0</span>;
        }
        color[<span class="hljs-number">1</span>] = <span class="hljs-number">0</span>;
      } <span class="hljs-keyword">else</span> {
        requiredMana[currentColor] -= source.value;
        <span class="hljs-keyword">if</span> (requiredMana[currentColor] &lt; <span class="hljs-number">0</span>) {
          requiredMana[currentColor] = <span class="hljs-number">0</span>;
        }
        requiredMana[currentColor] = <span class="hljs-number">0</span>;
      }
    }
  });
}
</code></pre>
<p>Now I have a menu that allows the user to create their own multicolor mana buttons. The buttons can be used the same as the standard ones, and properly display any cards that match the colors and amount of mana provided by those sources. It's probably not the most efficient solution, though I'll probably never consider this project done. I'll probably come back to it and improve it along my journey, but for where I'm at in my career right now, I'm happy with the fact that it works</p>
]]></content:encoded></item><item><title><![CDATA[How a calculator taught me that I can be a developer]]></title><description><![CDATA[I decided to go into software development about 3 months ago.
At the time, I wasn’t sure where to begin. I had some basic knowledge of HTML and CSS from a course I had taken a few years previous, but there are so many programming languages out there....]]></description><link>https://blog.tannerwiltshire.com/how-a-calculator-taught-me-that-i-can-be-a-developer</link><guid isPermaLink="true">https://blog.tannerwiltshire.com/how-a-calculator-taught-me-that-i-can-be-a-developer</guid><category><![CDATA[Web Development]]></category><category><![CDATA[learn coding]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Tanner Wiltshire]]></dc:creator><pubDate>Thu, 16 Apr 2020 19:48:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/dC6Pb2JdAqs/upload/v1638909722763/FUHpzrulG.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I decided to go into software development about 3 months ago.</p>
<p>At the time, I wasn’t sure where to begin. I had some basic knowledge of HTML and CSS from a course I had taken a few years previous, but there are so many programming languages out there. As a beginner with no frame of reference, how are you supposed to know what to choose?</p>
<p>Fortunately I have a friend who works in the industry, Quinn, who has been very generous with answering my non-stop questions. He was able to inform me about what technologies were relevant and suggested I start with JavaScript. He pointed me in the direction of Wes Bos, recommending his Beginner JavaScript course.</p>
<p>Being where I am in my life (full time job, bills to pay, saving for a house, you get the picture), I didn’t really have the extra money laying around for that course. I worked through a couple free courses to learn the basics. Once I had a basic understanding of JavaScript syntax and concepts, I enrolled for JavaScript 30, a free course in which Wes helps you build 30 things with JavaScript.</p>
<p>From the first video, I was lost. What’s a document element? What is an event listener? Most of the resources I found didn’t explain what I’ve now come to know as the DOM (though there were occasional mentions of it).</p>
<p>Stumbling through the first two videos, I saw a few CSS properties I had never heard of, including among others CSS Grid and Flexbox. Conveniently, Wes also has a free CSS Grid course, so I put JavaScript on pause to learn something a little more fundamental.</p>
<p>I decided to try something more personal with the new skills, and so I built and published my first website, www.tannerwiltshire.com. It’s nothing fancy, but I did it’s mine and therefore I’m proud of it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638909777124/l4-vszbVs.png" alt="First version of www.tannerwiltshire.com" /></p>
<p>Feeling a little better about my foundations, I started working through the freeCodeCamp JavaScript course. There were many times that I felt like giving up. The main issue I had was feeling like I was learning lots of JavaScript, but not how to apply it. I could use the console to work with functions and arrays no problem, but I had no idea how to use JavaScript to make a webpage interactive. So, even with (still) no knowledge of what the DOM was (or that it existed), I went back to JavaScript 30.</p>
<p>I followed along a little easier this time. After another 10 videos or so, I began to understand a couple of pieces of how to interact with elements and styles of the document. Then, in one video, Wes broke things down in a way that stuck with me.</p>
<p>He said, “First, we’re going to get our elements, then we are going to build our functions. Then we are going to hook up the event listeners”.</p>
<p>That was a game changer. It eliminated the “I have no idea where to even start” piece that was plaguing me whenever I looked at any beginner projects.</p>
<p>So I challenged myself to build a calculator from scratch, without using a tutorial or any outside help. I thought, I know how a calculator works, I should be able to knock this out in one day.</p>
<p>It was a lot harder than I thought. It ended up taking me twice as long as I expected. Even now, days later, I’m still finding mistakes in it.</p>
<p>But I learned a lot through the process!</p>
<p>Any time I had some piece of code that wasn’t working, I just commented it out and tried again a different way. I still have all the comments in there, and I can see about 3 or 4 different ways that I tried to approach aspects of the project.</p>
<p>I’ve always been generally good at finding things through google searches. Here, I learned how to be more specific about what I was looking for and follow trails from one search result to another to piece together answers to my questions.</p>
<p>I learned so many new methods for the DOM, strings, arrays, and numbers. It’s one thing to go through a course where they tell you about a method and even have examples for you to play with to test your understanding. However, when it’s the answer that you’ve found to an actual problem you’re working on, the understanding occurs on a deeper level.</p>
<p>I know the code isn’t perfect. I’ll probably come back to it in a year and think “Jeez, what was I thinking?” But I did achieve my goal of programming a calculator, even if it isn’t done the best way.</p>
<p>I’ve heard that the first thing to do when you’re planning to get into developing is to start thinking of yourself as a developer. Imposter syndrome is a real thing, and when all I’d done is some free online courses it was all too easy to think myself a fraud.</p>
<p>My top 3 takeaways from this experience:</p>
<p>It’s okay to not know the answer. A lot of the time you won’t.</p>
<p>Failure is good. If you’re not failing, you’re not really learning much.</p>
<p>Break things down into bite sized pieces (Okay, I knew this one already, I just wasn’t taking small enough bites).</p>
<p>I still don’t know everything about the DOM or how to manipulate it, but I now know that it’s a gap in my knowledge, and I can get to work on filling it. I’ve proven to myself that I can be a developer, and I know how I’m going to get there: one step at a time.</p>
]]></content:encoded></item></channel></rss>