1// ===----------------------------------------------------------------------===// 2// Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved. 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// https://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// ===----------------------------------------------------------------------===// 16 17/** 18 * Dark mode theme switcher 19 * Supports three modes: light, dark, and system (auto) 20 */ 21;(function () { 22 'use strict' 23 24 const THEMES = { 25 LIGHT: 'light', 26 DARK: 'dark', 27 SYSTEM: 'system' 28 } 29 30 // Initialize theme on page load (before DOM is ready to avoid flash) 31 initializeTheme() 32 33 // Activate the dropdown once DOM is ready 34 document.addEventListener('DOMContentLoaded', function () { 35 activateDropdown(document.getElementById('theme-select')) 36 }) 37 38 function initializeTheme() { 39 const savedTheme = getSavedTheme() 40 const effectiveTheme = getEffectiveTheme(savedTheme) 41 42 applyTheme(effectiveTheme) 43 } 44 45 function activateDropdown(select) { 46 if (!select) return 47 48 const savedTheme = getSavedTheme() 49 select.value = savedTheme 50 51 // Add change listener 52 select.addEventListener('change', onDropdownChange) 53 } 54 55 function onDropdownChange(event) { 56 const selectedTheme = event.target.value 57 58 saveTheme(selectedTheme) 59 60 const effectiveTheme = getEffectiveTheme(selectedTheme) 61 applyTheme(effectiveTheme) 62 } 63 64 function getEffectiveTheme(theme) { 65 // If system mode, determine based on system preference 66 if (theme === THEMES.SYSTEM || theme === null) { 67 const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches 68 return prefersDark ? THEMES.DARK : THEMES.LIGHT 69 } 70 return theme 71 } 72 73 function applyTheme(theme) { 74 const isDark = theme === THEMES.DARK 75 document.documentElement.classList.toggle('dark-theme', isDark) 76 document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light') 77 } 78 79 function getSavedTheme() { 80 try { 81 return window.localStorage && window.localStorage.getItem('theme') || THEMES.SYSTEM 82 } catch (e) { 83 return THEMES.SYSTEM 84 } 85 } 86 87 function saveTheme(theme) { 88 try { 89 window.localStorage && window.localStorage.setItem('theme', theme) 90 } catch (e) { 91 // localStorage not available 92 } 93 } 94 95 // Listen for system theme changes (only when in system mode) 96 if (window.matchMedia) { 97 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) { 98 const savedTheme = getSavedTheme() 99 100 // Only auto-switch if user is in system mode 101 if (savedTheme === THEMES.SYSTEM) { 102 const effectiveTheme = e.matches ? THEMES.DARK : THEMES.LIGHT 103 applyTheme(effectiveTheme) 104 } 105 }) 106 } 107})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.