Catégories
Astuces et Design

Thème et changement de thème avec React et styled-components

J'ai récemment eu un projet avec une exigence de prise en charge thématisation sur le site Internet. C'était une exigence un peu étrange, car l'application est principalement utilisée par une poignée d'administrateurs. Une surprise encore plus grande était qu'ils voulaient non seulement choisir entre des thèmes pré-créés, mais construire leurs propres thèmes. Je suppose que les gens veulent ce qu'ils veulent!

Expliquons cela en une liste complète d'exigences plus détaillées, puis faites-le!

  • Définir un thème (c.-à-d. couleur d'arrière-plan, couleur de police, boutons, liens, etc.)
  • Créer et enregistrez plusieurs thèmes
  • Sélectionner et appliquer un thème
  • Commutateur thèmes
  • Personnaliser un thème

Nous avons livré exactement cela à notre client, et la dernière fois que j'ai entendu dire, ils l'utilisaient avec plaisir!

Commençons à construire exactement cela. Nous allons utiliser React et styled-components. Tout le code source utilisé dans l'article se trouve dans le référentiel GitHub.

La mise en place

Configurons un projet avec React et des composants stylisés. Pour ce faire, nous utiliserons l'application create-react-app. Cela nous donne l'environnement dont nous avons besoin pour développer et tester rapidement des applications React.

Ouvrez une invite de commande et utilisez cette commande pour créer le projet:

npx create-react-app theme-builder

Le dernier argument, theme-builder, est simplement le nom du projet (et donc le nom du dossier). Vous pouvez utiliser tout ce que vous voulez.

Cela peut prendre un certain temps. Une fois terminé, accédez-y dans la ligne de commande avec cd theme-builder. Ouvrez le fichier src/App.js fichier et remplacez le contenu par ce qui suit:

import React from 'react';

function App() {
  return (
    

Theme Builder

); } export default App;

Il s'agit d'un composant de base de React que nous modifierons bientôt. Exécutez la commande suivante à partir du dossier racine du projet pour démarrer l'application:

# Or, npm run start
yarn start

Vous pouvez maintenant accéder à l'application en utilisant l'URL http://localhost:3000.

Un simple titre 1 qui dit Theme Builder en noir sur fond blanc.

create-react-app est fourni avec le fichier de test du composant App. Comme nous n'écrirons aucun test pour les composants dans le cadre de cet article, vous pouvez choisir de supprimer ce fichier.

Nous devons installer quelques dépendances pour notre application. Alors installons-les pendant que nous y sommes:

# Or, npm i ...
yarn add styled-components webfontloader lodash

Voici ce que nous obtenons:

  • styled-components: Une manière flexible de styliser les composants React avec CSS. Il fournit un support de thématisation prêt à l'emploi à l'aide d'un composant wrapper appelé, . Ce composant est chargé de fournir le thème à tous les autres composants React qui y sont intégrés. Nous verrons cela en action dans une minute.
  • Chargeur de polices Web: Le chargeur de polices Web permet de charger des polices à partir de diverses sources, telles que Google Fonts, Adobe Fonts, etc. Nous utiliserons cette bibliothèque pour charger des polices lorsqu'un thème est appliqué.
  • lodash: Ceci est une bibliothèque utilitaire JavaScript pour quelques petits extras pratiques.

Définir un thème

C'est la première de nos exigences. Un thème doit avoir une certaine structure pour définir l'apparence, y compris les couleurs, les polices, etc. Pour notre application, nous définirons chaque thème avec ces propriétés:

  • identifiant unique
  • nom du thème
  • définitions de couleur
  • polices
Capture d'écran d'un éditeur de code montrant la structure organisée des propriétés d'un thème de vagues de mer.
Un thème est un groupe structuré de propriétés que nous utiliserons dans l'application.

Vous pouvez avoir plus de propriétés et / ou différentes façons de le structurer, mais ce sont les choses que nous allons utiliser pour notre exemple.

Créez et enregistrez plusieurs thèmes

Donc, nous venons de voir comment définir un thème. Créons maintenant plusieurs thèmes en ajoutant un dossier dans le projet à l'adresse src/theme et un fichier qu'il contient appelé, schema.json. Voici ce que nous pouvons insérer dans ce fichier pour définir les thèmes "lumière" et "vague de mer":

{
  "data" : {
    "light" : {
      "id": "T_001",
      "name": "Light",
      "colors": {
        "body": "#FFFFFF",
        "text": "#000000",
        "button": {
          "text": "#FFFFFF",
          "background": "#000000"
        },
        "link": {
          "text": "teal",
          "opacity": 1
        }
      },
      "font": "Tinos"
    },
    "seaWave" : {
      "id": "T_007",
      "name": "Sea Wave",
      "colors": {
        "body": "#9be7ff",
        "text": "#0d47a1",
        "button": {
          "text": "#ffffff",
          "background": "#0d47a1"
        },
        "link": {
          "text": "#0d47a1",
          "opacity": 0.8
        }
      },
      "font": "Ubuntu"
    }
  }
}

Le contenu du schema.json Le fichier peut être enregistré dans une base de données afin que nous puissions conserver tous les thèmes avec la sélection de thème. Pour l'instant, nous allons simplement le stocker dans le navigateur localStorage. Pour ce faire, nous allons créer un autre dossier à src/utils avec un nouveau fichier appelé, storage.js. Nous n'avons besoin que de quelques lignes de code pour configurer localStorage:

export const setToLS = (key, value) => {
  window.localStorage.setItem(key, JSON.stringify(value));
}

export const getFromLS = key => {
  const value = window.localStorage.getItem(key);

  if (value) {
    return JSON.parse(value);
  }
}

Ce sont des fonctions utilitaires simples pour stocker des données dans le navigateur localStorage et pour récupérer à partir de là. Nous allons maintenant charger les thèmes dans le navigateur localStorage lorsque l'application est lancée pour la première fois. Pour ce faire, ouvrez le index.js fichier et remplacez le contenu par ce qui suit,

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

import * as themes from './theme/schema.json';
import { setToLS } from './utils/storage';

const Index = () => {
  setToLS('all-themes', themes.default);
  return(
    
  )
}

ReactDOM.render(
  
  document.getElementById('root')
);

Ici, nous obtenons les informations sur le thème du schema.json fichier et en l'ajoutant au localStorage en utilisant la clé all-themes. Si vous avez arrêté l'exécution de l'application, veuillez la redémarrer et accéder à l'interface utilisateur. Vous pouvez utiliser DevTools dans le navigateur pour voir les thèmes sont chargés dans localStorage.

Le thème avec DevTools s'ouvre et affiche les propriétés du thème dans la console.
Tous les accessoires de thème sont correctement stockés dans le navigateur localStorage, comme vu dans DevTools, sous Application → Stockage local.

Sélectionnez et appliquez un thème

Nous pouvons maintenant utiliser la structure du thème et fournir l'objet de thème au wrapper.

Tout d'abord, nous allons créer un hook React personnalisé. Cela gérera le thème sélectionné, sachant si un thème est chargé correctement ou a des problèmes. Commençons par un nouveau useTheme.js fichier dans le src/theme dossier avec ceci dedans:

import { useEffect, useState } from 'react';
import { setToLS, getFromLS } from '../utils/storage';
import _ from 'lodash';

export const useTheme = () => {
  const themes = getFromLS('all-themes');
  const (theme, setTheme) = useState(themes.data.light);
  const (themeLoaded, setThemeLoaded) = useState(false);

  const setMode = mode => {
    setToLS('theme', mode)
    setTheme(mode);
  };

  const getFonts = () => {
    const allFonts = _.values(_.mapValues(themes.data, 'font'));
    return allFonts;
  }

  useEffect(() =>{
    const localTheme = getFromLS('theme');
    localTheme ? setTheme(localTheme) : setTheme(themes.data.light);
    setThemeLoaded(true);
  }, ());

  return { theme, themeLoaded, setMode, getFonts };
};

Ce hook React personnalisé renvoie le thème sélectionné à partir de localStorage et un booléen pour indiquer si le thème est correctement chargé à partir du stockage. Il expose également une fonction, setMode, pour appliquer un thème par programme. Nous y reviendrons dans un instant. Avec cela, nous obtenons également une liste de polices que nous pouvons charger plus tard à l'aide d'un chargeur de polices Web.

Ce serait une bonne idée d'utiliser des styles globaux pour contrôler des éléments, comme la couleur d'arrière-plan du site, la police, le bouton, etc. styled-components fournit un composant appelé, createGlobalStyle qui établit des composants globaux orientés thème. Configurons-les dans un fichier appelé, GlobalStyles.js dans le src/theme dossier avec le code suivant:

import { createGlobalStyle} from "styled-components";

export const GlobalStyles = createGlobalStyle`
  body {
    background: ${({ theme }) => theme.colors.body};
    color: ${({ theme }) => theme.colors.text};
    font-family: ${({ theme }) => theme.font};
    transition: all 0.50s linear;
  }

  a {
    color: ${({ theme }) => theme.colors.link.text};
    cursor: pointer;
  }

  button {
    border: 0;
    display: inline-block;
    padding: 12px 24px;
    font-size: 14px;
    border-radius: 4px;
    margin-top: 5px;
    cursor: pointer;
    background-color: #1064EA;
    color: #FFFFFF;
    font-family: ${({ theme }) => theme.font};
  }

  button.btn {
    background-color: ${({ theme }) => theme.colors.button.background};
    color: ${({ theme }) => theme.colors.button.text};
  }
`;

Juste un peu de CSS pour le , des liens et des boutons, non? Nous pouvons les utiliser dans le App.js fichier pour voir le thème en action en remplaçant le contenu par celui-ci:

// 1: Import
import React, { useState, useEffect } from 'react';
import styled, { ThemeProvider } from "styled-components";
import WebFont from 'webfontloader';
import { GlobalStyles } from './theme/GlobalStyles';
import {useTheme} from './theme/useTheme';

// 2: Create a cotainer
const Container = styled.div`
  margin: 5px auto 5px auto;
`;

function App() {
  // 3: Get the selected theme, font list, etc.
  const {theme, themeLoaded, getFonts} = useTheme();
  const (selectedTheme, setSelectedTheme) = useState(theme);

  useEffect(() => {
    setSelectedTheme(theme);
   }, (themeLoaded));

  // 4: Load all the fonts
  useEffect(() => {
    WebFont.load({
      google: {
        families: getFonts()
      }
    });
  });

  // 5: Render if the theme is loaded.
  return (
    <>
    {
      themeLoaded && 
        
        
          

Theme Builder

This is a theming system with a Theme Switcher and Theme Builder. Do you want to see the source code? Click here.

} ); } export default App;

Quelques choses se passent ici:

  1. Nous importons le useState et useEffect Crochets React ce qui nous aidera à garder une trace de l'une des variables d'état et de leurs changements en raison des effets secondaires. Nous importons ThemeProvider et styled à partir de composants stylisés. le WebFont est également importé pour charger les polices. Nous importons également le thème personnalisé, useTheme, et le composant de style global, GlobalStyles.
  2. Nous créons un Container composant en utilisant les styles CSS et styled composant.
  3. Nous déclarons les variables d'état et surveillez les changements.
  4. Nous chargeons toutes les polices qui sont requis par l'application.
  5. Nous rendons un tas de texte et un lien. Mais notez que nous enveloppons tout le contenu avec le wrapper qui prend le thème sélectionné comme accessoire. Nous passons également dans le composant.

Actualisez l'application et nous devrions voir le thème «lumière» par défaut activé.

Le thème avec un fond blanc et un texte noir.
Hé, regardez ce design épuré et austère!

Nous devrions probablement voir si le changement de thème fonctionne. Alors, ouvrons le useTheme.js fichier et modifiez cette ligne:

localTheme ? setTheme(localTheme) : setTheme(themes.data.light);

…à:

localTheme ? setTheme(localTheme) : setTheme(themes.data.seaWave);

Actualisez à nouveau l'application et j'espère que nous verrons le thème «vague de mer» en action.

Le même thème avec un jeu de couleurs bleu avec un fond bleu clair et un texte bleu foncé et un bouton bleu.
Nous surfons maintenant sur les vagues de ce thème à dominante bleue.

Changer de thème

Génial! Nous sommes en mesure d'appliquer correctement les thèmes. Que diriez-vous de créer un moyen de changer de thème simplement en cliquant sur un bouton? Bien sûr, nous pouvons le faire! Nous pouvons également fournir une sorte d'aperçu du thème.

Un en-tête indique à l'utilisateur de sélectionner un thème et deux composants de carte se trouvent sous l'en-tête, côte à côte, montrant des aperçus du thème de la lumière et du thème des vagues de la mer.
Un aperçu de chaque thème est fourni dans la liste des options.

Appelons chacune de ces cases un ThemeCard, et les configurer de manière à ce qu'ils puissent prendre sa définition de thème comme accessoire. Nous allons passer en revue tous les thèmes, les parcourir en boucle et les peupler comme un ThemeCard composant.

{
  themes.length > 0 && 
  themes.map(theme =>(
    
  ))
}

Passons maintenant au balisage pour un ThemeCard. Le vôtre peut sembler différent, mais remarquez comment nous extrayons ses propres propriétés de couleur et de police, puis les appliquons:

const ThemeCard = props => {
  return(
    
      Click on the button to set this theme
       themeSwitcher(props.theme) }
        style={{backgroundColor: `${data(_.camelCase(props.theme.name)).colors.button.background}`, color: `${data(_.camelCase(props.theme.name)).colors.button.text}`, fontFamily: `${data(_.camelCase(props.theme.name)).font}`}}>
        {props.theme.name}
      
    
  )
}

