useAppearance.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { onMounted, ref } from 'vue';
  2. type Appearance = 'light' | 'dark' | 'system';
  3. export function updateTheme(value: Appearance) {
  4. if (typeof window === 'undefined') {
  5. return;
  6. }
  7. if (value === 'system') {
  8. const mediaQueryList = window.matchMedia(
  9. '(prefers-color-scheme: dark)',
  10. );
  11. const systemTheme = mediaQueryList.matches ? 'dark' : 'light';
  12. document.documentElement.classList.toggle(
  13. 'dark',
  14. systemTheme === 'dark',
  15. );
  16. } else {
  17. document.documentElement.classList.toggle('dark', value === 'dark');
  18. }
  19. }
  20. const setCookie = (name: string, value: string, days = 365) => {
  21. if (typeof document === 'undefined') {
  22. return;
  23. }
  24. const maxAge = days * 24 * 60 * 60;
  25. document.cookie = `${name}=${value};path=/;max-age=${maxAge};SameSite=Lax`;
  26. };
  27. const mediaQuery = () => {
  28. if (typeof window === 'undefined') {
  29. return null;
  30. }
  31. return window.matchMedia('(prefers-color-scheme: dark)');
  32. };
  33. const getStoredAppearance = () => {
  34. if (typeof window === 'undefined') {
  35. return null;
  36. }
  37. return localStorage.getItem('appearance') as Appearance | null;
  38. };
  39. const handleSystemThemeChange = () => {
  40. const currentAppearance = getStoredAppearance();
  41. updateTheme(currentAppearance || 'system');
  42. };
  43. export function initializeTheme() {
  44. if (typeof window === 'undefined') {
  45. return;
  46. }
  47. // Initialize theme from saved preference or default to system...
  48. const savedAppearance = getStoredAppearance();
  49. updateTheme(savedAppearance || 'system');
  50. // Set up system theme change listener...
  51. mediaQuery()?.addEventListener('change', handleSystemThemeChange);
  52. }
  53. const appearance = ref<Appearance>('system');
  54. export function useAppearance() {
  55. onMounted(() => {
  56. const savedAppearance = localStorage.getItem(
  57. 'appearance',
  58. ) as Appearance | null;
  59. if (savedAppearance) {
  60. appearance.value = savedAppearance;
  61. }
  62. });
  63. function updateAppearance(value: Appearance) {
  64. appearance.value = value;
  65. // Store in localStorage for client-side persistence...
  66. localStorage.setItem('appearance', value);
  67. // Store in cookie for SSR...
  68. setCookie('appearance', value);
  69. updateTheme(value);
  70. }
  71. return {
  72. appearance,
  73. updateAppearance,
  74. };
  75. }