PageSourceSearch

https://theutz.com/static/marmite.js

js theutz.com collected 2026-10-06 02:44:58 UTC 6,587 bytes, 225 lines download raw bytes

1// Theme switcher - light/dark
2const themeSwitcher = {
3    // Config
4    _scheme: "auto",
5    toggleButton: document.querySelectorAll(".theme-toggle"),
6    rootAttribute: "data-theme",
7    localStorageKey: "picoPreferredColorScheme",
8    
9    // Init
10    init() {
11        this.scheme = this.schemeFromLocalStorage;
12        this.initToggle();
13        this.updateIcon();
14    },
15    
16    // Get color scheme from local storage
17    get schemeFromLocalStorage() {
18        return window.localStorage?.getItem(this.localStorageKey);
19    },
20    
21    // Preferred color scheme
22    get preferredColorScheme() {
23        return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
24    },
25    
26    // Init toggle
27    initToggle() {
28        // for each toggle button add event listener
29        this.toggleButton.forEach((button) => {
30            button.addEventListener(
31                "click",
32                (event) => {
33                    event.preventDefault();
34                    // Toggle scheme
35                    this.scheme = this.scheme === "dark" ? "light" : "dark";
36                    this.updateIcon();
37                },
38                false
39            );
40        });
41    },
42    
43    // Set scheme
44    set scheme(scheme) {
45        if (scheme == "auto" || scheme == null) {
46            this._scheme = this.preferredColorScheme;
47        } else if (scheme == "dark" || scheme == "light") {
48            this._scheme = scheme;
49        }
50        this.applyScheme();
51        this.schemeToLocalStorage();
52    },
53    
54    // Get scheme
55    get scheme() {
56        return this._scheme;
57    },
58    
59    // Apply scheme
60    applyScheme() {
61        document.querySelector("html")?.setAttribute(this.rootAttribute, this.scheme);
62    },
63    
64    // Store scheme to local storage
65    schemeToLocalStorage() {
66        window.localStorage?.setItem(this.localStorageKey, this.scheme);
67    },
68    
69    // Update icon based on the current scheme
70    updateIcon() {
71        // for each toggle button update icon
72        this.toggleButton.forEach((button) => {
73            if (this.scheme === "dark") {
74                button.innerHTML = "☼"; // Sun icon for light mode
75                button.title = "light mode";
76            } else {
77                button.innerHTML = "☽"; // Moon icon for dark mode
78                button.title = "dark mode"; 
79            }
80        });
81    },
82};
83
84// Init
85themeSwitcher.init();
86
87// Menu
88
89const menuToggle = document.getElementById('menu-toggle');
90const headerMenu = document.getElementById('header-menu');
91
92menuToggle.addEventListener('click', function () {
93    headerMenu.classList.toggle('active');
94});
95
96
97// Selected menu animation
98document.addEventListener("DOMContentLoaded", function () {
99    const menuItems = document.querySelectorAll('.menu-item');
100    const underline = document.querySelector('.underline');
101
102    function setUnderline(item) {
103        underline.style.width = `${item.offsetWidth}px`; 
104        underline.style.transform = `translateX(${item.offsetLeft}px)`; 
105    }
106
107    const activeItem = document.querySelector('.menu-item.active');
108    if (activeItem) {
109        setUnderline(activeItem); 
110    }
111
112    menuItems.forEach(item => {
113        item.addEventListener('click', function (event) {
114            if (this.classList.contains('active')) {
115                return; 
116            }
117
118            menuItems.forEach(i => {
119                i.classList.remove('active');
120            });
121
122            this.classList.add('active');
123            
124            setUnderline(this);
125        });
126    });
127});
128
129
130// Colorscheme switcher
131function colorschemeSwitcher() {
132    const colorschemes = [
133        'catppuccin',
134        'clean',
135        'dracula',
136        'github',
137        'gruvbox',
138        'iceberg',
139        'minimal',
140        'minimal_wb',
141        'monokai',
142        'nord',
143        'one',
144        'solarized',
145        'typewriter'
146    ];
147
148    const colorschemeDropdown = document.querySelectorAll('.colorscheme-toggle');
149
150    colorschemeDropdown.forEach((dropdown) => {
151
152        dropdown.addEventListener('change', function () {
153            const colorscheme = this.value;
154            const colorschemeLink = document.querySelector('#colorscheme-link');
155            if (colorscheme === 'default') {
156                if (colorschemeLink) {
157                    colorschemeLink.remove();
158                }
159
160                localStorage.removeItem('marmitePreferredColorScheme');
161                return;
162            }
163            if (colorschemeLink) {
164                colorschemeLink.href = `static/colorschemes/${colorscheme}.css`;
165            } else {
166                const link = document.createElement('link');
167                link.id = 'colorscheme-link';
168                link.rel = 'stylesheet';
169                link.href = `static/colorschemes/${colorscheme}.css`;
170                document.head.appendChild(link);
171            }
172            localStorage.setItem('marmitePreferredColorScheme', colorscheme);
173
174            colorschemeDropdown.forEach((dropdown) => {
175                dropdown.value = colorscheme;
176            });
177        });
178
179        colorschemes.forEach((colorscheme) => {
180            const option = document.createElement('option');
181            option.value = colorscheme;
182            option.textContent = colorscheme;
183            dropdown.appendChild(option);
184        });
185
186        const colorscheme = localStorage.getItem('marmitePreferredColorScheme');
187        if (colorscheme) {
188            dropdown.value = colorscheme;
189            dropdown.dispatchEvent(new Event('change'));
190        }
191    });
192}
193
194// Function to change Giscus theme
195function changeGiscusTheme(newTheme) {
196  function sendMessage(message) {
197    const iframe = document.querySelector('iframe.giscus-frame');
198    if (!iframe) return;
199    iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
200  }
201  
202  sendMessage({
203    setConfig: {
204      theme: newTheme
205    }
206  });
207}
208
209// Add event listener for system theme changes
210window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
211  // Update theme switcher scheme
212  themeSwitcher.scheme = e.matches ? 'dark' : 'light';
213  
214  // Update giscus theme
215  changeGiscusTheme(e.matches ? 'dark' : 'light');
216});
217
218// Set initial giscus theme based on current theme when page loads
219document.addEventListener("DOMContentLoaded", function() {
220  // Check if giscus is present
221  if (document.querySelector('iframe.giscus-frame')) {
222    const isDarkMode = themeSwitcher.scheme === 'dark';
223    changeGiscusTheme(isDarkMode ? 'dark' : 'light');
224  }
225});

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.