Ensuite, créons un fichier appelé ThemeSelector.js dans notre le src dossier. Copiez le contenu d'ici et déposez-le dans le fichier pour établir notre sélecteur de thème, que nous devons importer dans App.js:

import ThemeSelector from './ThemeSelector';

Maintenant, nous pouvons l'utiliser dans le Container composant:


  // same as before
  

Actualisons maintenant le navigateur et voyons comment fonctionne le changement de thème.

Une capture d'écran animée montrant le thème changeant lorsqu'il est sélectionné dans la liste des options de la carte à thème.

La partie amusante est que vous pouvez ajouter autant de thèmes dans le schema.json fichier pour les charger dans l'interface utilisateur et basculer. Regarde ça schema.json fichier pour plus de thèmes. Veuillez noter que nous enregistrons également les informations du thème appliqué dans localStorage, la sélection sera donc conservée lorsque vous rouvrirez l'application la prochaine fois.

Thème sélectionné stocké dans le stockage local.

Personnaliser un thème

Peut-être que vos utilisateurs aiment certains aspects d'un thème et certains aspects d'un autre. Pourquoi les faire choisir entre eux alors qu'ils peuvent leur donner la possibilité de définir eux-mêmes les accessoires du thème! Nous pouvons créer une interface utilisateur simple qui permet aux utilisateurs de sélectionner les options d'apparence qu'ils souhaitent et même d'enregistrer leurs préférences.

