@customviews-js/customviews 1.1.2 → 1.1.3
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 +113 -53
- package/dist/custom-views.core.cjs.js.map +1 -1
- package/dist/custom-views.core.esm.js +113 -53
- package/dist/custom-views.core.esm.js.map +1 -1
- package/dist/custom-views.esm.js +113 -53
- package/dist/custom-views.esm.js.map +1 -1
- package/dist/custom-views.js +113 -53
- 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/url-state-manager.d.ts +2 -2
- package/dist/types/core/url-state-manager.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/lib/custom-views.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/types/types.d.ts +1 -1
- package/dist/types/types/types.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.3
|
|
3
3
|
* (c) 2025 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -124,14 +124,16 @@ class URLStateManager {
|
|
|
124
124
|
return url.toString();
|
|
125
125
|
}
|
|
126
126
|
/**
|
|
127
|
-
* Encode state into URL-safe string
|
|
127
|
+
* Encode state into URL-safe string (Toggles and Tabs only currently)
|
|
128
128
|
*/
|
|
129
129
|
static encodeState(state) {
|
|
130
130
|
try {
|
|
131
131
|
// Create a compact representation
|
|
132
|
-
const compact = {
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
const compact = {};
|
|
133
|
+
// Add toggles if present and non-empty
|
|
134
|
+
if (state.toggles && state.toggles.length > 0) {
|
|
135
|
+
compact.t = state.toggles;
|
|
136
|
+
}
|
|
135
137
|
// Add tab groups if present
|
|
136
138
|
if (state.tabs && Object.keys(state.tabs).length > 0) {
|
|
137
139
|
compact.g = Object.entries(state.tabs);
|
|
@@ -157,7 +159,7 @@ class URLStateManager {
|
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
/**
|
|
160
|
-
* Decode custom state from URL parameter
|
|
162
|
+
* Decode custom state from URL parameter (Toggles and Tabs only currently)
|
|
161
163
|
*/
|
|
162
164
|
static decodeState(encoded) {
|
|
163
165
|
try {
|
|
@@ -182,10 +184,12 @@ class URLStateManager {
|
|
|
182
184
|
if (!compact || typeof compact !== 'object') {
|
|
183
185
|
throw new Error('Invalid compact state structure');
|
|
184
186
|
}
|
|
187
|
+
// Reconstruct State from compact format
|
|
188
|
+
// Reconstruct Toggles
|
|
185
189
|
const state = {
|
|
186
190
|
toggles: Array.isArray(compact.t) ? compact.t : []
|
|
187
191
|
};
|
|
188
|
-
// Reconstruct
|
|
192
|
+
// Reconstruct Tabs
|
|
189
193
|
if (Array.isArray(compact.g)) {
|
|
190
194
|
state.tabs = {};
|
|
191
195
|
for (const [groupId, tabId] of compact.g) {
|
|
@@ -868,7 +872,7 @@ class CustomViewsCore {
|
|
|
868
872
|
this.rootEl = opt.rootEl || document.body;
|
|
869
873
|
this.persistenceManager = new PersistenceManager();
|
|
870
874
|
this.visibilityManager = new VisibilityManager();
|
|
871
|
-
this.showUrlEnabled = opt.showUrl ??
|
|
875
|
+
this.showUrlEnabled = opt.showUrl ?? false;
|
|
872
876
|
this.lastAppliedState = this.cloneState(this.config?.defaultState);
|
|
873
877
|
}
|
|
874
878
|
getConfig() {
|
|
@@ -1068,9 +1072,9 @@ class CustomViewsCore {
|
|
|
1068
1072
|
});
|
|
1069
1073
|
}
|
|
1070
1074
|
cloneState(state) {
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
return
|
|
1075
|
+
if (!state)
|
|
1076
|
+
return {};
|
|
1077
|
+
return JSON.parse(JSON.stringify(state));
|
|
1074
1078
|
}
|
|
1075
1079
|
getTrackedStateSnapshot() {
|
|
1076
1080
|
if (this.lastAppliedState) {
|
|
@@ -1079,7 +1083,7 @@ class CustomViewsCore {
|
|
|
1079
1083
|
if (this.config) {
|
|
1080
1084
|
return this.cloneState(this.config.defaultState);
|
|
1081
1085
|
}
|
|
1082
|
-
return {
|
|
1086
|
+
return {};
|
|
1083
1087
|
}
|
|
1084
1088
|
}
|
|
1085
1089
|
|
|
@@ -1170,8 +1174,14 @@ class CustomViews {
|
|
|
1170
1174
|
const baseURL = opts.baseURL || '';
|
|
1171
1175
|
if (opts.assetsJsonPath) {
|
|
1172
1176
|
const assetsPath = prependBaseUrl(opts.assetsJsonPath, baseURL);
|
|
1173
|
-
|
|
1174
|
-
|
|
1177
|
+
try {
|
|
1178
|
+
const assetsJson = await (await fetch(assetsPath)).json();
|
|
1179
|
+
assetsManager = new AssetsManager(assetsJson, baseURL);
|
|
1180
|
+
}
|
|
1181
|
+
catch (error) {
|
|
1182
|
+
console.error(`[CustomViews] Failed to load assets JSON from ${assetsPath}:`, error);
|
|
1183
|
+
assetsManager = new AssetsManager({}, baseURL);
|
|
1184
|
+
}
|
|
1175
1185
|
}
|
|
1176
1186
|
else {
|
|
1177
1187
|
assetsManager = new AssetsManager({}, baseURL);
|
|
@@ -1184,7 +1194,7 @@ class CustomViews {
|
|
|
1184
1194
|
else {
|
|
1185
1195
|
console.error("No config provided, using minimal default config");
|
|
1186
1196
|
// Create a minimal default config
|
|
1187
|
-
config = { allToggles: [], defaultState: {
|
|
1197
|
+
config = { allToggles: [], defaultState: {} };
|
|
1188
1198
|
}
|
|
1189
1199
|
const coreOptions = {
|
|
1190
1200
|
assetsManager,
|
|
@@ -1645,9 +1655,61 @@ const WIDGET_STYLES = `
|
|
|
1645
1655
|
margin: 0;
|
|
1646
1656
|
}
|
|
1647
1657
|
|
|
1648
|
-
.cv-
|
|
1649
|
-
|
|
1650
|
-
width:
|
|
1658
|
+
.cv-toggle-switch {
|
|
1659
|
+
position: relative;
|
|
1660
|
+
width: 44px;
|
|
1661
|
+
height: 24px;
|
|
1662
|
+
background: #ccc;
|
|
1663
|
+
border-radius: 12px;
|
|
1664
|
+
margin-right: 12px;
|
|
1665
|
+
cursor: pointer;
|
|
1666
|
+
transition: background-color 0.3s ease;
|
|
1667
|
+
flex-shrink: 0;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.cv-toggle-switch:hover {
|
|
1671
|
+
background: #bbb;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
.cv-toggle-switch.cv-toggle-active {
|
|
1675
|
+
background: #007bff;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
.cv-toggle-switch.cv-toggle-active:hover {
|
|
1679
|
+
background: #0056b3;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
.cv-toggle-handle {
|
|
1683
|
+
position: absolute;
|
|
1684
|
+
top: 2px;
|
|
1685
|
+
left: 2px;
|
|
1686
|
+
width: 20px;
|
|
1687
|
+
height: 20px;
|
|
1688
|
+
background: white;
|
|
1689
|
+
border-radius: 50%;
|
|
1690
|
+
transition: transform 0.3s ease;
|
|
1691
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
.cv-toggle-switch.cv-toggle-active .cv-toggle-handle {
|
|
1695
|
+
transform: translateX(20px);
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
/* Dark theme toggle switch styles */
|
|
1699
|
+
.cv-widget-theme-dark .cv-toggle-switch {
|
|
1700
|
+
background: #4a5568;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
.cv-widget-theme-dark .cv-toggle-switch:hover {
|
|
1704
|
+
background: #5a6578;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
.cv-widget-theme-dark .cv-toggle-switch.cv-toggle-active {
|
|
1708
|
+
background: #63b3ed;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
.cv-widget-theme-dark .cv-toggle-switch.cv-toggle-active:hover {
|
|
1712
|
+
background: #4299e1;
|
|
1651
1713
|
}
|
|
1652
1714
|
|
|
1653
1715
|
.cv-tab-groups {
|
|
@@ -1876,11 +1938,11 @@ class CustomViewsWidget {
|
|
|
1876
1938
|
position: options.position || 'middle-left',
|
|
1877
1939
|
theme: options.theme || 'light',
|
|
1878
1940
|
showReset: options.showReset ?? true,
|
|
1879
|
-
title: options.title || '
|
|
1941
|
+
title: options.title || 'Customize View',
|
|
1880
1942
|
description: options.description || 'Toggle different content sections to customize your view. Changes are applied instantly and the URL will be updated for sharing.',
|
|
1881
1943
|
showWelcome: options.showWelcome ?? false,
|
|
1882
|
-
welcomeTitle: options.welcomeTitle || '
|
|
1883
|
-
welcomeMessage: options.welcomeMessage || 'This site
|
|
1944
|
+
welcomeTitle: options.welcomeTitle || 'Site Customization',
|
|
1945
|
+
welcomeMessage: options.welcomeMessage || 'This site is powered by Custom Views. Use the widget on the side (⚙) to customize your experience. Your preferences will be saved and can be shared via URL.<br><br>Learn more at <a href="https://github.com/customviews-js/customviews" target="_blank">customviews GitHub</a>.',
|
|
1884
1946
|
showTabGroups: options.showTabGroups ?? true
|
|
1885
1947
|
};
|
|
1886
1948
|
// No external state manager to initialize
|
|
@@ -1963,7 +2025,9 @@ class CustomViewsWidget {
|
|
|
1963
2025
|
? toggles.map(toggle => `
|
|
1964
2026
|
<div class="cv-custom-state-toggle">
|
|
1965
2027
|
<label>
|
|
1966
|
-
<
|
|
2028
|
+
<div class="cv-toggle-switch" data-toggle="${toggle}">
|
|
2029
|
+
<div class="cv-toggle-handle"></div>
|
|
2030
|
+
</div>
|
|
1967
2031
|
${this.formatToggleName(toggle)}
|
|
1968
2032
|
</label>
|
|
1969
2033
|
</div>
|
|
@@ -1994,7 +2058,7 @@ class CustomViewsWidget {
|
|
|
1994
2058
|
this.modal.innerHTML = `
|
|
1995
2059
|
<div class="cv-widget-modal cv-custom-state-modal">
|
|
1996
2060
|
<div class="cv-widget-modal-header">
|
|
1997
|
-
<h3
|
|
2061
|
+
<h3>${this.options.title}</h3>
|
|
1998
2062
|
<button class="cv-widget-modal-close" aria-label="Close modal">×</button>
|
|
1999
2063
|
</div>
|
|
2000
2064
|
<div class="cv-widget-modal-content">
|
|
@@ -2049,10 +2113,11 @@ class CustomViewsWidget {
|
|
|
2049
2113
|
this.loadCurrentStateIntoForm();
|
|
2050
2114
|
});
|
|
2051
2115
|
}
|
|
2052
|
-
// Listen to toggle
|
|
2053
|
-
const
|
|
2054
|
-
|
|
2055
|
-
|
|
2116
|
+
// Listen to toggle switches
|
|
2117
|
+
const toggleSwitches = this.modal.querySelectorAll('.cv-toggle-switch');
|
|
2118
|
+
toggleSwitches.forEach(toggleSwitch => {
|
|
2119
|
+
toggleSwitch.addEventListener('click', () => {
|
|
2120
|
+
toggleSwitch.classList.toggle('cv-toggle-active');
|
|
2056
2121
|
const state = this.getCurrentCustomStateFromModal();
|
|
2057
2122
|
this.core.applyState(state);
|
|
2058
2123
|
});
|
|
@@ -2101,14 +2166,14 @@ class CustomViewsWidget {
|
|
|
2101
2166
|
*/
|
|
2102
2167
|
getCurrentCustomStateFromModal() {
|
|
2103
2168
|
if (!this.modal) {
|
|
2104
|
-
return {
|
|
2169
|
+
return {};
|
|
2105
2170
|
}
|
|
2106
2171
|
// Collect toggle values
|
|
2107
2172
|
const toggles = [];
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
const toggle =
|
|
2111
|
-
if (toggle &&
|
|
2173
|
+
const toggleSwitches = this.modal.querySelectorAll('.cv-toggle-switch');
|
|
2174
|
+
toggleSwitches.forEach(toggleSwitch => {
|
|
2175
|
+
const toggle = toggleSwitch.dataset.toggle;
|
|
2176
|
+
if (toggle && toggleSwitch.classList.contains('cv-toggle-active')) {
|
|
2112
2177
|
toggles.push(toggle);
|
|
2113
2178
|
}
|
|
2114
2179
|
});
|
|
@@ -2121,7 +2186,11 @@ class CustomViewsWidget {
|
|
|
2121
2186
|
tabs[groupId] = select.value;
|
|
2122
2187
|
}
|
|
2123
2188
|
});
|
|
2124
|
-
|
|
2189
|
+
const result = { toggles };
|
|
2190
|
+
if (Object.keys(tabs).length > 0) {
|
|
2191
|
+
result.tabs = tabs;
|
|
2192
|
+
}
|
|
2193
|
+
return result;
|
|
2125
2194
|
}
|
|
2126
2195
|
/**
|
|
2127
2196
|
* Copy shareable URL to clipboard
|
|
@@ -2141,20 +2210,16 @@ class CustomViewsWidget {
|
|
|
2141
2210
|
return;
|
|
2142
2211
|
// Get currently active toggles (from custom state or default configuration)
|
|
2143
2212
|
const activeToggles = this.core.getCurrentActiveToggles();
|
|
2144
|
-
// First,
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
checkbox.disabled = false;
|
|
2149
|
-
checkbox.parentElement?.removeAttribute('aria-hidden');
|
|
2213
|
+
// First, deactivate all toggle switches
|
|
2214
|
+
const allToggleSwitches = this.modal.querySelectorAll('.cv-toggle-switch');
|
|
2215
|
+
allToggleSwitches.forEach(toggleSwitch => {
|
|
2216
|
+
toggleSwitch.classList.remove('cv-toggle-active');
|
|
2150
2217
|
});
|
|
2151
|
-
// Then
|
|
2218
|
+
// Then activate the ones that should be active
|
|
2152
2219
|
activeToggles.forEach(toggle => {
|
|
2153
|
-
const
|
|
2154
|
-
if (
|
|
2155
|
-
|
|
2156
|
-
checkbox.checked = true;
|
|
2157
|
-
}
|
|
2220
|
+
const toggleSwitch = this.modal?.querySelector(`[data-toggle="${toggle}"]`);
|
|
2221
|
+
if (toggleSwitch) {
|
|
2222
|
+
toggleSwitch.classList.add('cv-toggle-active');
|
|
2158
2223
|
}
|
|
2159
2224
|
});
|
|
2160
2225
|
// Load tab group selections
|
|
@@ -2207,7 +2272,7 @@ class CustomViewsWidget {
|
|
|
2207
2272
|
</div>
|
|
2208
2273
|
<div class="cv-widget-modal-content">
|
|
2209
2274
|
<div class="cv-welcome-content">
|
|
2210
|
-
<p>${this.options.welcomeMessage}</p>
|
|
2275
|
+
<p style="text-align: justify;">${this.options.welcomeMessage}</p>
|
|
2211
2276
|
|
|
2212
2277
|
<div class="cv-welcome-widget-preview">
|
|
2213
2278
|
<div class="cv-welcome-widget-icon">⚙</div>
|
|
@@ -2328,13 +2393,8 @@ function initializeFromScript() {
|
|
|
2328
2393
|
console.warn(`[CustomViews] Config file not found at ${fullConfigPath}. Using defaults.`);
|
|
2329
2394
|
// Provide minimal default config structure
|
|
2330
2395
|
configFile = {
|
|
2331
|
-
config: {
|
|
2332
|
-
|
|
2333
|
-
defaultState: { toggles: [] }
|
|
2334
|
-
},
|
|
2335
|
-
widget: {
|
|
2336
|
-
enabled: true
|
|
2337
|
-
}
|
|
2396
|
+
config: { allToggles: [], defaultState: {} },
|
|
2397
|
+
widget: { enabled: true }
|
|
2338
2398
|
};
|
|
2339
2399
|
}
|
|
2340
2400
|
else {
|