<?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[Cameron Thompson]]></title><description><![CDATA[Cameron Thompson]]></description><link>https://blog.cameronthompson.io</link><generator>RSS for Node</generator><lastBuildDate>Wed, 13 May 2026 15:22:23 GMT</lastBuildDate><atom:link href="https://blog.cameronthompson.io/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Filament Hero : Update]]></title><description><![CDATA[Hello everyone! 👋🏻
I just wanted to give an update on Filament Hero and the progress made due to Hacktoberfest! 
At the beginning of the month, I posted an article outlining a couple of my repos that will be participating in Hacktoberfest. This led...]]></description><link>https://blog.cameronthompson.io/filament-hero-update</link><guid isPermaLink="true">https://blog.cameronthompson.io/filament-hero-update</guid><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Tailwind CSS]]></category><dc:creator><![CDATA[Cameron Thompson]]></dc:creator><pubDate>Thu, 28 Oct 2021 17:16:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635441277951/MNbTFMhd1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone! 👋🏻</p>
<p>I just wanted to give an update on Filament Hero and the progress made due to Hacktoberfest! </p>
<p>At the beginning of the month, I posted an <a target="_blank" href="https://dev.to/cdthomp1/my-hacktoberfest-repos-2121">article</a> outlining a couple of my repos that will be participating in Hacktoberfest. This led to some great contributions to Filament Hero during the month! </p>
<h2 id="what-progressed">What Progressed?</h2>
<h3 id="new-design">New Design 📐</h3>
<p>When I was getting ready for Hacktoberfest, I decided to dedicate some time to polish the design for Filament Hero, mainly on the "backend". I worked out exactly what I wanted the application to do as well as what type of data models to create. </p>
<h4 id="new-models">New Models 📝</h4>
<p>I looked at my existing models and realized I can achieve a lot more if I added a few more properties. Updating and adding these new models will allow Filament Hero to be a better application to those who use it by keep track of more data as well as more metrics as well.</p>
<h4 id="new-crud-methods">New CRUD Methods 🚀</h4>
<p>With the new models, I needed new CRUD methods to match them. While doing so, I realized that MongoDB may not be the best choice, which lead me to ask the community what a better DB would be. I am currently still researching and experimenting different DB and ORM providers and I will provide an update with my results. </p>
<h3 id="newer-look">Newer Look 🔥</h3>
<p>I also played around with a newer look and feel with Filament Hero. I updated the data table and added toast notifications when the users creates, updates, or deletes a printer, filament, print, ect. While working on the data table, I noticed that the table gets very wide, especially on small screens, that makes it difficult to view all the information. My question to you is, is there a better way to present the data to the user. For example, to display a list of cars in a fleet with their current status and maintenance data I would normally create a table with all the properties having their own column. Do you just have a side scrolling table on mobile screens? Omit data on small screens? Is there a design pattern I should learn?</p>
<p>That is all that has happened to Filament Hero this month. I am grateful to those who participated in getting Filament Hero further in its development! If you would like to follow along with the development, or want to participate, please checkout <a target="_blank" href="https://filamenthero.com">FilamentHero.com</a>! </p>
]]></content:encoded></item><item><title><![CDATA[My Hacktoberfest Repos]]></title><description><![CDATA[Hello everyone! 👋🏻
Hacktoberfest is here! I have a couple of repos that I am going to be working on during the month and welcome anyone to work on the project as well! 
MongoDb, Express, Node.js Template
Repo Link
This template is designed to help ...]]></description><link>https://blog.cameronthompson.io/my-hacktoberfest-repos</link><guid isPermaLink="true">https://blog.cameronthompson.io/my-hacktoberfest-repos</guid><category><![CDATA[#hacktoberfest ]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[development]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Cameron Thompson]]></dc:creator><pubDate>Sat, 02 Oct 2021 19:03:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633201293613/HCayzH-wU.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="hello-everyone">Hello everyone! 👋🏻</h2>
<p>Hacktoberfest is here! I have a couple of repos that I am going to be working on during the month and welcome anyone to work on the project as well! </p>
<h2 id="mongodb-express-nodejs-template">MongoDb, Express, Node.js Template</h2>
<p><a target="_blank" href="https://github.com/cdthomp1/mongo-express-node-template">Repo Link</a>
This template is designed to help kick start Node.js applications that use Express.js, MongoDB, and Passport.js. Currently the application is set up to use ejs as the view engine, but can be adapted to use React or any other frontend framework. </p>
<h3 id="my-goals">My Goals</h3>
<p>Here are my goals for this project that I want to work on during the month</p>
<ul>
<li>Make this an npm script to allow for easy installation (similar to <code>npx create-react-app</code>) </li>
<li>Have an option to template with React</li>
</ul>
<h2 id="filament-hero">Filament Hero</h2>
<p><a target="_blank" href="https://github.com/cdthomp1/filament-hero">Repo Link</a>
This is a new project of mine that helps those who use a 3d printer keep track of their filament usage as well as the parameters that made a print great or bad. </p>
<h3 id="my-goals">My Goals</h3>
<ul>
<li>Help users store their print settings, so they can keep track of them</li>
<li>Clean up the dashboard and how data is loaded, for speed</li>
</ul>
<p>If you have any interest in any of these projects, please fork and work on it, I welcome any PR to be reviewed 😃</p>
<p>Happy Hacking! 💻  </p>
]]></content:encoded></item><item><title><![CDATA[Making a Mini Wiki with the SpaceX Api and Next.js]]></title><description><![CDATA[Tl;Dr;
I made a Mini Wiki using the  SpaceX Api and I learned a lot! I used Next.js and Tailwind CSS to build the application that can be viewed  here. The repo for this project can be found  here 
Mini wikis are an awesome way to learn how to work w...]]></description><link>https://blog.cameronthompson.io/making-a-mini-wiki-with-the-spacex-api-and-nextjs</link><guid isPermaLink="true">https://blog.cameronthompson.io/making-a-mini-wiki-with-the-spacex-api-and-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[api]]></category><category><![CDATA[learning]]></category><category><![CDATA[Tailwind CSS]]></category><dc:creator><![CDATA[Cameron Thompson]]></dc:creator><pubDate>Tue, 10 Aug 2021 06:22:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628576020265/BUo-8mKmW.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tl;Dr;
I made a Mini Wiki using the  <a target="_blank" href="https://github.com/cdthomp1/spacex-mini-wiki">SpaceX Api</a> and I learned a lot! I used Next.js and Tailwind CSS to build the application that can be viewed  <a target="_blank" href="https://spacex-mini-wiki.vercel.app">here</a>. The repo for this project can be found  <a target="_blank" href="https://github.com/cdthomp1/spacex-mini-wiki">here</a> </p>
<p>Mini wikis are an awesome way to learn how to work with an Api. There are several free Api's out there that provide informational data. For example, I have seen a couple of mini wiki's being made out of the Harry Potter Api and the Rick and Morty Api. These are great projects if you are learning a new framework or library as you need to read, transform, and display data. Occasionally, you can add a way to take user input to search for data or update data (depending on the Api rules).</p>
<p><a target="_blank" href="https://spacex-mini-wiki.vercel.app">Live Site</a></p>
<p><a target="_blank" href="https://github.com/cdthomp1/spacex-mini-wiki">Repo</a> </p>
<h2 id="the-spacex-api">The SpaceX Api</h2>
<p>The  <a target="_blank" href="https://github.com/cdthomp1/spacex-mini-wiki">SpaceX Api</a> , is an unofficial open source REST Api for SpaceX launch, rocket, core, capsule, starlink, launchpad, and landing pad data. This Api is what I use on my  <a target="_blank" href="https://cameronthompson.io">site</a>  to show the latest and upcoming launch information. For this project, I am going to use this Api to explore the rocket, launches, astronauts,  and capsule information. </p>
<h2 id="getting-started">Getting Started</h2>
<h3 id="the-boiler-plate">The Boiler Plate</h3>
<p>Getting started was super easy, using the script to generate a starter Next.js project I was able to get up and running in no time! After the script completed running, I removed unneeded code and files. The api directory can be thrown out, as well as the <code>Home.module.css</code> file. I cleaned out the <code>styles.css</code> file as well removed the boiler plate code from <code>index.js</code></p>
<h3 id="creating-the-pages">Creating the pages</h3>
<p>I am going need four additional pages for this project. Since I wanted to highlight the rocket, launches, astronauts, and capsule information from the Api, I created a page for each of these.  Each of these pages functionally do the same thing, get the respective data from the Api and pass the data in as a prop to the <code>Card</code> component. </p>
<p>Here is the card component: </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'tailwindcss/tailwind.css'</span>