Capture d'écran animée montrant une ouverture modale avec une liste d'options de thème pour personnaliser l'apparence, y compris le nom, la couleur d'arrière-plan, la couleur du texte, la couleur du texte du bouton, la couleur du lien et la police.

Nous ne couvrirons pas l'explication du code de création de thème dans les détails, mais cela devrait être facile en suivant le code dans le GitHub Repo. Le fichier source principal est CreateThemeContent.js et il est utilisé par App.js. Nous créons le nouvel objet de thème en collectant la valeur de chaque événement de changement d'élément d'entrée et en ajoutant l'objet à la collection d'objets de thème. C'est tout.

Avant de terminer…

Merci pour la lecture! J'espère que vous trouverez ce que nous avons couvert ici utile pour quelque chose sur lequel vous travaillez. Les systèmes de thématisation sont amusants! En fait, les propriétés personnalisées CSS en font de plus en plus une chose. Par exemple, consultez cette approche pour la couleur de Dieter Raber et ce résumé de Chris. Il existe également cette configuration de Michelle Barker qui repose sur des propriétés personnalisées utilisées avec Tailwind CSS. Voici encore une autre façon d'Andrés Galente.

Là où tous ces éléments sont un excellent exemple de création de thèmes, j'espère que cet article aidera à faire passer ce concept au niveau supérieur en stockant les propriétés, en basculant facilement entre les thèmes, en donnant aux utilisateurs un moyen de personnaliser un thème et en enregistrant ces préférences.

Connectons-nous! Vous pouvez me DM sur Twitter avec des commentaires, ou n'hésitez pas à suivre.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *