DEV Community

Cover image for ­čÄĘ Light mode e Dark mode e temas customizados com Styled-components e NextJS com Typescript.
Jairo J├║nior
Jairo J├║nior

Posted on • Updated on

­čÄĘ Light mode e Dark mode e temas customizados com Styled-components e NextJS com Typescript.

Introdu├ž├úo as tecnologias

NextJS

  • NextJS ├ę um framework React com o intuito de SSR (Server Side Rendering).

Styled-components

  • Styled-components ├ę uma biblioteca para React que permite a escrita de CSS in JS.

Vamos come├žar!

Criando a aplica├ž├úo

  • Para criar a aplica├ž├úo iremos rodar o comando yarn create next-app <nome do projeto>, ap├│s executar esse comando ele ir├í come├žar a criar o seu projeto NextJs (pode demorar um pouquinho).

Estruturando a aplica├ž├úo

  • Eu divido a minha estrutura do NextJS criando uma pasta src e colocando as minhas pastas e arquivos l├í, apenas deixando a pasta public de fora, mas isso vai de acordo com o seu gosto!

Configurando o Typescript

  • Para configurar o Typescript no projeto ├ę bem simples, iremos adicion├í-lo como depend├¬ncia de desenvolvimento no projeto yarn add typescript -D
  • Agora iremos criar o arquivo tsconfig.json, no seu terminal escreva touch tsconfig.json
  • Iremos modificar o nome das nossas p├íginas dentro de src/pages removendo a extens├úo .js e adicionando .tsx
  • E se tudo deu certo pelo menos eu espero que sim, podemos rodar yarn dev no nosso terminal e abrir├í a p├ígina do NextJS na porta :3000

Estrutura de pastas

Configurando o Styled-components

  • Vamos come├žar adicionado o styled-components no projeto, portanto escreve no seu terminal yarn add styled-components
  • Iremos criar um arquivo chamado _document.tsx dentro de src/pages, nele haver├í o seguinte conte├║do. Isso ├ę para as inje├ž├Áes de estilo no server side rendering.

    import Document, { DocumentContext } from 'next/document';
    import { ServerStyleSheet } from 'styled-components';
    
    export default class MyDocument extends Document {
      static async getInitialProps(ctx: DocumentContext) {
        const sheet = new ServerStyleSheet();
        const originalRenderPage = ctx.renderPage;
    
        try {
          ctx.renderPage = () =>
            originalRenderPage({
              enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
            });
    
          const initialProps = await Document.getInitialProps(ctx);
          return {
            ...initialProps,
            styles: (
              <>
                {initialProps.styles}
                {sheet.getStyleElement()}
              </>
            ),
          };
        } finally {
          sheet.seal();
        }
      }
    }
    
  • Dentro da nossa pasta src/styles vamos criar o arquivo styled.d.ts para sobrescrevermos os tipos do styled-components.

    import 'styled-components';
    
    declare module 'styled-components' {
      export interface DefaultTheme {
        title: string;
        colors: {
          primary: string;
          secundary: string;
    
          background: string;
          text: string;
        };
        fontSizes: {
          small: string;
          medium: string;
          large: string;
        };
      }
    
      export interface CustomTheme {
        title: string;
        colors: {
          primary: string;
          secundary: string;
    
          background: string;
          text: string;
        };
      }
    }
    
  • Dentro no nosso arquivo tsconfig.json vamos adicionar o seguinte atributo.

    ....
    "files": [
        "src/styles/styled.d.ts"
      ]
    
  • Vamos rapidinho criar um estilo global para a aplica├ž├úo, crie o arquivo global.ts dentro de src/styles

    import { createGlobalStyle } from 'styled-components';
    
    export default createGlobalStyle`
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        outline: 0;
      }
    
      body {
        background: #fff;
        color: black;
      }
    
      h1, h2, h3, h4, h5, h6, strong {
        font-weight: 700;
      }
    
      button {
        cursor: pointer;
      }
    `;
    
  • Agora vamos import├í-lo no arquivo index.tsx, delete os arquivos de estilo .css do projeto tamb├ęm!

    import GlobalStyles from '../styles/global';
    
    export default function Home() {
      return (
        <>
          <GlobalStyles />
        </>
      );
    }
    

