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