<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rodney Gitonga</title>
    <description>The latest articles on Forem by Rodney Gitonga (@fytroy).</description>
    <link>https://forem.com/fytroy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3698338%2F976bbb3a-ee74-4a49-9e49-7b6147db41bb.png</url>
      <title>Forem: Rodney Gitonga</title>
      <link>https://forem.com/fytroy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fytroy"/>
    <language>en</language>
    <item>
      <title>Building a Luxury Analytics Dashboard with Next.js 16 &amp; Tailwind v4</title>
      <dc:creator>Rodney Gitonga</dc:creator>
      <pubDate>Fri, 16 Jan 2026 23:16:48 +0000</pubDate>
      <link>https://forem.com/fytroy/building-a-luxury-analytics-dashboard-with-nextjs-16-tailwind-v4-155h</link>
      <guid>https://forem.com/fytroy/building-a-luxury-analytics-dashboard-with-nextjs-16-tailwind-v4-155h</guid>
      <description>&lt;p&gt;In the world of data analytics, dashboards are often purely functional—grids of numbers, standard charts, and utilitarian design. But for my latest project, LuxeMetric Dashboard, I wanted to challenge that norm. I set out to build a platform that doesn't just display data but presents it with the elegance of a high-end fashion brand.&lt;/p&gt;

&lt;p&gt;Here is how I combined the bleeding-edge power of Next.js 16 and React 19 with the refined aesthetics of Tailwind CSS v4 to create a portfolio piece that stands out.&lt;/p&gt;

&lt;p&gt;[Dashboard Preview]&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd9kb7bf8xg9jrcdkhqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd9kb7bf8xg9jrcdkhqk.png" alt=" " width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏗️ The Tech Stack: Bleeding Edge&lt;/p&gt;

&lt;p&gt;To make this dashboard perform as good as it looks, I chose a stack that pushes the boundaries of modern web development:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework&lt;/strong&gt;: &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js 16&lt;/a&gt; (App Router, Turbopack)&lt;br&gt;
   &lt;strong&gt;Core&lt;/strong&gt;: React 19 (Server Actions, &lt;code&gt;useActionState&lt;/code&gt;, &lt;code&gt;useOptimistic&lt;/code&gt;)&lt;br&gt;
   &lt;strong&gt;Styling&lt;/strong&gt;: &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS v4&lt;/a&gt; (Alpha/Beta)&lt;br&gt;
   &lt;strong&gt;UI Primitives&lt;/strong&gt;: Shadcn/ui&lt;br&gt;
   &lt;strong&gt;Animations&lt;/strong&gt;: Framer Motion (Scroll-linked &amp;amp; Layout animations)&lt;br&gt;
   &lt;strong&gt;Visualization&lt;/strong&gt;: Recharts&lt;/p&gt;

&lt;p&gt;💎 Design Philosophy: The "Luxe" Factor&lt;/p&gt;

&lt;p&gt;The core design goal was "Luxury." I wanted to avoid the generic "SaaS Blue" or "Bootstrap Default" look.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Palette: I used a curated "Stone" &amp;amp; "Amber" color palette inspired by high-end editorial layouts.&lt;/li&gt;
&lt;li&gt; Typography: Playfair Display serves as the primary serif font, adding an editorial touch to headers, while Inter maintains readability for data.&lt;/li&gt;
&lt;li&gt; Cinema-Style Reveals: Using the new View Transitions API, toggling between light and dark themes isn't just a flash—it's a smooth, cinematic reveal that feels tailored.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⚡ Key Features &amp;amp; Engineering Wins&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Real-Time Data with Server Actions&lt;br&gt;
Gone are the days of massive &lt;code&gt;useEffect&lt;/code&gt; chains for fetching data. I leveraged React 19 Server Actions to handle data fetching directly from the server. This keeps the client bundle small and the data fresh.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimistic UI&lt;br&gt;
Nothing kills sophistication like a loading spinner on a simple interaction. I used the &lt;code&gt;useOptimistic&lt;/code&gt; hook to make interactions like "Liking" a project or updating a metric feel instant. The UI updates immediately, while the server syncs in the background.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Web Workers for Heavy Lifting&lt;br&gt;
To ensure the main thread stays buttery smooth (targeting a 100/100 Lighthouse score), I offloaded heavy data simulations and calculations to Web Workers. This means complex charts render without janking the scroll or navigational animations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📊 Specialized Visualization&lt;/p&gt;

