feat: implement theme persistence and selection in header component, enhancing user experience with localStorage integration
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user