Skip to content

Conversation

@sachingwala
Copy link

@sachingwala sachingwala commented Dec 13, 2025

This PR resolves a dark mode UI issue where article titles became invisible
on hover due to insufficient contrast.

Changes included:

  • Fixed hover styles for article cards in dark mode
  • Added a proper dark/light theme toggle in the navbar
  • Configured ThemeProvider and Tailwind dark mode support
  • Prevented hydration mismatch issues

These changes improve accessibility, consistency, and overall user experience.
Fixes #15

Summary by CodeRabbit

Release Notes

  • New Features

    • Added dark mode support with a new theme toggle button for seamless switching between light and dark modes.
    • Redesigned application header with improved responsive layout and enhanced visual styling.
  • Style

    • Updated footer border styling for improved visual consistency.
    • Enhanced dark mode compatibility throughout the interface.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

Walkthrough

This PR introduces dark mode support by integrating next-themes for theme management, updating the header with responsive styling and a sticky border, simplifying the footer border styling, and adding a new ModeToggle component for theme switching. The ThemeProvider component's API is refactored to enforce fixed theme configuration.

Changes

Cohort / File(s) Summary
Theme Management & Dependencies
components/mode-toggle.tsx, components/theme-provider.tsx, package.json
Added ModeToggle client component using next-themes to toggle between dark/light themes with Sun/Moon icons; refactored ThemeProvider to enforce fixed configuration (class attribute, system default, system detection enabled); added next-themes and @radix-ui/react-slot dependencies.
Page & Footer Styling
app/page.tsx, components/footer.tsx
Updated page header with dark mode gradient container, sticky bordered header, gradient text title, and redesigned action area with ModeToggle placeholder and styled Submit Article button; simplified footer top border from gradient combination to plain gray border.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • ThemeProvider API surface change: The component signature was narrowed from accepting ThemeProviderProps with spread forwarding to accepting only children; verify all existing usages are compatible with the fixed configuration (attribute="class", defaultTheme="system", enableSystem).
  • New dependencies: Confirm version compatibility of next-themes ^0.4.6 and @radix-ui/react-slot ^1.2.4 with existing package versions.
  • Styling consistency: Verify dark mode gradient classes and responsive design work across all affected components.

Suggested reviewers

  • ceilican
  • Zahnentferner

Poem

🌙 A hop through the shadows, a toggle so neat,
Dark mode arrives, making day-code complete,
Themes wrap like burrows, from light into shade,
The rabbit's CSS dreams, gently displayed. ✨

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #15 requires adding a new stablecoin article and updating the articles index, but the changeset only modifies styling, adds theme toggle components, and updates dependencies with no article content changes. Add the new article content and update the articles index to meet issue #15 requirements, or verify the correct issue is linked.
Out of Scope Changes check ⚠️ Warning Changes to theme provider configuration, mode toggle component, and dark mode styling are not mentioned in issue #15 objectives, which focus on adding article content. Either remove the out-of-scope theme/styling changes or link them to a separate issue that documents these UI improvements.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title describes fixing dark mode hover issues and adding theme toggle support, which aligns with actual changes to styling and the new ModeToggle component, but the PR objectives mention adding a new article about stablecoins. Clarify whether the primary goal is the dark mode/theme fixes or adding the new stablecoin article, as the title and objectives appear misaligned.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
components/footer.tsx (1)

27-38: Missing dark mode styles in footer.

The footer lacks dark mode variants, which is inconsistent with the dark mode support added elsewhere in this PR. Several elements will have poor contrast in dark mode:

  • Line 27: border-gray-200 needs dark:border-zinc-800
  • Line 34: text-gray-600 needs dark:text-gray-400
  • Line 38: text-gray-600 needs dark:text-gray-400
-    <footer className="border-t border-gray-200 bg-gradient-to-r from-[#228B22]/5 via-[#91A511]/5 to-[#FFBF00]/5 backdrop-blur-sm mt-20">
+    <footer className="border-t border-gray-200 dark:border-zinc-800 bg-gradient-to-r from-[#228B22]/5 via-[#91A511]/5 to-[#FFBF00]/5 dark:from-[#228B22]/10 dark:via-[#91A511]/10 dark:to-[#FFBF00]/10 backdrop-blur-sm mt-20">

Similarly, update text colors with dark variants throughout the footer.

app/page.tsx (1)

78-97: Loading and error states lack dark mode support.

