feat: implement theme persistence and selection in header component, enhancing user experience with localStorage integration

This commit is contained in:
2025-12-15 09:01:56 -03:00
parent 4faf279c3e
commit c272ca05e8
3 changed files with 87 additions and 3 deletions

View File

@@ -2,6 +2,8 @@
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
import logo from '$lib/assets/logo_governo_PE.png'; import logo from '$lib/assets/logo_governo_PE.png';
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import { onMount } from 'svelte';
import { aplicarTemaDaisyUI } from '$lib/utils/temas';
type HeaderProps = { type HeaderProps = {
left?: Snippet; left?: Snippet;
@@ -9,6 +11,43 @@
}; };
const { left, right }: HeaderProps = $props(); const { left, right }: HeaderProps = $props();
let themeSelectEl: HTMLSelectElement | null = null;
function safeGetThemeLS(): string | null {
try {
const t = localStorage.getItem('theme');
return t && t.trim() ? t : null;
} catch {
return null;
}
}
onMount(() => {
const persisted = safeGetThemeLS();
if (persisted) {
// Sincroniza UI + HTML com o valor persistido (evita select ficar "aqua" indevido)
if (themeSelectEl && themeSelectEl.value !== persisted) {
themeSelectEl.value = persisted;
}
aplicarTemaDaisyUI(persisted);
}
});
function onThemeChange(e: Event) {
const nextValue = (e.currentTarget as HTMLSelectElement | null)?.value ?? null;
// Se o theme-change não atualizar (caso comum após login/logout),
// garantimos aqui a persistência + aplicação imediata.
if (nextValue) {
try {
localStorage.setItem('theme', nextValue);
} catch {
// ignore
}
aplicarTemaDaisyUI(nextValue);
}
}
</script> </script>
<header <header
@@ -36,9 +75,11 @@
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<select <select
bind:this={themeSelectEl}
class="select select-sm bg-base-100 border-base-300 w-40" class="select select-sm bg-base-100 border-base-300 w-40"
aria-label="Selecionar tema" aria-label="Selecionar tema"
data-choose-theme data-choose-theme
onchange={onThemeChange}
> >
<option value="aqua">Aqua</option> <option value="aqua">Aqua</option>
<option value="sgse-blue">Azul</option> <option value="sgse-blue">Azul</option>

View File

@@ -40,9 +40,6 @@
if (result.error) { if (result.error) {
console.error('Sign out error:', result.error); console.error('Sign out error:', result.error);
} }
// Resetar tema para padrão ao fazer logout
const { aplicarTemaPadrao } = await import('$lib/utils/temas');
aplicarTemaPadrao();
goto(resolve('/home')); goto(resolve('/home'));
} }
</script> </script>

View File

@@ -144,6 +144,52 @@ export function obterNomeDaisyUI(id: TemaId | string | null | undefined): string
return temaParaDaisyUI[tema.id] || 'aqua'; return temaParaDaisyUI[tema.id] || 'aqua';
} }
/**
* Lê o tema persistido pelo `theme-change` (chave "theme") no localStorage.
* Retorna o nome do tema do DaisyUI (ex.: "dark", "light", "aqua", "sgse-blue").
*/
export function obterTemaPersistidoNoLocalStorage(chave: string = 'theme'): string | null {
if (typeof window === 'undefined') return null;
try {
const tema = window.localStorage.getItem(chave);
return tema && tema.trim() ? tema : null;
} catch {
return null;
}
}
/**
* Aplica diretamente um tema do DaisyUI no `<html data-theme="...">`.
* (Não altera o localStorage)
*/
export function aplicarTemaDaisyUI(tema: string): void {
if (typeof document === 'undefined') return;
const htmlElement = document.documentElement;
if (!htmlElement) return;
// Normaliza qualquer estado anterior
htmlElement.removeAttribute('data-theme');
// Evita que `body[data-theme]` sobrescreva o tema do `<html>`
if (document.body) document.body.removeAttribute('data-theme');
htmlElement.setAttribute('data-theme', tema);
// Forçar reflow para garantir que o CSS seja aplicado
void htmlElement.offsetHeight;
}
/**
* Garante que o tema do `<html>` reflita SEMPRE o valor persistido no localStorage.
* Se não houver tema persistido, aplica o tema padrão.
*/
export function aplicarTemaDoLocalStorage(): void {
const temaPersistido = obterTemaPersistidoNoLocalStorage('theme');
if (temaPersistido) {
aplicarTemaDaisyUI(temaPersistido);
return;
}
aplicarTemaPadrao();
}
/** /**
* Aplicar tema ao documento HTML * Aplicar tema ao documento HTML
* NÃO salva no localStorage - apenas no banco de dados do usuário * NÃO salva no localStorage - apenas no banco de dados do usuário