PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / dark-mode-toggle / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/dark-mode-toggle/frontend.js

186 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function reducedMotion() {
5 return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
6 }
7
8 function initToggle(wrap) {
9 var cfg = {
10 toggleStyle: wrap.dataset.toggleStyle || 'switch',
11 position: wrap.dataset.position || 'inline',
12 floatCorner: wrap.dataset.floatCorner || 'bottom-right',
13 floatX: parseInt(wrap.dataset.floatX, 10) || 24,
14 floatY: parseInt(wrap.dataset.floatY, 10) || 24,
15 storageKey: wrap.dataset.storageKey || 'bkdm-theme',
16 attr: wrap.dataset.attr || 'data-theme',
17 darkVal: wrap.dataset.darkVal || 'dark',
18 lightVal: wrap.dataset.lightVal || 'light',
19 defaultTheme: wrap.dataset.default || 'light',
20 respectSystem: wrap.dataset.respectSystem !== 'false',
21 buttonSize: parseInt(wrap.dataset.buttonSize, 10) || 44,
22 borderRadius: parseInt(wrap.dataset.borderRadius, 10) || 50,
23 duration: reducedMotion() ? 0 : (parseInt(wrap.dataset.duration, 10) || 300),
24 showIcon: wrap.dataset.showIcon !== 'false',
25 showLabel: wrap.dataset.showLabel === 'true',
26 lightIcon: wrap.dataset.lightIcon || '☀️',
27 darkIcon: wrap.dataset.darkIcon || '🌙',
28 lightLabel: wrap.dataset.lightLabel || 'Light',
29 darkLabel: wrap.dataset.darkLabel || 'Dark',
30 hoverScale: wrap.dataset.hoverScale !== 'false',
31 shadow: wrap.dataset.shadow !== 'false',
32 lightBg: wrap.dataset.lightBg || '#f3f4f6',
33 lightColor: wrap.dataset.lightColor || '#111827',
34 darkBg: wrap.dataset.darkBg || '#1f2937',
35 darkColor: wrap.dataset.darkColor || '#f9fafb',
36 trackLight: wrap.dataset.trackLight || '#d1d5db',
37 trackDark: wrap.dataset.trackDark || '#4f46e5',
38 thumb: wrap.dataset.thumb || '#ffffff',
39 };
40
41 // Set CSS vars for floating offsets
42 wrap.style.setProperty('--bkdm-offset-x', cfg.floatX + 'px');
43 wrap.style.setProperty('--bkdm-offset-y', cfg.floatY + 'px');
44
45 // Determine initial theme
46 var saved = null;
47 try { saved = localStorage.getItem(cfg.storageKey); } catch (e) {}
48
49 var sysDark = cfg.respectSystem
50 ? window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
51 : false;
52
53 var current = saved || (sysDark ? cfg.darkVal : cfg.lightVal);
54 if (!saved && !sysDark) current = cfg.defaultTheme === 'dark' ? cfg.darkVal : cfg.lightVal;
55
56 // Build button
57 var btn = wrap.querySelector('.bkdm-btn');
58 if (!btn) return;
59
60 var thumbSize = Math.round(cfg.buttonSize * 0.5);
61
62 btn.style.minWidth = cfg.buttonSize + 'px';
63 btn.style.height = cfg.buttonSize + 'px';
64 btn.style.padding = '0 12px';
65 btn.style.borderRadius = cfg.borderRadius + 'px';
66 btn.style.fontSize = Math.round(cfg.buttonSize * 0.42) + 'px';
67 btn.style.transition = 'background ' + cfg.duration + 'ms ease, color ' + cfg.duration + 'ms ease, transform 0.15s ease';
68 if (cfg.shadow) btn.style.boxShadow = '0 2px 8px rgba(0,0,0,0.18)';
69
70 if (cfg.hoverScale) {
71 btn.addEventListener('mouseenter', function () { btn.style.transform = 'scale(1.08)'; });
72 btn.addEventListener('mouseleave', function () { btn.style.transform = 'scale(1)'; });
73 }
74
75 // Build inner HTML for switch style
76 var iconEl, trackEl, thumbEl, labelEl;
77
78 if (cfg.toggleStyle === 'switch') {
79 btn.style.background = 'none';
80 btn.style.boxShadow = 'none';
81 btn.style.padding = '0';
82 btn.style.minWidth = 'unset';
83 btn.style.height = 'unset';
84
85 if (cfg.showIcon) {
86 iconEl = document.createElement('span');
87 iconEl.className = 'bkdm-icon';
88 iconEl.style.fontSize = Math.round(cfg.buttonSize * 0.42) + 'px';
89 iconEl.style.transition = 'opacity ' + cfg.duration + 'ms ease';
90 btn.appendChild(iconEl);
91 }
92
93 trackEl = document.createElement('div');
94 trackEl.className = 'bkdm-track';
95 trackEl.style.width = (cfg.buttonSize + 4) + 'px';
96 trackEl.style.height = Math.round(cfg.buttonSize * 0.6) + 'px';
97 trackEl.style.borderRadius = cfg.borderRadius + 'px';
98 trackEl.style.transition = 'background ' + cfg.duration + 'ms ease';
99
100 thumbEl = document.createElement('div');
101 thumbEl.className = 'bkdm-thumb';
102 thumbSize = Math.round(cfg.buttonSize * 0.6) - 4;
103 thumbEl.style.width = thumbSize + 'px';
104 thumbEl.style.height = thumbSize + 'px';
105 thumbEl.style.background = cfg.thumb;
106 thumbEl.style.transition = 'transform ' + cfg.duration + 'ms ease';
107
108 trackEl.appendChild(thumbEl);
109 btn.appendChild(trackEl);
110
111 if (cfg.showLabel) {
112 labelEl = document.createElement('span');
113 labelEl.className = 'bkdm-label';
114 btn.appendChild(labelEl);
115 }
116 } else {
117 // icon/button style
118 if (cfg.showIcon) {
119 iconEl = document.createElement('span');
120 iconEl.className = 'bkdm-icon';
121 iconEl.style.transition = 'opacity ' + cfg.duration + 'ms ease';
122 btn.appendChild(iconEl);
123 }
124 if (cfg.showLabel) {
125 labelEl = document.createElement('span');
126 labelEl.className = 'bkdm-label';
127 btn.appendChild(labelEl);
128 }
129 }
130
131 function apply(theme) {
132 var isDark = (theme === cfg.darkVal);
133 current = theme;
134
135 // Apply attribute to html element
136 document.documentElement.setAttribute(cfg.attr.replace(/^data-/, ''), isDark ? cfg.darkVal : cfg.lightVal);
137 // Also set the full data attribute
138 document.documentElement.setAttribute(cfg.attr, isDark ? cfg.darkVal : cfg.lightVal);
139
140 try { localStorage.setItem(cfg.storageKey, theme); } catch (e) {}
141
142 btn.setAttribute('aria-pressed', String(isDark));
143
144 if (iconEl) iconEl.textContent = isDark ? cfg.darkIcon : cfg.lightIcon;
145 if (labelEl) labelEl.textContent = isDark ? cfg.darkLabel : cfg.lightLabel;
146
147 if (cfg.toggleStyle === 'switch') {
148 trackEl.style.background = isDark ? cfg.trackDark : cfg.trackLight;
149 var travelX = trackEl.offsetWidth - thumbSize - 4;
150 thumbEl.style.transform = isDark ? 'translateX(' + travelX + 'px)' : 'translateX(0)';
151 } else {
152 btn.style.background = isDark ? cfg.darkBg : cfg.lightBg;
153 btn.style.color = isDark ? cfg.darkColor : cfg.lightColor;
154 }
155 }
156
157 btn.addEventListener('click', function () {
158 var next = (current === cfg.darkVal) ? cfg.lightVal : cfg.darkVal;
159 apply(next);
160 });
161
162 // Initial paint (defer one tick so track has layout)
163 requestAnimationFrame(function () { apply(current); });
164
165 // Listen to system pref changes
166 if (cfg.respectSystem && window.matchMedia) {
167 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
168 try { if (localStorage.getItem(cfg.storageKey)) return; } catch (ex) {}
169 apply(e.matches ? cfg.darkVal : cfg.lightVal);
170 });
171 }
172 }
173
174 function init() {
175 var wraps = document.querySelectorAll('.bkdm-wrap[data-toggle-style]');
176 wraps.forEach(function (wrap) { initToggle(wrap); });
177 }
178
179 if (document.readyState === 'loading') {
180 document.addEventListener('DOMContentLoaded', init);
181 } else {
182 init();
183 }
184
185 }());
186