PageSourceSearch

https://webawesome.com/assets/scripts/theme.js

js webawesome.com collected 2026-10-02 07:17:37 UTC 4,180 bytes, 123 lines download raw bytes

1import { doViewTransition } from '../scripts/view-transitions.js';
2
3//
4// Updates the theme when a theme selector changes
5//
6async function updateTheme(value, isInitialLoad = false) {
7  const body = document.body;
8
9  // Get brand, palette, and theme name from the selected option, falling back to the saved values on pages without a
10  // theme selector so visiting them doesn't reset the user's choice
11  const themeSelector = document.querySelector('.theme-selector');
12  const selectedOption = themeSelector?.querySelector(`wa-dropdown-item[value="${value}"]`);
13  let brand = selectedOption?.getAttribute('data-brand') || localStorage.getItem('brand') || 'blue';
14  let palette = selectedOption?.getAttribute('data-palette') || localStorage.getItem('palette') || 'default';
15  let themeName = selectedOption?.textContent.trim() || 'Unknown';
16
17  if (!isInitialLoad) {
18    // Disable tooltip during theme transition
19    const tooltip = document.querySelector('#theme-tooltip');
20    if (tooltip) {
21      tooltip.disabled = true;
22    }
23
24    // Add fade-out class
25    body.classList.add('theme-transitioning');
26
27    // Wait for fade-out to complete
28    await new Promise(resolve => {
29      const handleTransitionEnd = event => {
30        if (event.target === body && event.propertyName === 'opacity') {
31          body.removeEventListener('transitionend', handleTransitionEnd);
32          resolve();
33        }
34      };
35      body.addEventListener('transitionend', handleTransitionEnd);
36    });
37  }
38
39  // Handle site theme vs regular theme
40  let href = `/dist/styles/themes/${value}.css`;
41
42  if (document.querySelector('wa-page')?.dataset.pageType === 'site') {
43    brand = 'orange';
44    href = `/assets/styles/theme-site.css`;
45    palette = 'default';
46    value = 'site';
47  } else {
48    localStorage.setItem('brand', brand);
49    localStorage.setItem('palette', palette);
50    localStorage.setItem('theme', value);
51    setCookie({ name: 'webawesome_brand', value: brand });
52    setCookie({ name: 'webawesome_palette', value: palette });
53    setCookie({ name: 'webawesome_theme', value });
54  }
55
56  // A page can pin its brand with data-page-brand on <wa-page> (e.g. Create stays orange). This gets applied after
57  // persistence so the pin never overwrites the user's saved brand choice.
58  const pageBrand = document.querySelector('wa-page')?.dataset.pageBrand;
59  if (pageBrand) {
60    brand = pageBrand;
61  }
62
63  // Update theme classes
64  const htmlElement = document.documentElement;
65  const classesToRemove = Array.from(htmlElement.classList).filter(
66    className =>
67      className.startsWith('wa-theme-') || className.startsWith('wa-brand-') || className.startsWith('wa-palette-'),
68  );
69  const themeStylesheet = document.getElementById('theme-stylesheet');
70
71  await doViewTransition(() => {
72    // Update the theme
73    if (themeStylesheet) {
74      themeStylesheet.href = href;
75    }
76
77    htmlElement.classList.remove(...classesToRemove);
78
79    // Add the new theme, brand, and palette classes
80    htmlElement.classList.add(`wa-theme-${value}`);
81    htmlElement.classList.add(`wa-brand-${brand}`);
82    htmlElement.classList.add(`wa-palette-${palette}`);
83
84    // Sync all theme selectors
85    document.querySelectorAll('.theme-selector').forEach(el => {
86      el.value = value;
87      el.setAttribute('value', value);
88    });
89
90    // Update tooltip content to reflect the new theme
91    const tooltip = document.querySelector('#theme-tooltip');
92    if (tooltip) {
93      tooltip.textContent = `${themeName} Theme`;
94    }
95  });
96
97  if (!isInitialLoad) {
98    // Remove transition class and re-enable tooltip after view transition completes
99    body.classList.remove('theme-transitioning');
100
101    const tooltip = document.querySelector('#theme-tooltip');
102    if (tooltip) {
103      tooltip.disabled = false;
104    }
105  }
106}
107
108// Handle changes
109document.addEventListener('input', event => {
110  if (event.target.matches('.theme-selector')) {
111    updateTheme(event.target.value);
112  }
113});
114
115// Initialize
116function initializeTheme() {
117  const savedTheme = localStorage.getItem('theme') || 'default';
118  updateTheme(savedTheme, true);
119}
120
121initializeTheme();
122
123document.addEventListener('turbo:render', initializeTheme);

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.