maverick-wave 5.8.0 → 5.10.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 +22 -12
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +10 -1
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +4 -3
- package/.claude/skills/mw-maverick-wave/references/components.md +23 -9
- package/.claude/skills/mw-maverick-wave/references/javascript.md +1 -1
- package/.claude/skills/mw-maverick-wave/references/layout.md +8 -3
- package/.claude/skills/mw-maverick-wave/references/theming.md +48 -25
- package/CHANGELOG.md +13 -0
- package/README.md +41 -24
- package/index.html +325 -20
- package/maverick-wave.min.css +61 -5
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/scripts/verify.js +7 -1
- package/src/js/main.js +24 -5
- package/src/partials/palette-container.html +105 -65
- package/src/partials/preview-container.html +136 -0
- package/src/partials/utilities-container.html +38 -0
- package/src/scss/abstracts/_functions.scss +31 -3
- package/src/scss/abstracts/_mixins.scss +62 -12
- package/src/scss/abstracts/_variables.scss +47 -21
- package/src/scss/base/_base.scss +97 -8
- package/src/scss/components/_badge.scss +1 -1
- package/src/scss/components/_buttons.scss +1 -1
- package/src/scss/components/_cards.scss +23 -14
- package/src/scss/components/_dropdown.scss +58 -1
- package/src/scss/components/_kanban.scss +10 -9
- package/src/scss/components/_lang-switch.scss +1 -1
- package/src/scss/components/_localhost-indicator.scss +1 -1
- package/src/scss/components/_modals.scss +13 -1
- package/src/scss/components/_pricing.scss +1 -1
- package/src/scss/components/_progress.scss +9 -5
- package/src/scss/components/_skeleton.scss +1 -1
- package/src/scss/components/_spinners.scss +5 -5
- package/src/scss/components/_stepper.scss +4 -1
- package/src/scss/components/_tabs.scss +28 -8
- package/src/scss/components/_tiles.scss +41 -16
- package/src/scss/components/_timelines.scss +12 -5
- package/src/scss/layout/_main.scss +1 -1
- package/src/scss/layout/_parallax.scss +10 -5
- package/src/scss/utilities/_elevation.scss +23 -0
- package/src/scss/utilities/_touch-targets.scss +1 -1
- package/src/scss/utilities/_variants.scss +74 -7
package/index.html
CHANGED
|
@@ -292,6 +292,26 @@
|
|
|
292
292
|
border-top: 1px solid var(--mw-border);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
/* Splits the list by where a switch shows up, because half of them act on
|
|
296
|
+
parts of the page the preview does not contain */
|
|
297
|
+
.variant-group {
|
|
298
|
+
margin: 20px 0 2px;
|
|
299
|
+
font-size: 0.78rem;
|
|
300
|
+
font-weight: 600;
|
|
301
|
+
color: var(--mw-text-color);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.variant-group:first-child {
|
|
305
|
+
margin-top: 4px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.variant-group-hint {
|
|
309
|
+
margin: 0 0 4px;
|
|
310
|
+
font-size: 0.68rem;
|
|
311
|
+
line-height: 1.35;
|
|
312
|
+
color: var(--mw-text-muted-color);
|
|
313
|
+
}
|
|
314
|
+
|
|
295
315
|
.variant-row {
|
|
296
316
|
display: flex;
|
|
297
317
|
align-items: center;
|
|
@@ -369,14 +389,129 @@
|
|
|
369
389
|
background: var(--mw-primary-accent-text-color);
|
|
370
390
|
}
|
|
371
391
|
|
|
392
|
+
/* The sticky bar would otherwise sit on the section title it jumps to */
|
|
393
|
+
#preview {
|
|
394
|
+
scroll-margin-top: calc(var(--mw-header-height) + 1rem);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.preview-head {
|
|
398
|
+
display: flex;
|
|
399
|
+
align-items: flex-start;
|
|
400
|
+
justify-content: space-between;
|
|
401
|
+
gap: 1rem;
|
|
402
|
+
margin-bottom: 1.5rem;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.preview-title {
|
|
406
|
+
margin: 0 0 0.35rem;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.preview-lede {
|
|
410
|
+
margin: 0;
|
|
411
|
+
max-inline-size: 60ch;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/* The panel is fixed over the right of the page, flush with the container
|
|
415
|
+
edge. Below xl there is no room to dodge it and it simply covers part of
|
|
416
|
+
the preview; from there the preview keeps to the strip beside it,
|
|
417
|
+
because a switch that moves something hidden behind the panel
|
|
418
|
+
demonstrates nothing. */
|
|
419
|
+
@media (width >= 1200px) {
|
|
420
|
+
body:has(.palette-panel:not([hidden])) #preview > .mw-container {
|
|
421
|
+
padding-inline-end: 460px;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Both wrap rather than squeezing a field to nothing on a phone */
|
|
426
|
+
.preview-row,
|
|
427
|
+
.preview-actions {
|
|
428
|
+
display: flex;
|
|
429
|
+
flex-wrap: wrap;
|
|
430
|
+
align-items: center;
|
|
431
|
+
gap: 0.75rem;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.preview-row .mw-input {
|
|
435
|
+
flex: 1 1 12rem;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* The one thing here that keeps moving without being touched, so Motion
|
|
439
|
+
tempo has something to show that a hover state cannot */
|
|
440
|
+
.preview-status {
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
gap: 14px;
|
|
444
|
+
margin: 0 0 1.25rem;
|
|
445
|
+
font-size: 0.82rem;
|
|
446
|
+
color: var(--mw-text-muted-color);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.preview-status strong {
|
|
450
|
+
display: block;
|
|
451
|
+
color: var(--mw-text-color);
|
|
452
|
+
font-weight: 500;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.preview-status small {
|
|
456
|
+
font-size: 0.75rem;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.preview-row .mw-select {
|
|
460
|
+
flex: 0 1 14rem;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* The spacing sits on the row and not on the label: the button is taller
|
|
464
|
+
than the caption beside it, so a margin under the label leaves the
|
|
465
|
+
button itself resting on the box */
|
|
466
|
+
.variant-setup-head {
|
|
467
|
+
display: flex;
|
|
468
|
+
align-items: baseline;
|
|
469
|
+
justify-content: space-between;
|
|
470
|
+
gap: 10px;
|
|
471
|
+
margin: 14px 0 10px;
|
|
472
|
+
}
|
|
473
|
+
|
|
372
474
|
.variant-setup-label {
|
|
373
475
|
display: block;
|
|
374
|
-
margin
|
|
375
|
-
margin-bottom: 5px;
|
|
476
|
+
margin: 0;
|
|
376
477
|
font-size: 0.7rem;
|
|
377
478
|
color: var(--mw-text-muted-color);
|
|
378
479
|
}
|
|
379
480
|
|
|
481
|
+
/* The one control here that leads somewhere - everything else in the
|
|
482
|
+
panel only changes what is on screen. Carries the brand colour so it
|
|
483
|
+
reads as the way out rather than as one more switch. */
|
|
484
|
+
.variant-share {
|
|
485
|
+
display: inline-flex;
|
|
486
|
+
align-items: center;
|
|
487
|
+
gap: 6px;
|
|
488
|
+
flex-shrink: 0;
|
|
489
|
+
padding: 5px 12px;
|
|
490
|
+
border-radius: 999px;
|
|
491
|
+
border: 1px solid var(--mw-primary-color);
|
|
492
|
+
background: var(--mw-primary-color);
|
|
493
|
+
color: var(--mw-primary-accent-text-color);
|
|
494
|
+
font: inherit;
|
|
495
|
+
font-size: 0.72rem;
|
|
496
|
+
font-weight: 500;
|
|
497
|
+
cursor: pointer;
|
|
498
|
+
transition: var(--mw-transition-fast);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.variant-share:hover {
|
|
502
|
+
background: var(--mw-primary-color-hover, var(--mw-primary-color));
|
|
503
|
+
transform: translateY(-1px);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.variant-share:active {
|
|
507
|
+
transform: translateY(0);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.variant-share:focus-visible {
|
|
511
|
+
outline: var(--mw-focus-ring-width) solid var(--mw-focus-ring-color);
|
|
512
|
+
outline-offset: var(--mw-focus-ring-offset);
|
|
513
|
+
}
|
|
514
|
+
|
|
380
515
|
.variant-setup {
|
|
381
516
|
display: block;
|
|
382
517
|
width: 100%;
|
|
@@ -401,7 +536,7 @@
|
|
|
401
536
|
<a class="mw-skip-link" href="#main">Skip to content</a>
|
|
402
537
|
|
|
403
538
|
<!-- Header -->
|
|
404
|
-
<header class="mw-header mw-
|
|
539
|
+
<header class="mw-header mw-localhost-indicator-activated">
|
|
405
540
|
<div class="mw-container">
|
|
406
541
|
@@include('./src/partials/header-container.html')
|
|
407
542
|
</div>
|
|
@@ -823,6 +958,18 @@
|
|
|
823
958
|
@@include('./src/partials/history-container.html')
|
|
824
959
|
</div>
|
|
825
960
|
</section>
|
|
961
|
+
<!-- Preview section, showcase only - see the partial -->
|
|
962
|
+
<section id="preview" class="mw-section">
|
|
963
|
+
<div class="mw-container">
|
|
964
|
+
<h2 class="mw-section-title">Preview</h2>
|
|
965
|
+
<p class="mw-section-intro">
|
|
966
|
+
One page-shaped example, so the variant switches in the palette
|
|
967
|
+
panel have something to act on that is not a component gallery. Open
|
|
968
|
+
the panel and the page lands here.
|
|
969
|
+
</p>
|
|
970
|
+
@@include('./src/partials/preview-container.html')
|
|
971
|
+
</div>
|
|
972
|
+
</section>
|
|
826
973
|
</main>
|
|
827
974
|
|
|
828
975
|
<!-- Footer -->
|
|
@@ -1013,9 +1160,21 @@
|
|
|
1013
1160
|
input.addEventListener('change', settle);
|
|
1014
1161
|
});
|
|
1015
1162
|
|
|
1163
|
+
const preview = document.getElementById('preview');
|
|
1164
|
+
|
|
1016
1165
|
const toggle = (open) => {
|
|
1017
1166
|
panel.hidden = !open;
|
|
1018
1167
|
toggleBtn.setAttribute('aria-expanded', String(open));
|
|
1168
|
+
|
|
1169
|
+
// Or the switches act on whatever section the reader is parked at,
|
|
1170
|
+
// which is one component at a time and says little about a look.
|
|
1171
|
+
//
|
|
1172
|
+
// `instant` against the smooth default in the reset: the preview sits
|
|
1173
|
+
// at the end of a page some 80 000px long, and over that distance a
|
|
1174
|
+
// smooth scroll either crawls through every section on the way or, as
|
|
1175
|
+
// here, never starts at all.
|
|
1176
|
+
if (open)
|
|
1177
|
+
preview?.scrollIntoView({ block: 'start', behavior: 'instant' });
|
|
1019
1178
|
};
|
|
1020
1179
|
|
|
1021
1180
|
toggleBtn.addEventListener('click', (event) => {
|
|
@@ -1116,6 +1275,58 @@
|
|
|
1116
1275
|
const root = document.documentElement;
|
|
1117
1276
|
const controls = [...list.querySelectorAll('input, select')];
|
|
1118
1277
|
|
|
1278
|
+
// Built on every render, put into the address bar by nobody: a setup
|
|
1279
|
+
// written to the URL as you go comes back on the next reload, and then
|
|
1280
|
+
// the showcase opens in someone else's look for good. Copy link is the
|
|
1281
|
+
// one way out of here, and what it hands over is this.
|
|
1282
|
+
//
|
|
1283
|
+
// URLSearchParams and not a hand-rolled separator: a value like the
|
|
1284
|
+
// heading font or the page width is full of commas, quotes and brackets,
|
|
1285
|
+
// and escaping those by hand is where this kind of thing breaks.
|
|
1286
|
+
let shareUrl = location.origin + location.pathname;
|
|
1287
|
+
|
|
1288
|
+
const buildShareUrl = (classes, dropped, pairs) => {
|
|
1289
|
+
const params = new URLSearchParams();
|
|
1290
|
+
if (classes.length) params.set('c', classes.join(' '));
|
|
1291
|
+
if (dropped.length) params.set('d', dropped.join(' '));
|
|
1292
|
+
pairs.forEach(([prop, value]) => params.set(prop, value));
|
|
1293
|
+
|
|
1294
|
+
const query = params.toString();
|
|
1295
|
+
return (
|
|
1296
|
+
location.origin + location.pathname + (query ? '#' + query : '')
|
|
1297
|
+
);
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// Back into the shape load() reads, so the link and a pasted setup go
|
|
1301
|
+
// through one parser rather than two that can drift apart. The target in
|
|
1302
|
+
// front of `: no` is only there to make the line read like the printed
|
|
1303
|
+
// one - load() matches on the class name alone.
|
|
1304
|
+
const readHash = () => {
|
|
1305
|
+
const params = new URLSearchParams(location.hash.slice(1));
|
|
1306
|
+
const lines = [];
|
|
1307
|
+
|
|
1308
|
+
const classes = params.get('c');
|
|
1309
|
+
if (classes) lines.push('html class="' + classes + '"');
|
|
1310
|
+
|
|
1311
|
+
(params.get('d') || '')
|
|
1312
|
+
.split(/\s+/)
|
|
1313
|
+
.filter(Boolean)
|
|
1314
|
+
.forEach((name) => lines.push('markup: no ' + name));
|
|
1315
|
+
|
|
1316
|
+
const pairs = [...params.entries()].filter(([key]) =>
|
|
1317
|
+
key.startsWith('--')
|
|
1318
|
+
);
|
|
1319
|
+
if (pairs.length) {
|
|
1320
|
+
lines.push(
|
|
1321
|
+
':root {',
|
|
1322
|
+
...pairs.map(([key, value]) => ` ${key}: ${value};`),
|
|
1323
|
+
'}'
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
return lines.length ? lines.join('\n') : null;
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1119
1330
|
const isOn = (input) =>
|
|
1120
1331
|
input.hasAttribute('data-variant-invert')
|
|
1121
1332
|
? !input.checked
|
|
@@ -1127,8 +1338,10 @@
|
|
|
1127
1338
|
if (document.activeElement === setup) return;
|
|
1128
1339
|
|
|
1129
1340
|
const classes = [];
|
|
1341
|
+
// Unformatted, because both the box and the link are written from
|
|
1342
|
+
// these and formatting only one of the two ways is a bug waiting
|
|
1130
1343
|
const notes = [];
|
|
1131
|
-
const
|
|
1344
|
+
const pairs = [];
|
|
1132
1345
|
|
|
1133
1346
|
// The palette is part of the setup, and it is printed first because a
|
|
1134
1347
|
// project sets its brand colours before it retunes anything else
|
|
@@ -1141,7 +1354,7 @@
|
|
|
1141
1354
|
['--mw-dark-page-background', palette.dark],
|
|
1142
1355
|
['--mw-light-page-background', palette.light],
|
|
1143
1356
|
].forEach(([prop, value]) => {
|
|
1144
|
-
if (value)
|
|
1357
|
+
if (value) pairs.push([prop, value]);
|
|
1145
1358
|
});
|
|
1146
1359
|
|
|
1147
1360
|
controls.forEach((control) => {
|
|
@@ -1152,9 +1365,7 @@
|
|
|
1152
1365
|
if (control.hasAttribute('data-variant-classes')) {
|
|
1153
1366
|
classes.push(control.value);
|
|
1154
1367
|
} else {
|
|
1155
|
-
|
|
1156
|
-
` ${control.dataset.variantProp}: ${control.value};`
|
|
1157
|
-
);
|
|
1368
|
+
pairs.push([control.dataset.variantProp, control.value]);
|
|
1158
1369
|
}
|
|
1159
1370
|
return;
|
|
1160
1371
|
}
|
|
@@ -1164,7 +1375,7 @@
|
|
|
1164
1375
|
const target = control.dataset.variantTarget;
|
|
1165
1376
|
if (target) {
|
|
1166
1377
|
if (!isOn(control)) {
|
|
1167
|
-
notes.push(target
|
|
1378
|
+
notes.push([target, control.dataset.variantClass]);
|
|
1168
1379
|
}
|
|
1169
1380
|
} else if (isOn(control)) {
|
|
1170
1381
|
classes.push(control.dataset.variantClass);
|
|
@@ -1175,12 +1386,24 @@
|
|
|
1175
1386
|
if (classes.length) {
|
|
1176
1387
|
lines.push('html class="' + classes.join(' ') + '"');
|
|
1177
1388
|
}
|
|
1178
|
-
lines.push(...notes);
|
|
1179
|
-
if (
|
|
1389
|
+
lines.push(...notes.map(([target, name]) => `${target}: no ${name}`));
|
|
1390
|
+
if (pairs.length) {
|
|
1391
|
+
lines.push(
|
|
1392
|
+
':root {',
|
|
1393
|
+
...pairs.map(([prop, value]) => ` ${prop}: ${value};`),
|
|
1394
|
+
'}'
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1180
1397
|
|
|
1181
1398
|
setup.value = lines.length
|
|
1182
1399
|
? lines.join('\n')
|
|
1183
1400
|
: 'Default setup - nothing to change.';
|
|
1401
|
+
|
|
1402
|
+
shareUrl = buildShareUrl(
|
|
1403
|
+
classes,
|
|
1404
|
+
notes.map(([, name]) => name),
|
|
1405
|
+
pairs
|
|
1406
|
+
);
|
|
1184
1407
|
};
|
|
1185
1408
|
|
|
1186
1409
|
const optionClasses = (control) =>
|
|
@@ -1252,21 +1475,103 @@
|
|
|
1252
1475
|
// Picking a palette repaints the page, and the box has to say so
|
|
1253
1476
|
window.mwRefreshSetup = render;
|
|
1254
1477
|
|
|
1255
|
-
setup.addEventListener('input', () => load(setup.value));
|
|
1478
|
+
setup.addEventListener('input', () => inPlace(() => load(setup.value)));
|
|
1256
1479
|
// Normalises what was pasted back into the shape render() writes
|
|
1257
1480
|
setup.addEventListener('blur', render);
|
|
1258
1481
|
|
|
1482
|
+
// Type and spacing switches change the height of all 80 000px of page
|
|
1483
|
+
// above the preview as well, so the section slides out from under
|
|
1484
|
+
// whoever is watching it - Text size alone moves it by 16 000px. Hold
|
|
1485
|
+
// its top edge where it was and the change happens in place.
|
|
1486
|
+
//
|
|
1487
|
+
// Only while the preview is on screen: correcting the scroll for someone
|
|
1488
|
+
// parked up in the component sections would move *them* by those 16 000
|
|
1489
|
+
// instead. `instant` because the smooth default would animate the
|
|
1490
|
+
// correction as a scroll of its own.
|
|
1491
|
+
const previewSection = document.getElementById('preview');
|
|
1492
|
+
|
|
1493
|
+
const inPlace = (change) => {
|
|
1494
|
+
const box = previewSection?.getBoundingClientRect();
|
|
1495
|
+
const watching =
|
|
1496
|
+
box && box.bottom > 0 && box.top < window.innerHeight;
|
|
1497
|
+
if (!watching) return change();
|
|
1498
|
+
|
|
1499
|
+
const before = box.top;
|
|
1500
|
+
change();
|
|
1501
|
+
const shift = previewSection.getBoundingClientRect().top - before;
|
|
1502
|
+
if (shift) window.scrollBy({ top: shift, behavior: 'instant' });
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1259
1505
|
controls.forEach((control) =>
|
|
1260
|
-
control.addEventListener('change', () =>
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1506
|
+
control.addEventListener('change', () =>
|
|
1507
|
+
inPlace(() => {
|
|
1508
|
+
apply(control);
|
|
1509
|
+
render();
|
|
1510
|
+
})
|
|
1511
|
+
)
|
|
1264
1512
|
);
|
|
1265
1513
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1514
|
+
const shared = readHash();
|
|
1515
|
+
if (shared) {
|
|
1516
|
+
// Drives the switches, which drive the page - then render() normalises
|
|
1517
|
+
// the box and writes the link back in the order it prints
|
|
1518
|
+
load(shared);
|
|
1519
|
+
render();
|
|
1520
|
+
} else {
|
|
1521
|
+
// Without a link the showcase opens in its own look, every time. That
|
|
1522
|
+
// has to be spelled out: Firefox restores form state across a reload,
|
|
1523
|
+
// so the switches would otherwise come back set the way the last visit
|
|
1524
|
+
// left them, and the page with them.
|
|
1525
|
+
//
|
|
1526
|
+
// The markup is the one source for that starting state - the written
|
|
1527
|
+
// defaults for a plain switch, and for a targeted one whether the
|
|
1528
|
+
// class it stands for is actually on the element it names. A header
|
|
1529
|
+
// shipped without mw-header-reveal keeps it off.
|
|
1530
|
+
controls.forEach((control) => {
|
|
1531
|
+
const target = control.dataset.variantTarget;
|
|
1532
|
+
const el = target && document.querySelector(target);
|
|
1533
|
+
|
|
1534
|
+
if (el) {
|
|
1535
|
+
const present = el.classList.contains(
|
|
1536
|
+
control.dataset.variantClass
|
|
1537
|
+
);
|
|
1538
|
+
control.checked = control.hasAttribute('data-variant-invert')
|
|
1539
|
+
? !present
|
|
1540
|
+
: present;
|
|
1541
|
+
} else if (control.type === 'checkbox') {
|
|
1542
|
+
control.checked = control.defaultChecked;
|
|
1543
|
+
} else {
|
|
1544
|
+
const preset = [...control.options].find(
|
|
1545
|
+
(o) => o.defaultSelected
|
|
1546
|
+
);
|
|
1547
|
+
control.value = preset ? preset.value : '';
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
|
|
1551
|
+
controls.forEach(apply);
|
|
1552
|
+
render();
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
document
|
|
1556
|
+
.getElementById('variant-share')
|
|
1557
|
+
?.addEventListener('click', async (event) => {
|
|
1558
|
+
const button = event.currentTarget;
|
|
1559
|
+
const label = document.getElementById('variant-share-label');
|
|
1560
|
+
try {
|
|
1561
|
+
await navigator.clipboard.writeText(shareUrl);
|
|
1562
|
+
label.textContent = 'Copied';
|
|
1563
|
+
} catch {
|
|
1564
|
+
// Denied permission or an insecure origin. The address bar is no
|
|
1565
|
+
// help here - it never carries the setup - so hand the link over
|
|
1566
|
+
// in the box instead, where it can be selected by hand.
|
|
1567
|
+
setup.value = shareUrl;
|
|
1568
|
+
setup.select();
|
|
1569
|
+
label.textContent = 'Copy from the box';
|
|
1570
|
+
}
|
|
1571
|
+
setTimeout(() => {
|
|
1572
|
+
label.textContent = 'Copy link';
|
|
1573
|
+
}, 1600);
|
|
1574
|
+
});
|
|
1270
1575
|
});
|
|
1271
1576
|
|
|
1272
1577
|
// for the modals - the framework handles both shapes, div and <dialog>
|