vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.71k stars 26.84k forks source link

custom layout with styled components not work as expected #31712

Open mustafaskyer opened 2 years ago

mustafaskyer commented 2 years ago

What version of Next.js are you using?

12.0.4

What version of Node.js are you using?

v14.17.5

What browser are you using?

Chrome & Brave

What operating system are you using?

macOS

How are you deploying your application?

no deploying

Describe the Bug

Hello, any colors from styled components going through getLayout component (custom layout), these colors not effected and not applied to the styles

Expected Behavior

see background colors as expected.

To Reproduce

_document

import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
import { ServerStyleSheet } from 'styled-components';
class MyDocument extends Document {
    static async getInitialProps(ctx: DocumentContext) {
        const sheet = new ServerStyleSheet()
        const page = ctx.renderPage(
            App => props => sheet.collectStyles(
                <App {...props} />
            )
        )
        const styleTags = sheet.getStyleElement()
        return { ...page, styleTags, locale: ctx.locale }
    }

    render = () => (
        <Html dir={this.props.locale === 'ar' ? 'rtl' : 'ltr'}>
            <Head >
                {/* {this.props.styleTags} */}
            </Head>
            <body>
                <Main />
                <NextScript />
            </body>
        </Html>
    )
}

export default MyDocument

_app

import { ReactElement, useEffect, useMemo, useState } from 'react';
import type { AppProps } from 'next/app'
import { NextPage } from 'next'
import { appWithTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { ThemeProvider } from "styled-components"
import { GlobalStyles } from "themes/ThemeConfig"
import useDarkMode from 'use-dark-mode';
import 'antd/dist/antd.css';
import 'styles/variables.less';

type NextPageWithLayout = NextPage & {
  getLayout?: (page: ReactElement) => any
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout || ((page: ReactElement) => page)
  const { locale } = useRouter();
  const darkMode = useDarkMode(true)
  const [isMounted, setIsMounted] = useState(false)
  const dir = locale === 'ar' ? 'rtl' : 'ltr'

  useEffect(() => {
   setIsMounted(true)
  }, [])

  useEffect(() => {
    document.documentElement.dir = dir;
  }, [dir]);

  return getLayout(
    <ThemeProvider theme={{ mode: 'light' }}>
      <GlobalStyles locale={locale} />
      {isMounted && <Component {...pageProps} />}
    </ThemeProvider>
  )
}

export default appWithTranslation(MyApp);

index

import DashboardLayout from 'layouts/DashBoardLayout';
import type { NextPage } from 'next'
import { DashboardHeader } from 'components/index';

const Home: NextPage = () => {
  return (
    <div >
      <DashboardHeader />
      <h1 >{'Title'}</h1>
    </div>
  );
}

Home.getLayout = (page: any) => (
  <DashboardLayout >
    {page}
  </DashboardLayout>
)

export default Home

Dashboard Layout

import { color } from "colors";
import styled from "styled-components";
const DashboardLayout = (props) => {
    return (
        <>
            <StyledDashboardContainer variant={'appcolor'} />
            {props.children}
        </>
    )
}

export const StyledDashboardContainer = styled.div`
  background-color: ${color};
  padding: 4rem;
  border: 5px solid ${color};
`;

export default DashboardLayout;

colors

import theme from "styled-theming";

export const color = theme.variants("mode", "variant", {
  appcolor: { light: "#000", dark: "#eee" },
});
ljluestc commented 1 year ago

To fix the issue, you need to update your _app.tsx file to pass the correct theme mode (light or dark) to the ThemeProvider. In your case, you are always passing { mode: 'light' } to the theme, so the color variant for the light mode will be applied. To apply the dark mode variant, you need to read the darkMode.value from useDarkMode and pass it to the theme.

import { ReactElement, useEffect, useMemo, useState } from 'react';
import type { AppProps } from 'next/app';
import { NextPage } from 'next';
import { appWithTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { ThemeProvider } from 'styled-components';
import { GlobalStyles } from 'themes/ThemeConfig';
import useDarkMode from 'use-dark-mode';
import 'antd/dist/antd.css';
import 'styles/variables.less';

type NextPageWithLayout = NextPage & {
  getLayout?: (page: ReactElement) => any;
};

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout;
};

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout || ((page: ReactElement) => page);
  const { locale } = useRouter();
  const darkMode = useDarkMode(true); // Pass the default mode (true) to useDarkMode

  const dir = locale === 'ar' ? 'rtl' : 'ltr';

  useEffect(() => {
    document.documentElement.dir = dir;
  }, [dir]);

  return (
    <ThemeProvider theme={{ mode: darkMode.value ? 'dark' : 'light' }}>
      {/* Use darkMode.value to set the correct theme mode */}
      <GlobalStyles locale={locale} />
      {getLayout(<Component {...pageProps} />)}
    </ThemeProvider>
  );
}

export default appWithTranslation(MyApp);