rizzo-css 0.0.30 → 0.0.31
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/README.md +1 -1
- package/bin/rizzo-css.js +6 -6
- package/package.json +1 -1
- package/scaffold/astro/Navbar.astro +36 -2
- package/scaffold/astro/Search.astro +42 -0
- package/scaffold/vanilla/README-RIZZO.md +4 -2
- package/scaffold/vanilla/components/accordion.html +8 -0
- package/scaffold/vanilla/components/alert.html +8 -0
- package/scaffold/vanilla/components/avatar.html +8 -0
- package/scaffold/vanilla/components/badge.html +8 -0
- package/scaffold/vanilla/components/breadcrumb.html +8 -0
- package/scaffold/vanilla/components/button.html +8 -0
- package/scaffold/vanilla/components/cards.html +8 -0
- package/scaffold/vanilla/components/copy-to-clipboard.html +8 -0
- package/scaffold/vanilla/components/divider.html +8 -0
- package/scaffold/vanilla/components/dropdown.html +8 -0
- package/scaffold/vanilla/components/forms.html +8 -0
- package/scaffold/vanilla/components/icons.html +8 -0
- package/scaffold/vanilla/components/index.html +8 -0
- package/scaffold/vanilla/components/modal.html +8 -0
- package/scaffold/vanilla/components/navbar.html +8 -0
- package/scaffold/vanilla/components/pagination.html +8 -0
- package/scaffold/vanilla/components/progress-bar.html +8 -0
- package/scaffold/vanilla/components/search.html +8 -0
- package/scaffold/vanilla/components/settings.html +8 -0
- package/scaffold/vanilla/components/spinner.html +8 -0
- package/scaffold/vanilla/components/table.html +8 -0
- package/scaffold/vanilla/components/tabs.html +8 -0
- package/scaffold/vanilla/components/theme-switcher.html +8 -0
- package/scaffold/vanilla/components/toast.html +8 -0
- package/scaffold/vanilla/components/tooltip.html +8 -0
- package/scaffold/vanilla/index.html +8 -0
- package/scaffold/vanilla/js/main.js +78 -1
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ import 'rizzo-css';
|
|
|
61
61
|
**Without a bundler (plain HTML):** Use a CDN. Both unpkg and jsDelivr resolve the package root to the built CSS (via the `unpkg` / `jsdelivr` fields in this package). For reliability or to pin a version, use the explicit path:
|
|
62
62
|
|
|
63
63
|
```html
|
|
64
|
-
<!-- unpkg (pin version: replace @latest with @0.0.
|
|
64
|
+
<!-- unpkg (pin version: replace @latest with @0.0.31 or any version) -->
|
|
65
65
|
<link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />
|
|
66
66
|
|
|
67
67
|
<!-- or jsDelivr -->
|
package/bin/rizzo-css.js
CHANGED
|
@@ -58,7 +58,7 @@ Manual setup: HTML + CSS, plus any component pages you chose. Scaffolded with \`
|
|
|
58
58
|
- If you picked components, \`components/\` has their HTML pages and \`js/main.js\` is included (open \`components/index.html\` to browse).
|
|
59
59
|
- Set a theme: \`<html data-theme="github-dark-classic">\` (see \`npx rizzo-css theme\` for all themes).
|
|
60
60
|
|
|
61
|
-
**If you chose no components:** To add component JavaScript (modal, dropdown, tabs, toast, search, navbar, theme switcher, etc.), use the [Vanilla component docs](https://rizzo-css.vercel.app/docs/vanilla/components) or run \`npx rizzo-css init\` with Vanilla → **Full** in a temp folder and copy \`js/main.js\` and \`icons/\` into this project.
|
|
61
|
+
**If you chose no components:** To add component JavaScript (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher, etc.), use the [Vanilla component docs](https://rizzo-css.vercel.app/docs/vanilla/components) or run \`npx rizzo-css init\` with Vanilla → **Full** in a temp folder and copy \`js/main.js\` and \`icons/\` into this project.
|
|
62
62
|
|
|
63
63
|
Docs: [rizzo-css.vercel.app](https://rizzo-css.vercel.app)
|
|
64
64
|
`;
|
|
@@ -114,7 +114,7 @@ const RECOMMENDED_COMPONENTS = [
|
|
|
114
114
|
'Button', 'Badge', 'Card', 'Modal', 'Tabs', 'ThemeSwitcher', 'FormGroup', 'Alert', 'Toast', 'Dropdown',
|
|
115
115
|
];
|
|
116
116
|
|
|
117
|
-
// Vanilla components that need js/main.js for interactivity (modal, dropdown, tabs, toast, search, navbar mobile, theme switcher).
|
|
117
|
+
// Vanilla components that need js/main.js for interactivity (modal, dropdown, tabs, toast, search, navbar mobile, copy-to-clipboard, theme switcher).
|
|
118
118
|
const VANILLA_JS_COMPONENTS = ['Modal', 'Dropdown', 'Tabs', 'Toast', 'ThemeSwitcher'];
|
|
119
119
|
|
|
120
120
|
// Component dependencies per framework: when user selects a component, these are copied automatically so it works.
|
|
@@ -465,7 +465,7 @@ async function confirmRunInstall(pm) {
|
|
|
465
465
|
|
|
466
466
|
/** Ask user to copy js/main.js for vanilla interactive components. */
|
|
467
467
|
async function confirmCopyVanillaJs() {
|
|
468
|
-
const answer = await question('\nCopy js/main.js for modal, dropdown, tabs, toast, search, navbar
|
|
468
|
+
const answer = await question('\nCopy js/main.js for modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher? (Y/n) ');
|
|
469
469
|
return answer === '' || /^y(es)?$/i.test(answer);
|
|
470
470
|
}
|
|
471
471
|
|
|
@@ -811,7 +811,7 @@ Options (add):
|
|
|
811
811
|
--no-snippet Do not write RIZZO-SNIPPET.txt (link + theme copy-paste)
|
|
812
812
|
--readme Write README-RIZZO.md into the project
|
|
813
813
|
--force Overwrite existing rizzo.min.css without prompting
|
|
814
|
-
--vanilla-js (Vanilla) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, search, navbar, theme switcher)
|
|
814
|
+
--vanilla-js (Vanilla) Copy js/main.js for interactive components (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher)
|
|
815
815
|
|
|
816
816
|
Package managers:
|
|
817
817
|
Supported: npm, pnpm, yarn, bun. Detection: lockfiles (pnpm-lock.yaml, yarn.lock, bun.lockb, package-lock.json) or package.json "packageManager"/"devEngines.packageManager". Use --package-manager to override.
|
|
@@ -1465,7 +1465,7 @@ async function runAddToExisting(frameworkOverride, options) {
|
|
|
1465
1465
|
let mainJs = readFileSync(vanillaJsSrc, 'utf8');
|
|
1466
1466
|
mainJs = mainJs.replace(/\{\{DEFAULT_DARK\}\}/g, defaultDark).replace(/\{\{DEFAULT_LIGHT\}\}/g, defaultLight);
|
|
1467
1467
|
writeFileSync(vanillaJsPath, mainJs, 'utf8');
|
|
1468
|
-
console.log(' - Wrote js/main.js (for modal, dropdown, tabs, toast, search, navbar
|
|
1468
|
+
console.log(' - Wrote js/main.js (for modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher)');
|
|
1469
1469
|
}
|
|
1470
1470
|
} else if (needsJs && !existsSync(vanillaJsPath)) {
|
|
1471
1471
|
options._vanillaJsHint = true;
|
|
@@ -1526,7 +1526,7 @@ async function runAddToExisting(frameworkOverride, options) {
|
|
|
1526
1526
|
console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
|
|
1527
1527
|
console.log(' Component HTML files are in components/.');
|
|
1528
1528
|
if (options._vanillaJsHint) {
|
|
1529
|
-
console.log(' For interactive components (modal, dropdown, tabs, toast, search, navbar, theme switcher), add js/main.js — run again with --vanilla-js or copy from a Full scaffold.');
|
|
1529
|
+
console.log(' For interactive components (modal, dropdown, tabs, toast, search, navbar, copy-to-clipboard, theme switcher), add js/main.js — run again with --vanilla-js or copy from a Full scaffold.');
|
|
1530
1530
|
}
|
|
1531
1531
|
}
|
|
1532
1532
|
console.log('\nTo install the package: ' + pm.add('rizzo-css'));
|
package/package.json
CHANGED
|
@@ -24,11 +24,45 @@ const { siteName = 'Site', logo } = Astro.props;
|
|
|
24
24
|
<span class="navbar__settings-label">Settings</span>
|
|
25
25
|
</button>
|
|
26
26
|
</div>
|
|
27
|
-
<button type="button" class="navbar__toggle" aria-label="Toggle menu" aria-expanded="false">
|
|
27
|
+
<button type="button" class="navbar__toggle" id="navbar-toggle" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="navbar-menu">
|
|
28
|
+
<span class="sr-only">Menu</span>
|
|
28
29
|
<span class="navbar__toggle-icon" aria-hidden="true"><span></span><span></span><span></span></span>
|
|
29
30
|
</button>
|
|
30
|
-
<div class="navbar__menu" aria-hidden="true">
|
|
31
|
+
<div class="navbar__menu" id="navbar-menu" role="menu" aria-hidden="true">
|
|
31
32
|
<a href="/" class="navbar__link">Home</a>
|
|
32
33
|
</div>
|
|
33
34
|
</div>
|
|
34
35
|
</nav>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
(function initNavbarMobile() {
|
|
39
|
+
function init() {
|
|
40
|
+
var navbar = document.querySelector('.navbar');
|
|
41
|
+
if (!navbar) return;
|
|
42
|
+
var toggle = document.getElementById('navbar-toggle');
|
|
43
|
+
var menu = navbar.querySelector('.navbar__menu');
|
|
44
|
+
if (!toggle || !menu) return;
|
|
45
|
+
function setMenuOpen(open) {
|
|
46
|
+
menu.classList.toggle('navbar__menu--open', open);
|
|
47
|
+
navbar.classList.toggle('navbar--menu-open', open);
|
|
48
|
+
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
49
|
+
menu.setAttribute('aria-hidden', open ? 'false' : 'true');
|
|
50
|
+
}
|
|
51
|
+
toggle.addEventListener('click', function () {
|
|
52
|
+
setMenuOpen(!menu.classList.contains('navbar__menu--open'));
|
|
53
|
+
});
|
|
54
|
+
menu.querySelectorAll('.navbar__link').forEach(function (link) {
|
|
55
|
+
link.addEventListener('click', function () { setMenuOpen(false); });
|
|
56
|
+
});
|
|
57
|
+
document.addEventListener('keydown', function (e) {
|
|
58
|
+
if (e.key === 'Escape') {
|
|
59
|
+
if (menu.classList.contains('navbar__menu--open')) {
|
|
60
|
+
setMenuOpen(false);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
66
|
+
else init();
|
|
67
|
+
})();
|
|
68
|
+
</script>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
+
import SearchIcon from './icons/Search.astro';
|
|
2
3
|
interface Props { id?: string; }
|
|
3
4
|
const { id = 'search-main' } = Astro.props;
|
|
4
5
|
---
|
|
5
6
|
<div class="search" data-search>
|
|
6
7
|
<div class="search__trigger-wrapper">
|
|
7
8
|
<button type="button" class="search__trigger" aria-label="Open search" aria-expanded="false" aria-controls="{id}-panel">
|
|
9
|
+
<SearchIcon width={20} height={20} class="search__icon" />
|
|
8
10
|
<span class="search__trigger-text">Search</span>
|
|
9
11
|
</button>
|
|
10
12
|
</div>
|
|
@@ -14,3 +16,43 @@ const { id = 'search-main' } = Astro.props;
|
|
|
14
16
|
</div>
|
|
15
17
|
</div>
|
|
16
18
|
</div>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
(function initSearch() {
|
|
22
|
+
function init() {
|
|
23
|
+
document.querySelectorAll('[data-search]').forEach(function (search) {
|
|
24
|
+
if (search.__searchInited) return;
|
|
25
|
+
search.__searchInited = true;
|
|
26
|
+
var trigger = search.querySelector('.search__trigger');
|
|
27
|
+
var overlay = search.querySelector('[data-search-overlay]');
|
|
28
|
+
var input = search.querySelector('.search__input');
|
|
29
|
+
if (!trigger || !overlay || !input) return;
|
|
30
|
+
var previousActive = null;
|
|
31
|
+
function openSearch() {
|
|
32
|
+
previousActive = document.activeElement;
|
|
33
|
+
overlay.setAttribute('aria-hidden', 'false');
|
|
34
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
35
|
+
input.focus();
|
|
36
|
+
}
|
|
37
|
+
function closeSearch() {
|
|
38
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
39
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
40
|
+
if (previousActive && previousActive.focus) previousActive.focus();
|
|
41
|
+
previousActive = null;
|
|
42
|
+
}
|
|
43
|
+
trigger.addEventListener('click', function () {
|
|
44
|
+
if (overlay.getAttribute('aria-hidden') === 'true') openSearch();
|
|
45
|
+
else closeSearch();
|
|
46
|
+
});
|
|
47
|
+
overlay.addEventListener('click', function (e) {
|
|
48
|
+
if (e.target === overlay) closeSearch();
|
|
49
|
+
});
|
|
50
|
+
input.addEventListener('keydown', function (e) {
|
|
51
|
+
if (e.key === 'Escape') { e.preventDefault(); closeSearch(); }
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
56
|
+
else init();
|
|
57
|
+
})();
|
|
58
|
+
</script>
|
|
@@ -13,7 +13,7 @@ If you prefer to load CSS from a CDN instead of the local file, replace the `<li
|
|
|
13
13
|
- `<link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />`
|
|
14
14
|
- Or jsDelivr: `https://cdn.jsdelivr.net/npm/rizzo-css@latest/dist/rizzo.min.css`
|
|
15
15
|
|
|
16
|
-
(Replace `@latest` with a specific version, e.g. `@0.0.
|
|
16
|
+
(Replace `@latest` with a specific version, e.g. `@0.0.31`, in production.)
|
|
17
17
|
|
|
18
18
|
The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}`) when you run `rizzo-css init`. The theme selected during init is used on first load when you have no saved preference in the browser.
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}
|
|
|
22
22
|
- **Home** — `index.html` (hero, links to component showcase and docs). Edit the main content or add your own.
|
|
23
23
|
- **Component showcase** — `components/index.html` lists all components; `components/<name>.html` (e.g. `button.html`) each has a "Read the full docs" link to the main site. Edit or add HTML files; keep the same header/footer if you want the theme switcher and settings on every page.
|
|
24
24
|
- **CSS** — The CLI copies `css/rizzo.min.css`; the link uses `{{LINK_HREF}}` (replaced at init). To use a CDN, replace that with the CDN URL.
|
|
25
|
-
- **Scripts** — `js/main.js` provides theme sync, settings panel, toast, tabs, modal, dropdown, accordion, search (overlay),
|
|
25
|
+
- **Scripts** — `js/main.js` provides theme sync, settings panel, toast, tabs, modal, dropdown, accordion, search (overlay), navbar mobile menu, and copy-to-clipboard. Customize or extend as needed.
|
|
26
26
|
|
|
27
27
|
## What's included
|
|
28
28
|
|
|
@@ -37,6 +37,8 @@ The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}
|
|
|
37
37
|
- **Accordion** — Any `[data-accordion]` with `[data-accordion-trigger]` and panels; `data-allow-multiple="true"` for multiple open.
|
|
38
38
|
- **Search** — Any `[data-search]` with `.search__trigger`, `[data-search-overlay]`, `.search__panel`, and `.search__input`; trigger toggles overlay, Escape or overlay click closes.
|
|
39
39
|
- **Navbar** — Mobile menu: `.navbar__toggle` toggles `.navbar__menu`; Escape closes.
|
|
40
|
+
- **Copy to clipboard** — Buttons with `.copy-to-clipboard` and `data-copy-value`, or `[data-copy]` with `value` or `data-copy-value`; click copies text and shows feedback (icons/aria-label). Optional `data-copy-format` for “Copied {format}!”.
|
|
41
|
+
- **Tooltips** — Use `.tooltip-wrapper` with a `.tooltip` child, or `[data-tooltip]` on the trigger; no JS required (CSS :hover and :focus-within).
|
|
40
42
|
|
|
41
43
|
## Commands
|
|
42
44
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rizzo CSS — Vanilla JS component bundle
|
|
3
|
-
* Theme, toast, settings, tabs, modal, dropdown, accordion, search, navbar (mobile).
|
|
3
|
+
* Theme, toast, settings, tabs, modal, dropdown, accordion, search, navbar (mobile), copy-to-clipboard.
|
|
4
4
|
* Load this script after the DOM (e.g. before </body>).
|
|
5
5
|
*/
|
|
6
6
|
(function () {
|
|
@@ -284,6 +284,82 @@
|
|
|
284
284
|
window.openSettings = openSettings;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
// --- Copy to clipboard: .copy-to-clipboard [data-copy-value] or [data-copy] with value ---
|
|
288
|
+
function initCopyToClipboard() {
|
|
289
|
+
function setupButton(btn) {
|
|
290
|
+
if (btn.getAttribute('data-copy-inited') === 'true') return;
|
|
291
|
+
btn.setAttribute('data-copy-inited', 'true');
|
|
292
|
+
var host = btn.closest('.tooltip-host');
|
|
293
|
+
var defaultTooltip = (host && host.getAttribute('data-tooltip')) || 'Copy to clipboard';
|
|
294
|
+
if (host) host.setAttribute('data-copy-default-tooltip', defaultTooltip);
|
|
295
|
+
var defaultAria = btn.getAttribute('aria-label') || 'Copy to clipboard';
|
|
296
|
+
var getValue = function () { return btn.getAttribute('data-copy-value') || btn.getAttribute('value') || ''; };
|
|
297
|
+
var getFormat = function () { return btn.getAttribute('data-copy-format') || ''; };
|
|
298
|
+
var copyIcon = btn.querySelector('.copy-to-clipboard__icon--copy');
|
|
299
|
+
var checkIcon = btn.querySelector('.copy-to-clipboard__icon--check');
|
|
300
|
+
var feedback = btn.querySelector('.copy-to-clipboard__feedback');
|
|
301
|
+
var textSpan = btn.querySelector('.copy-to-clipboard__text');
|
|
302
|
+
function doCopy() {
|
|
303
|
+
var value = getValue();
|
|
304
|
+
if (!value && textSpan) value = textSpan.textContent || '';
|
|
305
|
+
if (!value) return;
|
|
306
|
+
function showSuccess() {
|
|
307
|
+
if (copyIcon) copyIcon.classList.add('copy-to-clipboard__icon--hidden');
|
|
308
|
+
if (checkIcon) checkIcon.classList.remove('copy-to-clipboard__icon--hidden');
|
|
309
|
+
if (feedback) feedback.textContent = getFormat() ? 'Copied ' + getFormat() + '!' : 'Copied!';
|
|
310
|
+
if (host) host.setAttribute('data-tooltip', getFormat() ? 'Copied ' + getFormat() + '!' : 'Copied!');
|
|
311
|
+
btn.setAttribute('aria-label', getFormat() ? 'Copied ' + getFormat() + '!' : 'Copied!');
|
|
312
|
+
var labelEl = btn.querySelector('.copy-trigger__text');
|
|
313
|
+
var previousLabel = labelEl ? labelEl.textContent : '';
|
|
314
|
+
if (labelEl) labelEl.textContent = 'Copied!';
|
|
315
|
+
setTimeout(function () {
|
|
316
|
+
if (copyIcon) copyIcon.classList.remove('copy-to-clipboard__icon--hidden');
|
|
317
|
+
if (checkIcon) checkIcon.classList.add('copy-to-clipboard__icon--hidden');
|
|
318
|
+
if (feedback) feedback.textContent = '';
|
|
319
|
+
if (host) host.setAttribute('data-tooltip', host.getAttribute('data-copy-default-tooltip') || defaultTooltip);
|
|
320
|
+
btn.setAttribute('aria-label', defaultAria);
|
|
321
|
+
if (labelEl) labelEl.textContent = previousLabel || 'Copy';
|
|
322
|
+
}, 2000);
|
|
323
|
+
}
|
|
324
|
+
if (typeof navigator.clipboard !== 'undefined' && navigator.clipboard.writeText) {
|
|
325
|
+
navigator.clipboard.writeText(value).then(showSuccess).catch(function () {
|
|
326
|
+
try {
|
|
327
|
+
var ta = document.createElement('textarea');
|
|
328
|
+
ta.value = value;
|
|
329
|
+
ta.style.position = 'fixed';
|
|
330
|
+
ta.style.left = '-9999px';
|
|
331
|
+
document.body.appendChild(ta);
|
|
332
|
+
ta.focus();
|
|
333
|
+
ta.select();
|
|
334
|
+
document.execCommand('copy');
|
|
335
|
+
document.body.removeChild(ta);
|
|
336
|
+
showSuccess();
|
|
337
|
+
} catch (e) {
|
|
338
|
+
if (window.showToast) window.showToast('Failed to copy', { variant: 'warning' });
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
} else {
|
|
342
|
+
try {
|
|
343
|
+
var ta = document.createElement('textarea');
|
|
344
|
+
ta.value = value;
|
|
345
|
+
ta.style.position = 'fixed';
|
|
346
|
+
ta.style.left = '-9999px';
|
|
347
|
+
document.body.appendChild(ta);
|
|
348
|
+
ta.focus();
|
|
349
|
+
ta.select();
|
|
350
|
+
document.execCommand('copy');
|
|
351
|
+
document.body.removeChild(ta);
|
|
352
|
+
showSuccess();
|
|
353
|
+
} catch (e) {
|
|
354
|
+
if (window.showToast) window.showToast('Failed to copy', { variant: 'warning' });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
btn.addEventListener('click', doCopy);
|
|
359
|
+
}
|
|
360
|
+
document.querySelectorAll('.copy-to-clipboard[data-copy-value], .copy-to-clipboard[data-copy], [data-copy]').forEach(setupButton);
|
|
361
|
+
}
|
|
362
|
+
|
|
287
363
|
// --- Tabs: init all [data-tabs] ---
|
|
288
364
|
function initTabs() {
|
|
289
365
|
document.querySelectorAll('[data-tabs]').forEach(function (tabsContainer) {
|
|
@@ -801,6 +877,7 @@
|
|
|
801
877
|
function run() {
|
|
802
878
|
initTheme();
|
|
803
879
|
initSettings();
|
|
880
|
+
initCopyToClipboard();
|
|
804
881
|
initTabs();
|
|
805
882
|
initModals();
|
|
806
883
|
initDropdowns();
|