<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>http://noahbuscher.com</id>
    <title>noahbuscher.com</title>
    <updated>2023-06-28T00:00:00.000Z</updated>
    <generator>Noahbot</generator>
    <author>
        <name>Noah Buscher</name>
        <email>me@noahbuscher.com</email>
        <uri>https://noahbuscher.com</uri>
    </author>
    <link rel="alternate" href="http://noahbuscher.com"/>
    <link rel="self" href="https://noahbuscher.com/feed.xml"/>
    <subtitle>Musings on software engineering, productivity, and life.</subtitle>
    <icon>http://noahbuscher.com/favicon.ico</icon>
    <rights>All rights reserved 2023, Noah Buscher</rights>
    <entry>
        <title type="html"><![CDATA[Radio Install in a Porsche Boxster]]></title>
        <id>987-headunit-install</id>
        <link href="https://noahbuscher.com/posts/987-headunit-install"/>
        <updated>2023-06-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Installing an aftermarket headunit in a Porsche 987.2 with the Sound Package Plus (SPP) option.]]></summary>
        <content type="html"><![CDATA[<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">The 987.2 Porsche Boxster is one of the best values in the used sports car market today. There is so much to love about the vehicle, but the OEM headunit is not one of them. It&#x27;s very dated, clunky, and doesn&#x27;t support CarPlay (!), so one of the first things I did after picking up my car was purchase and install a new headunit. I selected the Sony XAV-AX1000 headunit because:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">It&#x27;s one of the only aftermarket headunits with a physical volume knob</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">The matte black plastic finish very closely matches my Porsche&#x27;s interior</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">I didn&#x27;t need wireless CarPlay</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">It&#x27;s relatively cheap</li>
</ul>
<img alt="Sony XAV-AX1000 headunit installed" sizes="(max-width: 768px) 100vw,
    50vw" srcSet="/_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=384&amp;q=75 384w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit.jpeg&amp;w=3840&amp;q=75" width="0" height="0" decoding="async" data-nimg="1" class="w-full h-auto rounded-[8px]" loading="lazy" style="color:transparent"/>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">I also picked up <a rel="noreferrer" target="_blank" class="inline underline" href="https://www.crutchfield.com/S-TxiEMBKWi3K/p_003POR911B/American-International-POR911-Dash-Kit-Painted-Black.html">this dash kit from Crutchfield</a> as well to have the install look as factory as possible. I will say that the fit is <em>very</em> tight (it&#x27;s a friction fit) so triple check wiring before sliding this into the dash. If you do happen to get the kit stuck with the headunit in it, I&#x27;ve had luck freeing it with the help of a metal putty knife.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">My 987.2 has the Sound Package Plus (SPP), which is the middle tier between the basic speakers and the Bose speakers (which are much more difficult to connect). The connector I needed as a result was the Metra 70-9003 harness. The connector may come with a fuse tap, but I opted to just use a separately purcahsed unit that fit well in the fuse box without needing to drill any holes. Note that the Metra 70-9003 harness may not work with the base package.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Other supplies needed:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Electrical tape</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Assorted t-taps</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Assorted spade connectors</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Low-profile fuse tap</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Metra 70-1787 harness (seperate from the Metra 70-9003 harness, this is just a donor for the RCA cables)</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Stranded red wire (used to connect power from fuse tap to headunit)</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Banana plug adapter for connecing SiriusXM</li>
</ul>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Tools needed:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Heat gun/heat shrink</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Screwdriver set</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Soldering iron/solder</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Wire strippers</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Scissors</li>
</ul>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Also of note that my Porsche did not come equipped with steering wheel controls. If you vehicle does have steering wheel controls, you may need to purchase extra materials in order to get those to work, if so desired.</p>
<img alt="Sony XAV-AX1000 headunit" sizes="(max-width: 768px) 100vw,
    50vw" srcSet="/_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=384&amp;q=75 384w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fmedia%2Fposts%2Fporsche%2Fheadunit-desk.jpeg&amp;w=3840&amp;q=75" width="0" height="0" decoding="async" data-nimg="1" class="w-full h-auto rounded-[8px]" loading="lazy" style="color:transparent"/>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">The first thing I did was assemble the headunit inside of the dash kit and set it aside on my desk. The screws that come with the dash kit don&#x27;t work great but seem to be able to self-tap into the headunit. Just sure you screw them in flush, otherwise the unit won&#x27;t fit in the vehicle.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Next, it&#x27;s time to wire the Metra harness. You can view Crutchfield&#x27;s wiring diagram <a rel="noreferrer" target="_blank" class="inline underline" href="https://pdf.crutchfieldonline.com/ImageBank/v20161026152100/Manuals/120/120709003.PDF">here</a>. Next, you can splice the donor RCA cables from the 70-1787 harness with the speaker wires in the 70-9003 harness. Using your wire strippers, remove the outer layer of shielding from the RCA cables, exposing the positive wire and the stranded negative wire. Twist the stranded wire together and put the heat shrink tube over the cable. Solder the positive wire to the 70-9003 harness positive wire and solder the negative wire to the 70-9003 negative wire for the same speaker. Wrap each connection tightly with electrical tape, slide the heat shrink over the connections, and use your heat gun to set. Repeat this for the three other pairs of speakers.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Moving on to the install, removal of the headunit in the 987.2 is straightfoward, only requiring the removal of a few screws. <a rel="noreferrer" target="_blank" class="inline underline" href="https://www.youtube.com/watch?v=D9iRykamWKE">This YouTube video</a> explains it well. I reccommend disconnecting your battery first if possible, as you should do whenever working with your car&#x27;s electrical system. Be delicate as the OEM headunit is still valuable and you may want to swap it back before selling your vehicle.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">You can now remove the trim around the fuse compartment and tap the fuse; I used C6 as it turns on and off with the ignition. Crimp a length of the stranded red wire to the tapped fuse connector and snake it through to the headunit area. I had the wire rest on the trim below the steering wheel and it hasn&#x27;t caused any issues. Re-attach the fusebox surrounding trim and use a spade connector to attach the fuse tap wire to the power input for the headunit. I wrapped the connection with electrical tape to prevent shorts.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">At this point you may want to tap the parking lights in order to control automatic dimming of the headunit. I did not do that during my install, so you&#x27;ll need to look at a diagram to see what color to look out for. I will note, however, that you are able to easily manually dim the display in the settings.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Now, plug the RCA connectors into the respective pre-amp outputs on the headunit to connect the speakers. When you disconnected the original factory headunit, there was a twelve-pin blue connector. The pink wire with the red stripe powers the vehicle&#x27;s amplifier (under passenger seat in SPP-equipped vehicles). I used the <em>&quot;Remote Out&quot;</em> wire in the new headunit to power both the amp as well as the powered AM/FM radio antenna. Use t-taps to connect both the red and white striped wire and the powered antenna wire (thicker, solid blue wire in the main harness). At this point you can also connect the SiriusXM adapter if your vehicle is equipped.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Finally, after you&#x27;ve checked all of your connections you can (carefully!) slide your headunit into place, reconnect the battery, and test it out! If you are noticing a fair amount of feedback, you can optionally add an inline ground loop isolator between the pre-amp output and your harness to reduce some of the interference.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Enjoy your new radio and feel free to <a rel="noreferrer" target="_blank" class="inline underline" href="mailto:me@noahbuscher.com">email me</a> and I can try and answer any questions you may have.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg"><em>Please note I am not an expert at this and am not responsible for the safety of yourself or and damage to your vehicle, the headunit, etc.</em></p>]]></content>
        <author>
            <name>Noah Buscher</name>
            <email>me@noahbuscher.com</email>
            <uri>https://noahbuscher.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Zed Public Beta]]></title>
        <id>zed</id>
        <link href="https://noahbuscher.com/posts/zed"/>
        <updated>2023-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[My first impressions with Zed's public beta - a native, minimal code editor focused on multiplayer.]]></summary>
        <content type="html"><![CDATA[<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">I have been a dedicated <a rel="noreferrer" target="_blank" class="inline underline" href="https://nova.app">Nova</a> user for over three years. I switched over from <a rel="noreferrer" target="_blank" class="inline underline" href="https://code.visualstudio.com">VSCode</a> after tiring of the slow performance and &quot;uncanny valley&quot; interface. I&#x27;m a sucker for a well-done native app, and Panic really hit the sweet spot with Nova: a beautiful, minimal editor that felt right at home on macOS. It was also extremely fast to boot, indexing files and rendering 50,000 LOC+ without even breaking a sweat on the M1 Pro.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Unfortunately, I&#x27;ve been looking for an alternative as of late due to the high frequency of Nova crashes and lack of updates from Panic. Still, the editor scene hasn&#x27;t changed much from what it looked like half a decade ago, with a smattering of Electron apps, Coda/Nova, some stalwarts such as Sublime Text and TextMate, and, of course, the venerated Vim/Emacs/Neovim trio.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">I&#x27;m not one to spend a lot of time messing around with my tooling; I just want whatever editor I use to have a shallow learning curve and be <em>performant</em>. Somehow, looking for a new editor last week, I came across Zed&#x27;s <a rel="noreferrer" target="_blank" class="inline underline" href="https://twitter.com/zeddotdev/status/1636034629848403968">tweet</a>:</p>
<blockquote class="ml-8 flex-1 flex-grow w-full text-sm leading-6 max-w-lg border-l-2 border-gray-dark pl-4 text-gray-dark">
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Zed is officially in public beta for macOS! We&#x27;ve been building Zed in Zed for a year now, and here&#x27;s what we&#x27;re loving most about it... 🧵</p>
</blockquote>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Since then, I&#x27;ve been playing around with and <a rel="noreferrer" target="_blank" class="inline underline" href="https://github.com/noahbuscher/zed">customizing</a> the editor to see what living with a Rust-powered, minimal editor could look like.</p>
<h3 class="flex-1 flex-grow w-full text-base leading-6 max-w-lg">Install &amp; Setup</h3>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Zed was very simple to set up; after downloading the &#x27;.dmg,&#x27; I had an instance ready to code in a matter of seconds. That&#x27;s instant points over terminal-based editors. I will note here that Zed is currently <em>only</em> available on macOS. <a rel="noreferrer" target="_blank" class="inline underline" href="https://github.com/zed-industries/community/issues/174">Support</a> for Linux and Windows, according to the team, is:</p>
<blockquote class="ml-8 flex-1 flex-grow w-full text-sm leading-6 max-w-lg border-l-2 border-gray-dark pl-4 text-gray-dark">
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">[...] planned, but it is not being prioritized in the short term.</p>
</blockquote>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Customizing the editor was also very straightforward. They have a default editor configuration that you can use, but I found it easier to open a custom settings file and see what was available via their beautiful autocomplete.</p>
<img alt="Zed&#x27;s settings page with autocomplete open" sizes="(max-width: 768px) 100vw,
    50vw" srcSet="/_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=384&amp;q=75 384w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fmedia%2Fposts%2Fzed%2Fzed-autocomplete.png&amp;w=3840&amp;q=75" width="0" height="0" decoding="async" data-nimg="1" class="w-full h-auto rounded-[8px]" loading="lazy" style="color:transparent"/>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">There are a few things that I was surprised I wasn&#x27;t able to customize yet, such as:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Setting the interface&#x27;s font</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Setting the interface&#x27;s font size, independently of the editor</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Enabling (or disabling) icons or colors for the file tree view</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Allow hiding hidden files</li>
</ul>
<h3 class="flex-1 flex-grow w-full text-base leading-6 max-w-lg">Performance</h3>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">This is where Zed really shines. Loading a <code class="bg-[#F4F2F0]">package-lock.json</code> with over 7500 lines is instantaneous—quite literally. Even Nova would take at least a few hundred ms to parse and color a blob of that size, however, Zed doesn&#x27;t even flinch. There is also zero scroll lagging, autocomplete delays, etc. that I could notice in any of my testing. I&#x27;m not sure of the actual numbers, but in my initial testing, Zed felt like the fastest editor I&#x27;ve ever used.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">That is to be expected, of course: the editor was written in Rust and, as stated in their docs, performance was a top concern while developing the app over the course of this past year. Put another way, VSCode is a 2000&#x27;s Land Rover Discovery with tons of buttons and features, whereas Zed is a sleek McLaren F1 - minimal, extremely fast, and with three front seats. Why three front seats?</p>
<h3 class="flex-1 flex-grow w-full text-base leading-6 max-w-lg">Multiplayer</h3>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Zed&#x27;s big bet is on multiplayer. The editor comes with first-class support for real-time pairing, bundled right into the editor. By no means do you <em>need</em> to use the feature in order to derive a lot out of Zed, however, as more people hop on the Zed bullet train, I can see it becoming an integral part of many people&#x27;s (and companies&#x27;) workflows.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">As stated by the team:</p>
<blockquote class="ml-8 flex-1 flex-grow w-full text-sm leading-6 max-w-lg border-l-2 border-gray-dark pl-4 text-gray-dark">
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">[Multiplayer] makes it easy to have nuanced, real-time conversations about any part of your codebase, whether the code in question was committed last year or hasn&#x27;t yet been saved to disk.</p>
</blockquote>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">VSCode does have <a rel="noreferrer" target="_blank" class="inline underline" href="https://code.visualstudio.com/learn/collaboration/live-share">Live Share</a>, but it feels tacked on to the interface, whereas in Zed, pairing feels just like any other feature within the editor: seamless. It almost invites you to collaborate with your team.</p>
<h3 class="flex-1 flex-grow w-full text-base leading-6 max-w-lg">Ecosystem</h3>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">As Zed is still in public beta, there is surely a lot coming down the pipeline. For the time being, however, there were a few features I definitely missed from Nova:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">No extension market (1st or 3rd party)</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">No way to add/edit themes (it comes pre-bundled with a number, however)</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">No dark/light mode based on system</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Limited git integration</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">No markdown preview</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Limited language support</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">No spellcheck</li>
</ul>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">I could not find anything regarding Zed Industries&#x27; plan for supporting extensions (if there even is one), however, I hope they do allow for writing extensions with a scripting language such as JavaScript. Forcing developers to build in Rust may be good for performance, but in a world where <em>everyone</em> is building VSCode extensions, it will cripple the marketplace&#x27;s offerings from the start.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Besides the aforementioned list, Zed really has most of the niceties I&#x27;m used to built right in. I have come across a few small bugs, which is to be expected at this stage of development, but none of which have detracted me from getting my work done.</p>
<h3 class="flex-1 flex-grow w-full text-base leading-6 max-w-lg">Recap</h3>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Zed is a fantastic editor - it&#x27;s eye-wateringly fast, extremely minimal (and beautiful), has a talented team behind it, and is a natural transition for anyone who has familiarity with both terminal and GUI-based editors. However, in a world that is dominated by the free, open-source VSCode, I am curious to see how Zed&#x27;s extension ecosystem grows and what Zed Industries&#x27; plan is for monetizing their product.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">For the time being, I have found the editor a pleasure to work with, and I will be using Zed as my daily driver moving forward. If you&#x27;re tired of VSCode&#x27;s large size, cluttered interface, and slow performance, I urge you to <a rel="noreferrer" target="_blank" class="inline underline" href="https://zed.dev/download">download</a> Zed&#x27;s beta and give it a try. I think you&#x27;ll be pleasantly surprised.</p>]]></content>
        <author>
            <name>Noah Buscher</name>
            <email>me@noahbuscher.com</email>
            <uri>https://noahbuscher.com</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Create a Markdown Portfolio with Next.js]]></title>
        <id>create-markdown-portfolio-next-js</id>
        <link href="https://noahbuscher.com/posts/create-markdown-portfolio-next-js"/>
        <updated>2023-03-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to create a markdown-based portfolio site (or blog) for fun and profit with Next.js, Typescript, and Tailwind.]]></summary>
        <content type="html"><![CDATA[<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">So you&#x27;ve set out to create a new portfolio for yourself. You start gathering inspiration from platforms like <a rel="noreferrer" target="_blank" class="inline underline" href="https://godly.website">Godly</a> and <a rel="noreferrer" target="_blank" class="inline underline" href="https://minimal.gallery">Minimal Gallery</a>, draw some rectangles in Figma, and open your text editor. You pause. There&#x27;s thousands of ways to build your website, how do you decide which to go with? You want your website to be beautiful for the users, but you also want to be able to quickly add new posts and case studies.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">You decide you want to have a dynamic website (good choice!), but the dozens of CMS options weigh on you. Do you pick headless or full-stack? What if you just make a theme? So many choices.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">I was faced with the same dilemma a few months ago. I finally had the motivation to create a new personal website, but wasn&#x27;t sure where to start. I decided to keep things simple, I&#x27;d write it with a library I knew very well: React. That only solved half of the equation, however. When it came time to decide how to power the dynamic content on the site, I knew I wanted it to be free, easy to use, and open source. A static site powered by Next.js and markdown was the obvious choice.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg"><a rel="noreferrer" target="_blank" class="inline underline" href="https://github.com/noahbuscher/markdown-portfolio-tutorial">View the source on GitHub</a>.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">To get started on creating your portfolio, run the following commands. I&#x27;m using <a rel="noreferrer" target="_blank" class="inline underline" href="https://pnpm.io">pnpm</a>, but feel free to use <code class="bg-[#F4F2F0]">yarn</code> or <code class="bg-[#F4F2F0]">npm</code>!</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-text" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span>pnpm dlx create-next-app@latest --typescript</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg"><code class="bg-[#F4F2F0]">cd</code> into your new project and run the following commands to install the necessary packages and bootstrap Tailwind:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-text" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span>pnpm install dayjs
</span></span><span>pnpm install gray-matter react-markdown tailwindcss postcss autoprefixer -D
</span><span>pnpm dlx tailwindcss init -p</span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">That&#x27;s a <em>lot</em> of packages. Let&#x27;s break them down...</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc"><a rel="noreferrer" target="_blank" class="inline underline" href="https://www.npmjs.com/package/gray-matter">gray-matter</a> will be used to parse &quot;front-matter&quot; from our markdown files (we&#x27;ll read more about this later!)</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc"><a rel="noreferrer" target="_blank" class="inline underline" href="https://www.npmjs.com/package/react-markdown">react-markdown</a> is a React component to render markdown content</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc"><code class="bg-[#F4F2F0]">tailwindcss postcss autoprefixer</code> are requirements for <a rel="noreferrer" target="_blank" class="inline underline" href="https://tailwindcss.com/docs/guides/nextjs">installing Tailwind</a> for Next.js</li>
</ul>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Phew! Let&#x27;s continue our setup by finishing the Tailwind install...</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Add the following to the <code class="bg-[#F4F2F0]">module.exports</code> in the generated <code class="bg-[#F4F2F0]">tailwind.config.js</code> file:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-text" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span>content: [
</span></span><span>	&quot;./pages/**/*.{js,ts,jsx,tsx}&quot;,
</span><span>	&quot;./components/**/*.{js,ts,jsx,tsx}&quot;,
</span><span>	&quot;./layouts/**/*.{js,ts,jsx,tsx}&quot;,
</span><span>	&quot;./utils/**/*.{js,ts,jsx,tsx}&quot;
</span><span>],</span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">To bring the styles into your project, add the following to the <code class="bg-[#F4F2F0]">styles/globals.css</code> file:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-text" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span>@tailwind base;
</span></span><span>@tailwind components;
</span><span>@tailwind utilities;</span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Great! Finally, let&#x27;s create our new directories by running the following in the root:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-text" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span>mkdir _projects
</span></span><span>mkdir public/projects
</span><span>mkdir layouts
</span><span>mkdir components
</span><span>mkdir utils</span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">We&#x27;re finally ready to start coding!</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">To get started, create a new layout file, <code class="bg-[#F4F2F0]">ProjectCard.tsx</code> in the <code class="bg-[#F4F2F0]">components</code> directory. This component will be displayed for each project on the home page&#x27;s grid.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">In <code class="bg-[#F4F2F0]">components/ProjectCard.tsx</code> add:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">Image</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;next/image&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">Link</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;next/link&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">ProjectCard</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  title</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  description</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  slug</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  photo</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  title</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  description</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  slug</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  photo</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Link</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">href</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript template-string template-punctuation" style="color:#905">`</span><span class="token script language-javascript template-string" style="color:#905">/project/</span><span class="token script language-javascript template-string interpolation interpolation-punctuation" style="color:#905">${</span><span class="token script language-javascript template-string interpolation" style="color:#905">slug</span><span class="token script language-javascript template-string interpolation interpolation-punctuation" style="color:#905">}</span><span class="token script language-javascript template-string template-punctuation" style="color:#905">`</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">div</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">flex-1 flex flex-col gap-2</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Image</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">src</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">photo</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">alt</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">title</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">width</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">0</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">height</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">0</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">sizes</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">100vw</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">w-full h-full aspect-square object-cover</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#690">priority</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#999">/&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">h3</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">text-black font-bold text-xs</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token" style="color:#999">{</span><span>title</span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">h3</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">p</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">text-gray-500 text-xs</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token" style="color:#999">{</span><span>description</span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">p</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">div</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">  </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#DD4A68">Link</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token module" style="color:#07a">default</span><span> </span><span class="token maybe-class-name">ProjectCard</span><span class="token" style="color:#999">;</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Now we need a place to display all of our project cards. Create a new layout called <code class="bg-[#F4F2F0]">Grid.tsx</code> in the <code class="bg-[#F4F2F0]">layouts</code> directory.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">In <code class="bg-[#F4F2F0]">layouts/Grid.tsx</code>, add the following:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">ProjectCard</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../components/ProjectCard&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token" style="color:#07a">type</span><span> </span><span class="token" style="color:#999">{</span><span> </span><span class="token maybe-class-name">Project</span><span> </span><span class="token" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../layouts/Project&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Grid</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> projects </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> projects</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">[</span><span class="token" style="color:#999">]</span><span> </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">div</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">flex flex-col gap-12 max-w-screen-md mx-auto</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">h2</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">text-black font-bold text-lg</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">Projects</span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">h2</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">div</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">grid grid-cols-2 md:grid-cols-4 gap-8</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">{</span><span>projects</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">map</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> meta </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>        </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">ProjectCard</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">          </span><span class="token" style="color:#690">key</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">slug</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">          </span><span class="token" style="color:#690">title</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">title</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">          </span><span class="token" style="color:#690">description</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">description</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">          </span><span class="token" style="color:#690">slug</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">slug</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">          </span><span class="token" style="color:#690">photo</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">photo</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">        </span><span class="token" style="color:#999">/&gt;</span><span>
</span></span><span><span>      </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">}</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">div</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">  </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">div</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token module" style="color:#07a">default</span><span> </span><span class="token maybe-class-name">Grid</span><span class="token" style="color:#999">;</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Let&#x27;s add a demo project now! In the <code class="bg-[#F4F2F0]">_projects</code> at your root, create a new file. The name doesn&#x27;t matter, but I find it helpful to make it the same as the URL slug. In that file, add soemthing similar to the following:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-md" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token front-matter-block" style="color:#999">---</span><span class="token front-matter-block">
</span></span><span><span class="token front-matter-block"></span><span class="token front-matter-block front-matter yaml language-yaml">title: Example Project
</span></span><span>slug: example-project
</span><span>date: February 1, 2023
</span><span>description: Just an example project!
</span><span><span class="token front-matter-block front-matter yaml language-yaml">photo: /projects/example-project.jpg</span><span class="token front-matter-block">
</span></span><span><span class="token front-matter-block"></span><span class="token front-matter-block" style="color:#999">---</span><span>
</span></span><span>
</span><span>Something about Example Project...</span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">The area between the <code class="bg-[#F4F2F0]">---</code>&#x27;s is called &quot;front-matter&quot;, and it&#x27;s what we brought <code class="bg-[#F4F2F0]">gray-matter</code> in to parse for us. Everything under the second seperator is the content of the case study. It can be any valid markdown.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Save the file and let&#x27;s move on to tying things together!</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">In your <code class="bg-[#F4F2F0]">pages/index.tsx</code> file that Next.js generated, replace the content with the following. Feel free to ignore the missing <code class="bg-[#F4F2F0]">Project</code> type for now. We&#x27;ll add that soon!</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports">path</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;path&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports" style="color:#999">{</span><span class="token imports"> promises </span><span class="token imports module" style="color:#07a">as</span><span class="token imports"> fs </span><span class="token imports" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;fs&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports">matter</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;gray-matter&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports">dayjs</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;dayjs&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">Grid</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../layouts/Grid&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token" style="color:#07a">type</span><span> </span><span class="token" style="color:#999">{</span><span> </span><span class="token maybe-class-name">Project</span><span> </span><span class="token" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../layouts/Project&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token" style="color:#905">PROJECTS_DIR</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#690">&quot;_projects&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#07a">function</span><span> </span><span class="token" style="color:#DD4A68">getStaticProps</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projectsDir </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>process</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">cwd</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#905">PROJECTS_DIR</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> files </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readdir</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> postPaths </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> files</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">filter</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    </span><span class="token" style="color:#07a">const</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">extname</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token control-flow" style="color:#07a">return</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">===</span><span> </span><span class="token" style="color:#690">&quot;.md&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projects </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> </span><span class="token known-class-name" style="color:#DD4A68">Promise</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">all</span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    postPaths</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">map</span><span class="token" style="color:#999">(</span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> contents </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readFile</span><span class="token" style="color:#999">(</span><span>path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">,</span><span> file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#690">&quot;utf8&quot;</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> parsed </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#DD4A68">matter</span><span class="token" style="color:#999">(</span><span>contents</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>      </span><span class="token" style="color:#07a">const</span><span> project </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>        content</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">content</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>        meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">data</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>      </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>      </span><span class="token control-flow" style="color:#07a">return</span><span> project</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> sortedProjects </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> projects</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">sort</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>a</span><span class="token" style="color:#999">,</span><span> b</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span>
</span></span><span><span>    </span><span class="token" style="color:#DD4A68">dayjs</span><span class="token" style="color:#999">(</span><span>a</span><span class="token" style="color:#999">.</span><span class="token property-access">meta</span><span class="token" style="color:#999">.</span><span class="token property-access">date</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">isAfter</span><span class="token" style="color:#999">(</span><span class="token" style="color:#DD4A68">dayjs</span><span class="token" style="color:#999">(</span><span>b</span><span class="token" style="color:#999">.</span><span class="token property-access">meta</span><span class="token" style="color:#999">.</span><span class="token property-access">date</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">-</span><span class="token" style="color:#905">1</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#905">1</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    props</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>      projects</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> sortedProjects</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token module" style="color:#07a">default</span><span> </span><span class="token" style="color:#07a">function</span><span> </span><span class="token maybe-class-name" style="color:#DD4A68">Home</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> projects </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> projects</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">[</span><span class="token" style="color:#999">]</span><span> </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">main</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">mx-10 sm:mx-0 my-10</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Grid</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">projects</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">projects</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905"> </span><span class="token" style="color:#999">/&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">main</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">This may look a little confusing if you&#x27;ve never seen <code class="bg-[#F4F2F0]">getStaticProps</code> before, but you can read more about it <a rel="noreferrer" target="_blank" class="inline underline" href="https://nextjs.org/docs/basic-features/data-fetching/get-static-props">in the Next.js docs</a>. All it&#x27;s doing here is getting an array of Projects that we then use <code class="bg-[#F4F2F0]">dayjs</code> to sort from a human-readable date in the metadata and pass that array as a prop to our <code class="bg-[#F4F2F0]">Grid</code>.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Now just run <code class="bg-[#F4F2F0]">pnpm dev</code> and you should see your project on the home page!</p>
<img alt="Our first project rendered to the home page" sizes="(max-width: 768px) 100vw,
    50vw" srcSet="/_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=384&amp;q=75 384w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-home.png&amp;w=3840&amp;q=75" width="0" height="0" decoding="async" data-nimg="1" class="w-full h-auto rounded-[8px]" loading="lazy" style="color:transparent"/>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Feel free to add more projects and see how it sorts by date and adds them to the grid.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Now, if you try and click on a project, you&#x27;ll notice it takes you to a <code class="bg-[#F4F2F0]">404</code> page. Let&#x27;s go ahead and add a single project layout by creating a file called <code class="bg-[#F4F2F0]">Project.tsx</code> in <code class="bg-[#F4F2F0]">layouts</code>. In <code class="bg-[#F4F2F0]">Project.tsx</code>, add the following:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">Image</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;next/image&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">type</span><span> </span><span class="token maybe-class-name" style="color:#DD4A68">ProjectMeta</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  title</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  description</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  slug</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  date</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  photo</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">type</span><span> </span><span class="token maybe-class-name" style="color:#DD4A68">Project</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">ProjectMeta</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  content</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Project</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  project</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  renderedProjectContent</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  project</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  renderedProjectContent</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">div</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">flex flex-col gap-8 max-w-screen-md mx-auto</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">h2</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">text-black font-bold text-lg</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token" style="color:#999">{</span><span>project</span><span class="token" style="color:#999">.</span><span class="token property-access">meta</span><span class="token" style="color:#999">.</span><span class="token property-access">title</span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">h2</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">h3</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">text-gray-500 text-base</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token" style="color:#999">{</span><span>project</span><span class="token" style="color:#999">.</span><span class="token property-access">meta</span><span class="token" style="color:#999">.</span><span class="token property-access">description</span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">h3</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Image</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">src</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">project</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">photo</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">alt</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">project</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">meta</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">title</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">width</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">0</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">height</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">0</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">sizes</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">100vw</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">w-full h-full</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">priority</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">    </span><span class="token" style="color:#999">/&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">div</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">flex flex-col gap-8</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">dangerouslySetInnerHTML</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905"> __html</span><span class="token script language-javascript" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span class="token script language-javascript" style="color:#905"> renderedProjectContent </span><span class="token script language-javascript" style="color:#999">}</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">    </span><span class="token" style="color:#999">/&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">  </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">div</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token module" style="color:#07a">default</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">;</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">⚠️ Note the <code class="bg-[#F4F2F0]">dangerouslySetInnerHTML</code>. It&#x27;s ok to use here as the only user&#x27;s content that will be rendered there is your&#x27;s. This is not a great practice, however, and you should not do this on a platform that other&#x27;s are able to post content to.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">In the next step, we are going to be writing a utility to generate that HTML. To do so, create a new file called <code class="bg-[#F4F2F0]">markdown.tsx</code> in the <code class="bg-[#F4F2F0]">utils</code> directory and add the following:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">Link</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;next/link&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">*</span><span class="token imports"> </span><span class="token imports module" style="color:#07a">as</span><span class="token imports"> </span><span class="token imports maybe-class-name">ReactDOMServer</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react-dom/server&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">ReactMarkdown</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react-markdown&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Img</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> </span><span class="token spread" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">...</span><span>props </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">any</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">img</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">rounded-[8px] max-w-screen-lg mx-auto w-full</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#905"> </span><span class="token spread" style="color:#999">{</span><span class="token spread" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">...</span><span class="token spread" style="color:#905">props</span><span class="token spread" style="color:#999">}</span><span class="token" style="color:#905"> </span><span class="token" style="color:#999">/&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Text</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> children</span><span class="token" style="color:#999">,</span><span> node </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> children</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">React</span><span class="token" style="color:#999">.</span><span class="token property-access maybe-class-name">ReactNode</span><span class="token" style="color:#999">;</span><span> node</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">any</span><span> </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token control-flow" style="color:#07a">if</span><span> </span><span class="token" style="color:#999">(</span><span>node</span><span class="token" style="color:#999">.</span><span class="token property-access">children</span><span class="token" style="color:#999">[</span><span class="token" style="color:#905">0</span><span class="token" style="color:#999">]</span><span class="token" style="color:#999">.</span><span class="token property-access">tagName</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">===</span><span> </span><span class="token" style="color:#690">&quot;img&quot;</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    </span><span class="token" style="color:#07a">const</span><span> image</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">any</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> node</span><span class="token" style="color:#999">.</span><span class="token property-access">children</span><span class="token" style="color:#999">[</span><span class="token" style="color:#905">0</span><span class="token" style="color:#999">]</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Img</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">src</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">image</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">properties</span><span class="token script language-javascript" style="color:#999">.</span><span class="token script language-javascript property-access" style="color:#905">src</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905"> </span><span class="token" style="color:#999">/&gt;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span>
</span></span><span>
</span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">p</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">flex-1 flex-grow w-full text-xs leading-6 max-w-screen-md mx-auto</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">{</span><span>children</span><span class="token" style="color:#999">}</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">p</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Anchor</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> children</span><span class="token" style="color:#999">,</span><span> href </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">any</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">Link</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">href</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">href</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">inline underline</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">{</span><span>children</span><span class="token" style="color:#999">}</span><span class="token plain-text">
</span></span><span><span class="token plain-text">  </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#DD4A68">Link</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable" style="color:#DD4A68">renderMarkdownToHTML</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span>markup</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token maybe-class-name">ReactDOMServer</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">renderToStaticMarkup</span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">ReactMarkdown</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">components</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">
</span></span><span><span class="token script language-javascript" style="color:#905">        p</span><span class="token script language-javascript" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span class="token script language-javascript" style="color:#905"> </span><span class="token script language-javascript maybe-class-name" style="color:#905">Text</span><span class="token script language-javascript" style="color:#999">,</span><span class="token script language-javascript" style="color:#905">
</span></span><span><span class="token script language-javascript" style="color:#905">        img</span><span class="token script language-javascript" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span class="token script language-javascript" style="color:#905"> </span><span class="token script language-javascript maybe-class-name" style="color:#905">Img</span><span class="token script language-javascript" style="color:#999">,</span><span class="token script language-javascript" style="color:#905">
</span></span><span><span class="token script language-javascript" style="color:#905">        a</span><span class="token script language-javascript" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span class="token script language-javascript" style="color:#905"> </span><span class="token script language-javascript maybe-class-name" style="color:#905">Anchor</span><span class="token script language-javascript" style="color:#999">,</span><span class="token script language-javascript" style="color:#905">
</span></span><span><span class="token script language-javascript" style="color:#905">      </span><span class="token script language-javascript" style="color:#999">}</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">    </span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">      </span><span class="token" style="color:#999">{</span><span>markup</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">trim</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">!</span><span class="token" style="color:#999">}</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#DD4A68">ReactMarkdown</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">This component uses <code class="bg-[#F4F2F0]">react-markdown</code> to enable us to define JSX component mappings for markdown elements! Feel free to get creative here and expand upon what&#x27;s already in there.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">So far so good! We&#x27;re getting close. Now we just need to create a new file called <code class="bg-[#F4F2F0]">[slug].tsx</code> in <code class="bg-[#F4F2F0]">pages/project</code> that will pull that new component in. In <code class="bg-[#F4F2F0]">[slug.tsx]</code>, add the following:</p>
<pre><div style="color:black;background:#f5f2f0;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto"><code class="language-tsx" style="color:black;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;font-size:1em;text-align:left;white-space:pre-wrap;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">React</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;react&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports" style="color:#999">{</span><span class="token imports"> promises </span><span class="token imports module" style="color:#07a">as</span><span class="token imports"> fs </span><span class="token imports" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;fs&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports">path</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;path&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports">matter</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;gray-matter&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports maybe-class-name">ProjectLayout</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../../layouts/Project&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token imports" style="color:#999">{</span><span class="token imports"> renderMarkdownToHTML </span><span class="token imports" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../../utils/markdown&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token module" style="color:#07a">import</span><span> </span><span class="token" style="color:#07a">type</span><span> </span><span class="token" style="color:#999">{</span><span> </span><span class="token maybe-class-name">Project</span><span> </span><span class="token" style="color:#999">}</span><span> </span><span class="token module" style="color:#07a">from</span><span> </span><span class="token" style="color:#690">&quot;../../layouts/Project&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token" style="color:#905">PROJECTS_DIR</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#690">&quot;_projects&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#07a">function</span><span> </span><span class="token" style="color:#DD4A68">getStaticProps</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span> params </span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> params</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> slug</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span> </span><span class="token" style="color:#999">}</span><span> </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projectsDir </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>process</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">cwd</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#905">PROJECTS_DIR</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> files </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readdir</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projectPaths </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> files</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">filter</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    </span><span class="token" style="color:#07a">const</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">extname</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token control-flow" style="color:#07a">return</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">===</span><span> </span><span class="token" style="color:#690">&quot;.md&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projects </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> </span><span class="token known-class-name" style="color:#DD4A68">Promise</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">all</span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    projectPaths</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">map</span><span class="token" style="color:#999">(</span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> contents </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readFile</span><span class="token" style="color:#999">(</span><span>path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">,</span><span> file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#690">&quot;utf8&quot;</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> parsed </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#DD4A68">matter</span><span class="token" style="color:#999">(</span><span>contents</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>      </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>        content</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">content</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>        meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">data</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>      </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> project </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> projects</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">find</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>p</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> p</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?.</span><span>meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?.</span><span>slug </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">===</span><span> params</span><span class="token" style="color:#999">.</span><span class="token property-access">slug</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> renderedProjectContent </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#DD4A68">renderMarkdownToHTML</span><span class="token" style="color:#999">(</span><span>project</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?.</span><span>content</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">!</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    props</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>      project</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>      renderedProjectContent</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#07a">function</span><span> </span><span class="token" style="color:#DD4A68">getStaticPaths</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projectsDir </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>process</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">cwd</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#905">PROJECTS_DIR</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#07a">const</span><span> files </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readdir</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projectPaths </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> files</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">filter</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    </span><span class="token" style="color:#07a">const</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">extname</span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token control-flow" style="color:#07a">return</span><span> ext </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">===</span><span> </span><span class="token" style="color:#690">&quot;.md&quot;</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> projects </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> </span><span class="token known-class-name" style="color:#DD4A68">Promise</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">all</span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>    projectPaths</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">map</span><span class="token" style="color:#999">(</span><span class="token" style="color:#07a">async</span><span> </span><span class="token" style="color:#999">(</span><span>file</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> contents </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token control-flow" style="color:#07a">await</span><span> fs</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">readFile</span><span class="token" style="color:#999">(</span><span>path</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">join</span><span class="token" style="color:#999">(</span><span>projectsDir</span><span class="token" style="color:#999">,</span><span> file</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">,</span><span> </span><span class="token" style="color:#690">&quot;utf8&quot;</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>      </span><span class="token" style="color:#07a">const</span><span> parsed </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#DD4A68">matter</span><span class="token" style="color:#999">(</span><span>contents</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>      </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>        content</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">content</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>        meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> parsed</span><span class="token" style="color:#999">.</span><span class="token property-access">data</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>      </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>    </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token" style="color:#07a">const</span><span> paths </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> projects</span><span class="token" style="color:#999">.</span><span class="token method property-access" style="color:#DD4A68">map</span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">(</span><span>project</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    params</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span> slug</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> project</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?.</span><span>meta</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">?.</span><span>slug </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span>  </span><span class="token control-flow" style="color:#07a">return</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>    paths</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>    fallback</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#905">false</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span>
</span></span><span>
</span><span><span></span><span class="token" style="color:#07a">const</span><span> </span><span class="token function-variable maybe-class-name" style="color:#DD4A68">Project</span><span> </span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=</span><span> </span><span class="token" style="color:#999">(</span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  project</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span>  renderedProjectContent</span><span class="token" style="color:#999">,</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#999">{</span><span>
</span></span><span><span>  project</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span>  renderedProjectContent</span><span class="token" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">:</span><span> </span><span class="token" style="color:#690">string</span><span class="token" style="color:#999">;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">}</span><span class="token" style="color:#999">)</span><span> </span><span class="token arrow" style="color:#9a6e3a;background:hsla(0, 0%, 100%, .5)">=&gt;</span><span> </span><span class="token" style="color:#999">(</span><span>
</span></span><span><span>  </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#905">main</span><span class="token" style="color:#905"> </span><span class="token" style="color:#690">className</span><span class="token attr-equals" style="color:#999">=</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#07a">mx-10 sm:mx-0 my-10</span><span class="token" style="color:#999">&quot;</span><span class="token" style="color:#999">&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">    </span><span class="token" style="color:#999">&lt;</span><span class="token" style="color:#DD4A68">ProjectLayout</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">project</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">project</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">      </span><span class="token" style="color:#690">renderedProjectContent</span><span class="token script language-javascript script-punctuation" style="color:#905">=</span><span class="token script language-javascript" style="color:#999">{</span><span class="token script language-javascript" style="color:#905">renderedProjectContent</span><span class="token script language-javascript" style="color:#999">}</span><span class="token" style="color:#905">
</span></span><span><span class="token" style="color:#905">    </span><span class="token" style="color:#999">/&gt;</span><span class="token plain-text">
</span></span><span><span class="token plain-text">  </span><span class="token" style="color:#999">&lt;/</span><span class="token" style="color:#905">main</span><span class="token" style="color:#999">&gt;</span><span>
</span></span><span><span></span><span class="token" style="color:#999">)</span><span class="token" style="color:#999">;</span><span>
</span></span><span>
</span><span><span></span><span class="token module" style="color:#07a">export</span><span> </span><span class="token module" style="color:#07a">default</span><span> </span><span class="token maybe-class-name">Project</span><span class="token" style="color:#999">;</span></span></code></div></pre>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Similar to the <code class="bg-[#F4F2F0]">index.tsx</code> page, we are grabbing the list of projects again, however this time we are filtering to find the single project whose slug matches that in the dynamic page&#x27;s URL. Then, we are defining a function called <code class="bg-[#F4F2F0]">getStaticPaths</code> that is another special Next.js feature to dynamically create the static paths for generated content (in this case, our Projects!). You can read more about that <a rel="noreferrer" target="_blank" class="inline underline" href="https://nextjs.org/docs/basic-features/data-fetching/get-static-paths">in the Next.js docs</a>.</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Great! If you go back to the home page and click a project, you should now see it takes you to a single project page!</p>
<img alt="A single project page" sizes="(max-width: 768px) 100vw,
    50vw" srcSet="/_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=384&amp;q=75 384w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fmedia%2Fposts%2Fmarkdown-portfolio%2Fexample-project-single.png&amp;w=3840&amp;q=75" width="0" height="0" decoding="async" data-nimg="1" class="w-full h-auto rounded-[8px]" loading="lazy" style="color:transparent"/>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">That&#x27;s really all you need to get started! You now have a simple markdown-powered portfolio. You can use this as a jumping-off point to continue building out the (easy-to-update) portfolio of your dreams! Here&#x27;s some ideas to get you started:</p>
<ul class="ml-8">
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Use <a rel="noreferrer" target="_blank" class="inline underline" href="https://www.npmjs.com/package/next-sitemap">next-sitemap</a> to generate a sitemap to all of your dynamic routes to make it easier for search engines to index your site</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">As you probably noted, some of the code we wrote isn&#x27;t very <a rel="noreferrer" target="_blank" class="inline underline" href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>; maybe extract some of the repeated code into more utils</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Add a navbar and footer</li>
<li class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg list-disc">Add more pages to tell visitors about yourself or how to get in touch with you</li>
</ul>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg">Looking foward to see what y&#x27;all create!</p>
<p class="flex-1 flex-grow w-full text-sm leading-6 max-w-lg"><a rel="noreferrer" target="_blank" class="inline underline" href="https://github.com/noahbuscher/markdown-portfolio-tutorial">View the source on GitHub</a>.</p>]]></content>
        <author>
            <name>Noah Buscher</name>
            <email>me@noahbuscher.com</email>
            <uri>https://noahbuscher.com</uri>
        </author>
    </entry>
</feed>