<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feed.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Oscar Marion</title><description>Recent content on Oscar Marion</description><link>https://osr.im</link><language>en</language><atom:link href="https://osr.im/feed.xml" rel="self" type="application/rss+xml"/><image><url>https://osr.im/_astro/og-profile.DuVv9CWN_ZU5VL3.png</url><title>Oscar Marion</title><link>https://osr.im/</link></image><item><title>Upgrade all Homebrew casks with --greedy</title><link>https://osr.im/notes/brew-greedy</link><guid isPermaLink="true">https://osr.im/notes/brew-greedy</guid><description>brew upgrade skips casks that update themselves, like VS Code, Zed or Raycast. Add --greedy to make Homebrew upgrade them too.</description><pubDate>Mon, 19 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;brew upgrade&lt;/code&gt; skips casks that update themselves, like VS Code, Zed or Raycast. Add &lt;code&gt;--greedy&lt;/code&gt; to make &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; upgrade them too.&lt;/p&gt;
&lt;p&gt;These casks are set to &lt;code&gt;auto_updates true&lt;/code&gt;, and Homebrew leaves them to the app’s own updater (&lt;a href=&quot;https://docs.brew.sh/FAQ&quot;&gt;Homebrew FAQ&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To see which casks &lt;code&gt;--greedy&lt;/code&gt; adds:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; outdated&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --cask&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --greedy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then upgrade them. The flag also picks up casks with &lt;code&gt;version :latest&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; upgrade&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --cask&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --greedy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make it the default, add this to &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; HOMEBREW_UPGRADE_GREEDY&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;--greedy&lt;/code&gt; compares the cask with Homebrew’s install record, not with the installed app. If an app already updated itself, Homebrew reinstalls the cask’s version anyway.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/brew-greedy.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>tooling</category></item><item><title>Tailscale HTTPS certificates on TrueNAS</title><link>https://osr.im/notes/tailscale-truenas</link><guid isPermaLink="true">https://osr.im/notes/tailscale-truenas</guid><description>Replace the Not Secure warning on TrueNAS’ web UI with a Let’s Encrypt certificate from tailscale cert.</description><pubDate>Sun, 11 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have been using Tailscale in my homelab for over two years at this point, and I use their &lt;a href=&quot;https://tailscale.com/docs/features/magicdns&quot;&gt;MagicDNS&lt;/a&gt; feature to access my TrueNAS server on the go: &lt;code&gt;https://truenas.tail123456.ts.net&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After adding TrueNAS to a tailnet (&lt;a href=&quot;https://tailscale.com/docs/integrations/truenas&quot;&gt;official guide&lt;/a&gt;), the browser flags its web UI as not secure, since TrueNAS has no certificate for its &lt;code&gt;ts.net&lt;/code&gt; name. Let’s fix that.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Chrome flags the TrueNAS sign-in page on its ts.net name as Not Secure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1280&quot; height=&quot;691&quot; src=&quot;https://osr.im/_astro/tailscale-truenas.RtEdjymY_q6WXK.webp&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In reality, the certificate warning matters less on a tailnet, since WireGuard encrypts the traffic between your devices. So in my case, this is more of a “cosmetic” endeavor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;a class=&quot;heading-anchor&quot; href=&quot;#requirements&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;MagicDNS and HTTPS Certificates enabled in the Tailscale admin console: &lt;strong&gt;Network → DNS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The TrueNAS Tailscale app is installed and connected.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;get-the-certificate-and-key&quot;&gt;Get the certificate and key&lt;a class=&quot;heading-anchor&quot; href=&quot;#get-the-certificate-and-key&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;You can run the commands below from the Tailscale container shell. From the TrueNAS shell, prefix each command with &lt;code&gt;docker exec ix-tailscale-tailscale-1&lt;/code&gt; (run &lt;code&gt;docker ps&lt;/code&gt; if you’re unsure of the container name).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;1-get-the-certificate&quot;&gt;1. Get the certificate&lt;/h3&gt;
&lt;p&gt;Tailscale asks &lt;em&gt;Let’s Encrypt&lt;/em&gt; for a certificate for the NAS’s tailnet name. Use the exact name shown on the &lt;strong&gt;Machines&lt;/strong&gt; page of the admin console.&lt;/p&gt;
&lt;p&gt;You get four PEM blocks: your certificate, then &lt;a href=&quot;https://letsencrypt.org/certificates/&quot;&gt;&lt;em&gt;Let’s Encrypt&lt;/em&gt;’s chain of trust&lt;/a&gt;. Copy all four.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;tailscale&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; cert&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --cert-file&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;hos&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;tailne&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;.ts.net&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-get-the-private-key&quot;&gt;2. Get the private key&lt;/h3&gt;
&lt;p&gt;This prints the private key that matches the certificate. Paste it into TrueNAS, &lt;strong&gt;nowhere else&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;tailscale&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; cert&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --key-file&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;hos&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;tailne&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;.ts.net&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;import-the-certificate&quot;&gt;Import the certificate&lt;a class=&quot;heading-anchor&quot; href=&quot;#import-the-certificate&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In TrueNAS: &lt;strong&gt;Credentials → Certificates → Import&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: anything, but include today’s date so you can tell certificates apart at the next renewal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add to Trusted Store&lt;/strong&gt;: &lt;code&gt;off&lt;/code&gt;. The trusted store holds the certificates TrueNAS trusts when it connects to other servers. Your own certificate doesn’t belong there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certificate&lt;/strong&gt;: all four PEM blocks from &lt;em&gt;step 1&lt;/em&gt;, in order&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private Key&lt;/strong&gt;: the private key from &lt;em&gt;step 2&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Passphrase&lt;/strong&gt;: leave empty&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then select &lt;strong&gt;Import&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;apply-it-to-the-truenas-gui&quot;&gt;Apply it to the TrueNAS GUI&lt;a class=&quot;heading-anchor&quot; href=&quot;#apply-it-to-the-truenas-gui&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;System → General Settings → GUI → Settings → GUI SSL Certificate.&lt;/strong&gt; Save and wait for the web service to restart.&lt;/p&gt;
&lt;h2 id=&quot;cleanup&quot;&gt;Cleanup&lt;a class=&quot;heading-anchor&quot; href=&quot;#cleanup&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can now go back to &lt;strong&gt;Credentials → Certificates&lt;/strong&gt; and delete any expired Tailscale certificates.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You now have a valid HTTPS connection every time you connect to your TrueNAS GUI using the &lt;code&gt;*.ts.net&lt;/code&gt; MagicDNS subdomain. Certificates have a 90-day expiry, so you’ll need to run these steps again. I will look into automating this process in the future, but for now that’s all I’ve got.&lt;/p&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/tailscale-truenas.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>self-hosting</category></item><item><title>Bring back old Opus in Claude Code</title><link>https://osr.im/notes/claude-code-model-picker-older-opus</link><guid isPermaLink="true">https://osr.im/notes/claude-code-model-picker-older-opus</guid><description>I still use Opus 4.6 and 4.8 regularly, as I often find Opus 5 too verbose (and Fable too expensive). Here is how to add them back to the /model picker.</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I still use Opus 4.6 and 4.8 regularly, as I often find Opus 5 too verbose (and Fable too expensive). Here is how to add them back to the &lt;code&gt;/model&lt;/code&gt; picker.&lt;/p&gt;
&lt;p&gt;Add this to &lt;code&gt;~/.claude/settings.json&lt;/code&gt;. The rows appear after the built-in ones:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;&quot;modelPicker&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &quot;options&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&quot;claude-opus-4-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&quot;Opus 4.8&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&quot;claude-opus-4-6&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&quot;Opus 4.6&quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Set &lt;code&gt;modelPicker.replaceBuiltInOptions: true&lt;/code&gt; to show only these rows.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/claude-code-model-picker-older-opus.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>ai</category><category>tooling</category></item><item><title>Craft over prompts</title><link>https://osr.im/articles/craft</link><guid isPermaLink="true">https://osr.im/articles/craft</guid><description>I ran out of Claude Code tokens the other day and, for a few minutes, it felt like I had forgotten how to write code.</description><pubDate>Mon, 24 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I ran out of Claude Code tokens the other day. And froze. Eight years into my software engineering career, dozens of projects, thousands of lines shipped… And yet, for a few minutes, it felt like I had forgotten how to write code. That’s when I realized I needed to take a step back. A little late, I know.&lt;/p&gt;
&lt;p&gt;Most software engineers I work with have been using AI coding tools for years. We have seen the models evolve &lt;strong&gt;from barely usable to genuinely impressive&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There have been skeptics all along, often experienced software engineers for whom this whole thing is &lt;a href=&quot;https://www.tomshardware.com/tech-industry/artificial-intelligence/linus-torvalds-reckons-ai-is-90-percent-marketing-and-10-percent-reality&quot; title=&quot;null&quot;&gt;90% marketing and 10% reality&lt;/a&gt;. But in the past few weeks, I see more and more of the ones who had previously embraced AI coding now &lt;a href=&quot;https://www.youtube.com/watch?v=0ZUkQF6boNg&amp;amp;pp=ygUJYWkgY29kaW5n&quot; title=&quot;null&quot;&gt;taking a break&lt;/a&gt; from it.&lt;/p&gt;
&lt;p&gt;I started using ChatGPT “research preview” in 2022 and gradually adopted various models in my day-to-day work as the &lt;abbr title=&quot;Integrated Development Environment&quot;&gt;IDE&lt;/abbr&gt; integrations improved. It got really good, really fast. In just three years, we went from copying code back and forth with a browser-based chatbot, to having code autocompletion in the editor, to AI agents finally letting me drink my matcha latte in peace while doing all the work for me.&lt;/p&gt;
&lt;p&gt;Why would anyone want to go back?&lt;/p&gt;
&lt;h2 id=&quot;just-build-something&quot;&gt;“Just build something”&lt;a class=&quot;heading-anchor&quot; href=&quot;#just-build-something&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Take a look at how the industry views our work. For business people, &lt;strong&gt;code is a black box&lt;/strong&gt; sitting between ideation and product. It’s a highly complex, expensive step that they hope will enable sales. But it comes with many scary words they don’t &lt;em&gt;really&lt;/em&gt; understand: technical debt, scaling issues, regressions. Believe me, if they could avoid code altogether, they would.&lt;/p&gt;
&lt;p&gt;In fact, they have tried. Think about the rise of “no-code” tools. Sure, there is still code behind them, but you only see the &lt;abbr title=&quot;Graphical User Interface&quot;&gt;GUI&lt;/abbr&gt;. And if there’s a bug, it is another company’s problem. Just like with serverless, servers haven’t gone anywhere; they’re just for someone else to scale and deploy to.&lt;/p&gt;
&lt;p&gt;Meet the new kid in town: &lt;strong&gt;vibe-coding&lt;/strong&gt;. Write a prompt with your idea, wait, nudge, repeat, ship, make money. That’s the dream products like &lt;a href=&quot;https://lovable.dev/&quot; title=&quot;null&quot;&gt;Lovable&lt;/a&gt;, &lt;a href=&quot;https://bolt.new/&quot; title=&quot;null&quot;&gt;Bolt&lt;/a&gt; or &lt;a href=&quot;https://v0.app/&quot; title=&quot;null&quot;&gt;v0&lt;/a&gt; are selling. You don’t need to be a software engineer. You don’t need to see the code. “Just build something,” and they’ll do the rest. But when something goes wrong, &lt;strong&gt;whose problem is it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Whether you like it or not, you are responsible for the code you ship to end-users. And having to fix code you did not write, let alone understand, is &lt;a href=&quot;https://x.com/leojrr/status/1901560276488511759?lang=en&quot; title=&quot;null&quot;&gt;not a good place to be&lt;/a&gt;. Especially if your shiny new &lt;abbr title=&quot;Software as a Service&quot;&gt;SaaS&lt;/abbr&gt; handles any kind of personal or sensitive data.&lt;/p&gt;
&lt;p&gt;Software engineers are not immune to this. In fact, back in the day, we copy-pasted code from StackOverflow, sometimes bitterly regretting it. But the scale and speed at which these models take us is unprecedented. We started by offloading boring tasks: &lt;em&gt;write tests&lt;/em&gt;, &lt;em&gt;create dummy data&lt;/em&gt;, &lt;em&gt;document code&lt;/em&gt;, &lt;em&gt;rename symbols&lt;/em&gt;. As the models got better, we asked them to debug errors, create features. Then, we let them execute commands on our machines.&lt;/p&gt;
&lt;p&gt;Let’s be honest, it sometimes feels like magic. And &lt;strong&gt;sometimes&lt;/strong&gt;, it &lt;a href=&quot;https://www.tomshardware.com/tech-industry/artificial-intelligence/ai-coding-platform-goes-rogue-during-code-freeze-and-deletes-entire-company-database-replit-ceo-apologizes-after-ai-engine-says-it-made-a-catastrophic-error-in-judgment-and-destroyed-all-production-data&quot;&gt;deletes the production database&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;youre-absolutely-right&quot;&gt;“You’re absolutely right!”&lt;a class=&quot;heading-anchor&quot; href=&quot;#youre-absolutely-right&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the pattern that finally clicked for me: these models speak beautifully, but they forget quickly. They’re confident, but they hallucinate. They flatter you, but only because &lt;a href=&quot;https://www.nytimes.com/2025/09/26/well/is-ai-validation-healthy.html&quot; title=&quot;null&quot;&gt;they’re optimized to please&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is a disturbing dissonance between the honeymoon phase the industry is in and the growing red flags raised by the community. If you’ve ever watched a model confidently walk you down a path that doesn’t exist, invent facts, or do the opposite of what it’s saying… you know the feeling.&lt;/p&gt;
&lt;p&gt;Big Tech executives love to &lt;a href=&quot;https://www.businessinsider.com/ai-code-meta-microsoft-google-llamacon-engineers-2025-4&quot; title=&quot;null&quot;&gt;declare that 25% to 30%&lt;/a&gt; of their code is now written by AI, treating it like a KPI. But they rarely mention how much time engineers spend reviewing AI-generated code and cleaning up the mess, and how frustrating that work actually is.&lt;/p&gt;
&lt;h2 id=&quot;work-that-didnt-spark-joy&quot;&gt;Work that didn’t spark joy&lt;a class=&quot;heading-anchor&quot; href=&quot;#work-that-didnt-spark-joy&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I kicked off a side project a little while ago. I wanted to try &lt;a href=&quot;https://svelte.dev&quot; title=&quot;null&quot;&gt;Svelte 5&lt;/a&gt;. After the initial scaffolding, I let Claude Code drive most of the basic features while I wrote the documentation and refined my prompts.&lt;/p&gt;
&lt;p&gt;In just a few hours, I got the basic features to work. That sounds like a massive time saver, right? But after the initial prototype, most of my time was spent prompting it to remove all the over-engineered abstractions and break up the 500+ line files it spewed.&lt;/p&gt;
&lt;p&gt;The tool that was supposed to give me superpowers had me waiting between each prompt, wondering if its non-deterministic neural network would produce anything good next.&lt;/p&gt;
&lt;p&gt;Between the constant back-and-forth every time it failed to deliver working code and the hours spent compacting the context window and optimizing my prompts, this ended up putting a weird distance between me and the project. I became a middle manager instead of learning about Svelte 5. And I was not having much fun.&lt;/p&gt;
&lt;h2 id=&quot;the-indigo-trend&quot;&gt;The indigo trend&lt;a class=&quot;heading-anchor&quot; href=&quot;#the-indigo-trend&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are endless ways to be creative. Mine is to start projects from zero, having to figure out the user experience, the code architecture, the right patterns. Finding good variable names. Experiment. Make mistakes. Going through libraries documentation. Refactor.&lt;/p&gt;
&lt;p&gt;Have you heard of the indigo trend? AI-generated &lt;abbr title=&quot;User Interfaces&quot;&gt;UIs&lt;/abbr&gt; almost always use the same color: &lt;span style=&quot;color: #615FFF; font-weight: 500;&quot;&gt;indigo-500&lt;/span&gt;. Wes Bos &lt;a href=&quot;https://www.youtube.com/watch?v=AG_791Y-vs4&quot; title=&quot;null&quot;&gt;interviewed Tailwind’s creator&lt;/a&gt; about it, and it turns out the reason is simple: it was Tailwind UI’s default color at a time when many models were in their training phase.&lt;/p&gt;
&lt;p&gt;The funny part is that it’s only going to get worse, as future models are being trained on that growing sea of generic purple landing pages. These models are trained on existing code; &lt;strong&gt;they output existing patterns&lt;/strong&gt;, sometimes verbatim. It is harmless enough with color palettes, but not when it regurgitates a security vulnerability.&lt;/p&gt;
&lt;p&gt;At some point, &lt;strong&gt;the so-called efficiency gains aren’t worth the loss of craft&lt;/strong&gt;. When the hype settles, I believe we should (&lt;em&gt;and will&lt;/em&gt;) use &lt;abbr title=&quot;Large Language Models&quot;&gt;LLMs&lt;/abbr&gt; like any other tool: for the small set of jobs they’re actually good at.&lt;/p&gt;
&lt;h2 id=&quot;my-ai-detox&quot;&gt;My AI-detox&lt;a class=&quot;heading-anchor&quot; href=&quot;#my-ai-detox&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Here is the plan&lt;/strong&gt;. For now, I am going back to basics. No Artificial Intelligence. Just me, my laptop, and a trusty old matcha latte.&lt;/p&gt;
&lt;p&gt;So far, so good. It feels slower to kick off a project, but writing code brings much more joy than vibe-coding my way into oblivion. And what’s more, it doesn’t even feel slower over a few days of work.&lt;/p&gt;
&lt;p&gt;If you’re not taking an AI coding break like me, I’ve come up with &lt;strong&gt;a few rules for my future self&lt;/strong&gt;, for when I will reintroduce these tools to my workflow.&lt;/p&gt;
&lt;h3 id=&quot;own-what-you-ship&quot;&gt;Own what you ship&lt;/h3&gt;
&lt;p&gt;→ If you can’t &lt;strong&gt;fully&lt;/strong&gt; explain each line, don’t merge it.&lt;/p&gt;
&lt;h3 id=&quot;disable-ai-in-your-ide&quot;&gt;Disable AI in your IDE&lt;/h3&gt;
&lt;p&gt;→ Uninstall &lt;abbr title=&quot;Command-Line Interface&quot;&gt;CLI&lt;/abbr&gt; agents, and use models only in the browser when necessary. Or in Raycast. But keep it away from your editor; it’s too tempting.&lt;/p&gt;
&lt;h3 id=&quot;learn-the-basics&quot;&gt;Learn the basics&lt;/h3&gt;
&lt;p&gt;→ By no means an exhaustive list, but here are some major concepts: &lt;a href=&quot;https://www.youtube.com/watch?v=wjZofJX0v4M&quot; title=&quot;null&quot;&gt;transformers&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=nKSk_TiR8YA&quot; title=&quot;null&quot;&gt;tokens&lt;/a&gt;, &lt;a href=&quot;https://docs.claude.com/en/docs/build-with-claude/context-windows&quot; title=&quot;null&quot;&gt;context windows&lt;/a&gt;, why &lt;a href=&quot;https://www.youtube.com/watch?v=cfqtFvWOfg0&quot; title=&quot;null&quot;&gt;hallucinations happen&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;prefer-local-models&quot;&gt;Prefer local models&lt;/h3&gt;
&lt;p&gt;→ Mostly to stay in control instead of being at the mercy of your internet connection and every model update. I use &lt;a href=&quot;https://lmstudio.ai/&quot;&gt;LM Studio&lt;/a&gt; as it supports &lt;a href=&quot;https://lmstudio.ai/blog/unified-mlx-engine&quot;&gt;MLX&lt;/a&gt; for Apple Silicon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As of November 2025, &lt;em&gt;Qwen3-coder-30b&lt;/em&gt; has been solid for me. Local models are usually less capable than the big cloud ones running on thousands of GPUs, so I recommend breaking your requests into smaller, focused prompts to get the best results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;use-it-to-review-your-code&quot;&gt;Use it to review your code&lt;/h3&gt;
&lt;p&gt;→ Especially on solo projects, it’s better than having no one review your code. Expect false positives, but at times you will catch a real issue or code smell. It’s easy to &lt;a href=&quot;https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review&quot;&gt;enable on GitHub&lt;/a&gt; and the free tier is generous.&lt;/p&gt;
&lt;h3 id=&quot;use-it-to-learn&quot;&gt;Use it to learn&lt;/h3&gt;
&lt;p&gt;→ Ask questions, request comparisons, and come up with edge cases to your tests. Remember to always double-check sources, especially when it comes to dependencies, as these models quite often use outdated specs.&lt;/p&gt;</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/article/craft.png" medium="image" type="image/png" width="1200" height="630"/><category>article</category><category>ai</category></item><item><title>How to resize logical volume in Proxmox</title><link>https://osr.im/notes/resize-ubuntu-volume-proxmox</link><guid isPermaLink="true">https://osr.im/notes/resize-ubuntu-volume-proxmox</guid><description>When an Ubuntu VM on Proxmox runs out of disk space: resize the disk in Proxmox, then extend the partition and the volume inside the VM.</description><pubDate>Sun, 06 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;allocate-more-space-on-proxmox&quot;&gt;Allocate more space on Proxmox&lt;a class=&quot;heading-anchor&quot; href=&quot;#allocate-more-space-on-proxmox&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Go to your VM &amp;gt; &lt;strong&gt;Hardware tab&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select the disk you want to resize&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Disk Action&lt;/strong&gt; dropdown in the menu bar, then &lt;strong&gt;Resize&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Resize the disk as much as you need:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt=&quot;proxmox-resize-disk&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;739&quot; height=&quot;435&quot; src=&quot;https://osr.im/_astro/proxmox-resize-disk.DyADHxZ9_ZAez6b.webp&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;extend-the-partition-in-the-vm&quot;&gt;Extend the partition in the VM&lt;a class=&quot;heading-anchor&quot; href=&quot;#extend-the-partition-in-the-vm&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make the partition see the space (&lt;code&gt;/dev/sda3&lt;/code&gt; in my case):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; cfdisk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, resize the partition within &lt;strong&gt;cfdisk&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extend the Physical Volume (PV) from the partition:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; pvresize&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /dev/sda3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extend the Logical Volume (LV) to use all the space in the Volume Group (VG):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; lvextend&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; +100%FREE&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /dev/ubuntu-vg/ubuntu-lv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resize the file system:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; resize2fs&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /dev/ubuntu-vg/ubuntu-lv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check that the file system sees the new space:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;df&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://packetpushers.net/blog/ubuntu-extend-your-default-lvm-space&quot;&gt;https://packetpushers.net/blog/ubuntu-extend-your-default-lvm-space&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/resize-ubuntu-volume-proxmox.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>self-hosting</category></item><item><title>Manually trigger DDNS update on a UDM Pro</title><link>https://osr.im/notes/how-to-manually-trigger-ddns-update-on-a-udm-pro</link><guid isPermaLink="true">https://osr.im/notes/how-to-manually-trigger-ddns-update-on-a-udm-pro</guid><description>To my surprise, there is no way to trigger a DDNS update from the Unifi Dashboard. Here is how to force one over SSH instead of restarting the console.</description><pubDate>Sat, 19 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I ran into this issue today, and to my surprise, there is no way of doing that from the Unifi Dashboard. While most of the responses you will find on Ubiquiti’s forums and on Reddit suggest restarting the console altogether, &lt;em&gt;u/TheFuer&lt;/em&gt; on Reddit &lt;a href=&quot;https://www.reddit.com/r/Ubiquiti/comments/gbppr9/comment/jqcn35m/?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;posted a much better way to do it&lt;/a&gt;, using the CLI.&lt;/p&gt;
&lt;p&gt;First, connect to your UDM Pro via SSH. You can follow &lt;a href=&quot;https://evanmccann.net/blog/2020/5/udm-ssh&quot;&gt;this guide&lt;/a&gt; if you don’t have it setup yet.&lt;/p&gt;
&lt;h2 id=&quot;1-determine-the-configcommand-that-the-udm-is-using-by-typing-this-command&quot;&gt;1. Determine the config/command that the UDM is using by typing this command:&lt;a class=&quot;heading-anchor&quot; href=&quot;#1-determine-the-configcommand-that-the-udm-is-using-by-typing-this-command&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; ps&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; aux&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#702C00&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; inadyn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should return something similar to this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;        1432&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  0.0&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  0.0&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;   6336&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  3256&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;        S&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;    00:49&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;   0:00&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /usr/sbin/inadyn&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /run/ddns-eth8-inadyn.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;       24298&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  0.0&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  0.0&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;   4924&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;   680&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; pts/0&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;    S+&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;   01:00&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;   0:00&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --color&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; inadyn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-run-inadyn-with-a-force-flag-to-force-the-update-replace-the-path-with-the-one-the-previous-command-returned&quot;&gt;2. Run inadyn with a force flag to force the update. Replace The path with the one the previous command returned:&lt;a class=&quot;heading-anchor&quot; href=&quot;#2-run-inadyn-with-a-force-flag-to-force-the-update-replace-the-path-with-the-one-the-previous-command-returned&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; inadyn&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --force&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; /run/ddns-eth8-inadyn.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should get the following once the update is successful:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;inadyn[25647]:&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; In-a-dyn&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; 2.9.1&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; Dynamic&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; DNS&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; client.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;inadyn[25647]:&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; Update&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; forced&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; alias&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; all.dnsomatic.com,&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; IP#&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; XXX.XXX.XXX.XXX&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;inadyn[25647]:&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; Updating&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; cache&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; all.dnsomatic.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/how-to-manually-trigger-ddns-update-on-a-udm-pro.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>self-hosting</category></item><item><title>Blacklisting Google .mov and .zip TLDs</title><link>https://osr.im/notes/blacklisting-google-mov-and-zip-tlds</link><guid isPermaLink="true">https://osr.im/notes/blacklisting-google-mov-and-zip-tlds</guid><description>Google has made the .zip and .mov top-level domains available for public registration, and cybercriminals are already using them in phishing campaigns.</description><pubDate>Tue, 23 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Google has made the .zip and .mov top-level domains available for public registration, and cybercriminals are already using them in phishing campaigns. It might be a good idea to block them all together for now: here are the steps for PiHole users.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log into your PiHole admin interface&lt;/li&gt;
&lt;li&gt;Click on the “ RegEx filter” tab&lt;/li&gt;
&lt;li&gt;In the “Regular Expression” field, write ^.*.(zip|mov)$&lt;/li&gt;
&lt;li&gt;Click on “Add to Blacklist”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt=&quot;Add domain to blacklist&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1002&quot; height=&quot;394&quot; src=&quot;https://osr.im/_astro/pihole-google-zip-mov-blocking.CYpsYi6N_Z26EbQ5.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can make sure the filtering is working by accessing &lt;strong&gt;somethingfishy.zip&lt;/strong&gt; or &lt;strong&gt;notamoviefile.mov&lt;/strong&gt;. If everything is setup correctly, you should get an ERR_ADDRESS_INVALID from your browser.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ERR_ADDRESS_INVALID&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;723&quot; height=&quot;299&quot; src=&quot;https://osr.im/_astro/chrome-invalid-address.BzdUikZH_ZaCnrX.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;You should also see the following on your PiHole query logs:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;pihole-logs-mov-zip&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;969&quot; height=&quot;232&quot; src=&quot;https://osr.im/_astro/pihole-logs-mov-zip.CEK0p3xe_Z2cEJpQ.webp&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/blacklisting-google-mov-and-zip-tlds.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>self-hosting</category><category>security</category></item><item><title>Zoom TKL shortcuts (Bluetooth and RGB)</title><link>https://osr.im/notes/zoom-tkl-shortcuts-bluetooth-and-rgb</link><guid isPermaLink="true">https://osr.im/notes/zoom-tkl-shortcuts-bluetooth-and-rgb</guid><description>I gathered all the Zoom TKL shortcuts I could find on the web: Bluetooth pairing, function keys and RGB.</description><pubDate>Fri, 21 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Via customization web application: &lt;a href=&quot;https://usevia.app/&quot;&gt;usevia.app&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Zoom TKL JSON File &lt;a href=&quot;https://res.cloudinary.com/dbit9v7da/raw/upload/f_auto/q_auto/v1682340780/osr-dev/notes/zoom87_wireless_1_u1u8py.json&quot;&gt;can be found here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bluetooth&quot;&gt;Bluetooth&lt;a class=&quot;heading-anchor&quot; href=&quot;#bluetooth&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Initiate bluetooth pairing (Device 1)&lt;/td&gt;
&lt;td&gt;FN + Z (Hold)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initiate bluetooth pairing (Device 2)&lt;/td&gt;
&lt;td&gt;FN + X (Hold)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initiate bluetooth pairing (Device 3)&lt;/td&gt;
&lt;td&gt;FN + C (Hold)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connect to bluetooth device {1, 2, 3}&lt;/td&gt;
&lt;td&gt;FN + {Z, X, C}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;general&quot;&gt;General&lt;a class=&quot;heading-anchor&quot; href=&quot;#general&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Restore to factory settings&lt;/td&gt;
&lt;td&gt;FN + Space + Backspace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset keyboard&lt;/td&gt;
&lt;td&gt;FN + Shift + R&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wired mode&lt;/td&gt;
&lt;td&gt;FN + Space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter deep sleep mode&lt;/td&gt;
&lt;td&gt;FN + Tab (Hold)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;function-keys&quot;&gt;Function keys&lt;a class=&quot;heading-anchor&quot; href=&quot;#function-keys&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Increase brightness&lt;/td&gt;
&lt;td&gt;FN + F1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrease brightness&lt;/td&gt;
&lt;td&gt;FN + F2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter Mission Control&lt;/td&gt;
&lt;td&gt;FN + F3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open home folder&lt;/td&gt;
&lt;td&gt;FN + F4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refresh&lt;/td&gt;
&lt;td&gt;FN + F5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Previous track&lt;/td&gt;
&lt;td&gt;FN + F7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Play / pause song&lt;/td&gt;
&lt;td&gt;FN + F8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Next track&lt;/td&gt;
&lt;td&gt;FN + F9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mute&lt;/td&gt;
&lt;td&gt;FN + F10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volume up&lt;/td&gt;
&lt;td&gt;FN + F11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volume down&lt;/td&gt;
&lt;td&gt;FN + F12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;rgb&quot;&gt;RGB&lt;a class=&quot;heading-anchor&quot; href=&quot;#rgb&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Increase RGB brightness&lt;/td&gt;
&lt;td&gt;FN + ↑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrease RGB brightness&lt;/td&gt;
&lt;td&gt;FN + ↓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increase RGB speed&lt;/td&gt;
&lt;td&gt;FN + →&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrease RGB speed&lt;/td&gt;
&lt;td&gt;FN + ←&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle RGB&lt;/td&gt;
&lt;td&gt;FN + \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increase RGB hue&lt;/td&gt;
&lt;td&gt;FN + P&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrease RGB hue&lt;/td&gt;
&lt;td&gt;FN + ;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increase RGB saturation&lt;/td&gt;
&lt;td&gt;FN + [&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrease RGB saturation&lt;/td&gt;
&lt;td&gt;FN + ’&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change RGB mode&lt;/td&gt;
&lt;td&gt;FN + ]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/note/zoom-tkl-shortcuts-bluetooth-and-rgb.png" medium="image" type="image/png" width="1200" height="630"/><category>note</category><category>hardware</category></item><item><title>Stop Wasting Build Minutes</title><link>https://osr.im/articles/husky</link><guid isPermaLink="true">https://osr.im/articles/husky</guid><description>CI pipelines are great. But sometimes they fail over a silly linting error that could’ve been caught earlier on your own machine.</description><pubDate>Tue, 06 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CI pipelines are &lt;strong&gt;great&lt;/strong&gt;. They make sure your code doesn’t break anything and follows conventions. Usually, they run tasks like unit tests, linting, and builds.&lt;/p&gt;
&lt;p&gt;But sometimes the pipeline fails over a silly linting error. It did its job—stopping bad code from shipping—but that could’ve been caught earlier &lt;strong&gt;on your own machine&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;The fix? Automate these checks locally before your PR. That’s where Git hooks come in. This tutorial covers the basics to help you get you and your team started.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing git hooks comes with a few challenges&lt;/strong&gt;, mainly to ensure they are installed on your teammates’ machines.&lt;/p&gt;
&lt;h2 id=&quot;husky-&quot;&gt;Husky? 🐶&lt;a class=&quot;heading-anchor&quot; href=&quot;#husky-&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/typicode/husky&quot;&gt;Husky&lt;/a&gt; is a tiny tool that makes it easy to set up git hooks and share them across your team. We will use it together with &lt;a href=&quot;https://github.com/okonet/lint-staged&quot;&gt;lint staged&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;1-install-husky&quot;&gt;1. Install husky&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; husky&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;# or&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; husky&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-enable-git-hooks&quot;&gt;2. Enable git hooks&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; husky&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-automate-git-hook-installation-for-your-teammates&quot;&gt;3. Automate git hook installation for your teammates&lt;/h3&gt;
&lt;p&gt;For npm, add this prepare script to your package.json:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &amp;quot;prepare&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;npx husky install&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yarn requires a slightly different configuration:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &amp;quot;private&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;    &amp;quot;postinstall&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;npx husky install&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using Yarn2 in a non-private repo? Check &lt;a href=&quot;https://typicode.github.io/husky/#/?id=yarn-2&quot;&gt;this link&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;4-install-lint-staged&quot;&gt;4. Install lint-staged&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; lint-staged&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;# or&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; lint-staged&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the lint-staged configuration to your package.json and customise it to your needs. We assume that you already have linters and tests scripts set up.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;lint-staged&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &amp;quot;*.{ts,tsx}&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;    &amp;quot;npm run format&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#66707B&quot;&gt;// prettier --write script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;    &amp;quot;npm run lint:fix&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#66707B&quot;&gt; // eslint --fix script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;    &amp;quot;npm run test&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#66707B&quot;&gt; // jest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-create-your-hook&quot;&gt;5. Create your hook&lt;/h3&gt;
&lt;p&gt;This command will create a .husky folder at the root of your project:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; husky&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; .husky/pre-commit&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; &amp;quot;npx lint-staged&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-did-we-achieve&quot;&gt;What did we achieve?&lt;a class=&quot;heading-anchor&quot; href=&quot;#what-did-we-achieve&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Git hooks (via Husky) now run lint &lt;strong&gt;checks on each commit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Linting only targets staged .ts and .tsx files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-fixable&lt;/strong&gt; errors are fixed and committed; others cause the commit to fail with error details.&lt;/li&gt;
&lt;li&gt;Hooks are automatically &lt;strong&gt;installed for teammates&lt;/strong&gt; through the prepare/postinstall scripts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Git 2.9+ is required for Husky, as it uses core.hooksPath to point to the .husky folder.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;Git hooks help catch mistakes early, keep your Git history clean, and save build minutes. Just remember, they complement—&lt;em&gt;not replace&lt;/em&gt;—CI pipelines. And if needed, you can skip hooks with –no-verify.&lt;/p&gt;
&lt;p&gt;Thanks for reading! 😃&lt;/p&gt;</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/article/husky.png" medium="image" type="image/png" width="1200" height="630"/><category>article</category><category>tooling</category></item><item><title>A simple Tailwind &amp; CRA setup</title><link>https://osr.im/articles/cra</link><guid isPermaLink="true">https://osr.im/articles/cra</guid><description>In this guide, I’ll show you how to install Tailwind on a new Create React App (CRA) project. As a bonus, we’ll also add dark/light theme support.</description><pubDate>Fri, 19 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide, I’ll show you how to install Tailwind on a new Create React App (CRA) project. As a bonus, we’ll also add dark/light theme support.&lt;/p&gt;
&lt;h2 id=&quot;why-tailwind&quot;&gt;Why Tailwind?&lt;a class=&quot;heading-anchor&quot; href=&quot;#why-tailwind&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tailwind is a popular &lt;strong&gt;utility-first&lt;/strong&gt; CSS framework. It’s lightweight (1.4kB vs. Bootstrap’s 60.9kB), highly customizable, and works with CRA, Next.js, Vue, Svelte, and more. Unlike Bootstrap, it doesn’t come with pre-made components, which means more flexibility.&lt;/p&gt;
&lt;h2 id=&quot;the-standard-way&quot;&gt;The Standard Way&lt;a class=&quot;heading-anchor&quot; href=&quot;#the-standard-way&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tailwind suggests using CRACO to customize CRA. While that works, it’s a bit much for simpler setups.&lt;/p&gt;
&lt;h2 id=&quot;our-approach&quot;&gt;Our Approach&lt;a class=&quot;heading-anchor&quot; href=&quot;#our-approach&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ll streamline things by using PostCSS and npm scripts to compile the CSS before running CRA.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A GitHub repository with the final code &lt;a href=&quot;https://github.com/oscar-marion/tailwind-cra-tutorial&quot;&gt;can be found here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-install-cra&quot;&gt;1. Install CRA&lt;/h3&gt;
&lt;p&gt;This command will create a starter project with Typescript support. You can of course remove the template flag and use regular Javascript.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; create-react-app&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; my-react-app&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; --template&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; typescript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-go-to-your-app-folder-and-install-tailwind-postcss-and-autoprefixer-like-so&quot;&gt;2. Go to your app folder and install Tailwind, PostCSS and Autoprefixer like so:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; tailwindcss&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; autoprefixer&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; postcss-cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-create-a-postcssconfigjs-file-at-the-root-of-your-project&quot;&gt;3. Create a postcss.config.js file at the root of your project:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; tailwindcss&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;tailwindcss&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  plugins: [&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt;tailwindcss&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;./tailwind.config.js&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;autoprefixer&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;)],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-create-a-tailwind-configuration-file-by-running&quot;&gt;4. Create a Tailwind configuration file by running:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; tailwind&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should get a tailwind.config.js file that looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  purge: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  darkMode: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#66707B&quot;&gt;// or &amp;#39;media&amp;#39; or &amp;#39;class&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  theme: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    extend: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  variants: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    extend: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  plugins: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-create-a-tailwindcss-file-in-your-project&quot;&gt;5. Create a tailwind.css file in your project,&lt;/h3&gt;
&lt;p&gt;For instance under src/styles/tailwind.css:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; base;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; components;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; utilities;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;6-add-a-css-script-to-packagejson&quot;&gt;6. Add a css script to package.json&lt;/h3&gt;
&lt;p&gt;As well as a prestart and a prebuild:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;  &amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;    &amp;quot;css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;postcss ./src/styles/tailwind.css -o ./src/styles/tailwind.generated.css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;    &amp;quot;prestart&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;npm run css&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;    &amp;quot;prebuild&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;npm run css&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;7-import-tailwind-css-file&quot;&gt;7. Import Tailwind css file&lt;/h3&gt;
&lt;p&gt;This way, we’re making Tailwind classes available to all our app’s components.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;/*...*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;import &amp;quot;./styles/tailwind.generated.css&amp;quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;/*...*/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don’t forget to add tailwind.generated.css to .gitignore, as this file gets generated each time we run the start or build command.
We didn’t use Tailwind classes yet, but now is a good time to run npm run startand check that everything works.&lt;/p&gt;
&lt;h2 id=&quot;make-some-changes&quot;&gt;Make some changes&lt;a class=&quot;heading-anchor&quot; href=&quot;#make-some-changes&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To check that the Tailwind classes get picked up, open ./src/App.ts and edit the Learn React link className property:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  className&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;App-link mt-2 rounded bg-white px-2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  href&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;https://reactjs.org&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  target&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;_blank&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;  rel&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;noopener noreferrer&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  Learn React&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see the changes in your browser pretty instantly and your Learn React link should now look like this:&lt;/p&gt;
&lt;h3 id=&quot;cleanup-the-production-build&quot;&gt;Cleanup the production build&lt;/h3&gt;
&lt;p&gt;Say we want to deploy this app right now. When running npm run build , CRA is kind enough to provide some information on our bundle size. As you can see, this app is quite hefty:&lt;/p&gt;
&lt;p&gt;The bundled css weighs far too much, and there’s a reason for it: it includes all the Tailwind css classes from the @base, @components and @utilities that we set earlier. We want this on our development environment, but certainly not in production — only the used classes should be included in the build.&lt;/p&gt;
&lt;p&gt;To clean up the unused classes, we’ll need to change the purge configuration of tailwind.config.js file to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  purge: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    mode: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;all&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    content: [&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;./src/**/*.ts&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;./src/**/*.tsx&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you didn’t go for the Typescript template, make sure to change your file extensions accordingly.
Now, let’s make sure Tailwind knows we run the build in a production environment by installing cross-env:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; cross-env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And change our prebuild script to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;prebuild&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;cross-env NODE_ENV=production npm run css&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you run the build script, the bundled css weight should decrease a lot. To test that, npm run build once again:&lt;/p&gt;
&lt;p&gt;Finally, let’s make sure our Tailwind classes are still applied: serve the built project by running npx serve -s build. Learn React should still look like on the dev environment.&lt;/p&gt;
&lt;h2 id=&quot;bonus-setup-a-light--dark-mode-switcher&quot;&gt;Bonus: setup a light / dark mode switcher&lt;a class=&quot;heading-anchor&quot; href=&quot;#bonus-setup-a-light--dark-mode-switcher&quot; aria-label=&quot;Link to this section&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;1-use-css-variables&quot;&gt;1. Use CSS variables&lt;/h3&gt;
&lt;p&gt;Let’s extract the colors that are currently set in the src/App.css classes and set them as css variables:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-primary&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#282c34&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-secondary&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#ffffff&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-accent&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#61dafb&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now assign them to Tailwind variables. Your entire configuration should look like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#023B95&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  purge: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    mode: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;all&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    content: [&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;./src/**/*.ts&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;./src/**/*.tsx&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  darkMode: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#66707B&quot;&gt;// or &amp;#39;media&amp;#39; or &amp;#39;class&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  theme: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    extend: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;      colors: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;        primary: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;var(--color-primary)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;        secondary: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;var(--color-secondary)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;        accent: &lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;var(--color-accent)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  variants: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    extend: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  plugins: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you changed the Tailwind configuration, you’ll have to stop the dev server and launch npm run startagain.&lt;/p&gt;
&lt;p&gt;In App.css, you can remove the background-color and color properties set for the .App-header class, as well as the entire .App-link class.&lt;/p&gt;
&lt;p&gt;Going back to App.tsx, make some changes to get the same look as before:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add bg-primary text-secondaryto the header className attribute&lt;/li&gt;
&lt;li&gt;For the Learn React link, replace App-link class by text-accent and bg-white by bg-secondary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-enable-dark-mode&quot;&gt;2. Enable dark mode&lt;/h3&gt;
&lt;p&gt;Create the light CSS variables under a data attribute set on the root div in App.tsx. To do that, add this to App.css, below the CSS variables you set before:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;data-theme&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-primary&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#ffffff&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-secondary&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#282c34&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#702C00&quot;&gt;  --color-accent&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;#61dafb&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now switch between these themes. To keep things simple for this tutorial, we will handle the theme in the component’s local state with the useState hook. In the real world, you would obviously save user preference in a cookie or in localStorage. You could also base the initial theme on prefers-color-scheme.&lt;/p&gt;
&lt;p&gt;Let’s set our localState:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;theme&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;setTheme&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(“dark”)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the current theme to the App.tsx root div:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#024C1A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#6E011A;font-style:italic&quot;&gt;=“App”&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt; data-theme&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;theme&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let’s create our handler:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light-high-contrast&quot; style=&quot;background-color:#ffffff;color:#0e1116;overflow-x:auto&quot; tabindex=&quot;0&quot; data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; React, { MouseEvent, useState } &lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; &amp;#39;react&amp;#39;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;theme&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#023B95&quot;&gt;setTheme&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(“dark”)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt; handleSwitchTheme&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#702C00&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#702C00&quot;&gt; MouseEvent&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#702C00&quot;&gt;HTMLAnchorElement&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;&amp;gt;) &lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;    e.&lt;/span&gt;&lt;span style=&quot;color:#622CBC&quot;&gt;preventDefault&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#622CBC&quot;&gt;    setTheme&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;(theme &lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; &amp;quot;dark&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; &amp;quot;light&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#A0111F&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#032563&quot;&gt; &amp;quot;dark&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#66707B&quot;&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0E1116&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time to add a switch theme button. We will use the Learn more link and change it to our needs:&lt;/p&gt;
&lt;p&gt;Try hitting the Switch theme button. If this fancy light theme shows up, congratulations, you got everything working!&lt;/p&gt;</content:encoded><dc:creator>Oscar Marion</dc:creator><media:content url="https://osr.im/og/article/cra.png" medium="image" type="image/png" width="1200" height="630"/><category>article</category><category>web</category></item></channel></rss>