@customviews-js/customviews 1.1.0 → 1.1.1
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 +362 -219
- package/dist/custom-views.core.cjs.js +1133 -1016
- package/dist/custom-views.core.cjs.js.map +1 -1
- package/dist/custom-views.core.esm.js +1133 -1016
- package/dist/custom-views.core.esm.js.map +1 -1
- package/dist/custom-views.esm.js +1133 -1016
- package/dist/custom-views.esm.js.map +1 -1
- package/dist/custom-views.js +1130 -1013
- package/dist/custom-views.js.map +1 -1
- package/dist/custom-views.min.js +2 -2
- package/dist/custom-views.min.js.map +1 -1
- package/dist/types/core/core.d.ts.map +1 -1
- package/dist/types/core/custom-elements.d.ts.map +1 -1
- package/dist/types/core/render.d.ts +3 -0
- package/dist/types/core/render.d.ts.map +1 -1
- package/dist/types/core/tab-manager.d.ts.map +1 -1
- package/dist/types/core/toggle-manager.d.ts +28 -0
- package/dist/types/core/toggle-manager.d.ts.map +1 -0
- package/dist/types/entry/browser-entry.d.ts.map +1 -1
- package/dist/types/lib/custom-views.d.ts.map +1 -1
- package/dist/types/styles/toggle-styles.d.ts +1 -1
- package/dist/types/styles/toggle-styles.d.ts.map +1 -1
- package/dist/types/styles/widget-styles.d.ts +1 -1
- package/dist/types/styles/widget-styles.d.ts.map +1 -1
- package/package.json +61 -61
package/dist/custom-views.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @customviews-js/customviews v1.1.
|
|
2
|
+
* @customviews-js/customviews v1.1.1
|
|
3
3
|
* (c) 2025 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -9,83 +9,6 @@
|
|
|
9
9
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.CustomViews = {}));
|
|
10
10
|
})(this, (function (exports) { 'use strict';
|
|
11
11
|
|
|
12
|
-
/** --- Basic renderers --- */
|
|
13
|
-
function renderImage(el, asset) {
|
|
14
|
-
if (!asset.src)
|
|
15
|
-
return;
|
|
16
|
-
el.innerHTML = '';
|
|
17
|
-
const img = document.createElement('img');
|
|
18
|
-
img.src = asset.src;
|
|
19
|
-
img.alt = asset.alt || '';
|
|
20
|
-
// Apply custom styling if provided
|
|
21
|
-
if (asset.className) {
|
|
22
|
-
img.className = asset.className;
|
|
23
|
-
}
|
|
24
|
-
if (asset.style) {
|
|
25
|
-
img.setAttribute('style', asset.style);
|
|
26
|
-
}
|
|
27
|
-
// Default styles (can be overridden by asset.style)
|
|
28
|
-
img.style.maxWidth = img.style.maxWidth || '100%';
|
|
29
|
-
img.style.height = img.style.height || 'auto';
|
|
30
|
-
img.style.display = img.style.display || 'block';
|
|
31
|
-
el.appendChild(img);
|
|
32
|
-
}
|
|
33
|
-
function renderText(el, asset) {
|
|
34
|
-
if (asset.content != null) {
|
|
35
|
-
el.textContent = asset.content;
|
|
36
|
-
}
|
|
37
|
-
// Apply custom styling if provided
|
|
38
|
-
if (asset.className) {
|
|
39
|
-
el.className = asset.className;
|
|
40
|
-
}
|
|
41
|
-
if (asset.style) {
|
|
42
|
-
el.setAttribute('style', asset.style);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function renderHtml(el, asset) {
|
|
46
|
-
if (asset.content != null) {
|
|
47
|
-
el.innerHTML = asset.content;
|
|
48
|
-
}
|
|
49
|
-
// Apply custom styling if provided
|
|
50
|
-
if (asset.className) {
|
|
51
|
-
el.className = asset.className;
|
|
52
|
-
}
|
|
53
|
-
if (asset.style) {
|
|
54
|
-
el.setAttribute('style', asset.style);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/** --- Unified asset renderer --- */
|
|
58
|
-
function detectAssetType(asset) {
|
|
59
|
-
// If src exists, it's an image
|
|
60
|
-
if (asset.src)
|
|
61
|
-
return 'image';
|
|
62
|
-
// If content contains HTML tags, it's HTML
|
|
63
|
-
if (asset.content && /<[^>]+>/.test(asset.content)) {
|
|
64
|
-
return 'html';
|
|
65
|
-
}
|
|
66
|
-
return 'text';
|
|
67
|
-
}
|
|
68
|
-
function renderAssetInto(el, assetId, assetsManager) {
|
|
69
|
-
const asset = assetsManager.get(assetId);
|
|
70
|
-
if (!asset)
|
|
71
|
-
return;
|
|
72
|
-
const type = asset.type || detectAssetType(asset);
|
|
73
|
-
switch (type) {
|
|
74
|
-
case 'image':
|
|
75
|
-
renderImage(el, asset);
|
|
76
|
-
break;
|
|
77
|
-
case 'text':
|
|
78
|
-
renderText(el, asset);
|
|
79
|
-
break;
|
|
80
|
-
case 'html':
|
|
81
|
-
renderHtml(el, asset);
|
|
82
|
-
break;
|
|
83
|
-
default:
|
|
84
|
-
el.innerHTML = asset.content || String(asset);
|
|
85
|
-
console.warn('[CustomViews] Unknown asset type:', type);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
12
|
/**
|
|
90
13
|
* Manages persistence of custom views state using browser localStorage
|
|
91
14
|
*/
|
|
@@ -346,6 +269,98 @@
|
|
|
346
269
|
}
|
|
347
270
|
}
|
|
348
271
|
|
|
272
|
+
/** --- Icon utilities --- */
|
|
273
|
+
function ensureFontAwesomeInjected() {
|
|
274
|
+
const isFontAwesomeLoaded = Array.from(document.styleSheets).some(sheet => sheet.href && (sheet.href.includes('font-awesome') || sheet.href.includes('fontawesome')));
|
|
275
|
+
if (isFontAwesomeLoaded)
|
|
276
|
+
return;
|
|
277
|
+
const link = document.createElement('link');
|
|
278
|
+
link.rel = 'stylesheet';
|
|
279
|
+
link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
|
|
280
|
+
link.setAttribute('data-customviews-fontawesome', 'true');
|
|
281
|
+
document.head.appendChild(link);
|
|
282
|
+
}
|
|
283
|
+
function replaceIconShortcodes(text) {
|
|
284
|
+
// Handle Font Awesome shortcodes
|
|
285
|
+
return text.replace(/:fa-([\w-]+):/g, (_, icon) => `<i class="fa fa-${icon}"></i>`);
|
|
286
|
+
}
|
|
287
|
+
/** --- Basic renderers --- */
|
|
288
|
+
function renderImage(el, asset) {
|
|
289
|
+
if (!asset.src)
|
|
290
|
+
return;
|
|
291
|
+
el.innerHTML = '';
|
|
292
|
+
const img = document.createElement('img');
|
|
293
|
+
img.src = asset.src;
|
|
294
|
+
img.alt = asset.alt || '';
|
|
295
|
+
// Apply custom styling if provided
|
|
296
|
+
if (asset.className) {
|
|
297
|
+
img.className = asset.className;
|
|
298
|
+
}
|
|
299
|
+
if (asset.style) {
|
|
300
|
+
img.setAttribute('style', asset.style);
|
|
301
|
+
}
|
|
302
|
+
// Default styles (can be overridden by asset.style)
|
|
303
|
+
img.style.maxWidth = img.style.maxWidth || '100%';
|
|
304
|
+
img.style.height = img.style.height || 'auto';
|
|
305
|
+
img.style.display = img.style.display || 'block';
|
|
306
|
+
el.appendChild(img);
|
|
307
|
+
}
|
|
308
|
+
function renderText(el, asset) {
|
|
309
|
+
if (asset.content != null) {
|
|
310
|
+
el.textContent = asset.content;
|
|
311
|
+
}
|
|
312
|
+
// Apply custom styling if provided
|
|
313
|
+
if (asset.className) {
|
|
314
|
+
el.className = asset.className;
|
|
315
|
+
}
|
|
316
|
+
if (asset.style) {
|
|
317
|
+
el.setAttribute('style', asset.style);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function renderHtml(el, asset) {
|
|
321
|
+
if (asset.content != null) {
|
|
322
|
+
el.innerHTML = asset.content;
|
|
323
|
+
}
|
|
324
|
+
// Apply custom styling if provided
|
|
325
|
+
if (asset.className) {
|
|
326
|
+
el.className = asset.className;
|
|
327
|
+
}
|
|
328
|
+
if (asset.style) {
|
|
329
|
+
el.setAttribute('style', asset.style);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/** --- Unified asset renderer --- */
|
|
333
|
+
function detectAssetType(asset) {
|
|
334
|
+
// If src exists, it's an image
|
|
335
|
+
if (asset.src)
|
|
336
|
+
return 'image';
|
|
337
|
+
// If content contains HTML tags, it's HTML
|
|
338
|
+
if (asset.content && /<[^>]+>/.test(asset.content)) {
|
|
339
|
+
return 'html';
|
|
340
|
+
}
|
|
341
|
+
return 'text';
|
|
342
|
+
}
|
|
343
|
+
function renderAssetInto(el, assetId, assetsManager) {
|
|
344
|
+
const asset = assetsManager.get(assetId);
|
|
345
|
+
if (!asset)
|
|
346
|
+
return;
|
|
347
|
+
const type = asset.type || detectAssetType(asset);
|
|
348
|
+
switch (type) {
|
|
349
|
+
case 'image':
|
|
350
|
+
renderImage(el, asset);
|
|
351
|
+
break;
|
|
352
|
+
case 'text':
|
|
353
|
+
renderText(el, asset);
|
|
354
|
+
break;
|
|
355
|
+
case 'html':
|
|
356
|
+
renderHtml(el, asset);
|
|
357
|
+
break;
|
|
358
|
+
default:
|
|
359
|
+
el.innerHTML = asset.content || String(asset);
|
|
360
|
+
console.warn('[CustomViews] Unknown asset type:', type);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
349
364
|
// Constants for selectors
|
|
350
365
|
const TABGROUP_SELECTOR = 'cv-tabgroup';
|
|
351
366
|
const TAB_SELECTOR = 'cv-tab';
|
|
@@ -367,8 +382,8 @@
|
|
|
367
382
|
return;
|
|
368
383
|
// Determine the active tab for this group
|
|
369
384
|
const activeTabId = this.resolveActiveTab(groupId, tabs, cfgGroups, groupEl);
|
|
370
|
-
// Apply visibility to child cv-tab elements
|
|
371
|
-
const tabElements = groupEl.
|
|
385
|
+
// Apply visibility to direct child cv-tab elements only (not nested ones)
|
|
386
|
+
const tabElements = Array.from(groupEl.children).filter((child) => child.tagName.toLowerCase() === TAB_SELECTOR);
|
|
372
387
|
tabElements.forEach((tabEl) => {
|
|
373
388
|
const tabId = tabEl.getAttribute('id');
|
|
374
389
|
if (!tabId)
|
|
@@ -400,8 +415,8 @@
|
|
|
400
415
|
}
|
|
401
416
|
}
|
|
402
417
|
}
|
|
403
|
-
// 3. Fallback to first cv-tab child in DOM
|
|
404
|
-
const firstTab = groupEl.
|
|
418
|
+
// 3. Fallback to first direct cv-tab child in DOM
|
|
419
|
+
const firstTab = Array.from(groupEl.children).find((child) => child.tagName.toLowerCase() === TAB_SELECTOR);
|
|
405
420
|
if (firstTab) {
|
|
406
421
|
return firstTab.getAttribute('id');
|
|
407
422
|
}
|
|
@@ -426,6 +441,28 @@
|
|
|
426
441
|
static buildNavs(rootEl, cfgGroups, onTabClick) {
|
|
427
442
|
// Find all cv-tabgroup elements with nav="auto" or no nav attribute
|
|
428
443
|
const tabGroups = rootEl.querySelectorAll(NAV_AUTO_SELECTOR);
|
|
444
|
+
// Check if any tab headers contain Font Awesome shortcodes
|
|
445
|
+
// Inject Font Awesome CSS only if needed
|
|
446
|
+
let hasFontAwesomeShortcodes = false;
|
|
447
|
+
tabGroups.forEach((groupEl) => {
|
|
448
|
+
const groupId = groupEl.getAttribute('id');
|
|
449
|
+
if (!groupId)
|
|
450
|
+
return;
|
|
451
|
+
const tabElements = Array.from(groupEl.children).filter((child) => child.tagName.toLowerCase() === 'cv-tab');
|
|
452
|
+
tabElements.forEach((tabEl) => {
|
|
453
|
+
const tabId = tabEl.getAttribute('id');
|
|
454
|
+
if (!tabId)
|
|
455
|
+
return;
|
|
456
|
+
const header = tabEl.getAttribute('header') || this.getTabLabel(tabId, groupId, cfgGroups) || tabId;
|
|
457
|
+
if (/:fa-[\w-]+:/.test(header)) {
|
|
458
|
+
hasFontAwesomeShortcodes = true;
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
// Inject Font Awesome only if shortcodes are found
|
|
463
|
+
if (hasFontAwesomeShortcodes) {
|
|
464
|
+
ensureFontAwesomeInjected();
|
|
465
|
+
}
|
|
429
466
|
tabGroups.forEach((groupEl) => {
|
|
430
467
|
const groupId = groupEl.getAttribute('id');
|
|
431
468
|
if (!groupId)
|
|
@@ -434,8 +471,8 @@
|
|
|
434
471
|
let navContainer = groupEl.querySelector(`.${NAV_CONTAINER_CLASS}`);
|
|
435
472
|
if (navContainer)
|
|
436
473
|
return; // Already built
|
|
437
|
-
// Get
|
|
438
|
-
const tabElements = Array.from(groupEl.
|
|
474
|
+
// Get only direct child tabs (not nested ones)
|
|
475
|
+
const tabElements = Array.from(groupEl.children).filter((child) => child.tagName.toLowerCase() === TAB_SELECTOR);
|
|
439
476
|
if (tabElements.length === 0)
|
|
440
477
|
return;
|
|
441
478
|
// Create nav container
|
|
@@ -453,7 +490,8 @@
|
|
|
453
490
|
listItem.className = 'nav-item';
|
|
454
491
|
const navLink = document.createElement('a');
|
|
455
492
|
navLink.className = 'nav-link';
|
|
456
|
-
|
|
493
|
+
// Replace icon shortcodes in header
|
|
494
|
+
navLink.innerHTML = replaceIconShortcodes(header);
|
|
457
495
|
navLink.href = '#';
|
|
458
496
|
navLink.setAttribute('data-tab-id', tabId);
|
|
459
497
|
navLink.setAttribute('data-group-id', groupId);
|
|
@@ -545,157 +583,267 @@
|
|
|
545
583
|
}
|
|
546
584
|
}
|
|
547
585
|
|
|
586
|
+
class AssetsManager {
|
|
587
|
+
assets;
|
|
588
|
+
baseURL;
|
|
589
|
+
constructor(assets, baseURL = '') {
|
|
590
|
+
this.assets = assets;
|
|
591
|
+
this.baseURL = baseURL;
|
|
592
|
+
if (!this.validate()) {
|
|
593
|
+
console.warn('Invalid assets:', this.assets);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
// Check each asset has content or src
|
|
597
|
+
validate() {
|
|
598
|
+
return Object.values(this.assets).every(a => a.src || a.content);
|
|
599
|
+
}
|
|
600
|
+
get(assetId) {
|
|
601
|
+
const asset = this.assets[assetId];
|
|
602
|
+
if (!asset)
|
|
603
|
+
return undefined;
|
|
604
|
+
// If there's a baseURL and the asset has a src property, prepend the baseURL
|
|
605
|
+
if (this.baseURL && asset.src) {
|
|
606
|
+
// Create a shallow copy to avoid mutating the original asset
|
|
607
|
+
return {
|
|
608
|
+
...asset,
|
|
609
|
+
src: this.prependBaseURL(asset.src)
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
return asset;
|
|
613
|
+
}
|
|
614
|
+
prependBaseURL(path) {
|
|
615
|
+
// Don't prepend if the path is already absolute (starts with http:// or https://)
|
|
616
|
+
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
617
|
+
return path;
|
|
618
|
+
}
|
|
619
|
+
// Ensure baseURL doesn't end with / and path starts with /
|
|
620
|
+
const cleanBaseURL = this.baseURL.endsWith('/') ? this.baseURL.slice(0, -1) : this.baseURL;
|
|
621
|
+
const cleanPath = path.startsWith('/') ? path : '/' + path;
|
|
622
|
+
return cleanBaseURL + cleanPath;
|
|
623
|
+
}
|
|
624
|
+
loadFromJSON(json) {
|
|
625
|
+
this.assets = json;
|
|
626
|
+
}
|
|
627
|
+
loadAdditionalAssets(additionalAssets) {
|
|
628
|
+
this.assets = { ...this.assets, ...additionalAssets };
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Constants for selectors
|
|
633
|
+
const TOGGLE_DATA_SELECTOR = "[data-cv-toggle], [data-customviews-toggle]";
|
|
634
|
+
const TOGGLE_ELEMENT_SELECTOR = "cv-toggle";
|
|
635
|
+
const TOGGLE_SELECTOR = `${TOGGLE_DATA_SELECTOR}, ${TOGGLE_ELEMENT_SELECTOR}`;
|
|
636
|
+
/**
|
|
637
|
+
* ToggleManager handles discovery, visibility, and asset rendering for toggle elements
|
|
638
|
+
*/
|
|
639
|
+
class ToggleManager {
|
|
640
|
+
/**
|
|
641
|
+
* Apply toggle visibility to all toggle elements in the DOM
|
|
642
|
+
*/
|
|
643
|
+
static applyToggles(rootEl, activeToggles) {
|
|
644
|
+
rootEl.querySelectorAll(TOGGLE_SELECTOR).forEach(el => {
|
|
645
|
+
const categories = this.getToggleCategories(el);
|
|
646
|
+
const shouldShow = categories.some(cat => activeToggles.includes(cat));
|
|
647
|
+
this.applyToggleVisibility(el, shouldShow);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Render assets into toggle elements that are currently visible
|
|
652
|
+
*/
|
|
653
|
+
static renderAssets(rootEl, activeToggles, assetsManager) {
|
|
654
|
+
rootEl.querySelectorAll(TOGGLE_SELECTOR).forEach(el => {
|
|
655
|
+
const categories = this.getToggleCategories(el);
|
|
656
|
+
const toggleId = this.getToggleId(el);
|
|
657
|
+
if (toggleId && categories.some(cat => activeToggles.includes(cat))) {
|
|
658
|
+
renderAssetInto(el, toggleId, assetsManager);
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Get toggle categories from an element (supports both data attributes and cv-toggle elements)
|
|
664
|
+
*/
|
|
665
|
+
static getToggleCategories(el) {
|
|
666
|
+
if (el.tagName.toLowerCase() === 'cv-toggle') {
|
|
667
|
+
const category = el.getAttribute('category');
|
|
668
|
+
return (category || '').split(/\s+/).filter(Boolean);
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
const data = el.dataset.cvToggle || el.dataset.customviewsToggle;
|
|
672
|
+
return (data || '').split(/\s+/).filter(Boolean);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Get toggle ID from an element
|
|
677
|
+
*/
|
|
678
|
+
static getToggleId(el) {
|
|
679
|
+
return el.dataset.cvId || el.dataset.customviewsId || el.getAttribute('data-cv-id') || el.getAttribute('data-customviews-id') || undefined;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Apply simple class-based visibility to a toggle element
|
|
683
|
+
*/
|
|
684
|
+
static applyToggleVisibility(el, visible) {
|
|
685
|
+
if (visible) {
|
|
686
|
+
el.classList.remove('cv-hidden');
|
|
687
|
+
el.classList.add('cv-visible');
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
el.classList.add('cv-hidden');
|
|
691
|
+
el.classList.remove('cv-visible');
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
548
696
|
/**
|
|
549
697
|
* Styles for toggle visibility and animations
|
|
550
698
|
*/
|
|
551
|
-
const TOGGLE_STYLES = `
|
|
552
|
-
/* Core toggle visibility transitions */
|
|
553
|
-
[data-cv-toggle], [data-customviews-toggle] {
|
|
554
|
-
transition: opacity 150ms ease,
|
|
555
|
-
transform 150ms ease,
|
|
556
|
-
max-height 200ms ease,
|
|
557
|
-
margin 150ms ease;
|
|
558
|
-
will-change: opacity, transform, max-height, margin;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
.cv-visible {
|
|
562
|
-
opacity: 1 !important;
|
|
563
|
-
transform: translateY(0) !important;
|
|
564
|
-
max-height: var(--cv-max-height, 9999px) !important;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
.cv-hidden {
|
|
568
|
-
opacity: 0 !important;
|
|
569
|
-
transform: translateY(-4px) !important;
|
|
570
|
-
pointer-events: none !important;
|
|
571
|
-
padding-top: 0 !important;
|
|
572
|
-
padding-bottom: 0 !important;
|
|
573
|
-
border-top-width: 0 !important;
|
|
574
|
-
border-bottom-width: 0 !important;
|
|
575
|
-
max-height: 0 !important;
|
|
576
|
-
margin-top: 0 !important;
|
|
577
|
-
margin-bottom: 0 !important;
|
|
578
|
-
overflow: hidden !important;
|
|
579
|
-
}
|
|
699
|
+
const TOGGLE_STYLES = `
|
|
700
|
+
/* Core toggle visibility transitions */
|
|
701
|
+
[data-cv-toggle], [data-customviews-toggle], cv-toggle {
|
|
702
|
+
transition: opacity 150ms ease,
|
|
703
|
+
transform 150ms ease,
|
|
704
|
+
max-height 200ms ease,
|
|
705
|
+
margin 150ms ease;
|
|
706
|
+
will-change: opacity, transform, max-height, margin;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.cv-visible {
|
|
710
|
+
opacity: 1 !important;
|
|
711
|
+
transform: translateY(0) !important;
|
|
712
|
+
max-height: var(--cv-max-height, 9999px) !important;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.cv-hidden {
|
|
716
|
+
opacity: 0 !important;
|
|
717
|
+
transform: translateY(-4px) !important;
|
|
718
|
+
pointer-events: none !important;
|
|
719
|
+
padding-top: 0 !important;
|
|
720
|
+
padding-bottom: 0 !important;
|
|
721
|
+
border-top-width: 0 !important;
|
|
722
|
+
border-bottom-width: 0 !important;
|
|
723
|
+
max-height: 0 !important;
|
|
724
|
+
margin-top: 0 !important;
|
|
725
|
+
margin-bottom: 0 !important;
|
|
726
|
+
overflow: hidden !important;
|
|
727
|
+
}
|
|
580
728
|
`;
|
|
581
729
|
|
|
582
730
|
/**
|
|
583
731
|
* Styles for tab groups and tab navigation
|
|
584
732
|
*/
|
|
585
|
-
const TAB_STYLES = `
|
|
586
|
-
/* Tab navigation styles - Bootstrap-style tabs matching MarkBind */
|
|
587
|
-
.cv-tabs-nav {
|
|
588
|
-
display: flex;
|
|
589
|
-
flex-wrap: wrap;
|
|
590
|
-
padding-left: 0;
|
|
591
|
-
margin-top: 0.5rem;
|
|
592
|
-
margin-bottom: 1rem;
|
|
593
|
-
list-style: none;
|
|
594
|
-
border-bottom: 1px solid #dee2e6;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
.cv-tabs-nav .nav-item {
|
|
598
|
-
margin-bottom: -1px;
|
|
599
|
-
list-style: none;
|
|
600
|
-
display: inline-block;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
.cv-tabs-nav .nav-link {
|
|
604
|
-
display: block;
|
|
605
|
-
padding: 0.5rem 1rem;
|
|
606
|
-
color: #495057;
|
|
607
|
-
text-decoration: none;
|
|
608
|
-
background-color: transparent;
|
|
609
|
-
border: 1px solid transparent;
|
|
610
|
-
border-top-left-radius: 0.25rem;
|
|
611
|
-
border-top-right-radius: 0.25rem;
|
|
612
|
-
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
|
|
613
|
-
cursor: pointer;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
.cv-tabs-nav .nav-link:hover,
|
|
617
|
-
.cv-tabs-nav .nav-link:focus {
|
|
618
|
-
border-color: #e9ecef #e9ecef #dee2e6;
|
|
619
|
-
isolation: isolate;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
.cv-tabs-nav .nav-link.active {
|
|
623
|
-
color: #495057;
|
|
624
|
-
background-color: #fff;
|
|
625
|
-
border-color: #dee2e6 #dee2e6 #fff;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
.cv-tabs-nav .nav-link:focus {
|
|
629
|
-
outline: 0;
|
|
630
|
-
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/* Legacy button-based nav (deprecated, kept for compatibility) */
|
|
634
|
-
.cv-tabs-nav-item {
|
|
635
|
-
background: none;
|
|
636
|
-
border: none;
|
|
637
|
-
border-bottom: 2px solid transparent;
|
|
638
|
-
padding: 0.5rem 1rem;
|
|
639
|
-
cursor: pointer;
|
|
640
|
-
font-size: 1rem;
|
|
641
|
-
color: #6c757d;
|
|
642
|
-
transition: color 150ms ease, border-color 150ms ease;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
.cv-tabs-nav-item:hover {
|
|
646
|
-
color: #495057;
|
|
647
|
-
border-bottom-color: #dee2e6;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
.cv-tabs-nav-item.active {
|
|
651
|
-
color: #007bff;
|
|
652
|
-
border-bottom-color: #007bff;
|
|
653
|
-
font-weight: 500;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
.cv-tabs-nav-item:focus {
|
|
657
|
-
outline: 2px solid #007bff;
|
|
658
|
-
outline-offset: 2px;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/* Tab panel base styles */
|
|
662
|
-
cv-tab {
|
|
663
|
-
display: block;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
/* Override visibility for tab panels - use display instead of collapse animation */
|
|
667
|
-
cv-tab.cv-hidden {
|
|
668
|
-
display: none !important;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
cv-tab.cv-visible {
|
|
672
|
-
display: block !important;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
cv-tabgroup {
|
|
676
|
-
display: block;
|
|
677
|
-
margin-bottom: 1.5rem;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
/* Bottom border line for tab groups */
|
|
681
|
-
.cv-tabgroup-bottom-border {
|
|
682
|
-
border-bottom: 1px solid #dee2e6;
|
|
683
|
-
margin-top: 1rem;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/* Tab content wrapper */
|
|
687
|
-
.cv-tab-content {
|
|
688
|
-
padding: 1rem 0;
|
|
689
|
-
}
|
|
733
|
+
const TAB_STYLES = `
|
|
734
|
+
/* Tab navigation styles - Bootstrap-style tabs matching MarkBind */
|
|
735
|
+
.cv-tabs-nav {
|
|
736
|
+
display: flex;
|
|
737
|
+
flex-wrap: wrap;
|
|
738
|
+
padding-left: 0;
|
|
739
|
+
margin-top: 0.5rem;
|
|
740
|
+
margin-bottom: 1rem;
|
|
741
|
+
list-style: none;
|
|
742
|
+
border-bottom: 1px solid #dee2e6;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.cv-tabs-nav .nav-item {
|
|
746
|
+
margin-bottom: -1px;
|
|
747
|
+
list-style: none;
|
|
748
|
+
display: inline-block;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.cv-tabs-nav .nav-link {
|
|
752
|
+
display: block;
|
|
753
|
+
padding: 0.5rem 1rem;
|
|
754
|
+
color: #495057;
|
|
755
|
+
text-decoration: none;
|
|
756
|
+
background-color: transparent;
|
|
757
|
+
border: 1px solid transparent;
|
|
758
|
+
border-top-left-radius: 0.25rem;
|
|
759
|
+
border-top-right-radius: 0.25rem;
|
|
760
|
+
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
|
|
761
|
+
cursor: pointer;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.cv-tabs-nav .nav-link:hover,
|
|
765
|
+
.cv-tabs-nav .nav-link:focus {
|
|
766
|
+
border-color: #e9ecef #e9ecef #dee2e6;
|
|
767
|
+
isolation: isolate;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.cv-tabs-nav .nav-link.active {
|
|
771
|
+
color: #495057;
|
|
772
|
+
background-color: #fff;
|
|
773
|
+
border-color: #dee2e6 #dee2e6 #fff;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.cv-tabs-nav .nav-link:focus {
|
|
777
|
+
outline: 0;
|
|
778
|
+
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/* Legacy button-based nav (deprecated, kept for compatibility) */
|
|
782
|
+
.cv-tabs-nav-item {
|
|
783
|
+
background: none;
|
|
784
|
+
border: none;
|
|
785
|
+
border-bottom: 2px solid transparent;
|
|
786
|
+
padding: 0.5rem 1rem;
|
|
787
|
+
cursor: pointer;
|
|
788
|
+
font-size: 1rem;
|
|
789
|
+
color: #6c757d;
|
|
790
|
+
transition: color 150ms ease, border-color 150ms ease;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.cv-tabs-nav-item:hover {
|
|
794
|
+
color: #495057;
|
|
795
|
+
border-bottom-color: #dee2e6;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.cv-tabs-nav-item.active {
|
|
799
|
+
color: #007bff;
|
|
800
|
+
border-bottom-color: #007bff;
|
|
801
|
+
font-weight: 500;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.cv-tabs-nav-item:focus {
|
|
805
|
+
outline: 2px solid #007bff;
|
|
806
|
+
outline-offset: 2px;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/* Tab panel base styles */
|
|
810
|
+
cv-tab {
|
|
811
|
+
display: block;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/* Override visibility for tab panels - use display instead of collapse animation */
|
|
815
|
+
cv-tab.cv-hidden {
|
|
816
|
+
display: none !important;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
cv-tab.cv-visible {
|
|
820
|
+
display: block !important;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
cv-tabgroup {
|
|
824
|
+
display: block;
|
|
825
|
+
margin-bottom: 1.5rem;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* Bottom border line for tab groups */
|
|
829
|
+
.cv-tabgroup-bottom-border {
|
|
830
|
+
border-bottom: 1px solid #dee2e6;
|
|
831
|
+
margin-top: 1rem;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/* Tab content wrapper */
|
|
835
|
+
.cv-tab-content {
|
|
836
|
+
padding: 1rem 0;
|
|
837
|
+
}
|
|
690
838
|
`;
|
|
691
839
|
|
|
692
840
|
/**
|
|
693
841
|
* Combined core styles for toggles and tabs
|
|
694
842
|
*/
|
|
695
|
-
const CORE_STYLES = `
|
|
696
|
-
${TOGGLE_STYLES}
|
|
697
|
-
|
|
698
|
-
${TAB_STYLES}
|
|
843
|
+
const CORE_STYLES = `
|
|
844
|
+
${TOGGLE_STYLES}
|
|
845
|
+
|
|
846
|
+
${TAB_STYLES}
|
|
699
847
|
`;
|
|
700
848
|
/**
|
|
701
849
|
* Add styles for hiding and showing toggles animations and transitions to the document head
|
|
@@ -825,23 +973,10 @@ ${TAB_STYLES}
|
|
|
825
973
|
this.lastAppliedState = this.cloneState(state);
|
|
826
974
|
const toggles = state.toggles || [];
|
|
827
975
|
const finalToggles = this.visibilityManager.filterVisibleToggles(toggles);
|
|
828
|
-
//
|
|
829
|
-
this.rootEl
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
this.visibilityManager.applyElementVisibility(el, shouldShow);
|
|
833
|
-
});
|
|
834
|
-
// Render toggles
|
|
835
|
-
for (const category of finalToggles) {
|
|
836
|
-
this.rootEl.querySelectorAll(`[data-cv-toggle="${category}"], [data-customviews-toggle="${category}"]`).forEach(el => {
|
|
837
|
-
// if it has an id, then we should render the asset into it
|
|
838
|
-
// Support both (data-cv-id) and (data-customviews-id) attributes
|
|
839
|
-
const toggleId = el.dataset.cvId || el.dataset.customviewsId;
|
|
840
|
-
if (toggleId) {
|
|
841
|
-
renderAssetInto(el, toggleId, this.assetsManager);
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
}
|
|
976
|
+
// Apply toggle visibility
|
|
977
|
+
ToggleManager.applyToggles(this.rootEl, finalToggles);
|
|
978
|
+
// Render assets into toggles
|
|
979
|
+
ToggleManager.renderAssets(this.rootEl, finalToggles, this.assetsManager);
|
|
845
980
|
// Apply tab selections
|
|
846
981
|
TabManager.applySelections(this.rootEl, state.tabs || {}, this.config.tabGroups);
|
|
847
982
|
// Update nav active states (without rebuilding)
|
|
@@ -954,52 +1089,6 @@ ${TAB_STYLES}
|
|
|
954
1089
|
}
|
|
955
1090
|
}
|
|
956
1091
|
|
|
957
|
-
class AssetsManager {
|
|
958
|
-
assets;
|
|
959
|
-
baseURL;
|
|
960
|
-
constructor(assets, baseURL = '') {
|
|
961
|
-
this.assets = assets;
|
|
962
|
-
this.baseURL = baseURL;
|
|
963
|
-
if (!this.validate()) {
|
|
964
|
-
console.warn('Invalid assets:', this.assets);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
// Check each asset has content or src
|
|
968
|
-
validate() {
|
|
969
|
-
return Object.values(this.assets).every(a => a.src || a.content);
|
|
970
|
-
}
|
|
971
|
-
get(assetId) {
|
|
972
|
-
const asset = this.assets[assetId];
|
|
973
|
-
if (!asset)
|
|
974
|
-
return undefined;
|
|
975
|
-
// If there's a baseURL and the asset has a src property, prepend the baseURL
|
|
976
|
-
if (this.baseURL && asset.src) {
|
|
977
|
-
// Create a shallow copy to avoid mutating the original asset
|
|
978
|
-
return {
|
|
979
|
-
...asset,
|
|
980
|
-
src: this.prependBaseURL(asset.src)
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
return asset;
|
|
984
|
-
}
|
|
985
|
-
prependBaseURL(path) {
|
|
986
|
-
// Don't prepend if the path is already absolute (starts with http:// or https://)
|
|
987
|
-
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
988
|
-
return path;
|
|
989
|
-
}
|
|
990
|
-
// Ensure baseURL doesn't end with / and path starts with /
|
|
991
|
-
const cleanBaseURL = this.baseURL.endsWith('/') ? this.baseURL.slice(0, -1) : this.baseURL;
|
|
992
|
-
const cleanPath = path.startsWith('/') ? path : '/' + path;
|
|
993
|
-
return cleanBaseURL + cleanPath;
|
|
994
|
-
}
|
|
995
|
-
loadFromJSON(json) {
|
|
996
|
-
this.assets = json;
|
|
997
|
-
}
|
|
998
|
-
loadAdditionalAssets(additionalAssets) {
|
|
999
|
-
this.assets = { ...this.assets, ...additionalAssets };
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
1092
|
/**
|
|
1004
1093
|
* Helper function to prepend baseUrl to a path
|
|
1005
1094
|
* @param path The path to prepend the baseUrl to
|
|
@@ -1019,6 +1108,57 @@ ${TAB_STYLES}
|
|
|
1019
1108
|
return cleanbaseUrl + cleanPath;
|
|
1020
1109
|
}
|
|
1021
1110
|
|
|
1111
|
+
/**
|
|
1112
|
+
* Custom Elements for Tab Groups and Tabs
|
|
1113
|
+
*/
|
|
1114
|
+
/**
|
|
1115
|
+
* <cv-tab> element - represents a single tab panel
|
|
1116
|
+
*/
|
|
1117
|
+
class CVTab extends HTMLElement {
|
|
1118
|
+
connectedCallback() {
|
|
1119
|
+
// Element is managed by TabManager
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* <cv-tabgroup> element - represents a group of tabs
|
|
1124
|
+
*/
|
|
1125
|
+
class CVTabgroup extends HTMLElement {
|
|
1126
|
+
connectedCallback() {
|
|
1127
|
+
// Element is managed by TabManager
|
|
1128
|
+
// Emit ready event after a brief delay to ensure children are parsed
|
|
1129
|
+
setTimeout(() => {
|
|
1130
|
+
const event = new CustomEvent('cv:tabgroup-ready', {
|
|
1131
|
+
bubbles: true,
|
|
1132
|
+
detail: { groupId: this.getAttribute('id') }
|
|
1133
|
+
});
|
|
1134
|
+
this.dispatchEvent(event);
|
|
1135
|
+
}, 0);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* <cv-toggle> element - represents a toggleable content block
|
|
1140
|
+
*/
|
|
1141
|
+
class CVToggle extends HTMLElement {
|
|
1142
|
+
connectedCallback() {
|
|
1143
|
+
// Element is managed by Core
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Register custom elements
|
|
1148
|
+
*/
|
|
1149
|
+
function registerCustomElements() {
|
|
1150
|
+
// Only register if not already defined
|
|
1151
|
+
if (!customElements.get('cv-tab')) {
|
|
1152
|
+
customElements.define('cv-tab', CVTab);
|
|
1153
|
+
}
|
|
1154
|
+
if (!customElements.get('cv-tabgroup')) {
|
|
1155
|
+
customElements.define('cv-tabgroup', CVTabgroup);
|
|
1156
|
+
}
|
|
1157
|
+
if (!customElements.get('cv-toggle')) {
|
|
1158
|
+
customElements.define('cv-toggle', CVToggle);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1022
1162
|
/**
|
|
1023
1163
|
* Main CustomViews class for initializing and managing custom views
|
|
1024
1164
|
*/
|
|
@@ -1029,6 +1169,8 @@ ${TAB_STYLES}
|
|
|
1029
1169
|
* @returns Promise resolving to the CustomViewsCore instance or null if initialization fails
|
|
1030
1170
|
*/
|
|
1031
1171
|
static async init(opts) {
|
|
1172
|
+
// Register custom elements
|
|
1173
|
+
registerCustomElements();
|
|
1032
1174
|
// Load assets JSON if provided
|
|
1033
1175
|
let assetsManager;
|
|
1034
1176
|
const baseURL = opts.baseURL || '';
|
|
@@ -1071,627 +1213,644 @@ ${TAB_STYLES}
|
|
|
1071
1213
|
* Note: Styles are kept as a TypeScript string for compatibility with the build system.
|
|
1072
1214
|
* This approach ensures the styles are properly bundled and don't require separate CSS file handling.
|
|
1073
1215
|
*/
|
|
1074
|
-
const WIDGET_STYLES = `
|
|
1075
|
-
/* Rounded rectangle widget icon styles */
|
|
1076
|
-
.cv-widget-icon {
|
|
1077
|
-
position: fixed;
|
|
1078
|
-
/* Slightly transparent by default so the widget is subtle at the page edge */
|
|
1079
|
-
background: rgba(255, 255, 255, 0.92);
|
|
1080
|
-
color: rgba(0, 0, 0, 0.9);
|
|
1081
|
-
opacity: 0.6;
|
|
1082
|
-
display: flex;
|
|
1083
|
-
align-items: center;
|
|
1084
|
-
justify-content: center;
|
|
1085
|
-
font-size: 18px;
|
|
1086
|
-
font-weight: bold;
|
|
1087
|
-
cursor: pointer;
|
|
1088
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1089
|
-
z-index: 9998;
|
|
1090
|
-
transition: all 0.3s ease;
|
|
1091
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
.cv-widget-icon:hover {
|
|
1095
|
-
/* Become fully opaque on hover to improve readability */
|
|
1096
|
-
background: rgba(255, 255, 255, 1);
|
|
1097
|
-
color: rgba(0, 0, 0, 1);
|
|
1098
|
-
opacity: 1;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
/* Top-right: rounded end on left, sticks out leftward on hover */
|
|
1102
|
-
.cv-widget-top-right {
|
|
1103
|
-
top: 20px;
|
|
1104
|
-
right: 0;
|
|
1105
|
-
border-radius: 18px 0 0 18px;
|
|
1106
|
-
padding-left: 8px;
|
|
1107
|
-
justify-content: flex-start;
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
/* Top-left: rounded end on right, sticks out rightward on hover */
|
|
1111
|
-
.cv-widget-top-left {
|
|
1112
|
-
top: 20px;
|
|
1113
|
-
left: 0;
|
|
1114
|
-
border-radius: 0 18px 18px 0;
|
|
1115
|
-
padding-right: 8px;
|
|
1116
|
-
justify-content: flex-end;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
/* Bottom-right: rounded end on left, sticks out leftward on hover */
|
|
1120
|
-
.cv-widget-bottom-right {
|
|
1121
|
-
bottom: 20px;
|
|
1122
|
-
right: 0;
|
|
1123
|
-
border-radius: 18px 0 0 18px;
|
|
1124
|
-
padding-left: 8px;
|
|
1125
|
-
justify-content: flex-start;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
/* Bottom-left: rounded end on right, sticks out rightward on hover */
|
|
1129
|
-
.cv-widget-bottom-left {
|
|
1130
|
-
bottom: 20px;
|
|
1131
|
-
left: 0;
|
|
1132
|
-
border-radius: 0 18px 18px 0;
|
|
1133
|
-
padding-right: 8px;
|
|
1134
|
-
justify-content: flex-end;
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
/* Middle-left: rounded end on right, sticks out rightward on hover */
|
|
1138
|
-
.cv-widget-middle-left {
|
|
1139
|
-
top: 50%;
|
|
1140
|
-
left: 0;
|
|
1141
|
-
transform: translateY(-50%);
|
|
1142
|
-
border-radius: 0 18px 18px 0;
|
|
1143
|
-
padding-right: 8px;
|
|
1144
|
-
justify-content: flex-end;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
/* Middle-right: rounded end on left, sticks out leftward on hover */
|
|
1148
|
-
.cv-widget-middle-right {
|
|
1149
|
-
top: 50%;
|
|
1150
|
-
right: 0;
|
|
1151
|
-
transform: translateY(-50%);
|
|
1152
|
-
border-radius: 18px 0 0 18px;
|
|
1153
|
-
padding-left: 8px;
|
|
1154
|
-
justify-content: flex-start;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
.cv-widget-top-right,
|
|
1158
|
-
.cv-widget-middle-right,
|
|
1159
|
-
.cv-widget-bottom-right,
|
|
1160
|
-
.cv-widget-top-left,
|
|
1161
|
-
.cv-widget-middle-left,
|
|
1162
|
-
.cv-widget-bottom-left {
|
|
1163
|
-
height: 36px;
|
|
1164
|
-
width: 36px;
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
.cv-widget-middle-right:hover,
|
|
1168
|
-
.cv-widget-top-right:hover,
|
|
1169
|
-
.cv-widget-bottom-right:hover,
|
|
1170
|
-
.cv-widget-top-left:hover,
|
|
1171
|
-
.cv-widget-middle-left:hover,
|
|
1172
|
-
.cv-widget-bottom-left:hover {
|
|
1173
|
-
width: 55px;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
/* Modal content styles */
|
|
1177
|
-
.cv-widget-section {
|
|
1178
|
-
margin-bottom: 16px;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
.cv-widget-section:last-child {
|
|
1182
|
-
margin-bottom: 0;
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
.cv-widget-section label {
|
|
1186
|
-
display: block;
|
|
1187
|
-
margin-bottom: 4px;
|
|
1188
|
-
font-weight: 500;
|
|
1189
|
-
color: #555;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
.cv-widget-profile-select,
|
|
1193
|
-
.cv-widget-state-select {
|
|
1194
|
-
width: 100%;
|
|
1195
|
-
padding: 8px 12px;
|
|
1196
|
-
border: 1px solid #ddd;
|
|
1197
|
-
border-radius: 4px;
|
|
1198
|
-
background: white;
|
|
1199
|
-
font-size: 14px;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
.cv-widget-profile-select:focus,
|
|
1203
|
-
.cv-widget-state-select:focus {
|
|
1204
|
-
outline: none;
|
|
1205
|
-
border-color: #007bff;
|
|
1206
|
-
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
.cv-widget-profile-select:disabled,
|
|
1210
|
-
.cv-widget-state-select:disabled {
|
|
1211
|
-
background: #f8f9fa;
|
|
1212
|
-
color: #6c757d;
|
|
1213
|
-
cursor: not-allowed;
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
.cv-widget-current {
|
|
1217
|
-
margin: 16px 0;
|
|
1218
|
-
padding: 12px;
|
|
1219
|
-
background: #f8f9fa;
|
|
1220
|
-
border-radius: 4px;
|
|
1221
|
-
border-left: 4px solid #007bff;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
.cv-widget-current label {
|
|
1225
|
-
font-size: 12px;
|
|
1226
|
-
text-transform: uppercase;
|
|
1227
|
-
letter-spacing: 0.5px;
|
|
1228
|
-
color: #666;
|
|
1229
|
-
margin-bottom: 4px;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
.cv-widget-current-view {
|
|
1233
|
-
font-weight: 500;
|
|
1234
|
-
color: #333;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
.cv-widget-reset {
|
|
1238
|
-
width: 100%;
|
|
1239
|
-
padding: 8px 16px;
|
|
1240
|
-
background: #dc3545;
|
|
1241
|
-
color: white;
|
|
1242
|
-
border: none;
|
|
1243
|
-
border-radius: 4px;
|
|
1244
|
-
cursor: pointer;
|
|
1245
|
-
font-size: 14px;
|
|
1246
|
-
font-weight: 500;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
.cv-widget-reset:hover {
|
|
1250
|
-
background: #c82333;
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
.cv-widget-reset:active {
|
|
1254
|
-
background: #bd2130;
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
/* Responsive design for mobile */
|
|
1258
|
-
@media (max-width: 768px) {
|
|
1259
|
-
.cv-widget-top-right,
|
|
1260
|
-
.cv-widget-top-left {
|
|
1261
|
-
top: 10px;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
.cv-widget-bottom-right,
|
|
1265
|
-
.cv-widget-bottom-left {
|
|
1266
|
-
bottom: 10px;
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
/* All widgets stay flush with screen edges */
|
|
1270
|
-
.cv-widget-top-right,
|
|
1271
|
-
.cv-widget-bottom-right,
|
|
1272
|
-
.cv-widget-middle-right {
|
|
1273
|
-
right: 0;
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
.cv-widget-top-left,
|
|
1277
|
-
.cv-widget-bottom-left,
|
|
1278
|
-
.cv-widget-middle-left {
|
|
1279
|
-
left: 0;
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
/* Slightly smaller on mobile */
|
|
1283
|
-
.cv-widget-icon {
|
|
1284
|
-
width: 60px;
|
|
1285
|
-
height: 32px;
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
.cv-widget-icon:hover {
|
|
1289
|
-
width: 75px;
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
/* Modal styles */
|
|
1294
|
-
.cv-widget-modal-overlay {
|
|
1295
|
-
position: fixed;
|
|
1296
|
-
top: 0;
|
|
1297
|
-
left: 0;
|
|
1298
|
-
right: 0;
|
|
1299
|
-
bottom: 0;
|
|
1300
|
-
background: rgba(0, 0, 0, 0.5);
|
|
1301
|
-
display: flex;
|
|
1302
|
-
align-items: center;
|
|
1303
|
-
justify-content: center;
|
|
1304
|
-
z-index: 10002;
|
|
1305
|
-
animation: fadeIn 0.2s ease;
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
@keyframes fadeIn {
|
|
1309
|
-
from { opacity: 0; }
|
|
1310
|
-
to { opacity: 1; }
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
.cv-widget-modal {
|
|
1314
|
-
background: white;
|
|
1315
|
-
border-radius: 8px;
|
|
1316
|
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
|
1317
|
-
max-width: 400px;
|
|
1318
|
-
width: 90vw;
|
|
1319
|
-
max-height: 80vh;
|
|
1320
|
-
overflow-y: auto;
|
|
1321
|
-
animation: slideIn 0.2s ease;
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
@keyframes slideIn {
|
|
1325
|
-
from {
|
|
1326
|
-
opacity: 0;
|
|
1327
|
-
transform: scale(0.9) translateY(-20px);
|
|
1328
|
-
}
|
|
1329
|
-
to {
|
|
1330
|
-
opacity: 1;
|
|
1331
|
-
transform: scale(1) translateY(0);
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
.cv-widget-modal-header {
|
|
1336
|
-
display: flex;
|
|
1337
|
-
justify-content: space-between;
|
|
1338
|
-
align-items: center;
|
|
1339
|
-
padding: 16px 20px;
|
|
1340
|
-
border-bottom: 1px solid #e9ecef;
|
|
1341
|
-
background: #f8f9fa;
|
|
1342
|
-
border-radius: 8px 8px 0 0;
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
.cv-widget-modal-header h3 {
|
|
1346
|
-
margin: 0;
|
|
1347
|
-
font-size: 18px;
|
|
1348
|
-
font-weight: 600;
|
|
1349
|
-
color: #333;
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
.cv-widget-modal-close {
|
|
1353
|
-
background: none;
|
|
1354
|
-
border: none;
|
|
1355
|
-
font-size:
|
|
1356
|
-
cursor: pointer;
|
|
1357
|
-
padding: 0;
|
|
1358
|
-
width: 32px;
|
|
1359
|
-
height: 32px;
|
|
1360
|
-
display: flex;
|
|
1361
|
-
align-items: center;
|
|
1362
|
-
justify-content: center;
|
|
1363
|
-
border-radius: 4px;
|
|
1364
|
-
color: #666;
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
.cv-custom-state-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
.cv-custom-state-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
.cv-custom-state-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
.cv-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
.cv-custom-state-reset
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
.cv-welcome-got-it
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
.cv-
|
|
1693
|
-
|
|
1694
|
-
}
|
|
1216
|
+
const WIDGET_STYLES = `
|
|
1217
|
+
/* Rounded rectangle widget icon styles */
|
|
1218
|
+
.cv-widget-icon {
|
|
1219
|
+
position: fixed;
|
|
1220
|
+
/* Slightly transparent by default so the widget is subtle at the page edge */
|
|
1221
|
+
background: rgba(255, 255, 255, 0.92);
|
|
1222
|
+
color: rgba(0, 0, 0, 0.9);
|
|
1223
|
+
opacity: 0.6;
|
|
1224
|
+
display: flex;
|
|
1225
|
+
align-items: center;
|
|
1226
|
+
justify-content: center;
|
|
1227
|
+
font-size: 18px;
|
|
1228
|
+
font-weight: bold;
|
|
1229
|
+
cursor: pointer;
|
|
1230
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1231
|
+
z-index: 9998;
|
|
1232
|
+
transition: all 0.3s ease;
|
|
1233
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
.cv-widget-icon:hover {
|
|
1237
|
+
/* Become fully opaque on hover to improve readability */
|
|
1238
|
+
background: rgba(255, 255, 255, 1);
|
|
1239
|
+
color: rgba(0, 0, 0, 1);
|
|
1240
|
+
opacity: 1;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/* Top-right: rounded end on left, sticks out leftward on hover */
|
|
1244
|
+
.cv-widget-top-right {
|
|
1245
|
+
top: 20px;
|
|
1246
|
+
right: 0;
|
|
1247
|
+
border-radius: 18px 0 0 18px;
|
|
1248
|
+
padding-left: 8px;
|
|
1249
|
+
justify-content: flex-start;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/* Top-left: rounded end on right, sticks out rightward on hover */
|
|
1253
|
+
.cv-widget-top-left {
|
|
1254
|
+
top: 20px;
|
|
1255
|
+
left: 0;
|
|
1256
|
+
border-radius: 0 18px 18px 0;
|
|
1257
|
+
padding-right: 8px;
|
|
1258
|
+
justify-content: flex-end;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/* Bottom-right: rounded end on left, sticks out leftward on hover */
|
|
1262
|
+
.cv-widget-bottom-right {
|
|
1263
|
+
bottom: 20px;
|
|
1264
|
+
right: 0;
|
|
1265
|
+
border-radius: 18px 0 0 18px;
|
|
1266
|
+
padding-left: 8px;
|
|
1267
|
+
justify-content: flex-start;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* Bottom-left: rounded end on right, sticks out rightward on hover */
|
|
1271
|
+
.cv-widget-bottom-left {
|
|
1272
|
+
bottom: 20px;
|
|
1273
|
+
left: 0;
|
|
1274
|
+
border-radius: 0 18px 18px 0;
|
|
1275
|
+
padding-right: 8px;
|
|
1276
|
+
justify-content: flex-end;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
/* Middle-left: rounded end on right, sticks out rightward on hover */
|
|
1280
|
+
.cv-widget-middle-left {
|
|
1281
|
+
top: 50%;
|
|
1282
|
+
left: 0;
|
|
1283
|
+
transform: translateY(-50%);
|
|
1284
|
+
border-radius: 0 18px 18px 0;
|
|
1285
|
+
padding-right: 8px;
|
|
1286
|
+
justify-content: flex-end;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/* Middle-right: rounded end on left, sticks out leftward on hover */
|
|
1290
|
+
.cv-widget-middle-right {
|
|
1291
|
+
top: 50%;
|
|
1292
|
+
right: 0;
|
|
1293
|
+
transform: translateY(-50%);
|
|
1294
|
+
border-radius: 18px 0 0 18px;
|
|
1295
|
+
padding-left: 8px;
|
|
1296
|
+
justify-content: flex-start;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.cv-widget-top-right,
|
|
1300
|
+
.cv-widget-middle-right,
|
|
1301
|
+
.cv-widget-bottom-right,
|
|
1302
|
+
.cv-widget-top-left,
|
|
1303
|
+
.cv-widget-middle-left,
|
|
1304
|
+
.cv-widget-bottom-left {
|
|
1305
|
+
height: 36px;
|
|
1306
|
+
width: 36px;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.cv-widget-middle-right:hover,
|
|
1310
|
+
.cv-widget-top-right:hover,
|
|
1311
|
+
.cv-widget-bottom-right:hover,
|
|
1312
|
+
.cv-widget-top-left:hover,
|
|
1313
|
+
.cv-widget-middle-left:hover,
|
|
1314
|
+
.cv-widget-bottom-left:hover {
|
|
1315
|
+
width: 55px;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/* Modal content styles */
|
|
1319
|
+
.cv-widget-section {
|
|
1320
|
+
margin-bottom: 16px;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
.cv-widget-section:last-child {
|
|
1324
|
+
margin-bottom: 0;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.cv-widget-section label {
|
|
1328
|
+
display: block;
|
|
1329
|
+
margin-bottom: 4px;
|
|
1330
|
+
font-weight: 500;
|
|
1331
|
+
color: #555;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
.cv-widget-profile-select,
|
|
1335
|
+
.cv-widget-state-select {
|
|
1336
|
+
width: 100%;
|
|
1337
|
+
padding: 8px 12px;
|
|
1338
|
+
border: 1px solid #ddd;
|
|
1339
|
+
border-radius: 4px;
|
|
1340
|
+
background: white;
|
|
1341
|
+
font-size: 14px;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
.cv-widget-profile-select:focus,
|
|
1345
|
+
.cv-widget-state-select:focus {
|
|
1346
|
+
outline: none;
|
|
1347
|
+
border-color: #007bff;
|
|
1348
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.cv-widget-profile-select:disabled,
|
|
1352
|
+
.cv-widget-state-select:disabled {
|
|
1353
|
+
background: #f8f9fa;
|
|
1354
|
+
color: #6c757d;
|
|
1355
|
+
cursor: not-allowed;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.cv-widget-current {
|
|
1359
|
+
margin: 16px 0;
|
|
1360
|
+
padding: 12px;
|
|
1361
|
+
background: #f8f9fa;
|
|
1362
|
+
border-radius: 4px;
|
|
1363
|
+
border-left: 4px solid #007bff;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
.cv-widget-current label {
|
|
1367
|
+
font-size: 12px;
|
|
1368
|
+
text-transform: uppercase;
|
|
1369
|
+
letter-spacing: 0.5px;
|
|
1370
|
+
color: #666;
|
|
1371
|
+
margin-bottom: 4px;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
.cv-widget-current-view {
|
|
1375
|
+
font-weight: 500;
|
|
1376
|
+
color: #333;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
.cv-widget-reset {
|
|
1380
|
+
width: 100%;
|
|
1381
|
+
padding: 8px 16px;
|
|
1382
|
+
background: #dc3545;
|
|
1383
|
+
color: white;
|
|
1384
|
+
border: none;
|
|
1385
|
+
border-radius: 4px;
|
|
1386
|
+
cursor: pointer;
|
|
1387
|
+
font-size: 14px;
|
|
1388
|
+
font-weight: 500;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.cv-widget-reset:hover {
|
|
1392
|
+
background: #c82333;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
.cv-widget-reset:active {
|
|
1396
|
+
background: #bd2130;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/* Responsive design for mobile */
|
|
1400
|
+
@media (max-width: 768px) {
|
|
1401
|
+
.cv-widget-top-right,
|
|
1402
|
+
.cv-widget-top-left {
|
|
1403
|
+
top: 10px;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
.cv-widget-bottom-right,
|
|
1407
|
+
.cv-widget-bottom-left {
|
|
1408
|
+
bottom: 10px;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/* All widgets stay flush with screen edges */
|
|
1412
|
+
.cv-widget-top-right,
|
|
1413
|
+
.cv-widget-bottom-right,
|
|
1414
|
+
.cv-widget-middle-right {
|
|
1415
|
+
right: 0;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
.cv-widget-top-left,
|
|
1419
|
+
.cv-widget-bottom-left,
|
|
1420
|
+
.cv-widget-middle-left {
|
|
1421
|
+
left: 0;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/* Slightly smaller on mobile */
|
|
1425
|
+
.cv-widget-icon {
|
|
1426
|
+
width: 60px;
|
|
1427
|
+
height: 32px;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
.cv-widget-icon:hover {
|
|
1431
|
+
width: 75px;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/* Modal styles */
|
|
1436
|
+
.cv-widget-modal-overlay {
|
|
1437
|
+
position: fixed;
|
|
1438
|
+
top: 0;
|
|
1439
|
+
left: 0;
|
|
1440
|
+
right: 0;
|
|
1441
|
+
bottom: 0;
|
|
1442
|
+
background: rgba(0, 0, 0, 0.5);
|
|
1443
|
+
display: flex;
|
|
1444
|
+
align-items: center;
|
|
1445
|
+
justify-content: center;
|
|
1446
|
+
z-index: 10002;
|
|
1447
|
+
animation: fadeIn 0.2s ease;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
@keyframes fadeIn {
|
|
1451
|
+
from { opacity: 0; }
|
|
1452
|
+
to { opacity: 1; }
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
.cv-widget-modal {
|
|
1456
|
+
background: white;
|
|
1457
|
+
border-radius: 8px;
|
|
1458
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
|
1459
|
+
max-width: 400px;
|
|
1460
|
+
width: 90vw;
|
|
1461
|
+
max-height: 80vh;
|
|
1462
|
+
overflow-y: auto;
|
|
1463
|
+
animation: slideIn 0.2s ease;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
@keyframes slideIn {
|
|
1467
|
+
from {
|
|
1468
|
+
opacity: 0;
|
|
1469
|
+
transform: scale(0.9) translateY(-20px);
|
|
1470
|
+
}
|
|
1471
|
+
to {
|
|
1472
|
+
opacity: 1;
|
|
1473
|
+
transform: scale(1) translateY(0);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
.cv-widget-modal-header {
|
|
1478
|
+
display: flex;
|
|
1479
|
+
justify-content: space-between;
|
|
1480
|
+
align-items: center;
|
|
1481
|
+
padding: 16px 20px;
|
|
1482
|
+
border-bottom: 1px solid #e9ecef;
|
|
1483
|
+
background: #f8f9fa;
|
|
1484
|
+
border-radius: 8px 8px 0 0;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
.cv-widget-modal-header h3 {
|
|
1488
|
+
margin: 0;
|
|
1489
|
+
font-size: 18px;
|
|
1490
|
+
font-weight: 600;
|
|
1491
|
+
color: #333;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
.cv-widget-modal-close {
|
|
1495
|
+
background: none;
|
|
1496
|
+
border: none;
|
|
1497
|
+
font-size: 20px;
|
|
1498
|
+
cursor: pointer;
|
|
1499
|
+
padding: 0;
|
|
1500
|
+
width: 32px;
|
|
1501
|
+
height: 32px;
|
|
1502
|
+
display: flex;
|
|
1503
|
+
align-items: center;
|
|
1504
|
+
justify-content: center;
|
|
1505
|
+
border-radius: 4px;
|
|
1506
|
+
color: #666;
|
|
1507
|
+
line-height: 1;
|
|
1508
|
+
transition: all 0.2s ease;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
.cv-widget-modal-close:hover {
|
|
1512
|
+
background: #e9ecef;
|
|
1513
|
+
color: #333;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
.cv-widget-modal-content {
|
|
1517
|
+
padding: 20px;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
.cv-widget-modal-actions {
|
|
1521
|
+
margin-top: 20px;
|
|
1522
|
+
padding-top: 16px;
|
|
1523
|
+
border-top: 1px solid #e9ecef;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
.cv-widget-restore {
|
|
1527
|
+
width: 100%;
|
|
1528
|
+
padding: 10px 16px;
|
|
1529
|
+
background: #28a745;
|
|
1530
|
+
color: white;
|
|
1531
|
+
border: none;
|
|
1532
|
+
border-radius: 4px;
|
|
1533
|
+
cursor: pointer;
|
|
1534
|
+
font-size: 14px;
|
|
1535
|
+
font-weight: 500;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.cv-widget-restore:hover {
|
|
1539
|
+
background: #218838;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
.cv-widget-create-state {
|
|
1543
|
+
width: 100%;
|
|
1544
|
+
padding: 10px 16px;
|
|
1545
|
+
background: #007bff;
|
|
1546
|
+
color: white;
|
|
1547
|
+
border: none;
|
|
1548
|
+
border-radius: 4px;
|
|
1549
|
+
cursor: pointer;
|
|
1550
|
+
font-size: 14px;
|
|
1551
|
+
font-weight: 500;
|
|
1552
|
+
margin-bottom: 10px;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.cv-widget-create-state:hover {
|
|
1556
|
+
background: #0056b3;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/* Dark theme modal styles */
|
|
1560
|
+
.cv-widget-theme-dark .cv-widget-modal {
|
|
1561
|
+
background: #2d3748;
|
|
1562
|
+
color: #e2e8f0;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
.cv-widget-theme-dark .cv-widget-modal-header {
|
|
1566
|
+
background: #1a202c;
|
|
1567
|
+
border-color: #4a5568;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
.cv-widget-theme-dark .cv-widget-modal-header h3 {
|
|
1571
|
+
color: #e2e8f0;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
.cv-widget-theme-dark .cv-widget-modal-close {
|
|
1575
|
+
color: #a0aec0;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
.cv-widget-theme-dark .cv-widget-modal-close:hover {
|
|
1579
|
+
background: #4a5568;
|
|
1580
|
+
color: #e2e8f0;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.cv-widget-theme-dark .cv-widget-modal-actions {
|
|
1584
|
+
border-color: #4a5568;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
/* Custom state creator styles */
|
|
1588
|
+
.cv-custom-state-modal {
|
|
1589
|
+
max-width: 500px;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
.cv-custom-state-form h4 {
|
|
1593
|
+
margin: 20px 0 10px 0;
|
|
1594
|
+
font-size: 16px;
|
|
1595
|
+
font-weight: 600;
|
|
1596
|
+
color: #333;
|
|
1597
|
+
border-bottom: 1px solid #e9ecef;
|
|
1598
|
+
padding-bottom: 5px;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
.cv-custom-state-form p {
|
|
1602
|
+
font-size: 15px;
|
|
1603
|
+
line-height: 1.6;
|
|
1604
|
+
color: #555;
|
|
1605
|
+
margin-bottom: 24px;
|
|
1606
|
+
text-align: justify;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
.cv-custom-state-section {
|
|
1610
|
+
margin-bottom: 16px;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
.cv-custom-state-section label {
|
|
1614
|
+
display: block;
|
|
1615
|
+
margin-bottom: 4px;
|
|
1616
|
+
font-weight: 500;
|
|
1617
|
+
color: #555;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
.cv-custom-state-input {
|
|
1621
|
+
width: 100%;
|
|
1622
|
+
padding: 8px 12px;
|
|
1623
|
+
border: 1px solid #ddd;
|
|
1624
|
+
border-radius: 4px;
|
|
1625
|
+
background: white;
|
|
1626
|
+
font-size: 14px;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
.cv-custom-state-input:focus {
|
|
1630
|
+
outline: none;
|
|
1631
|
+
border-color: #007bff;
|
|
1632
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
.cv-custom-toggles {
|
|
1636
|
+
display: grid;
|
|
1637
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
1638
|
+
gap: 10px;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
.cv-custom-state-toggle {
|
|
1642
|
+
display: flex;
|
|
1643
|
+
align-items: center;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
.cv-custom-state-toggle label {
|
|
1647
|
+
display: flex;
|
|
1648
|
+
align-items: center;
|
|
1649
|
+
cursor: pointer;
|
|
1650
|
+
font-weight: normal;
|
|
1651
|
+
margin: 0;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.cv-custom-toggle-checkbox {
|
|
1655
|
+
margin-right: 8px;
|
|
1656
|
+
width: auto;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
.cv-tab-groups {
|
|
1660
|
+
margin-top: 20px;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
.cv-tab-group-control {
|
|
1664
|
+
margin-bottom: 15px;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
.cv-tab-group-control label {
|
|
1668
|
+
display: block;
|
|
1669
|
+
margin-bottom: 5px;
|
|
1670
|
+
font-weight: 500;
|
|
1671
|
+
font-size: 14px;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
.cv-tab-group-select {
|
|
1675
|
+
width: 100%;
|
|
1676
|
+
padding: 8px 12px;
|
|
1677
|
+
border: 1px solid #ced4da;
|
|
1678
|
+
border-radius: 4px;
|
|
1679
|
+
font-size: 14px;
|
|
1680
|
+
background-color: white;
|
|
1681
|
+
cursor: pointer;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
.cv-tab-group-select:focus {
|
|
1685
|
+
outline: none;
|
|
1686
|
+
border-color: #007bff;
|
|
1687
|
+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.cv-widget-theme-dark .cv-tab-group-select {
|
|
1691
|
+
background-color: #2d3748;
|
|
1692
|
+
border-color: #4a5568;
|
|
1693
|
+
color: #e2e8f0;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
.cv-custom-state-actions {
|
|
1697
|
+
display: flex;
|
|
1698
|
+
gap: 10px;
|
|
1699
|
+
margin-top: 20px;
|
|
1700
|
+
padding-top: 16px;
|
|
1701
|
+
border-top: 1px solid #e9ecef;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
.cv-custom-state-cancel,
|
|
1705
|
+
.cv-custom-state-copy-url {
|
|
1706
|
+
flex: 1;
|
|
1707
|
+
padding: 10px 16px;
|
|
1708
|
+
border: none;
|
|
1709
|
+
border-radius: 4px;
|
|
1710
|
+
cursor: pointer;
|
|
1711
|
+
font-size: 14px;
|
|
1712
|
+
font-weight: 500;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
.cv-custom-state-reset {
|
|
1716
|
+
flex: 1;
|
|
1717
|
+
padding: 10px 16px;
|
|
1718
|
+
border: none;
|
|
1719
|
+
border-radius: 4px;
|
|
1720
|
+
cursor: pointer;
|
|
1721
|
+
font-size: 14px;
|
|
1722
|
+
font-weight: 500;
|
|
1723
|
+
background: #dc3545;
|
|
1724
|
+
color: white;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
.cv-custom-state-reset:hover {
|
|
1728
|
+
background: #c82333;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
.cv-custom-state-cancel {
|
|
1732
|
+
background: #6c757d;
|
|
1733
|
+
color: white;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
.cv-custom-state-cancel:hover {
|
|
1737
|
+
background: #5a6268;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
.cv-custom-state-copy-url {
|
|
1741
|
+
background: #28a745;
|
|
1742
|
+
color: white;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
.cv-custom-state-copy-url:hover {
|
|
1746
|
+
background: #218838;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/* Dark theme custom state styles */
|
|
1750
|
+
.cv-widget-theme-dark .cv-custom-state-form h4 {
|
|
1751
|
+
color: #e2e8f0;
|
|
1752
|
+
border-color: #4a5568;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
.cv-widget-theme-dark .cv-custom-state-form p {
|
|
1756
|
+
color: #cbd5e0;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
.cv-widget-theme-dark .cv-custom-state-section label {
|
|
1760
|
+
color: #a0aec0;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
.cv-widget-theme-dark .cv-custom-state-input {
|
|
1764
|
+
background: #1a202c;
|
|
1765
|
+
border-color: #4a5568;
|
|
1766
|
+
color: #e2e8f0;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
.cv-widget-theme-dark .cv-custom-state-actions {
|
|
1770
|
+
border-color: #4a5568;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
/* Welcome modal styles */
|
|
1774
|
+
.cv-welcome-modal {
|
|
1775
|
+
max-width: 500px;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.cv-welcome-content {
|
|
1779
|
+
text-align: center;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
.cv-welcome-content p {
|
|
1783
|
+
font-size: 15px;
|
|
1784
|
+
line-height: 1.6;
|
|
1785
|
+
color: #555;
|
|
1786
|
+
margin-bottom: 24px;
|
|
1787
|
+
text-align: justify;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
.cv-welcome-widget-preview {
|
|
1791
|
+
display: flex;
|
|
1792
|
+
flex-direction: column;
|
|
1793
|
+
align-items: center;
|
|
1794
|
+
gap: 12px;
|
|
1795
|
+
padding: 20px;
|
|
1796
|
+
background: #f8f9fa;
|
|
1797
|
+
border-radius: 8px;
|
|
1798
|
+
margin-bottom: 24px;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
.cv-welcome-widget-icon {
|
|
1802
|
+
width: 36px;
|
|
1803
|
+
height: 36px;
|
|
1804
|
+
background: white;
|
|
1805
|
+
color: black;
|
|
1806
|
+
border-radius: 0 18px 18px 0;
|
|
1807
|
+
display: flex;
|
|
1808
|
+
align-items: center;
|
|
1809
|
+
justify-content: center;
|
|
1810
|
+
font-size: 18px;
|
|
1811
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
.cv-welcome-widget-label {
|
|
1815
|
+
font-size: 14px;
|
|
1816
|
+
color: #666;
|
|
1817
|
+
margin: 0;
|
|
1818
|
+
font-weight: 500;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
.cv-welcome-got-it {
|
|
1822
|
+
width: 100%;
|
|
1823
|
+
padding: 12px 24px;
|
|
1824
|
+
background: #007bff;
|
|
1825
|
+
color: white;
|
|
1826
|
+
border: none;
|
|
1827
|
+
border-radius: 4px;
|
|
1828
|
+
cursor: pointer;
|
|
1829
|
+
font-size: 16px;
|
|
1830
|
+
font-weight: 600;
|
|
1831
|
+
transition: background 0.2s ease;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
.cv-welcome-got-it:hover {
|
|
1835
|
+
background: #0056b3;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
.cv-welcome-got-it:active {
|
|
1839
|
+
background: #004494;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
/* Dark theme welcome modal styles */
|
|
1843
|
+
.cv-widget-theme-dark .cv-welcome-content p {
|
|
1844
|
+
color: #cbd5e0;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
.cv-widget-theme-dark .cv-welcome-widget-preview {
|
|
1848
|
+
background: #1a202c;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
.cv-widget-theme-dark .cv-welcome-widget-label {
|
|
1852
|
+
color: #a0aec0;
|
|
1853
|
+
}
|
|
1695
1854
|
`;
|
|
1696
1855
|
/**
|
|
1697
1856
|
* Inject widget styles into the document head
|
|
@@ -1726,8 +1885,8 @@ ${TAB_STYLES}
|
|
|
1726
1885
|
title: options.title || 'Custom Views',
|
|
1727
1886
|
description: options.description || 'Toggle different content sections to customize your view. Changes are applied instantly and the URL will be updated for sharing.',
|
|
1728
1887
|
showWelcome: options.showWelcome ?? false,
|
|
1729
|
-
welcomeTitle: options.welcomeTitle || '
|
|
1730
|
-
welcomeMessage: options.welcomeMessage || 'This
|
|
1888
|
+
welcomeTitle: options.welcomeTitle || 'This website uses Custom Views',
|
|
1889
|
+
welcomeMessage: options.welcomeMessage || 'This site uses Custom Views to let you personalize your experience. Use the widget on the side (⚙) to show or hide different content sections based on your preferences. Your selections will be saved and can be shared via URL.',
|
|
1731
1890
|
showTabGroups: options.showTabGroups ?? true
|
|
1732
1891
|
};
|
|
1733
1892
|
// No external state manager to initialize
|
|
@@ -1807,13 +1966,13 @@ ${TAB_STYLES}
|
|
|
1807
1966
|
this.modal.className = 'cv-widget-modal-overlay';
|
|
1808
1967
|
this.applyThemeToModal();
|
|
1809
1968
|
const toggleControls = toggles.length
|
|
1810
|
-
? toggles.map(toggle => `
|
|
1811
|
-
<div class="cv-custom-state-toggle">
|
|
1812
|
-
<label>
|
|
1813
|
-
<input type="checkbox" class="cv-custom-toggle-checkbox" data-toggle="${toggle}" />
|
|
1814
|
-
${this.formatToggleName(toggle)}
|
|
1815
|
-
</label>
|
|
1816
|
-
</div>
|
|
1969
|
+
? toggles.map(toggle => `
|
|
1970
|
+
<div class="cv-custom-state-toggle">
|
|
1971
|
+
<label>
|
|
1972
|
+
<input type="checkbox" class="cv-custom-toggle-checkbox" data-toggle="${toggle}" />
|
|
1973
|
+
${this.formatToggleName(toggle)}
|
|
1974
|
+
</label>
|
|
1975
|
+
</div>
|
|
1817
1976
|
`).join('')
|
|
1818
1977
|
: `<p class="cv-no-toggles">No configurable sections available.</p>`;
|
|
1819
1978
|
// Get tab groups
|
|
@@ -1822,46 +1981,46 @@ ${TAB_STYLES}
|
|
|
1822
1981
|
if (this.options.showTabGroups && tabGroups && tabGroups.length > 0) {
|
|
1823
1982
|
const tabGroupControls = tabGroups.map(group => {
|
|
1824
1983
|
const options = group.tabs.map(tab => `<option value="${tab.id}">${tab.label || tab.id}</option>`).join('');
|
|
1825
|
-
return `
|
|
1826
|
-
<div class="cv-tab-group-control">
|
|
1827
|
-
<label for="tab-group-${group.id}">${group.label || group.id}</label>
|
|
1828
|
-
<select id="tab-group-${group.id}" class="cv-tab-group-select" data-group-id="${group.id}">
|
|
1829
|
-
${options}
|
|
1830
|
-
</select>
|
|
1831
|
-
</div>
|
|
1984
|
+
return `
|
|
1985
|
+
<div class="cv-tab-group-control">
|
|
1986
|
+
<label for="tab-group-${group.id}">${group.label || group.id}</label>
|
|
1987
|
+
<select id="tab-group-${group.id}" class="cv-tab-group-select" data-group-id="${group.id}">
|
|
1988
|
+
${options}
|
|
1989
|
+
</select>
|
|
1990
|
+
</div>
|
|
1832
1991
|
`;
|
|
1833
1992
|
}).join('');
|
|
1834
|
-
tabGroupsHTML = `
|
|
1835
|
-
<h4>Tab Groups</h4>
|
|
1836
|
-
<div class="cv-tab-groups">
|
|
1837
|
-
${tabGroupControls}
|
|
1838
|
-
</div>
|
|
1993
|
+
tabGroupsHTML = `
|
|
1994
|
+
<h4>Tab Groups</h4>
|
|
1995
|
+
<div class="cv-tab-groups">
|
|
1996
|
+
${tabGroupControls}
|
|
1997
|
+
</div>
|
|
1839
1998
|
`;
|
|
1840
1999
|
}
|
|
1841
|
-
this.modal.innerHTML = `
|
|
1842
|
-
<div class="cv-widget-modal cv-custom-state-modal">
|
|
1843
|
-
<div class="cv-widget-modal-header">
|
|
1844
|
-
<h3>Customize View</h3>
|
|
1845
|
-
<button class="cv-widget-modal-close" aria-label="Close modal"
|
|
1846
|
-
</div>
|
|
1847
|
-
<div class="cv-widget-modal-content">
|
|
1848
|
-
<div class="cv-custom-state-form">
|
|
1849
|
-
<p>${this.options.description}</p>
|
|
1850
|
-
|
|
1851
|
-
<h4>Content Sections</h4>
|
|
1852
|
-
<div class="cv-custom-toggles">
|
|
1853
|
-
${toggleControls}
|
|
1854
|
-
</div>
|
|
1855
|
-
|
|
1856
|
-
${tabGroupsHTML}
|
|
1857
|
-
|
|
1858
|
-
<div class="cv-custom-state-actions">
|
|
1859
|
-
${this.options.showReset ? `<button class="cv-custom-state-reset">Reset to Default</button>` : ''}
|
|
1860
|
-
<button class="cv-custom-state-copy-url">Copy Shareable URL</button>
|
|
1861
|
-
</div>
|
|
1862
|
-
</div>
|
|
1863
|
-
</div>
|
|
1864
|
-
</div>
|
|
2000
|
+
this.modal.innerHTML = `
|
|
2001
|
+
<div class="cv-widget-modal cv-custom-state-modal">
|
|
2002
|
+
<div class="cv-widget-modal-header">
|
|
2003
|
+
<h3>Customize View</h3>
|
|
2004
|
+
<button class="cv-widget-modal-close" aria-label="Close modal">×</button>
|
|
2005
|
+
</div>
|
|
2006
|
+
<div class="cv-widget-modal-content">
|
|
2007
|
+
<div class="cv-custom-state-form">
|
|
2008
|
+
<p>${this.options.description}</p>
|
|
2009
|
+
|
|
2010
|
+
<h4>Content Sections</h4>
|
|
2011
|
+
<div class="cv-custom-toggles">
|
|
2012
|
+
${toggleControls}
|
|
2013
|
+
</div>
|
|
2014
|
+
|
|
2015
|
+
${tabGroupsHTML}
|
|
2016
|
+
|
|
2017
|
+
<div class="cv-custom-state-actions">
|
|
2018
|
+
${this.options.showReset ? `<button class="cv-custom-state-reset">Reset to Default</button>` : ''}
|
|
2019
|
+
<button class="cv-custom-state-copy-url">Copy Shareable URL</button>
|
|
2020
|
+
</div>
|
|
2021
|
+
</div>
|
|
2022
|
+
</div>
|
|
2023
|
+
</div>
|
|
1865
2024
|
`;
|
|
1866
2025
|
document.body.appendChild(this.modal);
|
|
1867
2026
|
this.attachStateModalEventListeners();
|
|
@@ -2046,25 +2205,25 @@ ${TAB_STYLES}
|
|
|
2046
2205
|
this.modal = document.createElement('div');
|
|
2047
2206
|
this.modal.className = 'cv-widget-modal-overlay cv-welcome-modal-overlay';
|
|
2048
2207
|
this.applyThemeToModal();
|
|
2049
|
-
this.modal.innerHTML = `
|
|
2050
|
-
<div class="cv-widget-modal cv-welcome-modal">
|
|
2051
|
-
<div class="cv-widget-modal-header">
|
|
2052
|
-
<h3>${this.options.welcomeTitle}</h3>
|
|
2053
|
-
<button class="cv-widget-modal-close" aria-label="Close modal">×</button>
|
|
2054
|
-
</div>
|
|
2055
|
-
<div class="cv-widget-modal-content">
|
|
2056
|
-
<div class="cv-welcome-content">
|
|
2057
|
-
<p>${this.options.welcomeMessage}</p>
|
|
2058
|
-
|
|
2059
|
-
<div class="cv-welcome-widget-preview">
|
|
2060
|
-
<div class="cv-welcome-widget-icon">⚙</div>
|
|
2061
|
-
<p class="cv-welcome-widget-label">Look for this widget on the side of the screen</p>
|
|
2062
|
-
</div>
|
|
2063
|
-
|
|
2064
|
-
<button class="cv-welcome-got-it">Got it!</button>
|
|
2065
|
-
</div>
|
|
2066
|
-
</div>
|
|
2067
|
-
</div>
|
|
2208
|
+
this.modal.innerHTML = `
|
|
2209
|
+
<div class="cv-widget-modal cv-welcome-modal">
|
|
2210
|
+
<div class="cv-widget-modal-header">
|
|
2211
|
+
<h3>${this.options.welcomeTitle}</h3>
|
|
2212
|
+
<button class="cv-widget-modal-close" aria-label="Close modal">×</button>
|
|
2213
|
+
</div>
|
|
2214
|
+
<div class="cv-widget-modal-content">
|
|
2215
|
+
<div class="cv-welcome-content">
|
|
2216
|
+
<p>${this.options.welcomeMessage}</p>
|
|
2217
|
+
|
|
2218
|
+
<div class="cv-welcome-widget-preview">
|
|
2219
|
+
<div class="cv-welcome-widget-icon">⚙</div>
|
|
2220
|
+
<p class="cv-welcome-widget-label">Look for this widget on the side of the screen</p>
|
|
2221
|
+
</div>
|
|
2222
|
+
|
|
2223
|
+
<button class="cv-welcome-got-it">Got it!</button>
|
|
2224
|
+
</div>
|
|
2225
|
+
</div>
|
|
2226
|
+
</div>
|
|
2068
2227
|
`;
|
|
2069
2228
|
document.body.appendChild(this.modal);
|
|
2070
2229
|
this.attachWelcomeModalEventListeners();
|
|
@@ -2106,46 +2265,6 @@ ${TAB_STYLES}
|
|
|
2106
2265
|
}
|
|
2107
2266
|
}
|
|
2108
2267
|
|
|
2109
|
-
/**
|
|
2110
|
-
* Custom Elements for Tab Groups and Tabs
|
|
2111
|
-
*/
|
|
2112
|
-
/**
|
|
2113
|
-
* <cv-tab> element - represents a single tab panel
|
|
2114
|
-
*/
|
|
2115
|
-
class CVTab extends HTMLElement {
|
|
2116
|
-
connectedCallback() {
|
|
2117
|
-
// Element is managed by TabManager
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
/**
|
|
2121
|
-
* <cv-tabgroup> element - represents a group of tabs
|
|
2122
|
-
*/
|
|
2123
|
-
class CVTabgroup extends HTMLElement {
|
|
2124
|
-
connectedCallback() {
|
|
2125
|
-
// Element is managed by TabManager
|
|
2126
|
-
// Emit ready event after a brief delay to ensure children are parsed
|
|
2127
|
-
setTimeout(() => {
|
|
2128
|
-
const event = new CustomEvent('cv:tabgroup-ready', {
|
|
2129
|
-
bubbles: true,
|
|
2130
|
-
detail: { groupId: this.getAttribute('id') }
|
|
2131
|
-
});
|
|
2132
|
-
this.dispatchEvent(event);
|
|
2133
|
-
}, 0);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
/**
|
|
2137
|
-
* Register custom elements
|
|
2138
|
-
*/
|
|
2139
|
-
function registerCustomElements() {
|
|
2140
|
-
// Only register if not already defined
|
|
2141
|
-
if (!customElements.get('cv-tab')) {
|
|
2142
|
-
customElements.define('cv-tab', CVTab);
|
|
2143
|
-
}
|
|
2144
|
-
if (!customElements.get('cv-tabgroup')) {
|
|
2145
|
-
customElements.define('cv-tabgroup', CVTabgroup);
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
|
|
2149
2268
|
/**
|
|
2150
2269
|
* Initialize CustomViews from script tag attributes and config file
|
|
2151
2270
|
* This function handles the automatic initialization of CustomViews when included via script tag
|
|
@@ -2174,8 +2293,6 @@ ${TAB_STYLES}
|
|
|
2174
2293
|
return;
|
|
2175
2294
|
}
|
|
2176
2295
|
window.__customViewsInitInProgress = true;
|
|
2177
|
-
// Register custom elements early
|
|
2178
|
-
registerCustomElements();
|
|
2179
2296
|
try {
|
|
2180
2297
|
// Find the script tag
|
|
2181
2298
|
let scriptTag = document.currentScript;
|