DEV Community

loading...
Cover image for 🎨 Light mode e Dark mode e temas customizados com Styled-components e NextJS com Typescript.

🎨 Light mode e Dark mode e temas customizados com Styled-components e NextJS com Typescript.

jjairojr profile image Jairo Júnior ・4 min read

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;
      }
    `;export default {
      title: 'dark',
    
      colors: {
        primary: '#161616',
        secundary: '#555',
    
        background: '#333',
        text: '#fff',
      },
    };
    
  • E pronto!!! O resultado final ficará assim

Exemplo GIF

Projeto no Github
Linkedin

Discussion (2)

pic
Editor guide
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
maganezz profile image
Maganez

Mano vc não tem noção do quanto me ajudou! Muito Obrigadoo!