&lt;p&gt;One of the highlights is the Seasonality Page. It uses an interactive Area Chart to visualize trends over time, allowing users to scrub through data with responsive tooltips. It’s not just about showing the number; it’s about showing the story behind the number.&lt;/p&gt;

&lt;p&gt;🚀 Conclusion&lt;/p&gt;

&lt;p&gt;Building LuxeMetric was a journey into the future of React. Next.js 16 and Tailwind v4 are game-changers for developer experience and performance.&lt;/p&gt;

&lt;p&gt;If you're interested in the code or want to see how I implemented specific features like the View Transitions or Web Workers, check out the repository below!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fytroy/LuxeMetricDashboard" rel="noopener noreferrer"&gt;Link to GitHub Repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hi, I'm Rodney Gitonga, a Data Analytics Officer &amp;amp; BI Specialist. Connect with me on &lt;a href="https://www.linkedin.com/in/rodney-gitonga-9299a41ba/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>showdev</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How I Built a Daily Streak Keeper with Python &amp; GitHub Actions</title>
      <dc:creator>Rodney Gitonga</dc:creator>
      <pubDate>Fri, 16 Jan 2026 23:06:27 +0000</pubDate>
      <link>https://forem.com/fytroy/how-i-built-a-daily-streak-keeper-with-python-github-actions-3bge</link>
      <guid>https://forem.com/fytroy/how-i-built-a-daily-streak-keeper-with-python-github-actions-3bge</guid>
      <description>&lt;p&gt;&lt;em&gt;A guide on automating GitHub activity to keep your contribution streak alive using Python and GitHub Actions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🚀 How I Built a Daily Streak Keeper with Python &amp;amp; GitHub Actions&lt;/p&gt;

&lt;p&gt;We've all been there—staring at that one gray square in our GitHub contribution graph that broke a perfect streak. Whether you're busy, sick, or just forgot to push code, losing a streak can be demotivating.&lt;/p&gt;

&lt;p&gt;I decided to solve this problem by automating a daily commit using Python and GitHub Actions. Here is how I built my Daily Streak Keeper.&lt;/p&gt;

&lt;p&gt;💡 The Idea&lt;/p&gt;

