@customviews-js/customviews 1.1.7 → 1.1.9
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/dist/custom-views.core.cjs.js +300 -50
- package/dist/custom-views.core.cjs.js.map +1 -1
- package/dist/custom-views.core.esm.js +300 -50
- package/dist/custom-views.core.esm.js.map +1 -1
- package/dist/custom-views.esm.js +300 -50
- package/dist/custom-views.esm.js.map +1 -1
- package/dist/custom-views.js +300 -50
- 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 +8 -0
- package/dist/types/core/core.d.ts.map +1 -1
- package/dist/types/core/persistence.d.ts +8 -0
- package/dist/types/core/persistence.d.ts.map +1 -1
- package/dist/types/core/widget.d.ts.map +1 -1
- package/dist/types/entry/browser-entry.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/dist/types/utils/icons.d.ts +9 -2
- package/dist/types/utils/icons.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @customviews-js/customviews v1.1.
|
|
2
|
+
* @customviews-js/customviews v1.1.8
|
|
3
3
|
* (c) 2025 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
class PersistenceManager {
|
|
10
10
|
// Storage keys for localStorage
|
|
11
11
|
static STORAGE_KEYS = {
|
|
12
|
-
STATE: 'customviews-state'
|
|
12
|
+
STATE: 'customviews-state',
|
|
13
|
+
TAB_NAV_VISIBILITY: 'cv-tab-navs-visible'
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* Check if localStorage is available in the current environment
|
|
@@ -46,6 +47,35 @@ class PersistenceManager {
|
|
|
46
47
|
if (!this.isStorageAvailable())
|
|
47
48
|
return;
|
|
48
49
|
localStorage.removeItem(PersistenceManager.STORAGE_KEYS.STATE);
|
|
50
|
+
localStorage.removeItem(PersistenceManager.STORAGE_KEYS.TAB_NAV_VISIBILITY);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Persist tab nav visibility preference
|
|
54
|
+
*/
|
|
55
|
+
persistTabNavVisibility(visible) {
|
|
56
|
+
if (!this.isStorageAvailable())
|
|
57
|
+
return;
|
|
58
|
+
try {
|
|
59
|
+
localStorage.setItem(PersistenceManager.STORAGE_KEYS.TAB_NAV_VISIBILITY, visible ? 'true' : 'false');
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.warn('Failed to persist tab nav visibility:', error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get persisted tab nav visibility preference
|
|
67
|
+
*/
|
|
68
|
+
getPersistedTabNavVisibility() {
|
|
69
|
+
if (!this.isStorageAvailable())
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
const raw = localStorage.getItem(PersistenceManager.STORAGE_KEYS.TAB_NAV_VISIBILITY);
|
|
73
|
+
return raw === null ? null : raw === 'true';
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.warn('Failed to get persisted tab nav visibility:', error);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
49
79
|
}
|
|
50
80
|
/**
|
|
51
81
|
* Check if any persistence data exists
|
|
@@ -1097,14 +1127,10 @@ class CustomViewsCore {
|
|
|
1097
1127
|
this.applyState(newState);
|
|
1098
1128
|
});
|
|
1099
1129
|
// Apply stored nav visibility preference on page load
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
const visible = navPref === 'true';
|
|
1104
|
-
TabManager.setNavsVisibility(this.rootEl, visible);
|
|
1105
|
-
}
|
|
1130
|
+
const navPref = this.persistenceManager.getPersistedTabNavVisibility();
|
|
1131
|
+
if (navPref !== null) {
|
|
1132
|
+
TabManager.setNavsVisibility(this.rootEl, navPref);
|
|
1106
1133
|
}
|
|
1107
|
-
catch (e) { /* ignore */ }
|
|
1108
1134
|
// For session history, clicks on back/forward button
|
|
1109
1135
|
window.addEventListener("popstate", () => {
|
|
1110
1136
|
this.loadAndCallApplyState();
|
|
@@ -1171,6 +1197,8 @@ class CustomViewsCore {
|
|
|
1171
1197
|
else {
|
|
1172
1198
|
console.warn("No configuration loaded, cannot reset to default state");
|
|
1173
1199
|
}
|
|
1200
|
+
// Reset tab nav visibility to default (visible)
|
|
1201
|
+
TabManager.setNavsVisibility(this.rootEl, true);
|
|
1174
1202
|
// Clear URL
|
|
1175
1203
|
URLStateManager.clearURL();
|
|
1176
1204
|
}
|
|
@@ -1249,6 +1277,18 @@ class CustomViewsCore {
|
|
|
1249
1277
|
}
|
|
1250
1278
|
});
|
|
1251
1279
|
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Persist tab nav visibility preference
|
|
1282
|
+
*/
|
|
1283
|
+
persistTabNavVisibility(visible) {
|
|
1284
|
+
this.persistenceManager.persistTabNavVisibility(visible);
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Get persisted tab nav visibility preference
|
|
1288
|
+
*/
|
|
1289
|
+
getPersistedTabNavVisibility() {
|
|
1290
|
+
return this.persistenceManager.getPersistedTabNavVisibility();
|
|
1291
|
+
}
|
|
1252
1292
|
cloneState(state) {
|
|
1253
1293
|
if (!state)
|
|
1254
1294
|
return {};
|
|
@@ -2067,6 +2107,57 @@ const WIDGET_STYLES = `
|
|
|
2067
2107
|
gap: 1rem;
|
|
2068
2108
|
}
|
|
2069
2109
|
|
|
2110
|
+
/* Navigation toggle icon container */
|
|
2111
|
+
.cv-nav-toggle-container {
|
|
2112
|
+
display: flex;
|
|
2113
|
+
align-items: center;
|
|
2114
|
+
gap: 0.5rem;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
.cv-nav-icon {
|
|
2118
|
+
width: 2rem;
|
|
2119
|
+
height: 2rem;
|
|
2120
|
+
color: rgba(0, 0, 0, 0.8);
|
|
2121
|
+
display: flex;
|
|
2122
|
+
align-items: center;
|
|
2123
|
+
justify-content: center;
|
|
2124
|
+
flex-shrink: 0;
|
|
2125
|
+
transition: color 0.2s ease;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
/* Logo box - centered grey box on its own row */
|
|
2129
|
+
.cv-tabgroup-logo-box {
|
|
2130
|
+
width: 3.5rem;
|
|
2131
|
+
height: 3.5rem;
|
|
2132
|
+
background: rgba(0, 0, 0, 0.08);
|
|
2133
|
+
border-radius: 0.5rem;
|
|
2134
|
+
display: flex;
|
|
2135
|
+
align-items: center;
|
|
2136
|
+
justify-content: center;
|
|
2137
|
+
flex-shrink: 0;
|
|
2138
|
+
margin-bottom: 0.5rem;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
/* Title container for title alignment (without icon) */
|
|
2142
|
+
.cv-tabgroup-title-container {
|
|
2143
|
+
display: flex;
|
|
2144
|
+
align-items: center;
|
|
2145
|
+
gap: 0.5rem;
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
/* Hover state for icon - apply to the entire tabgroup-row */
|
|
2149
|
+
.cv-tabgroup-card.cv-tabgroup-header:hover .cv-nav-icon {
|
|
2150
|
+
color: #3e84f4;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
.cv-widget-theme-dark .cv-nav-icon {
|
|
2154
|
+
color: rgba(255, 255, 255, 0.8);
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
.cv-widget-theme-dark .cv-tabgroup-card.cv-tabgroup-header:hover .cv-nav-icon {
|
|
2158
|
+
color: #60a5fa;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2070
2161
|
/* Tab Group Card - Items */
|
|
2071
2162
|
.cv-tabgroup-card.cv-tabgroup-item {
|
|
2072
2163
|
display: flex;
|
|
@@ -2084,13 +2175,16 @@ const WIDGET_STYLES = `
|
|
|
2084
2175
|
/* Tab Group Info */
|
|
2085
2176
|
.cv-tabgroup-info {
|
|
2086
2177
|
flex: 1;
|
|
2178
|
+
display: flex;
|
|
2179
|
+
flex-direction: column;
|
|
2180
|
+
gap: 0.25rem;
|
|
2087
2181
|
}
|
|
2088
2182
|
|
|
2089
2183
|
.cv-tabgroup-title {
|
|
2090
2184
|
font-weight: 500;
|
|
2091
2185
|
font-size: 0.875rem;
|
|
2092
2186
|
color: rgba(0, 0, 0, 0.9);
|
|
2093
|
-
margin: 0 0 0
|
|
2187
|
+
margin: 0 0 0 0;
|
|
2094
2188
|
}
|
|
2095
2189
|
|
|
2096
2190
|
.cv-tabgroup-description {
|
|
@@ -2281,6 +2375,10 @@ const WIDGET_STYLES = `
|
|
|
2281
2375
|
.cv-btn-icon {
|
|
2282
2376
|
width: 1rem;
|
|
2283
2377
|
height: 1rem;
|
|
2378
|
+
display: flex;
|
|
2379
|
+
align-items: center;
|
|
2380
|
+
justify-content: center;
|
|
2381
|
+
transition: transform 0.2s ease;
|
|
2284
2382
|
}
|
|
2285
2383
|
|
|
2286
2384
|
/* Dark theme custom state styles */
|
|
@@ -2406,6 +2504,32 @@ const WIDGET_STYLES = `
|
|
|
2406
2504
|
.cv-widget-theme-dark .cv-welcome-widget-label {
|
|
2407
2505
|
color: #e2e8f0;
|
|
2408
2506
|
}
|
|
2507
|
+
|
|
2508
|
+
/* Dark theme logo box */
|
|
2509
|
+
.cv-widget-theme-dark .cv-tabgroup-logo-box {
|
|
2510
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
/* Spinning animation for reset button icon */
|
|
2514
|
+
@keyframes cv-spin {
|
|
2515
|
+
from {
|
|
2516
|
+
transform: rotate(0deg);
|
|
2517
|
+
}
|
|
2518
|
+
to {
|
|
2519
|
+
transform: rotate(-360deg);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
.cv-spinning {
|
|
2524
|
+
animation: cv-spin 0.6s ease-in-out;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
/* Hide widget icon in print view */
|
|
2528
|
+
@media print {
|
|
2529
|
+
.cv-widget-icon {
|
|
2530
|
+
display: none !important;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2409
2533
|
`;
|
|
2410
2534
|
/**
|
|
2411
2535
|
* Inject widget styles into the document head
|
|
@@ -2450,13 +2574,80 @@ function getResetIcon() {
|
|
|
2450
2574
|
</svg>`;
|
|
2451
2575
|
}
|
|
2452
2576
|
/**
|
|
2453
|
-
*
|
|
2577
|
+
* Copy icon for sharing URL button
|
|
2454
2578
|
*/
|
|
2455
|
-
function
|
|
2456
|
-
return `<svg
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2579
|
+
function getCopyIcon() {
|
|
2580
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 18 18" version="1.1" fill="currentColor">
|
|
2581
|
+
<g id="surface1">
|
|
2582
|
+
<path d="M 11.273438 0 L 2.546875 0 C 1.746094 0 1.089844 0.613281 1.089844
|
|
2583
|
+
1.363281 L 1.089844 10.910156 L 2.546875 10.910156 L 2.546875 1.363281 L 11.273438
|
|
2584
|
+
1.363281 Z M 13.453125 2.726562 L 5.453125 2.726562 C 4.65625 2.726562 4 3.339844 4
|
|
2585
|
+
4.089844 L 4 13.636719 C 4 14.386719 4.65625 15 5.453125 15 L 13.453125 15 C 14.253906
|
|
2586
|
+
15 14.910156 14.386719 14.910156 13.636719 L 14.910156 4.089844 C 14.910156 3.339844
|
|
2587
|
+
14.253906 2.726562 13.453125 2.726562 Z M 13.453125 13.636719 L 5.453125 13.636719 L
|
|
2588
|
+
5.453125 4.089844 L 13.453125 4.089844 Z M 13.453125 13.636719 "></path>
|
|
2589
|
+
</g>
|
|
2590
|
+
</svg>`;
|
|
2591
|
+
}
|
|
2592
|
+
function getTickIcon() {
|
|
2593
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="2 2 22 22" fill="currentColor">
|
|
2594
|
+
<path d="M 19.28125 5.28125 L 9 15.5625 L 4.71875 11.28125 L 3.28125 12.71875 L 8.28125 17.71875
|
|
2595
|
+
L 9 18.40625 L 9.71875 17.71875 L 20.71875 6.71875 Z"></path>
|
|
2596
|
+
</svg>`;
|
|
2597
|
+
}
|
|
2598
|
+
function getNavHeadingOnIcon() {
|
|
2599
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="250" height="181" viewBox="0 0 250 181">
|
|
2600
|
+
<rect y="34.5001" width="250" height="146" rx="4" stroke="currentColor" stroke-width="10" fill="none"/>
|
|
2601
|
+
<line x1="27" y1="62.0001" x2="77" y2="62.0001" stroke="currentColor" stroke-width="5"/>
|
|
2602
|
+
<line x1="27" y1="77.8888" x2="77" y2="77.8888" stroke="currentColor" stroke-width="5"/>
|
|
2603
|
+
<line x1="27" y1="97.4454" x2="221" y2="97.4454" stroke="currentColor" stroke-width="5"/>
|
|
2604
|
+
<line x1="27" y1="114.555" x2="221" y2="114.555" stroke="currentColor" stroke-width="5"/>
|
|
2605
|
+
<line x1="27" y1="132.889" x2="221" y2="132.889" stroke="currentColor" stroke-width="5"/>
|
|
2606
|
+
<line x1="27" y1="150" x2="221" y2="150" stroke="currentColor" stroke-width="5"/>
|
|
2607
|
+
<line x1="247.5" y1="43.0001" x2="247.5" y2="13.0001" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2608
|
+
<path d="M185 12.5001L247 12.5001" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2609
|
+
<line x1="204.09" y1="36.6095" x2="181.698" y2="10.0228" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2610
|
+
<path d="M125 9.50012L181 9.50012" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2611
|
+
<path d="M144.305 35.2579L120.095 6.56679" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2612
|
+
<path d="M120 6.50037L64 6.50037" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2613
|
+
<path d="M87.1957 36.1024L59 2.50008" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2614
|
+
<path d="M59 2.50037L3 2.50037" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2615
|
+
<path d="M2.5 38.5001L2.5 3.00012" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
|
|
2616
|
+
</svg>`;
|
|
2617
|
+
}
|
|
2618
|
+
function getNavHeadingOffIcon() {
|
|
2619
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="250" height="181" viewBox="0 0 250 181" fill="currentColor">
|
|
2620
|
+
<rect y="34.5001" width="250" height="146" rx="4" stroke="currentColor" stroke-width="10" fill="none"/>
|
|
2621
|
+
<line x1="27" y1="62" x2="77" y2="62" stroke="currentColor" stroke-width="5"/>
|
|
2622
|
+
<line x1="27" y1="77.8887" x2="77" y2="77.8887" stroke="currentColor" stroke-width="5"/>
|
|
2623
|
+
<line x1="27" y1="97.4453" x2="221" y2="97.4453" stroke="currentColor" stroke-width="5"/>
|
|
2624
|
+
<line x1="27" y1="114.555" x2="221" y2="114.555" stroke="currentColor" stroke-width="5"/>
|
|
2625
|
+
<line x1="27" y1="132.889" x2="221" y2="132.889" stroke="currentColor" stroke-width="5"/>
|
|
2626
|
+
<line x1="27" y1="150" x2="221" y2="150" stroke="currentColor" stroke-width="5"/>
|
|
2627
|
+
</svg>`;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Transition Icon for Navigation Headings
|
|
2631
|
+
*/
|
|
2632
|
+
function getNavDashed() {
|
|
2633
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="250" height="181" viewBox="0 0 250 181">
|
|
2634
|
+
<rect y="34.5001" width="250" height="146" rx="4" stroke="currentColor" stroke-width="10" fill="none"/>
|
|
2635
|
+
<line x1="27" y1="62.0001" x2="77" y2="62.0001" stroke="currentColor" stroke-width="5"/>
|
|
2636
|
+
<line x1="27" y1="77.8888" x2="77" y2="77.8888" stroke="currentColor" stroke-width="5"/>
|
|
2637
|
+
<line x1="27" y1="97.4454" x2="221" y2="97.4454" stroke="currentColor" stroke-width="5"/>
|
|
2638
|
+
<line x1="27" y1="114.555" x2="221" y2="114.555" stroke="currentColor" stroke-width="5"/>
|
|
2639
|
+
<line x1="27" y1="132.889" x2="221" y2="132.889" stroke="currentColor" stroke-width="5"/>
|
|
2640
|
+
<line x1="27" y1="150" x2="221" y2="150" stroke="currentColor" stroke-width="5"/>
|
|
2641
|
+
<path d="M245 37.0001V39.5001H250V37.0001H247.5H245ZM250 13.0001C250 11.6194 248.881 10.5001 247.5 10.5001C246.119 10.5001 245 11.6194 245 13.0001H247.5H250ZM250 31.0001C250 29.6194 248.881 28.5001 247.5 28.5001C246.119 28.5001 245 29.6194 245 31.0001H247.5H250ZM245 19.0001C245 20.3808 246.119 21.5001 247.5 21.5001C248.881 21.5001 250 20.3808 250 19.0001H247.5H245ZM247.5 37.0001H250V31.0001H247.5H245V37.0001H247.5ZM247.5 19.0001H250V13.0001H247.5H245V19.0001H247.5Z" fill="currentColor"/>
|
|
2642
|
+
<line x1="204.09" y1="36.6095" x2="181.698" y2="10.0228" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2643
|
+
<path d="M125 9.50012L181 9.50012" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2644
|
+
<path d="M144.305 35.2579L120.095 6.56679" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2645
|
+
<path d="M120 6.50037L64 6.50037" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2646
|
+
<path d="M87.1957 36.1024L59 2.50008" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2647
|
+
<path d="M59 2.50037L3 2.50037" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2648
|
+
<path d="M2.5 38.5001L2.5 3.00012" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2649
|
+
<path d="M185 12.5001L247 12.5001" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-dasharray="10 10"/>
|
|
2650
|
+
</svg>`;
|
|
2460
2651
|
}
|
|
2461
2652
|
|
|
2462
2653
|
class CustomViewsWidget {
|
|
@@ -2578,15 +2769,22 @@ class CustomViewsWidget {
|
|
|
2578
2769
|
const tabGroups = this.core.getTabGroups();
|
|
2579
2770
|
let tabGroupControlsHTML = '';
|
|
2580
2771
|
if (this.options.showTabGroups && tabGroups && tabGroups.length > 0) {
|
|
2772
|
+
// Determine initial nav visibility state
|
|
2773
|
+
const initialNavsVisible = TabManager.areNavsVisible(document.body);
|
|
2581
2774
|
tabGroupControlsHTML = `
|
|
2582
2775
|
<div class="cv-tabgroup-card cv-tabgroup-header">
|
|
2583
2776
|
<div class="cv-tabgroup-row">
|
|
2777
|
+
<div class="cv-tabgroup-logo-box" id="cv-nav-icon-box">
|
|
2778
|
+
<div class="cv-nav-icon" id="cv-nav-icon">${initialNavsVisible ? getNavHeadingOnIcon() : getNavHeadingOffIcon()}</div>
|
|
2779
|
+
</div>
|
|
2584
2780
|
<div class="cv-tabgroup-info">
|
|
2585
|
-
<
|
|
2781
|
+
<div class="cv-tabgroup-title-container">
|
|
2782
|
+
<p class="cv-tabgroup-title">Navigation Headers</p>
|
|
2783
|
+
</div>
|
|
2586
2784
|
<p class="cv-tabgroup-description">Show or hide navigation headers</p>
|
|
2587
2785
|
</div>
|
|
2588
2786
|
<label class="cv-toggle-switch cv-nav-toggle">
|
|
2589
|
-
<input class="cv-nav-pref-input" type="checkbox" aria-label="Show or hide navigation headers" />
|
|
2787
|
+
<input class="cv-nav-pref-input" type="checkbox" ${initialNavsVisible ? 'checked' : ''} aria-label="Show or hide navigation headers" />
|
|
2590
2788
|
<span class="cv-switch-bg"></span>
|
|
2591
2789
|
<span class="cv-switch-knob"></span>
|
|
2592
2790
|
</label>
|
|
@@ -2644,13 +2842,13 @@ class CustomViewsWidget {
|
|
|
2644
2842
|
<footer class="cv-modal-footer">
|
|
2645
2843
|
${this.options.showReset ? `
|
|
2646
2844
|
<button class="cv-reset-btn">
|
|
2647
|
-
|
|
2845
|
+
<span class="cv-reset-btn-icon">${getResetIcon()}</span>
|
|
2648
2846
|
<span>Reset to Default</span>
|
|
2649
2847
|
</button>
|
|
2650
2848
|
` : ''}
|
|
2651
2849
|
<button class="cv-share-btn">
|
|
2652
|
-
${getShareIcon()}
|
|
2653
2850
|
<span>Copy Shareable URL</span>
|
|
2851
|
+
<span class="cv-share-btn-icon">${getCopyIcon()}</span>
|
|
2654
2852
|
</button>
|
|
2655
2853
|
</footer>
|
|
2656
2854
|
</div>
|
|
@@ -2678,14 +2876,35 @@ class CustomViewsWidget {
|
|
|
2678
2876
|
if (copyUrlBtn) {
|
|
2679
2877
|
copyUrlBtn.addEventListener('click', () => {
|
|
2680
2878
|
this.copyShareableURL();
|
|
2879
|
+
// Visual feedback: change icon to tick for 3 seconds
|
|
2880
|
+
const iconContainer = copyUrlBtn.querySelector('.cv-share-btn-icon');
|
|
2881
|
+
if (iconContainer) {
|
|
2882
|
+
const originalIcon = iconContainer.innerHTML;
|
|
2883
|
+
iconContainer.innerHTML = getTickIcon();
|
|
2884
|
+
// Revert after 3 seconds
|
|
2885
|
+
setTimeout(() => {
|
|
2886
|
+
iconContainer.innerHTML = originalIcon;
|
|
2887
|
+
}, 3000);
|
|
2888
|
+
}
|
|
2681
2889
|
});
|
|
2682
2890
|
}
|
|
2683
2891
|
// Reset to default button
|
|
2684
2892
|
const resetBtn = this.modal.querySelector('.cv-reset-btn');
|
|
2685
2893
|
if (resetBtn) {
|
|
2686
2894
|
resetBtn.addEventListener('click', () => {
|
|
2895
|
+
// Add spinning animation to icon
|
|
2896
|
+
const resetIcon = resetBtn.querySelector('.cv-reset-btn-icon');
|
|
2897
|
+
if (resetIcon) {
|
|
2898
|
+
resetIcon.classList.add('cv-spinning');
|
|
2899
|
+
}
|
|
2687
2900
|
this.core.resetToDefault();
|
|
2688
2901
|
this.loadCurrentStateIntoForm();
|
|
2902
|
+
// Remove spinning animation after it completes
|
|
2903
|
+
setTimeout(() => {
|
|
2904
|
+
if (resetIcon) {
|
|
2905
|
+
resetIcon.classList.remove('cv-spinning');
|
|
2906
|
+
}
|
|
2907
|
+
}, 600); // 600ms matches the animation duration
|
|
2689
2908
|
});
|
|
2690
2909
|
}
|
|
2691
2910
|
// Listen to toggle switches
|
|
@@ -2719,14 +2938,34 @@ class CustomViewsWidget {
|
|
|
2719
2938
|
});
|
|
2720
2939
|
// Listener for show/hide tab navs
|
|
2721
2940
|
const tabNavToggle = this.modal.querySelector('.cv-nav-pref-input');
|
|
2722
|
-
|
|
2941
|
+
const navIcon = this.modal?.querySelector('#cv-nav-icon');
|
|
2942
|
+
const navHeaderCard = this.modal?.querySelector('.cv-tabgroup-card.cv-tabgroup-header');
|
|
2943
|
+
if (tabNavToggle && navIcon && navHeaderCard) {
|
|
2944
|
+
// Helper to update icon based on state
|
|
2945
|
+
const updateIcon = (isVisible, isHovering = false) => {
|
|
2946
|
+
if (isHovering) {
|
|
2947
|
+
// On hover, show the transition icon
|
|
2948
|
+
navIcon.innerHTML = getNavDashed();
|
|
2949
|
+
}
|
|
2950
|
+
else {
|
|
2951
|
+
// Normal state, show the status icon (on if visible, off if hidden)
|
|
2952
|
+
navIcon.innerHTML = isVisible ? getNavHeadingOnIcon() : getNavHeadingOffIcon();
|
|
2953
|
+
}
|
|
2954
|
+
};
|
|
2955
|
+
// Add hover listeners to entire header card
|
|
2956
|
+
navHeaderCard.addEventListener('mouseenter', () => {
|
|
2957
|
+
updateIcon(tabNavToggle.checked, true);
|
|
2958
|
+
});
|
|
2959
|
+
navHeaderCard.addEventListener('mouseleave', () => {
|
|
2960
|
+
updateIcon(tabNavToggle.checked, false);
|
|
2961
|
+
});
|
|
2962
|
+
// Add change listener
|
|
2723
2963
|
tabNavToggle.addEventListener('change', () => {
|
|
2724
2964
|
const visible = tabNavToggle.checked;
|
|
2725
|
-
//
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
catch (e) { /* ignore */ }
|
|
2965
|
+
// Update the icon based on new state (not hovering)
|
|
2966
|
+
updateIcon(visible, false);
|
|
2967
|
+
// Persist preference via core
|
|
2968
|
+
this.core.persistTabNavVisibility(visible);
|
|
2730
2969
|
// Apply to DOM using TabManager via core
|
|
2731
2970
|
try {
|
|
2732
2971
|
const rootEl = document.body;
|
|
@@ -2838,21 +3077,22 @@ class CustomViewsWidget {
|
|
|
2838
3077
|
});
|
|
2839
3078
|
// Load tab nav visibility preference
|
|
2840
3079
|
const navPref = (() => {
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
return TabManager.areNavsVisible(document.body);
|
|
2845
|
-
return raw === 'true';
|
|
2846
|
-
}
|
|
2847
|
-
catch (e) {
|
|
2848
|
-
return TabManager.areNavsVisible(document.body);
|
|
3080
|
+
const persisted = this.core.getPersistedTabNavVisibility();
|
|
3081
|
+
if (persisted !== null) {
|
|
3082
|
+
return persisted;
|
|
2849
3083
|
}
|
|
3084
|
+
return TabManager.areNavsVisible(document.body);
|
|
2850
3085
|
})();
|
|
2851
3086
|
const tabNavToggle = this.modal.querySelector('.cv-nav-pref-input');
|
|
3087
|
+
const navIcon = this.modal?.querySelector('#cv-nav-icon');
|
|
2852
3088
|
if (tabNavToggle) {
|
|
2853
3089
|
tabNavToggle.checked = navPref;
|
|
2854
3090
|
// Ensure UI matches actual visibility
|
|
2855
3091
|
TabManager.setNavsVisibility(document.body, navPref);
|
|
3092
|
+
// Update the nav icon to reflect the current state
|
|
3093
|
+
if (navIcon) {
|
|
3094
|
+
navIcon.innerHTML = navPref ? getNavHeadingOnIcon() : getNavHeadingOffIcon();
|
|
3095
|
+
}
|
|
2856
3096
|
}
|
|
2857
3097
|
}
|
|
2858
3098
|
/**
|
|
@@ -2869,12 +3109,19 @@ class CustomViewsWidget {
|
|
|
2869
3109
|
// Check if welcome has been shown before
|
|
2870
3110
|
const hasSeenWelcome = localStorage.getItem(STORAGE_KEY);
|
|
2871
3111
|
if (!hasSeenWelcome) {
|
|
2872
|
-
//
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3112
|
+
// Check if this page has any custom views elements
|
|
3113
|
+
const hasCustomViewElements = document.querySelector('cv-tabgroup') !== null ||
|
|
3114
|
+
document.querySelector('cv-tab') !== null ||
|
|
3115
|
+
document.querySelector('cv-toggle') !== null ||
|
|
3116
|
+
document.querySelector('[data-cv-toggle]') !== null;
|
|
3117
|
+
if (hasCustomViewElements) {
|
|
3118
|
+
// Show welcome modal after a short delay to let the page settle
|
|
3119
|
+
setTimeout(() => {
|
|
3120
|
+
this.createWelcomeModal();
|
|
3121
|
+
}, 500);
|
|
3122
|
+
// Mark as shown
|
|
3123
|
+
localStorage.setItem(STORAGE_KEY, 'true');
|
|
3124
|
+
}
|
|
2878
3125
|
}
|
|
2879
3126
|
}
|
|
2880
3127
|
/**
|
|
@@ -2973,17 +3220,20 @@ function initializeFromScript() {
|
|
|
2973
3220
|
}
|
|
2974
3221
|
window.__customViewsInitInProgress = true;
|
|
2975
3222
|
try {
|
|
2976
|
-
// Find the script tag
|
|
3223
|
+
// Find the script tag that loaded this script
|
|
2977
3224
|
let scriptTag = document.currentScript;
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
3225
|
+
if (!scriptTag || !scriptTag.hasAttribute('data-base-url')) {
|
|
3226
|
+
const dataAttrMatch = document.querySelector('script[data-base-url]');
|
|
3227
|
+
if (dataAttrMatch) {
|
|
3228
|
+
scriptTag = dataAttrMatch;
|
|
3229
|
+
}
|
|
3230
|
+
else {
|
|
3231
|
+
for (const script of document.scripts) {
|
|
3232
|
+
const src = script.src || '';
|
|
3233
|
+
if (/(?:custom[-_]views|@customviews-js\/customviews)(?:\.min)?\.(?:esm\.)?js($|\?)/i.test(src)) {
|
|
3234
|
+
scriptTag = script;
|
|
3235
|
+
break;
|
|
3236
|
+
}
|
|
2987
3237
|
}
|
|
2988
3238
|
}
|
|
2989
3239
|
}
|