Alternar temas com Javascript Interop no Blazor

· 4 min de leitura

Para pessoas como eu, que sofrem com flashbacks toda vez que abro uma página da web, criei uma solução super simples sobre como alternar entre o modo claro e escuro usando Javascript e chamá-lo do Blazor usando Javascript Interop.

#Definindo o atributo pai

Em primeiro lugar, temos que identificar o elemento pai com um identificador, isto porque mudamos as cores dependendo do valor desse identificador.

Para fazer isso em Javascript, teríamos que executar este comando

document.documentElement.setAttribute('data-theme', 'YOUR_IDFENTIFIER');

No nosso caso, queremos ter dois identificadores para cada tipo de estilo, que são light e dark.

Criando arquivo Javascript para lidar com a lógica

Agora temos a função de atualizar o identificador, agora vamos criar um arquivo Javscript com uma função que execute essa lógica. Nosso arquivo se chamará app.js

Nesse arquivo teremos uma função que chamará o código que mencionamos anteriormente.

var toggleTheme = function (identifier) {
    document.documentElement.setAttribute('data-theme', identifier);
}

Adicionando arquivo Javascript ao Blazor

Adicione o script ao aplicativo Blazor adicionando-o onde os scripts estão localizados.

<script src="~/js/app.js"></script>

Criando o serviço

Agora que temos o código Javascript, precisamos criar um serviço que se chamará ThemeToggleService.

Este serviço tratará da lógica para alternar entre o tema light e dark.

Injetando JSInterop

Para chamar qualquer Javascipt, temos que chamar o JSInterop, então temos que criar uma propriedade que irá injetar.

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorDarkmodeToggle.Data
{
    private readonly IJSRuntime jSRuntime;

    public ThemeToggleService(IJSRuntime jSRuntime)
    {
        this.jSRuntime = jSRuntime;
    }
}

Função para definir o identificador

Agora que criamos o serviço, vamos criar a função para definir o identificador, esta função irá apenas atualizar o data-theme na página.

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace BlazorDarkmodeToggle.Data
{
    public class ThemeToggleService
    {
        private readonly IJSRuntime jSRuntime;

        public ThemeToggleService(IJSRuntime jSRuntime)
        {
            this.jSRuntime = jSRuntime;
        }

        public bool IsLightTheme { get; set; } = true;
        public string GetIdentifier => IsLightTheme ? "light" : "dark";

        public async Task ToggleTheme() {
            IsLightTheme = !IsLightTheme;
            await jSRuntime.InvokeVoidAsync("toggleTheme", GetIdentifier);
        }
    }
}

Adicionar serviço à inicialização

Para disponibilizar o serviço para todos os componentes e páginas, temos que adicioná-lo ao arquivo Program.cs.

builder.Services.AddSingleton<ThemeToggleService>();

Então o arquivo vai ficar assim

using BlazorDarkmodeToggle.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddSingleton<ThemeToggleService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

Lembre-se de que isso pode mudar dependendo se você usa o Blazor Server ou o Blazor WebAssembly.

Preparando o CSS

Agora que temos parte do código pronto, temos que começar a trabalhar no CSS. O que precisamos fazer é definir todas as propriedades CSS que tratam das cores CSS, plano de fundo, etc.

:root {
    --background-color:#ffffff;
    --text-color:#000000;
}

Depois de fazer isso, usando o identificador, podemos facilmente alternar entre os identificadores, e ele usará qualquer um dos outros valores.

[data-theme="dark"] {
    --background-color: #000000;
    --text-color: #ffffff;
}

Para o desvanecimento legal da animação, vamos apenas adicionar uma propriedade transition a todas, para que fique bem.

* {
    transition: all 250ms;
}

Agora iremos atribuir essas variáveis a algumas classes css, para que possamos vê-las na página do Blazor.

.app-background {
    background-color: var(--background-color);
    width: 200px;
    height: 200px;
}

.app-text {
    color: var(--text-color);
}

Lembre-se de adicionar o arquivo ao aplicativo Blazor adicionando-o no head.

<link href="css/app.css" rel="stylesheet" />

Chamando do Blazor

Então, como vamos testar isso? Para simplificar, vamos apenas adicionar uma div com a classe app-background, e dentro dela terá um p com a classe app-text.Então, vamos criar uma página chamada Theme.razor na pasta Pages e adicionar algum código para isso

@page "/theme"
@using BlazorDarkmodeToggle.Data
@inject ThemeToggleService ThemeToggleService

<button class="btn btn-primary" @onclick=Toggle>Toggle theme</button>

<br />

<div class="app-background">
    <p class="app-text">Hello world!</p>
</div>

@code{
    public async Task Toggle()
    {
        await this.ThemeToggleService.ToggleTheme();
    }
}

Poderíamos testar isso acessando /theme, mas também vamos adicioná-lo à barra de navegação

<div class="nav-item px-3">
    <NavLink class="nav-link" href="theme">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Theme togle
    </NavLink>
</div>

Teste

Como você pode ver, assim que alternamos as mudanças de tema, fundo e cor da fonte, agora você pode ver o quão poderoso isso é, se você realmente desenvolver a página inteira usando essas variáveis ​​em CSS, você poderá ter temas diferentes e apenas alterná-los!

Que incrível!!

Código

Todo esse projeto está no Github e você pode encontrá-lo aqui!

Se você tiver qualquer problema ou dúvida, sinta-se à vontade para entrar em contato comigo em qualquer mídia social em @emimontesdeoca (no Twitter na verdade é @emimontesdeocaa com dois aa no final). Você também pode encontrar a maioria das minhas redes sociais no cabeçalho do blog.

Espero que você tenha gostado da postagem!

Recursos