Criando os temas

  • Vamos criar os temas agora! Dentro da pasta src/styles vamos criar uma pasta themes e nela um arquivo dark.ts (para o dark mode) o arquivo light.ts para o (light mode jura?) e um arquivo index.ts.
  • O arquivo dark.ts ter├í as seguintes cores (isso voc├¬ decide de acordo com o seu design)

    export default {
      title: 'dark',
    
      colors: {
        primary: '#161616',
        secundary: '#555',
    
        background: '#333',
        text: '#fff',
      },
    };
    
  • O arquivo light.ts ter├í as seguintes cores

    export default {
      title: 'light',
    
      colors: {
        primary: '#666',
        secundary: '#777',
    
        background: '#fff',
        text: '#333',
      },
    };
    
  • O arquivo index.ts ser├í respons├ível por misturar as cores de cada tema com o que seria comum entre os dois, exemplo: tamanho de fonte.

    import { DefaultTheme, CustomTheme } from 'styled-components';
    import dark from './dark';
    import light from './light';
    
    const defaultTheme = {
      fontSizes: {
        small: '16px',
        medium: '18px',
        large: '20px',
      },
    };
    
    function combineTheme(theme: CustomTheme): DefaultTheme {
      return { ...defaultTheme, ...theme };
    }
    
    export { combineTheme, dark, light };
    

Aplicando os temas!

  • Agora que j├í criamos nossos temas vamos import├í-los e fazer as trocas din├ómicas de temas, em src/pages vamos fazer algumas altera├ž├Áes no nosso index.tsx, mas antes vamos adicionar um componente de switch para ficar mais estiloso j├í que estamos falando de temas, portanto, escreve yarn add react-switch no seu terminal

    import React, { useState } from 'react';
    import { DefaultTheme, ThemeProvider } from 'styled-components';
    import Switch from 'react-switch';
    import { combineTheme, dark, light } from '../styles/themes';
    import GlobalStyles from '../styles/global';
    
    const Home: React.FC = () => {
      const [theme, setTheme] = useState<DefaultTheme>(combineTheme(light));
    
      const toggleTheme = () => {
        setTheme(theme.title === 'light' ? combineTheme(dark) : combineTheme(light));
      };
    
      return (
        <ThemeProvider theme={theme}>
          <GlobalStyles />
          <Switch checked={theme.title === 'dark'} onChange={toggleTheme} />
        </ThemeProvider>
      );
    };
    
    export default Home;
    
  • Agora vamos em src/styles no nosso arquivo global.ts e vamos fazer as seguintes altera├ž├Áes!

    import { createGlobalStyle } from 'styled-components';
    
    export default createGlobalStyle`
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        outline: 0;
      }
    
      body {
        background: ${props => props.theme.colors.background};
        color: ${props => props.theme.colors.text};
        font-size: ${props => props.theme.fontSizes.small}
      }
    
      h1, h2, h3, h4, h5, h6, strong {
        font-weight: 700;
      }
    
      button {
        cursor: pointer;
      }
    `;
    
  • E pronto!!! O resultado final ficar├í assim

Exemplo GIF

Projeto no Github
Linkedin

Top comments (6)

Collapse
 
marciofariagit profile image
Marcio Faria

Para persistir a categoria de tema, deixar salvo no localStorage.

const toggleTheme = () => {
if (theme.title === 'light') {
setTheme(combineTheme(dark))
localStorage.setItem('theme', 'dark')
}
if (theme.title === 'dark') {
setTheme(combineTheme(light))
localStorage.setItem('theme', 'light')
}
}

useEffect(() => {
function checkTheme() {
const typeTheme = localStorage.getItem('theme')
if (typeTheme != 'light') {
setTheme(combineTheme(dark))
}
if (typeTheme != 'dark') {
setTheme(combineTheme(light))
}
}

está bem basico, mas assim que puder eu atualizo.

Collapse
 
sostenesapollo profile image
S├│stenes Apollo

Pra quem quiser persistir ├ę s├│ usar cookies, que funcionam da mesma forma que o localstorage

Collapse
 
gabrieloureiro profile image
Gabriel Loureiro

Cara, interessante, mas ai nao ta persistindo o dado no localStorage, logo, nao tem utilidade. Estou tentando a alguns dias fazer isso no next, mas travei.

Collapse
 
jjairojr profile image
Jairo J├║nior

Fui ver isso somente hoje, me perdoe, tem como vc persistir o tema no localStorage sim, na fun├ž├úo do toggle vc pode colocar a l├│gica l├í e salvar. Caso ainda precise de ajuda comente aqui de novo que eu ajudo sim!

Collapse
 
maganezz profile image
Maganez

Mano vc n├úo tem no├ž├úo do quanto me ajudou! Muito Obrigadoo!

Collapse
 
jjairojr profile image
Jairo J├║nior

Tamo junto demais!!!!