Git Product home page Git Product logo

Comments (9)

linkb15 avatar linkb15 commented on June 12, 2024 1

In my case, I have 2 theme providers where one is forced and one is not forced. And in App Router, we can use the grouping folder (group1) and (group2).

Put the non forced in (group1) folder and forced one inside the layout of (group2) folder. In this case, the layouts will affects only the pages inside each own groups.

from next-themes.

rafaelquintanilha avatar rafaelquintanilha commented on June 12, 2024 1

That was my case, but I suppose you can set resolvedTheme to a useRef and then just pass it when unmounting the component.

Open two pages, one with the light theme and one with your implementation of forced dark. Opening the dark theme page will change the theme of the first one.

Also selecting any theme on the main website theme selector will change the dark theme page.

You're right. Sorry, I just covered my very narrow use-case.

What I ended up doing, however, is what is described here. That works fine with Tailwind because I can set the dark specifier on the inner component. It works correctly in multiple tabs as well. However, if it's important for you, this won't change resolvedTheme, as pointed out.

from next-themes.

dvvolynkin avatar dvvolynkin commented on June 12, 2024

I have 1 page that needs to be with a forced theme

having two global folders looks too much in this case

from next-themes.

dvvolynkin avatar dvvolynkin commented on June 12, 2024

I made a provider like this
But it doesn't solve the problem completely, for a second when loading the original theme appears

"use client"

import * as React from "react";
import { ThemeProvider as NextJSThemesProvider } from "next-themes";
import { ThemeProviderProps as NextJSThemesProviderProps } from "next-themes/dist/types";

interface ForcedThemeContextProps {
  forcedTheme: string | null;
  setForcedTheme: React.Dispatch<React.SetStateAction<string | null>>;
}

const ForcedThemeContext = React.createContext<ForcedThemeContextProps | undefined>(undefined);

export function useForcedThemeControl(): ForcedThemeContextProps {
  const context = React.useContext(ForcedThemeContext);
  if (!context) {
    throw new Error("useForcedThemeControl must be used within a ForcedThemeContextProvider");
  }
  return context;
}

interface ForcedThemeContextProviderProps {
  children: React.ReactNode;
}

export function ForcedThemeContextProvider({ children }: ForcedThemeContextProviderProps): JSX.Element {
  const [forcedTheme, setForcedTheme] = React.useState<string | null>(null);
  return (
    <ForcedThemeContext.Provider value={{ forcedTheme, setForcedTheme }}>
      {children}
    </ForcedThemeContext.Provider>
  );
}

interface ThemeSetterProps {
  children: React.ReactNode;
}

function DarkTheme({ children }: ThemeSetterProps): JSX.Element {
  const { setForcedTheme } = useForcedThemeControl();
  React.useEffect(() => {
    setForcedTheme("dark");
  }, []);
  return <>{children}</>;
}

function LightTheme({ children }: ThemeSetterProps): JSX.Element {
  const { setForcedTheme } = useForcedThemeControl();
  React.useEffect(() => {
    setForcedTheme("light");
  }, []);
  return <>{children}</>;
}

interface CombinedThemeProviderProps extends NextJSThemesProviderProps {
  children: React.ReactNode;
}

const CombinedThemeProvider = ({ children, ...props }: CombinedThemeProviderProps): JSX.Element => {
  const { forcedTheme } = useForcedThemeControl();
  return (
    <NextJSThemesProvider {...props} forcedTheme={forcedTheme || undefined}>
      {children}
    </NextJSThemesProvider>
  );
};

function ThemeProvider({ children, ...props }: CombinedThemeProviderProps): JSX.Element {
  return (
    <ForcedThemeContextProvider>
      <CombinedThemeProvider {...props}>
        {children}
      </CombinedThemeProvider>
    </ForcedThemeContextProvider>
  );
}

export {
  ThemeProvider,
  LightTheme,
  DarkTheme
}

from next-themes.

rafaelquintanilha avatar rafaelquintanilha commented on June 12, 2024

I was facing the same problem. Creating route segments would be enough, but I wanted to avoid this as I also had only one page with forced theme.

The solution I came up with was the following:

  1. Create a DarkModeWrapper client component:
"use client";

import { useTheme } from "next-themes";
import { useEffect } from "react";

export function DarkModeWrapper({ children }: { children: React.ReactNode }) {
  const { setTheme } = useTheme();

  useEffect(() => {
    setTheme("dark");
    return () => {
      setTheme("light");
    };
  }, []);

  return children;
}
  1. Wrap the desired page with it:
import { DarkModeWrapper } from "@/components/common/DarkModeWrapper";

export default Page = () => {
  return (
    <DarkModeWrapper>
      <h1>Hello Dark Mode</h1>
    </DarkModeWrapper>
  );
};

from next-themes.

dvvolynkin avatar dvvolynkin commented on June 12, 2024

Isn't setTheme setting theme globally?

In this case, your local wrapper is affecting the whole website

    setTheme("dark");
    return () => {
      setTheme("light");
    };
  }, []);

This code will make the dark theme on one page but will set the light theme for other pages even if the dark theme is selected there.

from next-themes.

rafaelquintanilha avatar rafaelquintanilha commented on June 12, 2024

Isn't setTheme setting theme globally?

In this case, your local wrapper is affecting the whole website

    setTheme("dark");
    return () => {
      setTheme("light");
    };
  }, []);

This code will make the dark theme on one page but will set the light theme for other pages even if the dark theme is selected there.

That was my case, but I suppose you can set resolvedTheme to a useRef and then just pass it when unmounting the component.

from next-themes.

dvvolynkin avatar dvvolynkin commented on June 12, 2024

That was my case, but I suppose you can set resolvedTheme to a useRef and then just pass it when unmounting the component.

Open two pages, one with the light theme and one with your implementation of forced dark.
Opening the dark theme page will change the theme of the first one.

Also selecting any theme on the main website theme selector will change the dark theme page.

from next-themes.

pacocoursey avatar pacocoursey commented on June 12, 2024

I solved this in a hacky way: using usePathname() in a client component, then determining whether the theme should be forced based on some regex matching for specific paths. Then, I passed the forced theme to the ThemeProvider. Pseudo code example here:

"use client"
import { usePathname } from 'next/navigation'
import { ThemeProvider } from 'next-themes'

export const Providers = (props) => {
	const pathname = usePathname();
	const forcedThemeFromPathname = pathname === "/dark-only" ? "dark" : undefined;

	return (
		<ThemeProvider forcedTheme={forcedThemeFromPathname}>
			{props.children}
		</ThemeProvider>
	)
}

I'd like to find a better solution but so far I've got nothing. We need a way to pass information up from a page.tsx (server component) file to the root layout.

from next-themes.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.