&lt;p&gt;The goal was simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Fetch a daily quote (to make the commit meaningful).&lt;/li&gt;
&lt;li&gt; Update the README.md with the new quote.&lt;/li&gt;
&lt;li&gt; Commit and push the changes automatically every day.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🛠️ The Tech Stack&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Python: To fetch the quote and update the file.&lt;/li&gt;
&lt;li&gt;  GitHub Actions: To schedule the script to run daily.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💻 The Code&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Python Script (&lt;code&gt;update_quote.py&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote a simple Python script that fetches a random quote from an API and updates the &lt;code&gt;README.md&lt;/code&gt; file. I used &lt;code&gt;dummyjson.com&lt;/code&gt; for stability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_quote&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dummyjson.com/quotes/random&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quote&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt; — &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Could not fetch a quote today. Keep coding!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error fetching quote: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_readme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;date_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="n"&gt;Template&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;README&lt;/span&gt;
    &lt;span class="n"&gt;readme_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
 🚀 Daily Streak Keeper

This repository automatically updates itself every day at 12:00 PM Nairobi Time to keep my GitHub contribution streak alive.

 📅 Quote for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;date_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

---
Last updated automatically by GitHub Actions.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;README.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readme_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_quote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;update_readme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The Automation (&lt;code&gt;daily-quote.yml&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, I needed this script to run automatically. GitHub Actions is perfect for this. I set up a workflow that runs every day at 12:00 PM Nairobi Time (09:00 UTC).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Daily Quote Update&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="s"&gt;09:00 UTC = 12:00 PM Nairobi Time&lt;/span&gt;
    &lt;span class="s"&gt;- cron&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt;   &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;update-readme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.x'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Python script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python update_quote.py&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit and Push&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;git config --global user.name "Quote Bot"&lt;/span&gt;
          &lt;span class="s"&gt;git config --global user.email "${{ github.actor }}@users.noreply.github.com"&lt;/span&gt;

          &lt;span class="s"&gt;git add README.md&lt;/span&gt;
          &lt;span class="s"&gt;if git diff-index --quiet HEAD; then&lt;/span&gt;
            &lt;span class="s"&gt;echo "No changes to commit"&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;git commit -m "Daily Quote: Updated README with new inspiration 📜"&lt;/span&gt;
            &lt;span class="s"&gt;git push&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎯 Conclusion&lt;/p&gt;

&lt;p&gt;This was a fun little project to ensure my profile stays active while also giving me a nice quote to read every day. It’s a great example of how powerful and easy GitHub Actions can be for automating simple tasks.&lt;/p&gt;

&lt;p&gt;Check out the code in the repository and feel free to fork it to create your own streak keeper! &lt;a href="https://github.com/fytroy/dskeeper" rel="noopener noreferrer"&gt;REPO&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>github</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Build a Professional Real-Time Chat App with Docker, Flask, and Socket.IO</title>
      <dc:creator>Rodney Gitonga</dc:creator>
      <pubDate>Sat, 10 Jan 2026 20:15:39 +0000</pubDate>
      <link>https://forem.com/fytroy/build-a-professional-real-time-chat-app-with-docker-flask-and-socketio-43h1</link>
      <guid>https://forem.com/fytroy/build-a-professional-real-time-chat-app-with-docker-flask-and-socketio-43h1</guid>
      <description>&lt;p&gt;💬 Instant Messaging Made Simple: Meet ProChat&lt;/p&gt;

&lt;p&gt;Building a real-time chat application is often seen as a "Right of Passage" for developers. It touches on so many critical concepts: WebSockets, asynchronous events, database persistence, and containerization. &lt;/p&gt;

&lt;p&gt;Today, I want to share ProChat (DockerChat), a project that takes this concept to the next level. It's not just a "Hello World" chat app; it's a fully functional, professional-grade communication tool that you can spin up in seconds thanks to Docker.&lt;/p&gt;

&lt;p&gt;![ProChat Interface]&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k1bo6q5u6nptjm8lcc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k1bo6q5u6nptjm8lcc9.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚀 Why This Project?&lt;/p&gt;

&lt;p&gt;Most chat tutorials stop at "sending a message." ProChat aims to be something you'd actually want to use. We focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ease of Deployment: If you have Docker, you have the app. No &lt;code&gt;requirements.txt&lt;/code&gt; hell, no database setup scripts.&lt;/li&gt;
&lt;li&gt;User Experience: A modern, dark-themed UI that feels responsive and alive.&lt;/li&gt;
&lt;li&gt;Feature Completeness: Channels, private DMs, media support, and persistent history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ Key Features&lt;/p&gt;

&lt;p&gt;Here is what makes ProChat stand out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Real-Time Communication&lt;br&gt;
Using Flask-Socket.IO, messages are delivered instantly (&amp;lt; 100ms latency). Whether you are in the same room or connecting over the internet, the chat flows naturally without refreshing the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-Channel &amp;amp; Private Messaging&lt;br&gt;
Users can hop between topic-based channels (&lt;code&gt;general&lt;/code&gt;, &lt;code&gt;tech&lt;/code&gt;, &lt;code&gt;gaming&lt;/code&gt;) or slide into DMs for private 1-on-1 conversations. The UI clearly separates these contexts, keeping your conversations organized.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rich Media Support&lt;br&gt;
Text is boring! ProChat supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emojis: A built-in picker with 100+ emojis.&lt;/li&gt;
&lt;li&gt;Images &amp;amp; Videos: Drag, drop, and share media directly in the chat.&lt;/li&gt;
&lt;li&gt;Links: URLs are automatically detected and clickable.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smart Persistence&lt;br&gt;
We use SQLite with Docker Volumes to ensure your data is safe. Restart the container? Your messages are still there. It's the perfect balance of simplicity and reliability for a self-hosted app.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🛠️ The Tech Stack&lt;/p&gt;

&lt;p&gt;We stuck to a robust, Python-centric stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Python 3.11 with Flask 2.3.3&lt;/li&gt;
&lt;li&gt;Real-Time Engine: Socket.IO with Eventlet for high-concurrency handling.&lt;/li&gt;
&lt;li&gt;Database: SQLAlchemy ORM with SQLite.&lt;/li&gt;
&lt;li&gt;Frontend: Vanilla JS (ES6+), HTML5, and CSS3. No heavy frameworks, just pure performance.&lt;/li&gt;
&lt;li&gt;DevOps: Docker &amp;amp; Docker Compose for orchestration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🏁 Quick Start&lt;/p&gt;

&lt;p&gt;Want to try it out? It's incredibly simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo (or download the files)&lt;/li&gt;
&lt;li&gt;Run with Docker Compose:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Open your browser to &lt;code&gt;http://localhost:5000&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it! You can open multiple tabs to simulate different users, or share your IP with a friend on the same network to chat instantly.&lt;/p&gt;

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

&lt;p&gt;Containerizing this application was a game-changer. It ensures that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected Python versions are used.&lt;/li&gt;
&lt;li&gt;Dependencies are isolated.&lt;/li&gt;
&lt;li&gt;The database file is preserved in a volume, separating code from data.&lt;/li&gt;
&lt;li&gt;User setup is reduced to a single command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔮 What's Next?&lt;/p&gt;

&lt;p&gt;This project was a fantastic journey into full-stack development. Future updates might include Redis for scaling across multiple nodes or user authentication integration.&lt;/p&gt;

&lt;p&gt;Check out the code and let me know what you think! &lt;/p&gt;




&lt;p&gt;Happy Coding! 🚀&lt;a href="https://github.com/fytroy/DockerChat" rel="noopener noreferrer"&gt;Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>showdev</category>
      <category>docker</category>
      <category>python</category>
    </item>
    <item>
      <title>Introducing Neon Protocol: The Cyberpunk Theme Your VS Code Needs</title>
      <dc:creator>Rodney Gitonga</dc:creator>
      <pubDate>Sat, 10 Jan 2026 18:36:01 +0000</pubDate>
      <link>https://forem.com/fytroy/introducing-neon-protocol-the-cyberpunk-theme-your-vs-code-needs-4h8p</link>
      <guid>https://forem.com/fytroy/introducing-neon-protocol-the-cyberpunk-theme-your-vs-code-needs-4h8p</guid>
      <description>&lt;p&gt;Are you tired of the same old flat, desaturated coding environments? Do you dream of electric sheep and high-tech dystopias while you debug?&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Neon Protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What is Neon Protocol?&lt;br&gt;
Neon Protocol is a cyberpunk-inspired VS Code theme designed for developers who want a visually striking and energetic coding environment. It's not just another dark theme; it's a high-octane visual upgrade for your editor.&lt;/p&gt;

&lt;p&gt;We've combined high-saturation neon colors with deep, dark gray bases to create a theme that pops without burning your retinas. It's perfect for late-night coding sessions where you want to feel like a hacker in a sci-fi movie.&lt;/p&gt;

&lt;p&gt;Key Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High-Contrast Neon Colors&lt;/strong&gt;: Vibrant syntax highlighting that makes your code easy to read and exciting to look at.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dark Gray Background&lt;/strong&gt;: Designed to be easy on the eyes, reducing strain during those marathon coding sessions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cyberpunk Aesthetic&lt;/strong&gt;: Every color is chosen to contribute to a futuristic, techy vibe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Scope Coverage&lt;/strong&gt;: Whether you're writing JavaScript, Python, Java, C++, Rust, or Go, Neon Protocol has you covered with consistent and beautiful highlighting.&lt;br&gt;
Get It Now&lt;br&gt;
Ready to upgrade your protocol? You can install Neon Protocol directly from the internal marketplace or build it yourself!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Local Installation&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Clone the repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install dependencies: &lt;em&gt;npm install&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build the package: &lt;em&gt;npm run build&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Package it: &lt;em&gt;vsce package&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: &lt;em&gt;code --install-extension neon-protocol-0.0.1.vsix&lt;/em&gt;&lt;br&gt;
Customization&lt;br&gt;
Want to tweak the matrix? You can customize the color palette by editing &lt;br&gt;
&lt;strong&gt;src/design-tokens.js&lt;/strong&gt;&lt;br&gt;
and rebuilding the theme. It's your environment—make it yours.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Created with ❤️ for cyberpunk enthusiasts and developers who love vibrant colors.&lt;a href="https://github.com/fytroy/NeonProtocol.vsTheme" rel="noopener noreferrer"&gt;Repo&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>New Year, New You Portfolio Challenge</title>
      <dc:creator>Rodney Gitonga</dc:creator>
      <pubDate>Thu, 08 Jan 2026 19:12:16 +0000</pubDate>
      <link>https://forem.com/fytroy/new-year-new-you-portfolio-challenge-fpm</link>
      <guid>https://forem.com/fytroy/new-year-new-you-portfolio-challenge-fpm</guid>
      <description>&lt;p&gt;This is a submission for the &lt;strong&gt;&lt;em&gt;New Year, New You Portfolio Challenge&lt;/em&gt;&lt;/strong&gt; Presented by Google AI(&lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;About Me&lt;br&gt;
I am an Engineer, Analyst, and Builder working at the intersection of analytical rigor and creative engineering.&lt;/p&gt;

&lt;p&gt;My philosophy is simple: "Data is the question. Code is the answer."&lt;/p&gt;

&lt;p&gt;I don't just write scripts, I architect clarity. In a world drowning in noise, I build systems that filter, process, and visualize the signal. I built this portfolio to move beyond a generic resume and create a digital identity that truly reflects my "T-shaped" skillset—deep in Data/backend, but capable of beautiful, interactive Frontend work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://roygitonga-468651799098.us-central1.run.app/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;br&gt;


&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://roygitonga-468651799098.us-central1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;p&gt;How I Built It&lt;br&gt;
I wanted a site that felt fast, premium, and "alive," so I avoided heavy frameworks and stuck to high-performance Vanilla HTML/CSS/JS with a "Neo-Dark" aesthetic.&lt;/p&gt;

&lt;p&gt;Tech Stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Frontend: HTML5, CSS3 (Glassmorphism), JavaScript (ES6+).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Visualization: Custom HTML5 Canvas for the hero animation and Chart.js for the skills radar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Infrastructure: Dockerized Nginx server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deployment: Google Cloud Run via Cloud Build.&lt;br&gt;
The Google AI Workflow: I used Gemini as my pair programmer throughout this process. It was instrumental in:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Design System: Helping me define the "Neo-Dark" color palette and glassmorphism tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complex Logic: Writing the initial math for the "Data Constellation" particle system in the hero section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cloud Deployment: Debugging tricky IAM permission errors (roles/cloudbuild.builds.builder) during the Google Cloud Run deployment, turning hours of troubleshooting into a 5-minute fix.&lt;br&gt;
What I'm Most Proud Of:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The "Data Constellation" Hero: Instead of a static image, I built an interactive network of connecting nodes that reacts to the mouse. It perfectly symbolizes my work—connecting data points to create meaning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Skills Radar: I ditched the boring list of bullet points for a dynamic, data-driven Radar Chart that visualizes my balance between "Analytics," "DevOps," and "Programming."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Containerized Deployment: This isn't just a static bucket upload; it's a fully containerized Nginx application running on Google Cloud Run. It scales automatically and loads instantly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
  </channel>
</rss>
