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