The loading spinner and error message screens still use light-only colors (from-green-50, via-yellow-50, text-gray-600), which will appear broken in dark mode.

Apply dark mode variants to match the main content area:

-      <div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 flex items-center justify-center">
+      <div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 dark:from-zinc-900 dark:via-zinc-900 dark:to-black flex items-center justify-center">
         <div className="text-center">
           <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#228B22] mx-auto mb-4"></div>
-          <p className="text-gray-600">Loading articles...</p>
+          <p className="text-gray-600 dark:text-zinc-400">Loading articles...</p>
         </div>
       </div>

Apply the same pattern to the error state (lines 91-96).

🧹 Nitpick comments (1)
app/page.tsx (1)

10-10: Unused import: ModeToggle is imported but not rendered.

The ModeToggle component is imported but commented out on line 140. Either render it or remove the import to avoid dead code.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 113d28d and 56e1e03.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • app/page.tsx (2 hunks)
  • components/footer.tsx (1 hunks)
  • components/mode-toggle.tsx (1 hunks)
  • components/theme-provider.tsx (1 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
components/mode-toggle.tsx (1)
components/ui/button.tsx (1)
  • Button (56-56)
🔇 Additional comments (3)
package.json (1)

12-19: LGTM!

The new dependencies are appropriate for the dark mode feature:

  • next-themes is the standard solution for theme management in Next.js apps
  • @radix-ui/react-slot supports the Button component's composition pattern
app/page.tsx (1)

102-161: LGTM on header dark mode implementation!

The header correctly implements dark mode with appropriate border, background, and text color variants. The sticky positioning and backdrop blur provide a polished UX.

components/theme-provider.tsx (1)

5-15: LGTM!

The ThemeProvider configuration is correct:

  • attribute="class" aligns with Tailwind's dark mode strategy
  • defaultTheme="system" respects user OS preferences
  • enableSystem enables automatic theme detection

Consider adding disableTransitionOnChange to prevent a brief flash of styles during theme transitions:

     <NextThemesProvider
       attribute="class"
       defaultTheme="system"
       enableSystem
+      disableTransitionOnChange
     >

This is optional and depends on whether you observe any visual glitches during theme switching.

Comment on lines +8 to +27
export function ModeToggle() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);

useEffect(() => setMounted(true), []);
if (!mounted) return null;

return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
aria-label="Toggle theme"
>
{theme === "dark" ? (
<Sun className="h-5 w-5" />
) : (
<Moon className="h-5 w-5" />
)}
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use resolvedTheme instead of theme for accurate theme detection.

When defaultTheme is "system" (as configured in ThemeProvider), the theme value can be "system" rather than the actual resolved theme ("dark" or "light"). This causes incorrect icon display and toggle behavior.

 export function ModeToggle() {
-  const { theme, setTheme } = useTheme();
+  const { resolvedTheme, setTheme } = useTheme();
   const [mounted, setMounted] = useState(false);

   useEffect(() => setMounted(true), []);
   if (!mounted) return null;

   return (
     <Button
       variant="ghost"
       size="icon"
-      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
+      onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
       aria-label="Toggle theme"
     >
-      {theme === "dark" ? (
+      {resolvedTheme === "dark" ? (
         <Sun className="h-5 w-5" />
       ) : (
         <Moon className="h-5 w-5" />
       )}
     </Button>
   );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function ModeToggle() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
aria-label="Toggle theme"
>
{theme === "dark" ? (
<Sun className="h-5 w-5" />
) : (
<Moon className="h-5 w-5" />
)}
</Button>
export function ModeToggle() {
const { resolvedTheme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
aria-label="Toggle theme"
>
{resolvedTheme === "dark" ? (
<Sun className="h-5 w-5" />
) : (
<Moon className="h-5 w-5" />
)}
</Button>
);
}
🤖 Prompt for AI Agents
In components/mode-toggle.tsx around lines 8 to 27, the component uses `theme`
which can be the literal "system" when defaultTheme is "system", causing
incorrect icon and toggle behavior; switch to using `resolvedTheme` from
useTheme for accurate current theme detection (use it for rendering the Sun/Moon
icon) and use `setTheme(resolvedTheme === "dark" ? "light" : "dark")` for the
onClick toggle; keep the mounted guard and import/useResolvedTheme as provided
by next-themes (or destructure `resolvedTheme` from useTheme), and ensure you
fall back safely if `resolvedTheme` is undefined.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant