maverick-wave 5.4.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/mw-maverick-wave/SKILL.md +13 -10
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +91 -0
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +5 -4
- package/.claude/skills/mw-maverick-wave/references/components.md +3 -0
- package/.claude/skills/mw-maverick-wave/references/javascript.md +19 -2
- package/.claude/skills/mw-maverick-wave/references/layout.md +20 -14
- package/.claude/skills/mw-maverick-wave/references/theming.md +44 -0
- package/CHANGELOG.md +17 -0
- package/CLAUDE.md +1 -1
- package/README.md +27 -4
- package/index.html +448 -0
- package/maverick-wave.min.css +5 -5
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/scripts/verify.js +4 -7
- package/src/js/main.js +157 -2
- package/src/partials/documentation-container.html +4 -0
- package/src/partials/footer-container.html +3 -0
- package/src/partials/history-container.html +67 -0
- package/src/partials/palette-container.html +325 -0
- package/src/partials/utilities-container.html +41 -0
- package/src/scss/abstracts/_functions.scss +11 -2
- package/src/scss/abstracts/_mixins.scss +36 -8
- package/src/scss/abstracts/_variables.scss +4 -4
- package/src/scss/base/_base.scss +3 -0
- package/src/scss/base/_reset.scss +4 -1
- package/src/scss/components/_accordions.scss +31 -7
- package/src/scss/components/_avatars.scss +4 -1
- package/src/scss/components/_blog-post.scss +2 -2
- package/src/scss/components/_cards.scss +13 -22
- package/src/scss/components/_coming-soon.scss +1 -1
- package/src/scss/components/_info.scss +2 -2
- package/src/scss/components/_lists.scss +1 -1
- package/src/scss/components/_panels.scss +1 -1
- package/src/scss/components/_pricing.scss +1 -1
- package/src/scss/components/_techstack-bucket.scss +1 -1
- package/src/scss/components/_tiles.scss +1 -1
- package/src/scss/components/_toasts.scss +1 -1
- package/src/scss/form-elements/_slider.scss +5 -23
- package/src/scss/layout/_footer.scss +1 -1
- package/src/scss/layout/_header-reveal.scss +33 -0
- package/src/scss/layout/_header.scss +9 -1
- package/src/scss/layout/_parallax.scss +20 -0
- package/src/scss/utilities/_index.scss +1 -0
- package/src/scss/utilities/_reveal.scss +22 -0
- package/src/scss/utilities/_variants.scss +90 -0
- package/.impeccable/config.local.json +0 -5
- package/.impeccable/hook.cache.json +0 -75
package/index.html
CHANGED
|
@@ -118,6 +118,253 @@
|
|
|
118
118
|
height: 50px;
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
|
|
122
|
+
/* Palette switcher, showcase only. The framework derives every tone from
|
|
123
|
+
the root colors, so the panel writes nothing but those. */
|
|
124
|
+
.palette-fab {
|
|
125
|
+
position: fixed;
|
|
126
|
+
right: 18px;
|
|
127
|
+
bottom: 18px;
|
|
128
|
+
z-index: 400;
|
|
129
|
+
width: 52px;
|
|
130
|
+
height: 52px;
|
|
131
|
+
border-radius: 50%;
|
|
132
|
+
border: 1px solid var(--mw-border-accent);
|
|
133
|
+
background: var(--mw-primary-color);
|
|
134
|
+
color: var(--mw-primary-accent-text-color);
|
|
135
|
+
box-shadow: var(--mw-elevation-4);
|
|
136
|
+
font-size: 1.25rem;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
transition: var(--mw-transition);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.palette-fab:hover {
|
|
142
|
+
background: var(--mw-primary-color-hover);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.palette-fab:active {
|
|
146
|
+
transform: scale(0.92);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.palette-panel {
|
|
150
|
+
position: fixed;
|
|
151
|
+
right: 18px;
|
|
152
|
+
bottom: 82px;
|
|
153
|
+
z-index: 400;
|
|
154
|
+
width: 360px;
|
|
155
|
+
/* The variant list makes the panel taller than a laptop in landscape -
|
|
156
|
+
the top of it would be behind the browser chrome without this */
|
|
157
|
+
max-height: calc(100dvh - 120px);
|
|
158
|
+
overflow-y: auto;
|
|
159
|
+
overscroll-behavior: contain;
|
|
160
|
+
padding: 18px;
|
|
161
|
+
border-radius: 12px;
|
|
162
|
+
border: 1px solid var(--mw-border);
|
|
163
|
+
background: var(--mw-card-background);
|
|
164
|
+
box-shadow: var(--mw-elevation-5);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.palette-heading {
|
|
168
|
+
font-size: 1.1rem;
|
|
169
|
+
margin-bottom: 4px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.palette-hint {
|
|
173
|
+
font-size: 0.8rem;
|
|
174
|
+
line-height: 1.35;
|
|
175
|
+
color: var(--mw-text-muted-color);
|
|
176
|
+
margin-bottom: 14px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.palette-grid {
|
|
180
|
+
display: grid;
|
|
181
|
+
grid-template-columns: 1fr 1fr;
|
|
182
|
+
gap: 6px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.palette-item {
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: 8px;
|
|
189
|
+
padding: 6px 8px;
|
|
190
|
+
border-radius: 8px;
|
|
191
|
+
border: 1px solid var(--mw-border);
|
|
192
|
+
background: transparent;
|
|
193
|
+
color: var(--mw-text-color);
|
|
194
|
+
font-size: 0.8rem;
|
|
195
|
+
text-align: left;
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
transition: var(--mw-transition);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.palette-item::before {
|
|
201
|
+
content: '';
|
|
202
|
+
width: 16px;
|
|
203
|
+
height: 16px;
|
|
204
|
+
flex-shrink: 0;
|
|
205
|
+
border-radius: 50%;
|
|
206
|
+
background: linear-gradient(
|
|
207
|
+
135deg,
|
|
208
|
+
var(--swatch-primary) 50%,
|
|
209
|
+
var(--swatch-secondary) 50%
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.palette-item:hover,
|
|
214
|
+
.palette-item.mw-active {
|
|
215
|
+
border-color: var(--mw-primary-text-color);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.palette-item.mw-active {
|
|
219
|
+
background: var(--mw-primary-background);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.palette-custom {
|
|
223
|
+
display: flex;
|
|
224
|
+
gap: 10px;
|
|
225
|
+
margin-top: 14px;
|
|
226
|
+
padding-top: 12px;
|
|
227
|
+
border-top: 1px solid var(--mw-border);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.palette-field {
|
|
231
|
+
flex: 1;
|
|
232
|
+
display: flex;
|
|
233
|
+
flex-direction: column;
|
|
234
|
+
gap: 4px;
|
|
235
|
+
font-size: 0.75rem;
|
|
236
|
+
color: var(--mw-text-muted-color);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.palette-field input {
|
|
240
|
+
width: 100%;
|
|
241
|
+
height: 30px;
|
|
242
|
+
padding: 2px;
|
|
243
|
+
border: 1px solid var(--mw-border);
|
|
244
|
+
border-radius: 6px;
|
|
245
|
+
background: var(--mw-card-background);
|
|
246
|
+
cursor: pointer;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* Single accent means the secondary picker writes a token nothing reads any
|
|
250
|
+
more - left live it is a knob that does nothing */
|
|
251
|
+
:root.mw-accent-single .palette-field:has(#palette-secondary) {
|
|
252
|
+
opacity: 0.4;
|
|
253
|
+
pointer-events: none;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.palette-heading-split {
|
|
257
|
+
margin-top: 18px;
|
|
258
|
+
padding-top: 14px;
|
|
259
|
+
border-top: 1px solid var(--mw-border);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.variant-row {
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
justify-content: space-between;
|
|
266
|
+
gap: 12px;
|
|
267
|
+
padding-block: 9px;
|
|
268
|
+
font-size: 0.8rem;
|
|
269
|
+
color: var(--mw-text-color);
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.variant-label {
|
|
274
|
+
display: flex;
|
|
275
|
+
flex-direction: column;
|
|
276
|
+
gap: 2px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.variant-label small {
|
|
280
|
+
font-size: 0.68rem;
|
|
281
|
+
line-height: 1.35;
|
|
282
|
+
color: var(--mw-text-muted-color);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.variant-row + .variant-row {
|
|
286
|
+
border-top: 1px solid var(--mw-border);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.variant-row select {
|
|
290
|
+
flex-shrink: 0;
|
|
291
|
+
max-width: 110px;
|
|
292
|
+
padding: 3px 6px;
|
|
293
|
+
font-size: 0.75rem;
|
|
294
|
+
color: var(--mw-text-color);
|
|
295
|
+
border: 1px solid var(--mw-border);
|
|
296
|
+
border-radius: 6px;
|
|
297
|
+
background: transparent;
|
|
298
|
+
cursor: pointer;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* Drawn by hand rather than reusing mw-toggle: a framework switch would
|
|
302
|
+
reshape itself along with the variants it is there to control */
|
|
303
|
+
.variant-row input[type='checkbox'] {
|
|
304
|
+
appearance: none;
|
|
305
|
+
flex-shrink: 0;
|
|
306
|
+
position: relative;
|
|
307
|
+
width: 34px;
|
|
308
|
+
height: 18px;
|
|
309
|
+
margin: 0;
|
|
310
|
+
border: 1px solid var(--mw-border);
|
|
311
|
+
border-radius: 9px;
|
|
312
|
+
background: var(--mw-gray-background);
|
|
313
|
+
cursor: pointer;
|
|
314
|
+
transition: var(--mw-transition);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.variant-row input[type='checkbox']::after {
|
|
318
|
+
content: '';
|
|
319
|
+
position: absolute;
|
|
320
|
+
top: 2px;
|
|
321
|
+
left: 2px;
|
|
322
|
+
width: 12px;
|
|
323
|
+
height: 12px;
|
|
324
|
+
border-radius: 50%;
|
|
325
|
+
background: var(--mw-text-muted-color);
|
|
326
|
+
transition: var(--mw-transition);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.variant-row input[type='checkbox']:checked {
|
|
330
|
+
background: var(--mw-primary-color);
|
|
331
|
+
border-color: var(--mw-primary-color);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.variant-row input[type='checkbox']:checked::after {
|
|
335
|
+
left: 18px;
|
|
336
|
+
background: var(--mw-primary-accent-text-color);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.variant-setup {
|
|
340
|
+
margin-top: 14px;
|
|
341
|
+
padding: 10px;
|
|
342
|
+
border-radius: 8px;
|
|
343
|
+
border: 1px solid var(--mw-border);
|
|
344
|
+
background: var(--mw-gray-background);
|
|
345
|
+
color: var(--mw-text-muted-color);
|
|
346
|
+
font-family: var(--mw-font-family-mono);
|
|
347
|
+
font-size: 0.68rem;
|
|
348
|
+
line-height: 1.5;
|
|
349
|
+
white-space: pre-wrap;
|
|
350
|
+
word-break: break-word;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@media (max-width: 480px) {
|
|
354
|
+
.palette-fab {
|
|
355
|
+
right: 12px;
|
|
356
|
+
bottom: 12px;
|
|
357
|
+
width: 46px;
|
|
358
|
+
height: 46px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.palette-panel {
|
|
362
|
+
right: 12px;
|
|
363
|
+
left: 12px;
|
|
364
|
+
bottom: 68px;
|
|
365
|
+
width: auto;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
121
368
|
</style>
|
|
122
369
|
|
|
123
370
|
<script src="maverick-wave.min.js"></script>
|
|
@@ -538,6 +785,17 @@
|
|
|
538
785
|
</div>
|
|
539
786
|
</div>
|
|
540
787
|
</section>
|
|
788
|
+
<!-- History section -->
|
|
789
|
+
<section id="history" class="mw-section mw-section-alternate">
|
|
790
|
+
<div class="mw-container">
|
|
791
|
+
<h2 class="mw-section-title">History</h2>
|
|
792
|
+
<p class="mw-section-intro">
|
|
793
|
+
The major releases so far. Everything in between - the minors and
|
|
794
|
+
the patch releases - sits in the changelog.
|
|
795
|
+
</p>
|
|
796
|
+
@@include('./src/partials/history-container.html')
|
|
797
|
+
</div>
|
|
798
|
+
</section>
|
|
541
799
|
</main>
|
|
542
800
|
|
|
543
801
|
<!-- Footer -->
|
|
@@ -546,6 +804,9 @@
|
|
|
546
804
|
@@include('./src/partials/footer-container.html')
|
|
547
805
|
</div>
|
|
548
806
|
</footer>
|
|
807
|
+
|
|
808
|
+
<!-- Palette switcher -->
|
|
809
|
+
@@include('./src/partials/palette-container.html')
|
|
549
810
|
<script>
|
|
550
811
|
// just for the showcase (login button triggers login error)
|
|
551
812
|
document.addEventListener('DOMContentLoaded', () => {
|
|
@@ -629,6 +890,193 @@
|
|
|
629
890
|
apply(cycleSwitch.querySelector('.mw-active'));
|
|
630
891
|
});
|
|
631
892
|
|
|
893
|
+
// just for the showcase: the palette switcher. Every tone in the framework
|
|
894
|
+
// is derived from the root colors with color-mix(), so writing those on the
|
|
895
|
+
// root element repaints the page - bar, ink, borders and tints included.
|
|
896
|
+
// Nothing is persisted - a palette is for looking at, a reload is the way back.
|
|
897
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
898
|
+
const fab = document.getElementById('palette-fab');
|
|
899
|
+
const panel = document.getElementById('palette-panel');
|
|
900
|
+
const primaryInput = document.getElementById('palette-primary');
|
|
901
|
+
const secondaryInput = document.getElementById('palette-secondary');
|
|
902
|
+
const items = [...document.querySelectorAll('.palette-item')];
|
|
903
|
+
if (!fab || !panel) return;
|
|
904
|
+
|
|
905
|
+
const root = document.documentElement;
|
|
906
|
+
|
|
907
|
+
const DARK_INK = '#131925';
|
|
908
|
+
const LIGHT_INK = '#f2f6fc';
|
|
909
|
+
|
|
910
|
+
const luminance = (hex) => {
|
|
911
|
+
const [r, g, b] = [1, 3, 5].map((i) => {
|
|
912
|
+
const channel = parseInt(hex.slice(i, i + 2), 16) / 255;
|
|
913
|
+
return channel <= 0.04045
|
|
914
|
+
? channel / 12.92
|
|
915
|
+
: ((channel + 0.055) / 1.055) ** 2.4;
|
|
916
|
+
});
|
|
917
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
const contrast = (a, b) => {
|
|
921
|
+
const [high, low] = [luminance(a), luminance(b)].sort(
|
|
922
|
+
(x, y) => y - x
|
|
923
|
+
);
|
|
924
|
+
return (high + 0.05) / (low + 0.05);
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
// Measured, not thresholded - a lightness cutoff gets a saturated mid
|
|
928
|
+
// tone wrong
|
|
929
|
+
const ink = (fill) =>
|
|
930
|
+
contrast(fill, DARK_INK) > contrast(fill, LIGHT_INK)
|
|
931
|
+
? DARK_INK
|
|
932
|
+
: LIGHT_INK;
|
|
933
|
+
|
|
934
|
+
// Cuts the transition the new colours started: the whole page
|
|
935
|
+
// interpolating at once is the expensive part, and the hex labels in the
|
|
936
|
+
// Colors section read computed values, so they need the landed ones
|
|
937
|
+
const settle = () => {
|
|
938
|
+
root.classList.add('mw-theme-switching');
|
|
939
|
+
void root.offsetHeight;
|
|
940
|
+
root.classList.remove('mw-theme-switching');
|
|
941
|
+
window.mwRefreshColorSwatches?.();
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
const paint = (name, color) => {
|
|
945
|
+
root.style.setProperty(`--mw-${name}-color`, color);
|
|
946
|
+
root.style.setProperty(`--mw-${name}-accent-text-color`, ink(color));
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
items.forEach((item) => {
|
|
950
|
+
const { primary, secondary, dark, light } = item.dataset;
|
|
951
|
+
item.style.setProperty('--swatch-primary', primary);
|
|
952
|
+
item.style.setProperty('--swatch-secondary', secondary);
|
|
953
|
+
|
|
954
|
+
item.addEventListener('click', () => {
|
|
955
|
+
items.forEach((other) =>
|
|
956
|
+
other.classList.toggle('mw-active', other === item)
|
|
957
|
+
);
|
|
958
|
+
paint('primary', primary);
|
|
959
|
+
paint('secondary', secondary);
|
|
960
|
+
root.style.setProperty('--mw-dark-page-background', dark);
|
|
961
|
+
root.style.setProperty('--mw-light-page-background', light);
|
|
962
|
+
primaryInput.value = primary;
|
|
963
|
+
secondaryInput.value = secondary;
|
|
964
|
+
settle();
|
|
965
|
+
});
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
// A hand-picked color belongs to no preset - the page backgrounds stay put
|
|
969
|
+
[
|
|
970
|
+
['primary', primaryInput],
|
|
971
|
+
['secondary', secondaryInput],
|
|
972
|
+
].forEach(([name, input]) => {
|
|
973
|
+
input.addEventListener('input', () => {
|
|
974
|
+
items.forEach((item) => item.classList.remove('mw-active'));
|
|
975
|
+
paint(name, input.value);
|
|
976
|
+
});
|
|
977
|
+
// Dragging the picker fires `input` per pixel - the rest waits for the end
|
|
978
|
+
input.addEventListener('change', settle);
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
const toggle = (open) => {
|
|
982
|
+
panel.hidden = !open;
|
|
983
|
+
fab.setAttribute('aria-expanded', String(open));
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
fab.addEventListener('click', (event) => {
|
|
987
|
+
event.stopPropagation();
|
|
988
|
+
toggle(panel.hidden);
|
|
989
|
+
});
|
|
990
|
+
document.addEventListener('click', (event) => {
|
|
991
|
+
if (!panel.hidden && !panel.contains(event.target)) toggle(false);
|
|
992
|
+
});
|
|
993
|
+
document.addEventListener('keydown', (event) => {
|
|
994
|
+
if (event.key === 'Escape') toggle(false);
|
|
995
|
+
});
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
// just for the showcase: the variant switches. Each one is a class on <html>
|
|
999
|
+
// or a single custom property, never a walk over the DOM - markup that
|
|
1000
|
+
// arrives later (a modal, a toast, a kanban card) is covered by the same
|
|
1001
|
+
// class that was already set. The readout at the bottom of the panel is the
|
|
1002
|
+
// whole setup a project would carry to get the look it is currently seeing.
|
|
1003
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
1004
|
+
const list = document.getElementById('variant-list');
|
|
1005
|
+
const setup = document.getElementById('variant-setup');
|
|
1006
|
+
if (!list || !setup) return;
|
|
1007
|
+
|
|
1008
|
+
const root = document.documentElement;
|
|
1009
|
+
const controls = [...list.querySelectorAll('input, select')];
|
|
1010
|
+
|
|
1011
|
+
const isOn = (input) =>
|
|
1012
|
+
input.hasAttribute('data-variant-invert')
|
|
1013
|
+
? !input.checked
|
|
1014
|
+
: input.checked;
|
|
1015
|
+
|
|
1016
|
+
const render = () => {
|
|
1017
|
+
const classes = [];
|
|
1018
|
+
const notes = [];
|
|
1019
|
+
const props = [];
|
|
1020
|
+
|
|
1021
|
+
controls.forEach((control) => {
|
|
1022
|
+
if (control.type !== 'checkbox') {
|
|
1023
|
+
if (control.value) {
|
|
1024
|
+
props.push(
|
|
1025
|
+
` ${control.dataset.variantProp}: ${control.value};`
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// A targeted class is one the markup already ships, so its absence is
|
|
1032
|
+
// the deviation worth naming - the rest are classes to add
|
|
1033
|
+
const target = control.dataset.variantTarget;
|
|
1034
|
+
if (target) {
|
|
1035
|
+
if (!isOn(control)) {
|
|
1036
|
+
notes.push(target + ': no ' + control.dataset.variantClass);
|
|
1037
|
+
}
|
|
1038
|
+
} else if (isOn(control)) {
|
|
1039
|
+
classes.push(control.dataset.variantClass);
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
const lines = [];
|
|
1044
|
+
if (classes.length) {
|
|
1045
|
+
lines.push('html class="' + classes.join(' ') + '"');
|
|
1046
|
+
}
|
|
1047
|
+
lines.push(...notes);
|
|
1048
|
+
if (props.length) lines.push(':root {', ...props, '}');
|
|
1049
|
+
|
|
1050
|
+
setup.textContent = lines.length
|
|
1051
|
+
? lines.join('\n')
|
|
1052
|
+
: 'Default setup - nothing to change.';
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
const apply = (control) => {
|
|
1056
|
+
if (control.type === 'checkbox') {
|
|
1057
|
+
const target = control.dataset.variantTarget;
|
|
1058
|
+
const el = target ? document.querySelector(target) : root;
|
|
1059
|
+
el?.classList.toggle(control.dataset.variantClass, isOn(control));
|
|
1060
|
+
} else if (control.value) {
|
|
1061
|
+
root.style.setProperty(control.dataset.variantProp, control.value);
|
|
1062
|
+
} else {
|
|
1063
|
+
root.style.removeProperty(control.dataset.variantProp);
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1067
|
+
controls.forEach((control) =>
|
|
1068
|
+
control.addEventListener('change', () => {
|
|
1069
|
+
apply(control);
|
|
1070
|
+
render();
|
|
1071
|
+
})
|
|
1072
|
+
);
|
|
1073
|
+
|
|
1074
|
+
// Applied on load too, so a browser that restored a checked box after a
|
|
1075
|
+
// reload does not leave the page and the panel disagreeing
|
|
1076
|
+
controls.forEach(apply);
|
|
1077
|
+
render();
|
|
1078
|
+
});
|
|
1079
|
+
|
|
632
1080
|
// for the modals - the framework handles both shapes, div and <dialog>
|
|
633
1081
|
const openModal = window.mwOpenModal;
|
|
634
1082
|
const closeModal = window.mwCloseModal;
|