From 3994d32d35d16afdf70cd68e29d1cdaafca37e21 Mon Sep 17 00:00:00 2001 From: Anthony G <1@anthony.sh> Date: Tue, 11 Aug 2026 08:58:58 +0200 Subject: [PATCH] feat: add ThemeToggle component with next-themes --- package-lock.json | 11 ++++++++ package.json | 1 + src/components/ThemeToggle.tsx | 50 ++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 src/components/ThemeToggle.tsx diff --git a/package-lock.json b/package-lock.json index b63427c..161f41e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "mariadb": "^3.5.3", "next": "^16.3.0", "next-intl": "^4.13.6", + "next-themes": "^0.4.6", "prisma": "^7.9.1", "react": "^19.2.8", "react-dom": "^19.2.8" @@ -7096,6 +7097,16 @@ "integrity": "sha512-M2L8jtPEAXj0CPmXbiW66THdr3OnDqA9IsU1hqv3CdxtVow3Bl9eXPdT9Opeji7L4AFrUZ016dJOs+CoTw66OA==", "license": "MIT" }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", diff --git a/package.json b/package.json index 2f8e4f7..9b42b22 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "mariadb": "^3.5.3", "next": "^16.3.0", "next-intl": "^4.13.6", + "next-themes": "^0.4.6", "prisma": "^7.9.1", "react": "^19.2.8", "react-dom": "^19.2.8" diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx new file mode 100644 index 0000000..3fdeca6 --- /dev/null +++ b/src/components/ThemeToggle.tsx @@ -0,0 +1,50 @@ +'use client' + +import { useTheme } from 'next-themes' +import { useEffect, useState } from 'react' + +function SunIcon() { + return ( + + ) +} + +function MoonIcon() { + return ( + + ) +} + +export function ThemeToggle() { + const { theme, setTheme } = useTheme() + const [mounted, setMounted] = useState(false) + + useEffect(() => { setMounted(true) }, []) + + if (!mounted) { + // Prevents hydration mismatch -- renders a same-size placeholder + return
+ } + + return ( + + ) +}