agent-ecosystem/landing/stores/theme.ts

61 lines
1.6 KiB
TypeScript

import { defineStore } from "pinia";
type ThemeName = "light" | "dark";
const themeCookieName = "theme";
function isThemeName(value: string | null | undefined): value is ThemeName {
return value === "dark" || value === "light";
}
function getCookieTheme(): ThemeName | null {
if (!import.meta.client) return null;
const cookie = document.cookie
.split("; ")
.find((item) => item.startsWith(`${themeCookieName}=`));
const value = cookie ? decodeURIComponent(cookie.split("=").slice(1).join("=")) : null;
return isThemeName(value) ? value : null;
}
function persistTheme(theme: ThemeName) {
localStorage.setItem(themeCookieName, theme);
document.cookie = `${themeCookieName}=${theme}; Path=/; Max-Age=31536000; SameSite=Lax`;
}
export const useThemeStore = defineStore("theme", {
state: () => ({
current: "light" as ThemeName,
userSelected: false
}),
actions: {
getInitialTheme(): ThemeName {
if (!import.meta.client) return "light";
const saved = localStorage.getItem(themeCookieName);
if (isThemeName(saved)) {
this.userSelected = true;
persistTheme(saved);
return saved;
}
const cookieTheme = getCookieTheme();
if (cookieTheme) {
this.userSelected = true;
persistTheme(cookieTheme);
return cookieTheme;
}
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
return "light";
},
setTheme(theme: ThemeName, fromUser: boolean) {
this.current = theme;
if (import.meta.client && fromUser) {
this.userSelected = true;
persistTheme(theme);
}
}
}
});