my website at ewancroft.uk

fix: correct theme toggle logic and update button accessibility

ewancroft.uk 72457019 4c6348f0

verified
Changed files
+67 -67
src
lib
components
+55 -55
src/app.css
··· 8 8 'Segoe UI Symbol', 'Noto Color Emoji'; 9 9 10 10 /* Ink - Text colors (adjusted for WCAG AA compliance) */ 11 - --color-ink-50: light-dark(oklch(97.31% 0.015 123.04), oklch(17.39% 0.023 124.58)); 12 - --color-ink-100: light-dark(oklch(93% 0.032 124.47), oklch(24.9% 0.042 126.8)); 13 - --color-ink-200: light-dark(oklch(85% 0.061 123.88), oklch(38.03% 0.07 126.15)); 14 - --color-ink-300: light-dark(oklch(75% 0.093 124.99), oklch(50.28% 0.098 126.82)); 15 - --color-ink-400: light-dark(oklch(65% 0.123 125.63), oklch(61.88% 0.124 126.72)); 16 - --color-ink-500: light-dark(oklch(55% 0.149 127.03), oklch(72.9% 0.149 127.03)); 17 - --color-ink-600: light-dark(oklch(45% 0.124 126.72), oklch(78.19% 0.123 125.63)); 18 - --color-ink-700: light-dark(oklch(35% 0.098 126.82), oklch(83.5% 0.093 124.99)); 19 - --color-ink-800: light-dark(oklch(25% 0.07 126.15), oklch(88.94% 0.061 123.88)); 20 - --color-ink-900: light-dark(oklch(18% 0.042 126.8), oklch(94.52% 0.032 124.47)); 21 - --color-ink-950: light-dark(oklch(12% 0.023 124.58), oklch(97.31% 0.015 123.04)); 11 + --color-ink-50: light-dark(oklch(17.39% 0.023 124.58), oklch(97.31% 0.015 123.04)); 12 + --color-ink-100: light-dark(oklch(24.9% 0.042 126.8), oklch(93% 0.032 124.47)); 13 + --color-ink-200: light-dark(oklch(38.03% 0.07 126.15), oklch(85% 0.061 123.88)); 14 + --color-ink-300: light-dark(oklch(50.28% 0.098 126.82), oklch(75% 0.093 124.99)); 15 + --color-ink-400: light-dark(oklch(61.88% 0.124 126.72), oklch(65% 0.123 125.63)); 16 + --color-ink-500: light-dark(oklch(72.9% 0.149 127.03), oklch(55% 0.149 127.03)); 17 + --color-ink-600: light-dark(oklch(78.19% 0.123 125.63), oklch(45% 0.124 126.72)); 18 + --color-ink-700: light-dark(oklch(83.5% 0.093 124.99), oklch(35% 0.098 126.82)); 19 + --color-ink-800: light-dark(oklch(88.94% 0.061 123.88), oklch(25% 0.07 126.15)); 20 + --color-ink-900: light-dark(oklch(94.52% 0.032 124.47), oklch(18% 0.042 126.8)); 21 + --color-ink-950: light-dark(oklch(97.31% 0.015 123.04), oklch(12% 0.023 124.58)); 22 22 23 23 /* Canvas - Background colors (adjusted for better contrast) */ 24 - --color-canvas-50: light-dark(oklch(98.5% 0.01 123.97), oklch(17.69% 0.027 125.57)); 25 - --color-canvas-100: light-dark(oklch(96.5% 0.02 123.69), oklch(25.56% 0.047 126.44)); 26 - --color-canvas-200: light-dark(oklch(92% 0.045 125.14), oklch(39.36% 0.083 127.85)); 27 - --color-canvas-300: light-dark(oklch(86% 0.075 125.55), oklch(51.84% 0.112 127.68)); 28 - --color-canvas-400: light-dark(oklch(80% 0.105 126.87), oklch(63.78% 0.141 128.14)); 29 - --color-canvas-500: light-dark(oklch(75.25% 0.135 128.13), oklch(75.25% 0.169 128.13)); 30 - --color-canvas-600: light-dark(oklch(63.78% 0.141 128.14), oklch(80% 0.105 126.87)); 31 - --color-canvas-700: light-dark(oklch(51.84% 0.112 127.68), oklch(86% 0.075 125.55)); 32 - --color-canvas-800: light-dark(oklch(39.36% 0.083 127.85), oklch(92% 0.045 125.14)); 33 - --color-canvas-900: light-dark(oklch(25.56% 0.047 126.44), oklch(96.5% 0.02 123.69)); 34 - --color-canvas-950: light-dark(oklch(17.69% 0.027 125.57), oklch(98.5% 0.01 123.97)); 24 + --color-canvas-50: light-dark(oklch(17.69% 0.027 125.57), oklch(98.5% 0.01 123.97)); 25 + --color-canvas-100: light-dark(oklch(25.56% 0.047 126.44), oklch(96.5% 0.02 123.69)); 26 + --color-canvas-200: light-dark(oklch(39.36% 0.083 127.85), oklch(92% 0.045 125.14)); 27 + --color-canvas-300: light-dark(oklch(51.84% 0.112 127.68), oklch(86% 0.075 125.55)); 28 + --color-canvas-400: light-dark(oklch(63.78% 0.141 128.14), oklch(80% 0.105 126.87)); 29 + --color-canvas-500: light-dark(oklch(75.25% 0.169 128.13), oklch(75.25% 0.135 128.13)); 30 + --color-canvas-600: light-dark(oklch(80% 0.105 126.87), oklch(63.78% 0.141 128.14)); 31 + --color-canvas-700: light-dark(oklch(86% 0.075 125.55), oklch(51.84% 0.112 127.68)); 32 + --color-canvas-800: light-dark(oklch(92% 0.045 125.14), oklch(39.36% 0.083 127.85)); 33 + --color-canvas-900: light-dark(oklch(96.5% 0.02 123.69), oklch(25.56% 0.047 126.44)); 34 + --color-canvas-950: light-dark(oklch(98.5% 0.01 123.97), oklch(17.69% 0.027 125.57)); 35 35 36 36 /* Sage - Primary colors (adjusted for WCAG AA compliance) */ 37 - --color-primary-50: light-dark(oklch(97.73% 0.02 121.83), oklch(18.09% 0.031 123.74)); 38 - --color-primary-100: light-dark(oklch(94% 0.042 123.12), oklch(26.23% 0.053 126.29)); 39 - --color-primary-200: light-dark(oklch(88% 0.082 123.68), oklch(40.39% 0.088 126.72)); 40 - --color-primary-300: light-dark(oklch(78% 0.122 124.71), oklch(53.63% 0.122 127.17)); 41 - --color-primary-400: light-dark(oklch(68% 0.155 125.79), oklch(65.86% 0.152 127.23)); 42 - --color-primary-500: light-dark(oklch(58% 0.182 127.42), oklch(77.77% 0.182 127.42)); 43 - --color-primary-600: light-dark(oklch(48% 0.152 127.23), oklch(81.83% 0.155 125.79)); 44 - --color-primary-700: light-dark(oklch(38% 0.122 127.17), oklch(86.28% 0.122 124.71)); 45 - --color-primary-800: light-dark(oklch(28% 0.088 126.72), oklch(90.67% 0.082 123.68)); 46 - --color-primary-900: light-dark(oklch(20% 0.053 126.29), oklch(95.38% 0.042 123.12)); 47 - --color-primary-950: light-dark(oklch(14% 0.031 123.74), oklch(97.73% 0.02 121.83)); 37 + --color-primary-50: light-dark(oklch(18.09% 0.031 123.74), oklch(97.73% 0.02 121.83)); 38 + --color-primary-100: light-dark(oklch(26.23% 0.053 126.29), oklch(94% 0.042 123.12)); 39 + --color-primary-200: light-dark(oklch(40.39% 0.088 126.72), oklch(88% 0.082 123.68)); 40 + --color-primary-300: light-dark(oklch(53.63% 0.122 127.17), oklch(78% 0.122 124.71)); 41 + --color-primary-400: light-dark(oklch(65.86% 0.152 127.23), oklch(68% 0.155 125.79)); 42 + --color-primary-500: light-dark(oklch(77.77% 0.182 127.42), oklch(58% 0.182 127.42)); 43 + --color-primary-600: light-dark(oklch(81.83% 0.155 125.79), oklch(48% 0.152 127.23)); 44 + --color-primary-700: light-dark(oklch(86.28% 0.122 124.71), oklch(38% 0.122 127.17)); 45 + --color-primary-800: light-dark(oklch(90.67% 0.082 123.68), oklch(28% 0.088 126.72)); 46 + --color-primary-900: light-dark(oklch(95.38% 0.042 123.12), oklch(20% 0.053 126.29)); 47 + --color-primary-950: light-dark(oklch(97.73% 0.02 121.83), oklch(14% 0.031 123.74)); 48 48 49 49 /* Mint - Secondary colors (adjusted for WCAG AA compliance) */ 50 - --color-secondary-50: light-dark(oklch(97.87% 0.024 121.9), oklch(18.72% 0.037 126.2)); 51 - --color-secondary-100: light-dark(oklch(94.5% 0.048 123.9), oklch(26.82% 0.058 127.38)); 52 - --color-secondary-200: light-dark(oklch(89% 0.097 124.41), oklch(42.08% 0.101 128.02)); 53 - --color-secondary-300: light-dark(oklch(80% 0.141 125.62), oklch(55.72% 0.137 128.49)); 54 - --color-secondary-400: light-dark(oklch(70% 0.178 127.04), oklch(68.58% 0.171 128.75)); 55 - --color-secondary-500: light-dark(oklch(60% 0.205 129.04), oklch(81.09% 0.205 129.04)); 56 - --color-secondary-600: light-dark(oklch(50% 0.171 128.75), oklch(84.3% 0.178 127.04)); 57 - --color-secondary-700: light-dark(oklch(40% 0.137 128.49), oklch(87.99% 0.141 125.62)); 58 - --color-secondary-800: light-dark(oklch(30% 0.101 128.02), oklch(91.89% 0.097 124.41)); 59 - --color-secondary-900: light-dark(oklch(22% 0.058 127.38), oklch(95.73% 0.048 123.9)); 60 - --color-secondary-950: light-dark(oklch(15% 0.037 126.2), oklch(97.87% 0.024 121.9)); 50 + --color-secondary-50: light-dark(oklch(18.72% 0.037 126.2), oklch(97.87% 0.024 121.9)); 51 + --color-secondary-100: light-dark(oklch(26.82% 0.058 127.38), oklch(94.5% 0.048 123.9)); 52 + --color-secondary-200: light-dark(oklch(42.08% 0.101 128.02), oklch(89% 0.097 124.41)); 53 + --color-secondary-300: light-dark(oklch(55.72% 0.137 128.49), oklch(80% 0.141 125.62)); 54 + --color-secondary-400: light-dark(oklch(68.58% 0.171 128.75), oklch(70% 0.178 127.04)); 55 + --color-secondary-500: light-dark(oklch(81.09% 0.205 129.04), oklch(60% 0.205 129.04)); 56 + --color-secondary-600: light-dark(oklch(84.3% 0.178 127.04), oklch(50% 0.171 128.75)); 57 + --color-secondary-700: light-dark(oklch(87.99% 0.141 125.62), oklch(40% 0.137 128.49)); 58 + --color-secondary-800: light-dark(oklch(91.89% 0.097 124.41), oklch(30% 0.101 128.02)); 59 + --color-secondary-900: light-dark(oklch(95.73% 0.048 123.9), oklch(22% 0.058 127.38)); 60 + --color-secondary-950: light-dark(oklch(97.87% 0.024 121.9), oklch(15% 0.037 126.2)); 61 61 62 62 /* Jade - Accent colors (adjusted for WCAG AA compliance) */ 63 - --color-accent-50: light-dark(oklch(98.05% 0.027 122.65), oklch(19.03% 0.041 126.73)); 64 - --color-accent-100: light-dark(oklch(95% 0.056 123.8), oklch(27.78% 0.066 127.71)); 65 - --color-accent-200: light-dark(oklch(90% 0.11 124.83), oklch(43.51% 0.11 128.91)); 66 - --color-accent-300: light-dark(oklch(82% 0.159 126.06), oklch(57.9% 0.149 129.35)); 67 - --color-accent-400: light-dark(oklch(72% 0.198 127.63), oklch(71.44% 0.186 129.59)); 68 - --color-accent-500: light-dark(oklch(62% 0.221 129.75), oklch(84.36% 0.221 129.75)); 69 - --color-accent-600: light-dark(oklch(52% 0.186 129.59), oklch(86.93% 0.198 127.63)); 70 - --color-accent-700: light-dark(oklch(42% 0.149 129.35), oklch(89.79% 0.159 126.06)); 71 - --color-accent-800: light-dark(oklch(32% 0.11 128.91), oklch(92.93% 0.11 124.83)); 72 - --color-accent-900: light-dark(oklch(23% 0.066 127.71), oklch(96.35% 0.056 123.8)); 73 - --color-accent-950: light-dark(oklch(16% 0.041 126.73), oklch(98.05% 0.027 122.65)); 63 + --color-accent-50: light-dark(oklch(19.03% 0.041 126.73), oklch(98.05% 0.027 122.65)); 64 + --color-accent-100: light-dark(oklch(27.78% 0.066 127.71), oklch(95% 0.056 123.8)); 65 + --color-accent-200: light-dark(oklch(43.51% 0.11 128.91), oklch(90% 0.11 124.83)); 66 + --color-accent-300: light-dark(oklch(57.9% 0.149 129.35), oklch(82% 0.159 126.06)); 67 + --color-accent-400: light-dark(oklch(71.44% 0.186 129.59), oklch(72% 0.198 127.63)); 68 + --color-accent-500: light-dark(oklch(84.36% 0.221 129.75), oklch(62% 0.221 129.75)); 69 + --color-accent-600: light-dark(oklch(86.93% 0.198 127.63), oklch(52% 0.186 129.59)); 70 + --color-accent-700: light-dark(oklch(89.79% 0.159 126.06), oklch(42% 0.149 129.35)); 71 + --color-accent-800: light-dark(oklch(92.93% 0.11 124.83), oklch(32% 0.11 128.91)); 72 + --color-accent-900: light-dark(oklch(96.35% 0.056 123.8), oklch(23% 0.066 127.71)); 73 + --color-accent-950: light-dark(oklch(98.05% 0.027 122.65), oklch(16% 0.041 126.73)); 74 74 } 75 75 76 76 @layer base {
+12 -12
src/lib/components/layout/ThemeToggle.svelte
··· 10 10 const stored = localStorage.getItem('theme'); 11 11 const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; 12 12 13 - isDark = stored === 'dark' || (!stored && prefersDark); 13 + isDark = stored === 'light' || (!stored && !prefersDark); 14 14 updateTheme(); 15 15 mounted = true; 16 16 ··· 33 33 const htmlElement = document.documentElement; 34 34 35 35 if (isDark) { 36 - htmlElement.classList.add('dark'); 37 - htmlElement.style.colorScheme = 'dark'; 38 - } else { 39 36 htmlElement.classList.remove('dark'); 40 37 htmlElement.style.colorScheme = 'light'; 38 + } else { 39 + htmlElement.classList.add('dark'); 40 + htmlElement.style.colorScheme = 'dark'; 41 41 } 42 42 } 43 43 44 44 function toggleTheme() { 45 45 isDark = !isDark; 46 - localStorage.setItem('theme', isDark ? 'dark' : 'light'); 46 + localStorage.setItem('theme', isDark ? 'light' : 'dark'); 47 47 updateTheme(); 48 48 } 49 49 </script> ··· 51 51 <button 52 52 onclick={toggleTheme} 53 53 class="relative flex h-10 w-10 items-center justify-center rounded-lg bg-canvas-200 text-ink-900 transition-all hover:bg-canvas-300 dark:bg-canvas-800 dark:text-ink-50 dark:hover:bg-canvas-700" 54 - aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'} 54 + aria-label={isDark ? 'Switch to dark mode' : 'Switch to light mode'} 55 55 type="button" 56 56 > 57 57 {#if mounted} 58 58 <div class="relative h-5 w-5"> 59 - <Sun 59 + <Moon 60 60 class="absolute inset-0 h-5 w-5 transition-all duration-300 {isDark 61 - ? 'scale-0 rotate-90 opacity-0' 62 - : 'scale-100 rotate-0 opacity-100'}" 61 + ? 'scale-100 rotate-0 opacity-100' 62 + : 'scale-0 rotate-90 opacity-0'}" 63 63 aria-hidden="true" 64 64 /> 65 - <Moon 65 + <Sun 66 66 class="absolute inset-0 h-5 w-5 transition-all duration-300 {isDark 67 - ? 'scale-100 rotate-0 opacity-100' 68 - : 'scale-0 -rotate-90 opacity-0'}" 67 + ? 'scale-0 -rotate-90 opacity-0' 68 + : 'scale-100 rotate-0 opacity-100'}" 69 69 aria-hidden="true" 70 70 /> 71 71 </div>