<span class="hljs-keyword">const</span> Card = <span class="hljs-function">(<span class="hljs-params">{<span class="hljs-built_in">document</span>}</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> {name, image, link} = <span class="hljs-built_in">document</span>
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-60 h-72 flex flex-col items-center justify-around mx-auto bg-white rounded-md filter drop-shadow-greenDrop my-5 p-4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-1"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"object-scale-down h-44"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mx-auto font-bold text-black"</span>&gt;</span>{name}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mx-auto w-28 h-14 flex items-center justify-center text-white font-bold bg-secondary rounded-md filter drop-shadow-blackDrop"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{link}</span>&gt;</span>Learn More<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Card
</code></pre>
<p>As long as the data being passed in has the properties of <code>name</code>, <code>image</code>, and <code>link</code>, the data will be shown on the card. </p>
<p>Here is the code for the Astronauts page:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Card'</span>
<span class="hljs-keyword">import</span> { getAstronauts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils/utils'</span>

<span class="hljs-keyword">const</span> astronauts = <span class="hljs-function">(<span class="hljs-params">{ astronauts }</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white xl:text-9xl md:text-9xl sm:text-9xl text-5xl p-5 font-barcode"</span>&gt;</span>SpaceX Astronauts<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-11/12 mx-auto flex flex-wrap gap-x-4"</span>&gt;</span>
                {astronauts.map((astronaut, index) =&gt; (<span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">document</span>=<span class="hljs-string">{astronaut}</span> /&gt;</span>))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
    )
}


<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{

    <span class="hljs-keyword">let</span> astronauts = <span class="hljs-keyword">await</span> getAstronauts();

    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">props</span>: {
            astronauts,
        },
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> astronauts
</code></pre>
<p>You will notice that Astronauts page uses a function from the <code>utils</code> file. We will go over that more in the  <a class="post-section-overview" href="#getting-data">Getting Data</a>  section of this article.</p>
<p>Each of the cards has a link to display more information about the rocket, astronaut, launch, ect. This is where I had to be subjective on the data I wanted to display as the Api has lots of data (please note, the astronaut endpoint is very small, so I used all of the data returned)!  </p>
<p>The pages to display launch data, rocket data, and dragon data are set up very similar to the astronaut page. The only difference is the data being displayed. The launch, rocket, and dragon endpoint have a lot of properties that are returned. I chose data that I thought was the most interesting and the most common. Of course you can render any of the properties as you see fit. </p>
<h3 id="getting-data">Getting Data</h3>
<p>Since I use a handful of endpoints of the SpaceX Api, I decided it would be best to have a set of functions that I can use throughout the application. I created a <code>utils</code> folder and file in the root directory.  I then filled it with the functions I needed to get the data. </p>
<p>Here is a function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLaunches</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> resLaunches = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.spacexdata.com/v4/launches'</span>)
    <span class="hljs-keyword">const</span> launchesData = <span class="hljs-keyword">await</span> resLaunches.json()
    <span class="hljs-keyword">if</span> (resLaunches.status !== <span class="hljs-number">200</span>) {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">message</span>: <span class="hljs-string">"Error Getting Launches"</span>
        }
    }
    <span class="hljs-keyword">let</span> launches = launchesData.map(<span class="hljs-function"><span class="hljs-params">launch</span> =&gt;</span> {
        <span class="hljs-keyword">let</span> img;
        <span class="hljs-keyword">if</span> (launch.links.patch.small === <span class="hljs-literal">null</span>) 
            img = <span class="hljs-string">"https://pbs.twimg.com/profile_images/1082744382585856001/rH_k3PtQ_400x400.jpg"</span>

        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">name</span>: launch.name,
          <span class="hljs-attr">image</span>: launch.links.patch.small || img,
          <span class="hljs-attr">link</span>: <span class="hljs-string">`/launch/<span class="hljs-subst">${launch.id}</span>`</span>
        }
      })

    <span class="hljs-keyword">return</span> launches
}
</code></pre>
<p>All of my functions follow a similar pattern to get the required data. This example function us handy as it checks to see if there is an image for the mission patch (as future missions are listed and not yet have a patch). I could remove those future missions, that would help solve this solution, but if a past mission patch is missing I would not have an image to show. </p>
<p>The endpoints that I call in the utils file return all of the data for that category. A future enhancement would be to store the responses in state so I don't have to make an additional Api call to get a single object (as far as I can tell, getting an object by Id returns the same properties as the objects returned on the "everything" endpoint).</p>
<h3 id="styling">Styling</h3>
<p>You can learn a lot from using an Api and presenting it on the page, but why not style your project so when you show others they can tolerate looking at it? I chose to use Tailwind CSS to style my project. I was nervous as it was the second project I have used with it but it turned out to be an awesome experience. Using Tailwind was fast, and simple to get the look I was going for. An additional plus was their documentation on how to extend some of their styles so I could add custom fonts, colors, and shadows.</p>
<h2 id="lessons-learned">Lessons Learned</h2>
<p>Here are the main lessons that I learned while working on this project</p>
<ul>
<li>The SpaceX Api is extensive and has lots of information</li>
<li>Tailwind CSS helps me develop applications faster </li>
<li>Next.js is powerful and has lots of awesome features </li>
</ul>
<h3 id="future-enhancements">Future Enhancements</h3>
<p>There are a few things I can improve on in this application</p>
<ul>
<li>Manage data through state, to limit the amount of api calls </li>
<li>Using Next image can help with larger images that need to load (especially on the launches page where there can be dozens of large images)</li>
<li>Look into using serverless functions to help limit the amount of work the client needs to do making api calls </li>
</ul>
<p>This was a great project to work on and I hope this helps you want to make your own Mini Wiki</p>
]]></content:encoded></item><item><title><![CDATA[Arduino Zoom Box]]></title><description><![CDATA[In January of this year (2021) I had been working remotely for about 9 months, with hundreds of Zoom meetings. Zoom is powerful, with the ability to have global shortcuts to mute/un-mute and to turn your camera on and off. But I am lazy, and pressing...]]></description><link>https://blog.cameronthompson.io/arduino-zoom-box</link><guid isPermaLink="true">https://blog.cameronthompson.io/arduino-zoom-box</guid><category><![CDATA[arduino]]></category><dc:creator><![CDATA[Cameron Thompson]]></dc:creator><pubDate>Sat, 31 Jul 2021 05:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627709333611/0MAdkF3XK.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In January of this year (2021) I had been working remotely for about 9 months, with hundreds of Zoom meetings. Zoom is powerful, with the ability to have global shortcuts to mute/un-mute and to turn your camera on and off. But I am lazy, and pressing the keyboard shortcut to do these actions was too much 😅 The Arduino Zoom Box was born.</p>
<h2 id="components">Components</h2>
<p>My Arduino Zoom Box contains the following:</p>
<p>Project Board</p>
<p>Arduino Pro Micro</p>
<p>A 7Seg Display</p>
<p>8 Tactile switch buttons</p>
<p>15 10k Ohms 1% resistors</p>
<p>Header pin sockets (optional but recommended)</p>
<h2 id="design">Design</h2>
<p>There were three main things I wanted my box to do; send a key combo based on a button press, have multiple folders for key shortcuts, display which folder I was on. Originally this was going to be inside an actually box, which is why you see the project board has been cut. Ultimately, I decided to take it out of the box and put it right on the desktop.</p>
<p>Here is my design:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4vgzyl56mrdpmiuztbr8.jpeg" alt="Project Design" />
You can see that each of the numbers on the buttons corresponds with a pin. I would have used a program like TinkerCad to create the design, but they don't have the Pro Micro board.</p>
<p>Here it is fully assembled:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yomcnjd49yd3ua7vhz3g.jpeg" alt="Fully Assembled" /></p>
<p>Here it is without the pro micro</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mcj5v4tmkjwewmcknj4y.jpeg" alt="Fully Assembled minus arduino" /></p>
<p>Here is the back</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0vsnidku1joh6u5b1nla.jpeg" alt="Back of the board" />
What a mess of wires! The light blue is Blue Tack that sticks to my angled Lego's under my monitor 😅 (A 3D printed version is coming!)</p>
<p>I have some plans to improve the placement listed in the "Future Plans" section of this article .</p>
<h2 id="the-code">The Code</h2>
<p>The code was relatively simple as I only needed to code the three things above. The display was super repetitive and could be reduced to one function (already noted in Future Plans). Assigning the buttons to the appropriate pins was also relative and easy (again a keyboard matrix would reduce the amount of pins). Coding the buttons to move folders was a little challenging as the button bounce would more than one folder at a time (a simple delay after the button press eliminated this).</p>
<p>The core of this code is the Keyboard library. Without the library, this project would have been very difficult to complete. This is a great library that gives me access to all the keys I need! I can also chain them to do complex things such as using the Spotlight feature on Mac. That can be seen in the example code linked below.</p>
<p>Here is the stripped down code that can be filled in (I did leave a section as an example):</p>
<p><a target="_blank" href="https://github.com/cdthomp1/zoom-box">Zoom Box Code</a></p>
<h2 id="future-plans">Future Plans</h2>
<p>I plan to enhance this project by designing and printing a "keyboard extension" that will attach to the left of my MX Keys keyboard, to bring the controls closer to my hands. I also plan on using a keyboard matrix to minimize the amount of pins taken up by the keyboard (this could allow for more keys). I have also looked at switching to cherry switches, for a more tactile feel.</p>
]]></content:encoded></item><item><title><![CDATA[Serverless Link Saving]]></title><description><![CDATA[Overview
This is an application to learn Netlify Functions, Netlify's version of Lambda Functions or serverless functions. This application helps a user save links while browsing the web. The most common use for this application is while browsing on ...]]></description><link>https://blog.cameronthompson.io/serverless-link-saving</link><guid isPermaLink="true">https://blog.cameronthompson.io/serverless-link-saving</guid><category><![CDATA[serverless]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Netlify]]></category><category><![CDATA[Apple]]></category><dc:creator><![CDATA[Cameron Thompson]]></dc:creator><pubDate>Fri, 04 Dec 2020 20:31:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607113856354/CCjHYMcQU.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>This is an application to learn Netlify Functions, Netlify's version of Lambda Functions or serverless functions. This application helps a user save links while browsing the web. The most common use for this application is while browsing on the go. Using Siri Shortcuts, I was able to add a custom option on the share sheet so that I can save the webpage to my own MongoDB instance. Then, those links that are stored are displayed on a website to be referenced at a later time, There is an option to mark a link as "read" as well as deleting links. Any links that is marked as 'read' is moved to the bottom of the list.</p>
<h2 id="background">Background</h2>
<p>I've noticed a problem where I would visit a webpage, deem it helpful and would want to come back to it later. I would open a new tab to continue browsing so I can save that webpage on the previous tab. After a short while, I would have dozens of open tabs on my mobile browser. I decided to work on this issue and solved it with serverless functions. I chose Netlify as the hosting platform and MongoDB as the database provider. I also created a Siri Shortcut to enhance this application. Future development on a Google Extension will soon take place to provide additional functionality.</p>
<p>The repo for this project can be found <a target="_blank" href="https://github.com/cdthomp1/link-saver-shortcut">here</a></p>
<h2 id="netlify-functions">Netlify Functions</h2>
<p>Netlify offers their own flavor of serverless functions called Netlify Functions. These alow users to develop applications without needing to maintain a server. Applications are also inherently scalable and faster for the end user. Please read Netlify's documentation on Netlify Functions: <a target="_blank" href="https://docs.netlify.com/functions/overview/">Netlify Docs (Functions)</a></p>
<h2 id="netlify-cli">Netlify CLI</h2>
<p>The easiest way to develop this application is to install the Netlify CLI. Follow their official documentation to get started: <a target="_blank" href="https://docs.netlify.com/cli/get-started/">Netlify Docs (Getting Started)</a></p>
<h2 id="environment-variables">Environment Variables</h2>
<p>Netlify offers the use of environment variables for your applications. To add environment variables to your netlify project, navigate to the settings area for your application called <code>Site settings</code>.</p>
<p>Then you will need to click on <code>Build &amp; deploy</code> on the menu on the left.</p>
<p>Scroll down until you reach the <code>Environment</code> section or you can <code>Environment</code> under <code>Build &amp; deploy</code> on the same menu.</p>
<p>You should see this screen:</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/netlify-setup-env-01.png" /></p>
<p>Click edit to add an environment variable</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/netlify-setup-env-02.png" /></p>
<p>We are going to add our environment variable for the MongoDB connection string. If you cloned this project, I called the MongoDB connection <code>MONGO_URI</code>, however you can call it whatever suits your needs. After you filled in the Key and Value fields, click save.</p>
<p>Please set this up before development! When you run <code>netlify dev</code> as we talked about earlier, the dev server will grab the environment variable for your application.</p>
<p>For more information on Netlify Functions, please visit the official docs: <a target="_blank" href="https://docs.netlify.com/configure-builds/environment-variables/">Netlify Docs (Environment Variables)</a></p>
<h2 id="siri-shortcuts-setup-optional">Siri Shortcuts Setup (optional)</h2>
<h3 id="building-the-shortcut">Building the Shortcut</h3>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-00.PNG" /><br />Open the Shortcuts application, download it from the app store if you need to. Click on the "+" in the top right corner to create a new Shortcut</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-01.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-02.PNG" /><br />On the next screen, click on the circle with the three dots, this will open up the details page where we can edit some important settings. We need to change the name to something semantic, but what you call it is up to you. We also want to enable the "Show in Share Sheet" option as well. We can leave the "Share Sheet Types" option with the default value of "Anything".</p>
<p>We can also choose our own Color and Glyph for our shortcut. Choose a combo that works for you. Lots of options! Once you are done, close the details drawer by clicking "done".</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-03.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-04.PNG" /><br />We are ready to create the shortcut! slide up on the drawer an select the "Web" action category. Scroll down until you find the "URLs" section, within that section, select "URL".</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-05.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-06.PNG" /><br />We now need to add our application url into the "URL" action. Click on "apple.com" to edit the URL.  </p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-07.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-08.PNG" /><br />Add your application URL. For example <code>https://super-cool-app-name.netlify.app/add?link=</code> As you are editing, you will see the "variables" section above the keyboard, scroll until you find the "Shortcut Input" variable. Click on the "Shortcut Input" variable on the action to set the type of input. We need to select the "URL" input type. </p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-09.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-10.PNG" /><br />We are now going to add an action to execute the URL action. Back to the "Web" action category, scroll down until you find the "Web Requests" method. Select the "Get Contents of URL" action. This should automatically fill the variable to be the "URL" action.</p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-11.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-12.PNG" /><br />We are technically done with the shortcut, so these next steps are optional, but are handy to have. We are going to add the "Show Notification" action to our shortcut. To find the "Show Notification", click on the "Scripting" action category. Scroll down to the "Notification" section and click on "Show Notification". </p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-13.PNG" /> <img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-14.PNG" /><br />We now need to edit the contents of our notification. Instead of "Hello World", we are going to add the return message from the API endpoint we hit, this will help us know if the server added the link, by returning back to us a message that says <code>{"message":"Link Added :)"}</code> or if we encountered an error.</p>
<p>To change the notification message, delete "Hello World" While you are deleting, you should see variables that can be inserted, select the "Contents of URL" variable. We then need to change the type of this variable. When the "Contents of URL" variable is selected, you should see a tray to change its type. Click on the blue "as File", brining up all the type options for this variable. scroll down until you find "URL" and select that type. </p>
<p><img src="https://raw.githubusercontent.com/cdthomp1/link-saver-shortcut/master/docs/images/shortcut-edit-15.PNG" /><br />We are now done with this shortcut! Give it try once you have deployed your application to Netlify. Happy Saving, Happy Reading! </p>

<h2 id="google-chrome-extension-future">Google Chrome Extension (Future)</h2>
]]></content:encoded></item></channel></rss>