From 3a874c82f7c4d7306835a36e9e807316d822be8d Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Wed, 25 Feb 2026 09:18:46 +0100 Subject: [PATCH 1/3] ci: add github actions workflow for build and lint --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..778cac5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI Enhancement + +on: + pull_request: + branches: [ main, develop ] + push: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' # Use the project's current version + cache: 'npm' # Technical Note: Configure caching for speed + + - name: Install Dependencies + run: npm ci # Technical Note: Cleaner/faster than 'npm install' + + - name: Run Lint + run: npm run lint + + - name: Build Project + run: npm run build # The core requirement of this feature \ No newline at end of file From 624f52dddb057409e01d686acf691cd5432650ba Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Wed, 25 Feb 2026 09:46:47 +0100 Subject: [PATCH 2/3] fix: resolve React lint error in ThemeToggle: - Replaced useEffect state update with lazy state initialization - Prevents cascading renders and improves mount performance - Resolves 'react-hooks/set-state-in-effect' failure in GitHub Actions" --- components/ui/ThemeToggle.tsx | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 components/ui/ThemeToggle.tsx diff --git a/components/ui/ThemeToggle.tsx b/components/ui/ThemeToggle.tsx new file mode 100644 index 0000000..63c3379 --- /dev/null +++ b/components/ui/ThemeToggle.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Sun, Moon } from "lucide-react"; + +export function ThemeToggle() { + // 1. Initialize state with a function so it only runs once on mount + const [dark, setDark] = useState(() => { + if (typeof window !== "undefined") { + return localStorage.getItem("theme") === "dark"; + } + return false; + }); + + // 2. This effect now only handles the DOM class, not state updates + useEffect(() => { + if (dark) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + }, [dark]); + + const toggleTheme = () => { + setDark((prev) => { + const newDark = !prev; + localStorage.setItem("theme", newDark ? "dark" : "light"); + return newDark; + }); + }; + + return ( + + ); +} From df051e29a3efcf8fbb991587fc7fa763c50658c2 Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Wed, 25 Feb 2026 09:57:24 +0100 Subject: [PATCH 3/3] fix: remove duplicate code and fix hook placement" --- components/ui/ThemeToggle.tsx | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/components/ui/ThemeToggle.tsx b/components/ui/ThemeToggle.tsx index f0bb3d9..acc816d 100644 --- a/components/ui/ThemeToggle.tsx +++ b/components/ui/ThemeToggle.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from "react"; import { Sun, Moon } from "lucide-react"; export function ThemeToggle() { - // 1. Initialize state with a function so it only runs once on mount + // 1. Initialize state properly to avoid cascading renders const [dark, setDark] = useState(() => { if (typeof window !== "undefined") { return localStorage.getItem("theme") === "dark"; @@ -12,7 +12,7 @@ export function ThemeToggle() { return false; }); - // 2. This effect now only handles the DOM class, not state updates + // 2. Synchronize the HTML class with the state useEffect(() => { if (dark) { document.documentElement.classList.add("dark"); @@ -27,25 +27,6 @@ export function ThemeToggle() { localStorage.setItem("theme", newDark ? "dark" : "light"); return newDark; }); - const [dark, setDark] = useState(false); - - useEffect(() => { - const saved = localStorage.getItem("theme"); - if (saved === "dark") { - document.documentElement.classList.add("dark"); - setDark(true); - } - }, []); - - const toggleTheme = () => { - if (dark) { - document.documentElement.classList.remove("dark"); - localStorage.setItem("theme", "light"); - } else { - document.documentElement.classList.add("dark"); - localStorage.setItem("theme", "dark"); - } - setDark(!dark); }; return ( @@ -56,5 +37,4 @@ export function ThemeToggle() { {dark ? : } ); -} -} +} \ No newline at end of file