Skip to content

feat: implement global dark/light mode toggle (#48)#50

Open
atmihaa-06 wants to merge 4 commits into
jpdevhub:mainfrom
atmihaa-06:feat/theme-toggle
Open

feat: implement global dark/light mode toggle (#48)#50
atmihaa-06 wants to merge 4 commits into
jpdevhub:mainfrom
atmihaa-06:feat/theme-toggle

Conversation

@atmihaa-06
Copy link
Copy Markdown
Contributor

@atmihaa-06 atmihaa-06 commented May 31, 2026

Description
This PR introduces a global theme-switching system to the FreshScan AI platform, allowing users to toggle between dark and light modes. This enhances accessibility and user experience by providing a high-contrast theme suited for different environments.

Key Changes
Theme Utility: Created src/lib/theme.ts to manage theme state persistence using localStorage and system preference detection.

Dynamic Styling: Updated index.css to leverage CSS custom properties, ensuring all UI components respond automatically to theme changes.

Initialization: Integrated initTheme() in main.tsx to prevent "theme flashing" (flicker) when the page loads.

UI Integration: Added a centralized THEME toggle button to the Navbar, ensuring easy access across all pages.

Refinement: Optimized typography colors and glass-panel transparency to maintain readability and contrast in both modes.

Implementation Details
State Management: The theme selection is persisted in localStorage.

Design System: Utilized Tailwind's utility-first approach paired with CSS variables defined in the :root and :root.light selectors.

Layout: Cleaned up redundant UI elements by removing the floating toggle button, centralizing controls in the navigation bar for a cleaner aesthetic.

Verification
[x] Toggle functionality confirmed in both Chrome and Firefox.

[x] Theme choice persists across browser reloads.

[x] Contrast ratios checked for all main headings (e.g., "Fish Freshness") in light mode.

Screenshots
Dark Mode:
dark

Light Mode:
lightmode

Closes #48


Summary by cubic

Adds a global dark/light mode toggle with CSS variables and a Navbar button. Adds global error toasts and centralizes API error handling for clearer network/server failures.

  • New Features

    • Theme toggle: persisted via localStorage, initialized early with initTheme() to prevent flash, and powered by CSS variables in index.css.
    • Global toasts: added react-hot-toast and <Toaster /> in App.tsx for network/server error notifications.
    • 404 page: added a catch-all Not Found route and page.
  • Refactors

    • API: introduced safeFetch() and handleResponse() in src/lib/api.ts; all uploads and Grad-CAM now share consistent error handling with friendly messages for 5xx and network drops.
    • Theme tokens: mapped to root variables (:root/:root.light), added heading/body color transitions, and improved light-mode contrast.
    • Auth: hardened OAuth start flow with clearer status/errors in AuthPage.

Written for commit 82e72c6. Summary will update on new commits.

Review in cubic

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

@atmihaa-06 is attempting to deploy a commit to the karan3431's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Copy Markdown

🎉 Thank you for your Pull Request! We're thrilled to have your contribution to FreshScan AI.

Before we review, please make sure you have:

  • Followed the CONTRIBUTING.md guidelines.
  • Ensured all automated CI checks (linting, tests) are passing.
  • Checked that your commit messages follow the Conventional Commits format.

A maintainer will review your code as soon as possible!

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/pages/NotFound.tsx">

<violation number="1" location="src/pages/NotFound.tsx:7">
P1: NotFound page hardcodes `text-gray-*` Tailwind utility classes that do not respond to the global dark/light theme. In the default dark mode (background `#131313`), `text-gray-800`, `text-gray-600`, and `text-gray-500` produce extremely poor contrast, making the page nearly unreadable and breaking the theme contract established by this PR.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/pages/NotFound.tsx
export default function NotFound() {
return (
<div className="flex flex-col items-center justify-center min-h-[60vh] text-center px-4">
<h1 className="text-6xl font-bold text-gray-800 mb-4">404</h1>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: NotFound page hardcodes text-gray-* Tailwind utility classes that do not respond to the global dark/light theme. In the default dark mode (background #131313), text-gray-800, text-gray-600, and text-gray-500 produce extremely poor contrast, making the page nearly unreadable and breaking the theme contract established by this PR.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/pages/NotFound.tsx, line 7:

<comment>NotFound page hardcodes `text-gray-*` Tailwind utility classes that do not respond to the global dark/light theme. In the default dark mode (background `#131313`), `text-gray-800`, `text-gray-600`, and `text-gray-500` produce extremely poor contrast, making the page nearly unreadable and breaking the theme contract established by this PR.</comment>

<file context>
@@ -0,0 +1,20 @@
+export default function NotFound() {
+  return (
+    <div className="flex flex-col items-center justify-center min-h-[60vh] text-center px-4">
+      <h1 className="text-6xl font-bold text-gray-800 mb-4">404</h1>
+      <h2 className="text-2xl font-semibold text-gray-600 mb-6">Page Not Found</h2>
+      <p className="text-gray-500 mb-8">
</file context>

Comment thread src/lib/theme.ts Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a global dark/light theme toggle (persisted via localStorage) and introduces app-wide error toasts for API/network failures, plus a new catch-all 404 route/page.

Changes:

  • Added theme initialization + toggle utilities and wired early theme init to reduce load flicker.
  • Refactored API fetching to use a shared wrapper with toast-based network/server error notifications.
  • Added a NotFound page and a * catch-all route.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/pages/NotFound.tsx New 404 page for unmatched routes.
src/pages/AuthPage.tsx Simplifies redirect status handling and adds guarded OAuth initiation.
src/main.tsx Calls initTheme() before rendering to prevent theme flash.
src/lib/theme.ts Adds theme toggle/init helpers (persistence + root class toggle).
src/lib/api.ts Adds safeFetch + shared response handling and toast error notifications.
src/index.css Introduces CSS-variable-driven theme tokens and light-mode overrides.
src/components/Navbar.tsx Adds a global THEME toggle button in the Navbar.
src/components/Layout.tsx (Currently) adds an unused theme import.
src/App.tsx Adds react-hot-toast Toaster and a * route to NotFound.
package.json Adds react-hot-toast.
package-lock.json Locks dependency changes for react-hot-toast and transitive deps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/Layout.tsx
import Navbar from './Navbar';
import BottomNav from './BottomNav';
import Footer from './Footer';
import { toggleTheme } from '../lib/theme';
Comment thread src/lib/theme.ts Outdated
Comment on lines +1 to +13
// src/lib/theme.ts
export const toggleTheme = () => {
const isLight = document.documentElement.classList.toggle('light');
localStorage.setItem('theme', isLight ? 'light' : 'dark');
};

export const initTheme = () => {
const savedTheme = localStorage.getItem('theme');
// Apply saved preference, or default to dark mode
if (savedTheme === 'light') {
document.documentElement.classList.add('light');
}
}; No newline at end of file
Comment thread src/pages/NotFound.tsx
Comment on lines +6 to +17
<div className="flex flex-col items-center justify-center min-h-[60vh] text-center px-4">
<h1 className="text-6xl font-bold text-gray-800 mb-4">404</h1>
<h2 className="text-2xl font-semibold text-gray-600 mb-6">Page Not Found</h2>
<p className="text-gray-500 mb-8">
Oops! The page you are looking for doesn't exist or has been moved.
</p>
<Link
to="/"
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
Return Home
</Link>
Comment thread src/components/Navbar.tsx
Comment on lines +96 to +101
<button
onClick={toggleTheme}
className="font-[family-name:var(--font-mono)] text-[10px] tracking-widest text-on-surface-variant hover:text-neon transition-colors duration-200 border border-outline-variant/30 px-3 py-1"
>
THEME
</button>
Comment thread src/lib/api.ts
Comment on lines +42 to +55
async function handleResponse(res: Response): Promise<Response> {
if (res.ok) return res;

// Handle 5xx errors (Server Side)
if (res.status >= 500) {
toast.error("Server error. Please try again later.");
} else {
// Handle 4xx errors
const err = await res.json().catch(() => ({ detail: res.statusText }));
throw new Error((err as { detail?: string }).detail || `HTTP ${res.status}`);
}

throw new Error(`HTTP ${res.status}`);
}
Comment thread src/lib/api.ts
Comment thread src/index.css
Comment on lines +56 to +60
:root.light {
--bg: #ffffff;
--on-surface: #121212;
--heading-color: #121212;
}
@jpdevhub
Copy link
Copy Markdown
Owner

Resolve the issues raised by copilot !

@atmihaa-06
Copy link
Copy Markdown
Contributor Author

I've addressed all the feedback:

Theme/UX: Implemented robust, system-aware theming with localStorage fallback and try/catch safety. Updated the 404 page and CSS variables to ensure full theme compatibility and contrast.

Accessibility: Added type="button" to the theme toggle.

API Stability: Updated api.ts to throw user-friendly error messages and consolidated the logic within safeFetch.

Everything is now consistent, accessible, and theme-aware. Ready for final review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FE-08: Dark / Light Mode Toggle

3 participants