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 • Edited 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!!!!