softui-css 1.4.0 → 1.6.0
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/softui.css +2652 -18
- package/dist/softui.js +940 -1
- package/dist/softui.min.css +1 -1
- package/dist/softui.min.js +1 -1
- package/package.json +2 -2
package/dist/softui.js
CHANGED
|
@@ -909,7 +909,8 @@ const SoftUI = (() => {
|
|
|
909
909
|
|
|
910
910
|
items.forEach(function(item) {
|
|
911
911
|
var text = item.textContent.toLowerCase();
|
|
912
|
-
var
|
|
912
|
+
var keywords = (item.getAttribute('data-keywords') || '').toLowerCase();
|
|
913
|
+
var match = !query || text.indexOf(query) !== -1 || keywords.indexOf(query) !== -1;
|
|
913
914
|
item.hidden = !match;
|
|
914
915
|
if (match) anyVisible = true;
|
|
915
916
|
});
|
|
@@ -2983,5 +2984,943 @@ const SoftUI = (() => {
|
|
|
2983
2984
|
});
|
|
2984
2985
|
});
|
|
2985
2986
|
|
|
2987
|
+
// =========================================
|
|
2988
|
+
// Color Picker
|
|
2989
|
+
// =========================================
|
|
2990
|
+
document.addEventListener('click', function(e) {
|
|
2991
|
+
var swatch = e.target.closest('.sui-color-picker .sui-color-swatch');
|
|
2992
|
+
if (!swatch) return;
|
|
2993
|
+
var picker = swatch.closest('.sui-color-picker');
|
|
2994
|
+
picker.querySelectorAll('.sui-color-swatch').forEach(function(s) {
|
|
2995
|
+
s.classList.remove('active');
|
|
2996
|
+
});
|
|
2997
|
+
swatch.classList.add('active');
|
|
2998
|
+
var color = swatch.getAttribute('data-color') || swatch.style.background || swatch.style.backgroundColor;
|
|
2999
|
+
picker.setAttribute('data-value', color);
|
|
3000
|
+
picker.dispatchEvent(new CustomEvent('sui-color-change', { detail: { color: color } }));
|
|
3001
|
+
});
|
|
3002
|
+
|
|
3003
|
+
// =========================================
|
|
3004
|
+
// Color Spectrum Picker
|
|
3005
|
+
// =========================================
|
|
3006
|
+
function initSpectrumPickers() {
|
|
3007
|
+
var pickers = document.querySelectorAll('.sui-color-spectrum');
|
|
3008
|
+
pickers.forEach(function(picker) { initSpectrum(picker); });
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
function initSpectrum(picker) {
|
|
3012
|
+
var canvasWrap = picker.querySelector('.sui-color-spectrum-canvas');
|
|
3013
|
+
var canvas = canvasWrap.querySelector('canvas');
|
|
3014
|
+
var ctx = canvas.getContext('2d');
|
|
3015
|
+
var cursor = canvasWrap.querySelector('.sui-color-spectrum-cursor');
|
|
3016
|
+
var hueBar = picker.querySelector('.sui-color-spectrum-hue');
|
|
3017
|
+
var hueCursor = picker.querySelector('.sui-color-spectrum-hue-cursor');
|
|
3018
|
+
var preview = picker.querySelector('.sui-color-spectrum-preview');
|
|
3019
|
+
var hexInput = picker.querySelector('.sui-color-spectrum-hex input');
|
|
3020
|
+
var rInput = picker.querySelector('input[data-channel="r"]');
|
|
3021
|
+
var gInput = picker.querySelector('input[data-channel="g"]');
|
|
3022
|
+
var bInput = picker.querySelector('input[data-channel="b"]');
|
|
3023
|
+
|
|
3024
|
+
var hue = 0, sat = 1, val = 1;
|
|
3025
|
+
|
|
3026
|
+
function resizeCanvas() {
|
|
3027
|
+
canvas.width = canvasWrap.offsetWidth;
|
|
3028
|
+
canvas.height = canvasWrap.offsetHeight;
|
|
3029
|
+
drawSatVal();
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
function hsvToRgb(h, s, v) {
|
|
3033
|
+
var i = Math.floor(h / 60) % 6;
|
|
3034
|
+
var f = h / 60 - Math.floor(h / 60);
|
|
3035
|
+
var p = v * (1 - s);
|
|
3036
|
+
var q = v * (1 - f * s);
|
|
3037
|
+
var t = v * (1 - (1 - f) * s);
|
|
3038
|
+
var r, g, b;
|
|
3039
|
+
switch (i) {
|
|
3040
|
+
case 0: r = v; g = t; b = p; break;
|
|
3041
|
+
case 1: r = q; g = v; b = p; break;
|
|
3042
|
+
case 2: r = p; g = v; b = t; break;
|
|
3043
|
+
case 3: r = p; g = q; b = v; break;
|
|
3044
|
+
case 4: r = t; g = p; b = v; break;
|
|
3045
|
+
case 5: r = v; g = p; b = q; break;
|
|
3046
|
+
}
|
|
3047
|
+
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
function rgbToHex(r, g, b) {
|
|
3051
|
+
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
function hexToRgb(hex) {
|
|
3055
|
+
hex = hex.replace('#', '');
|
|
3056
|
+
if (hex.length === 3) hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
|
|
3057
|
+
var n = parseInt(hex, 16);
|
|
3058
|
+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
function rgbToHsv(r, g, b) {
|
|
3062
|
+
r /= 255; g /= 255; b /= 255;
|
|
3063
|
+
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
3064
|
+
var h, s, v = max;
|
|
3065
|
+
var d = max - min;
|
|
3066
|
+
s = max === 0 ? 0 : d / max;
|
|
3067
|
+
if (max === min) { h = 0; }
|
|
3068
|
+
else {
|
|
3069
|
+
switch (max) {
|
|
3070
|
+
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
3071
|
+
case g: h = (b - r) / d + 2; break;
|
|
3072
|
+
case b: h = (r - g) / d + 4; break;
|
|
3073
|
+
}
|
|
3074
|
+
h *= 60;
|
|
3075
|
+
}
|
|
3076
|
+
return [h, s, v];
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
function drawSatVal() {
|
|
3080
|
+
var w = canvas.width, h = canvas.height;
|
|
3081
|
+
var hueRgb = hsvToRgb(hue, 1, 1);
|
|
3082
|
+
var hueColor = 'rgb(' + hueRgb[0] + ',' + hueRgb[1] + ',' + hueRgb[2] + ')';
|
|
3083
|
+
ctx.fillStyle = hueColor;
|
|
3084
|
+
ctx.fillRect(0, 0, w, h);
|
|
3085
|
+
var whiteGrad = ctx.createLinearGradient(0, 0, w, 0);
|
|
3086
|
+
whiteGrad.addColorStop(0, 'rgba(255,255,255,1)');
|
|
3087
|
+
whiteGrad.addColorStop(1, 'rgba(255,255,255,0)');
|
|
3088
|
+
ctx.fillStyle = whiteGrad;
|
|
3089
|
+
ctx.fillRect(0, 0, w, h);
|
|
3090
|
+
var blackGrad = ctx.createLinearGradient(0, 0, 0, h);
|
|
3091
|
+
blackGrad.addColorStop(0, 'rgba(0,0,0,0)');
|
|
3092
|
+
blackGrad.addColorStop(1, 'rgba(0,0,0,1)');
|
|
3093
|
+
ctx.fillStyle = blackGrad;
|
|
3094
|
+
ctx.fillRect(0, 0, w, h);
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3097
|
+
function updateUI() {
|
|
3098
|
+
var rgb = hsvToRgb(hue, sat, val);
|
|
3099
|
+
var hex = rgbToHex(rgb[0], rgb[1], rgb[2]);
|
|
3100
|
+
if (preview) preview.style.background = hex;
|
|
3101
|
+
if (hexInput) hexInput.value = hex.toUpperCase().slice(1);
|
|
3102
|
+
if (rInput) rInput.value = rgb[0];
|
|
3103
|
+
if (gInput) gInput.value = rgb[1];
|
|
3104
|
+
if (bInput) bInput.value = rgb[2];
|
|
3105
|
+
|
|
3106
|
+
cursor.style.left = (sat * 100) + '%';
|
|
3107
|
+
cursor.style.top = ((1 - val) * 100) + '%';
|
|
3108
|
+
|
|
3109
|
+
var hueRgb = hsvToRgb(hue, 1, 1);
|
|
3110
|
+
hueCursor.style.left = (hue / 360 * 100) + '%';
|
|
3111
|
+
hueCursor.style.background = 'rgb(' + hueRgb[0] + ',' + hueRgb[1] + ',' + hueRgb[2] + ')';
|
|
3112
|
+
|
|
3113
|
+
picker.setAttribute('data-value', hex);
|
|
3114
|
+
picker.dispatchEvent(new CustomEvent('sui-color-change', { detail: { hex: hex, rgb: rgb } }));
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
// Canvas drag
|
|
3118
|
+
function onCanvasMove(e) {
|
|
3119
|
+
var rect = canvasWrap.getBoundingClientRect();
|
|
3120
|
+
var x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;
|
|
3121
|
+
var y = (e.touches ? e.touches[0].clientY : e.clientY) - rect.top;
|
|
3122
|
+
sat = Math.max(0, Math.min(1, x / rect.width));
|
|
3123
|
+
val = Math.max(0, Math.min(1, 1 - y / rect.height));
|
|
3124
|
+
updateUI();
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
canvasWrap.addEventListener('mousedown', function(e) {
|
|
3128
|
+
e.preventDefault();
|
|
3129
|
+
onCanvasMove(e);
|
|
3130
|
+
function move(ev) { onCanvasMove(ev); }
|
|
3131
|
+
function up() { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', up); }
|
|
3132
|
+
document.addEventListener('mousemove', move);
|
|
3133
|
+
document.addEventListener('mouseup', up);
|
|
3134
|
+
});
|
|
3135
|
+
|
|
3136
|
+
canvasWrap.addEventListener('touchstart', function(e) {
|
|
3137
|
+
e.preventDefault();
|
|
3138
|
+
onCanvasMove(e);
|
|
3139
|
+
function move(ev) { ev.preventDefault(); onCanvasMove(ev); }
|
|
3140
|
+
function up() { document.removeEventListener('touchmove', move); document.removeEventListener('touchend', up); }
|
|
3141
|
+
document.addEventListener('touchmove', move, { passive: false });
|
|
3142
|
+
document.addEventListener('touchend', up);
|
|
3143
|
+
}, { passive: false });
|
|
3144
|
+
|
|
3145
|
+
// Hue drag
|
|
3146
|
+
function onHueMove(e) {
|
|
3147
|
+
var rect = hueBar.getBoundingClientRect();
|
|
3148
|
+
var x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;
|
|
3149
|
+
hue = Math.max(0, Math.min(360, x / rect.width * 360));
|
|
3150
|
+
drawSatVal();
|
|
3151
|
+
updateUI();
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
hueBar.addEventListener('mousedown', function(e) {
|
|
3155
|
+
e.preventDefault();
|
|
3156
|
+
onHueMove(e);
|
|
3157
|
+
function move(ev) { onHueMove(ev); }
|
|
3158
|
+
function up() { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', up); }
|
|
3159
|
+
document.addEventListener('mousemove', move);
|
|
3160
|
+
document.addEventListener('mouseup', up);
|
|
3161
|
+
});
|
|
3162
|
+
|
|
3163
|
+
hueBar.addEventListener('touchstart', function(e) {
|
|
3164
|
+
e.preventDefault();
|
|
3165
|
+
onHueMove(e);
|
|
3166
|
+
function move(ev) { ev.preventDefault(); onHueMove(ev); }
|
|
3167
|
+
function up() { document.removeEventListener('touchmove', move); document.removeEventListener('touchend', up); }
|
|
3168
|
+
document.addEventListener('touchmove', move, { passive: false });
|
|
3169
|
+
document.addEventListener('touchend', up);
|
|
3170
|
+
}, { passive: false });
|
|
3171
|
+
|
|
3172
|
+
// Hex input
|
|
3173
|
+
if (hexInput) {
|
|
3174
|
+
hexInput.addEventListener('input', function() {
|
|
3175
|
+
var v = hexInput.value.replace('#', '');
|
|
3176
|
+
if (v.length === 6 && /^[0-9A-Fa-f]{6}$/.test(v)) {
|
|
3177
|
+
var rgb = hexToRgb(v);
|
|
3178
|
+
var hsv = rgbToHsv(rgb[0], rgb[1], rgb[2]);
|
|
3179
|
+
hue = hsv[0]; sat = hsv[1]; val = hsv[2];
|
|
3180
|
+
drawSatVal();
|
|
3181
|
+
updateUI();
|
|
3182
|
+
}
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
// RGB inputs
|
|
3187
|
+
function onRgbInput() {
|
|
3188
|
+
var r = parseInt(rInput.value) || 0;
|
|
3189
|
+
var g = parseInt(gInput.value) || 0;
|
|
3190
|
+
var b = parseInt(bInput.value) || 0;
|
|
3191
|
+
r = Math.max(0, Math.min(255, r));
|
|
3192
|
+
g = Math.max(0, Math.min(255, g));
|
|
3193
|
+
b = Math.max(0, Math.min(255, b));
|
|
3194
|
+
var hsv = rgbToHsv(r, g, b);
|
|
3195
|
+
hue = hsv[0]; sat = hsv[1]; val = hsv[2];
|
|
3196
|
+
drawSatVal();
|
|
3197
|
+
updateUI();
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
if (rInput) rInput.addEventListener('input', onRgbInput);
|
|
3201
|
+
if (gInput) gInput.addEventListener('input', onRgbInput);
|
|
3202
|
+
if (bInput) bInput.addEventListener('input', onRgbInput);
|
|
3203
|
+
|
|
3204
|
+
// Init from data-color attribute or default
|
|
3205
|
+
var initColor = picker.getAttribute('data-color') || '#5B54E0';
|
|
3206
|
+
var initRgb = hexToRgb(initColor);
|
|
3207
|
+
var initHsv = rgbToHsv(initRgb[0], initRgb[1], initRgb[2]);
|
|
3208
|
+
hue = initHsv[0]; sat = initHsv[1]; val = initHsv[2];
|
|
3209
|
+
|
|
3210
|
+
resizeCanvas();
|
|
3211
|
+
updateUI();
|
|
3212
|
+
window.addEventListener('resize', resizeCanvas);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
if (document.readyState === 'loading') {
|
|
3216
|
+
document.addEventListener('DOMContentLoaded', initSpectrumPickers);
|
|
3217
|
+
} else {
|
|
3218
|
+
initSpectrumPickers();
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
// =========================================
|
|
3222
|
+
// File Upload
|
|
3223
|
+
// =========================================
|
|
3224
|
+
function formatFileSize(bytes) {
|
|
3225
|
+
if (bytes < 1024) return bytes + ' B';
|
|
3226
|
+
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
|
3227
|
+
return (bytes / 1048576).toFixed(1) + ' MB';
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
var fileIcons = {
|
|
3231
|
+
file: '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>',
|
|
3232
|
+
image: '<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',
|
|
3233
|
+
pdf: '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="15" x2="15" y2="15"/><line x1="9" y1="18" x2="13" y2="18"/><line x1="9" y1="12" x2="11" y2="12"/></svg>',
|
|
3234
|
+
video: '<svg viewBox="0 0 24 24"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>',
|
|
3235
|
+
audio: '<svg viewBox="0 0 24 24"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>',
|
|
3236
|
+
code: '<svg viewBox="0 0 24 24"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>',
|
|
3237
|
+
archive: '<svg viewBox="0 0 24 24"><path d="M21 8v13H3V8"/><path d="M1 3h22v5H1z"/><path d="M10 12h4"/></svg>',
|
|
3238
|
+
spreadsheet: '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="12" y1="9" x2="12" y2="21"/></svg>'
|
|
3239
|
+
};
|
|
3240
|
+
|
|
3241
|
+
function getFileType(file) {
|
|
3242
|
+
var type = file.type || '';
|
|
3243
|
+
var ext = file.name.split('.').pop().toLowerCase();
|
|
3244
|
+
if (type.startsWith('image/')) return 'image';
|
|
3245
|
+
if (type === 'application/pdf' || ext === 'pdf') return 'pdf';
|
|
3246
|
+
if (type.startsWith('video/')) return 'video';
|
|
3247
|
+
if (type.startsWith('audio/')) return 'audio';
|
|
3248
|
+
if (/^(js|ts|jsx|tsx|html|css|json|xml|py|rb|go|rs|java|c|cpp|php|sh|yml|yaml)$/.test(ext)) return 'code';
|
|
3249
|
+
if (/^(zip|rar|7z|tar|gz|bz2)$/.test(ext)) return 'archive';
|
|
3250
|
+
if (/^(csv|xlsx|xls|ods)$/.test(ext)) return 'spreadsheet';
|
|
3251
|
+
return 'file';
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
function getFileIcon(file) {
|
|
3255
|
+
return fileIcons[getFileType(file)];
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
function getFileIconClass(file) {
|
|
3259
|
+
return 'sui-file-item-icon-' + getFileType(file);
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
function getOrCreateContainer(zone, cls) {
|
|
3263
|
+
var wrap = zone.closest('.sui-file-upload-wrap');
|
|
3264
|
+
if (!wrap) {
|
|
3265
|
+
wrap = document.createElement('div');
|
|
3266
|
+
wrap.className = 'sui-file-upload-wrap';
|
|
3267
|
+
zone.parentNode.insertBefore(wrap, zone);
|
|
3268
|
+
wrap.appendChild(zone);
|
|
3269
|
+
}
|
|
3270
|
+
var container = wrap.querySelector('.' + cls);
|
|
3271
|
+
if (!container) {
|
|
3272
|
+
container = document.createElement('div');
|
|
3273
|
+
container.className = cls;
|
|
3274
|
+
wrap.appendChild(container);
|
|
3275
|
+
}
|
|
3276
|
+
return container;
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
function renderFileList(zone, files, append) {
|
|
3280
|
+
var container = getOrCreateContainer(zone, 'sui-file-list');
|
|
3281
|
+
if (!append) container.innerHTML = '';
|
|
3282
|
+
for (var i = 0; i < files.length; i++) {
|
|
3283
|
+
var f = files[i];
|
|
3284
|
+
var item = document.createElement('div');
|
|
3285
|
+
item.className = 'sui-file-item';
|
|
3286
|
+
item.innerHTML =
|
|
3287
|
+
'<div class="sui-file-item-icon ' + getFileIconClass(f) + '">' + getFileIcon(f) + '</div>' +
|
|
3288
|
+
'<div class="sui-file-item-info">' +
|
|
3289
|
+
'<div class="sui-file-item-name">' + f.name + '</div>' +
|
|
3290
|
+
'<div class="sui-file-item-size">' + formatFileSize(f.size) + '</div>' +
|
|
3291
|
+
'</div>' +
|
|
3292
|
+
'<button class="sui-file-item-remove" aria-label="Remove">×</button>';
|
|
3293
|
+
container.appendChild(item);
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
function renderFileProgress(zone, files, append) {
|
|
3298
|
+
var container = getOrCreateContainer(zone, 'sui-file-list');
|
|
3299
|
+
if (!append) container.innerHTML = '';
|
|
3300
|
+
for (var i = 0; i < files.length; i++) {
|
|
3301
|
+
var f = files[i];
|
|
3302
|
+
var item = document.createElement('div');
|
|
3303
|
+
item.className = 'sui-file-item';
|
|
3304
|
+
item.innerHTML =
|
|
3305
|
+
'<div class="sui-file-item-icon ' + getFileIconClass(f) + '">' + getFileIcon(f) + '</div>' +
|
|
3306
|
+
'<div class="sui-file-item-info sui-file-item-progress">' +
|
|
3307
|
+
'<div style="display:flex;justify-content:space-between;align-items:center;">' +
|
|
3308
|
+
'<div class="sui-file-item-name">' + f.name + '</div>' +
|
|
3309
|
+
'<span class="sui-file-item-status sui-file-item-status-uploading">0%</span>' +
|
|
3310
|
+
'</div>' +
|
|
3311
|
+
'<div class="sui-progress sui-progress-sm"><div class="sui-progress-bar sui-progress-primary" style="width:0%;"></div></div>' +
|
|
3312
|
+
'</div>' +
|
|
3313
|
+
'<button class="sui-file-item-remove" aria-label="Remove">×</button>';
|
|
3314
|
+
container.appendChild(item);
|
|
3315
|
+
simulateProgress(item);
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
function simulateProgress(item) {
|
|
3320
|
+
var bar = item.querySelector('.sui-progress-bar');
|
|
3321
|
+
var status = item.querySelector('.sui-file-item-status');
|
|
3322
|
+
var pct = 0;
|
|
3323
|
+
var interval = setInterval(function() {
|
|
3324
|
+
pct += Math.floor(Math.random() * 15) + 5;
|
|
3325
|
+
if (pct >= 100) {
|
|
3326
|
+
pct = 100;
|
|
3327
|
+
clearInterval(interval);
|
|
3328
|
+
bar.style.width = '100%';
|
|
3329
|
+
bar.className = 'sui-progress-bar sui-progress-success';
|
|
3330
|
+
status.className = 'sui-file-item-status sui-file-item-status-complete';
|
|
3331
|
+
status.textContent = '\u2713';
|
|
3332
|
+
} else {
|
|
3333
|
+
bar.style.width = pct + '%';
|
|
3334
|
+
status.textContent = pct + '%';
|
|
3335
|
+
}
|
|
3336
|
+
}, 300 + Math.random() * 200);
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
function renderFilePreview(zone, files, append) {
|
|
3340
|
+
var container = getOrCreateContainer(zone, 'sui-file-preview-grid');
|
|
3341
|
+
if (!append) container.innerHTML = '';
|
|
3342
|
+
for (var i = 0; i < files.length; i++) {
|
|
3343
|
+
var f = files[i];
|
|
3344
|
+
if (!f.type || !f.type.startsWith('image/')) continue;
|
|
3345
|
+
var item = document.createElement('div');
|
|
3346
|
+
item.className = 'sui-file-preview-item';
|
|
3347
|
+
item.innerHTML =
|
|
3348
|
+
'<img alt="' + f.name + '">' +
|
|
3349
|
+
'<button class="sui-file-preview-item-remove" aria-label="Remove">×</button>';
|
|
3350
|
+
container.appendChild(item);
|
|
3351
|
+
(function(img, file) {
|
|
3352
|
+
var reader = new FileReader();
|
|
3353
|
+
reader.onload = function(e) { img.src = e.target.result; };
|
|
3354
|
+
reader.readAsDataURL(file);
|
|
3355
|
+
})(item.querySelector('img'), f);
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// Delegated change on file inputs
|
|
3360
|
+
document.addEventListener('change', function(e) {
|
|
3361
|
+
if (!e.target.matches('.sui-file-upload input[type="file"]')) return;
|
|
3362
|
+
var input = e.target;
|
|
3363
|
+
var zone = input.closest('.sui-file-upload');
|
|
3364
|
+
if (!zone) return;
|
|
3365
|
+
var files = Array.from(input.files);
|
|
3366
|
+
if (!files.length) return;
|
|
3367
|
+
var mode = zone.getAttribute('data-sui-upload') || 'list';
|
|
3368
|
+
if (mode === 'preview') {
|
|
3369
|
+
renderFilePreview(zone, files);
|
|
3370
|
+
} else if (mode === 'progress') {
|
|
3371
|
+
renderFileProgress(zone, files);
|
|
3372
|
+
} else {
|
|
3373
|
+
renderFileList(zone, files);
|
|
3374
|
+
}
|
|
3375
|
+
input.value = '';
|
|
3376
|
+
});
|
|
3377
|
+
|
|
3378
|
+
// Delegated remove clicks
|
|
3379
|
+
document.addEventListener('click', function(e) {
|
|
3380
|
+
var removeBtn = e.target.closest('.sui-file-item-remove, .sui-file-preview-item-remove');
|
|
3381
|
+
if (!removeBtn) return;
|
|
3382
|
+
var item = removeBtn.closest('.sui-file-item, .sui-file-preview-item');
|
|
3383
|
+
if (item) item.remove();
|
|
3384
|
+
});
|
|
3385
|
+
|
|
3386
|
+
// Dragover styling
|
|
3387
|
+
document.addEventListener('dragover', function(e) {
|
|
3388
|
+
var zone = e.target.closest('.sui-file-upload');
|
|
3389
|
+
if (!zone) return;
|
|
3390
|
+
e.preventDefault();
|
|
3391
|
+
zone.classList.add('sui-file-upload-dragover');
|
|
3392
|
+
});
|
|
3393
|
+
|
|
3394
|
+
document.addEventListener('dragleave', function(e) {
|
|
3395
|
+
var zone = e.target.closest('.sui-file-upload');
|
|
3396
|
+
if (!zone) return;
|
|
3397
|
+
zone.classList.remove('sui-file-upload-dragover');
|
|
3398
|
+
});
|
|
3399
|
+
|
|
3400
|
+
document.addEventListener('drop', function(e) {
|
|
3401
|
+
var zone = e.target.closest('.sui-file-upload');
|
|
3402
|
+
if (!zone) return;
|
|
3403
|
+
e.preventDefault();
|
|
3404
|
+
zone.classList.remove('sui-file-upload-dragover');
|
|
3405
|
+
var files = Array.from(e.dataTransfer.files);
|
|
3406
|
+
if (!files.length) return;
|
|
3407
|
+
var mode = zone.getAttribute('data-sui-upload') || 'list';
|
|
3408
|
+
if (mode === 'preview') {
|
|
3409
|
+
renderFilePreview(zone, files, true);
|
|
3410
|
+
} else if (mode === 'progress') {
|
|
3411
|
+
renderFileProgress(zone, files, true);
|
|
3412
|
+
} else {
|
|
3413
|
+
renderFileList(zone, files, true);
|
|
3414
|
+
}
|
|
3415
|
+
});
|
|
3416
|
+
|
|
3417
|
+
// =========================================
|
|
3418
|
+
// Radial Progress
|
|
3419
|
+
// =========================================
|
|
3420
|
+
function initRadialProgress() {
|
|
3421
|
+
var radials = document.querySelectorAll('.sui-radial[data-value]');
|
|
3422
|
+
radials.forEach(function(el) {
|
|
3423
|
+
var fill = el.querySelector('.sui-radial-fill');
|
|
3424
|
+
if (!fill) return;
|
|
3425
|
+
var value = parseFloat(el.getAttribute('data-value')) || 0;
|
|
3426
|
+
value = Math.max(0, Math.min(100, value));
|
|
3427
|
+
var circumference = parseFloat(fill.getAttribute('stroke-dasharray') || fill.style.strokeDasharray);
|
|
3428
|
+
if (!circumference) {
|
|
3429
|
+
var r = fill.getAttribute('r');
|
|
3430
|
+
circumference = 2 * Math.PI * parseFloat(r);
|
|
3431
|
+
}
|
|
3432
|
+
fill.style.strokeDasharray = circumference;
|
|
3433
|
+
fill.style.strokeDashoffset = circumference;
|
|
3434
|
+
var valueEl = el.querySelector('.sui-radial-value');
|
|
3435
|
+
var duration = el.classList.contains('sui-radial-animated') ? 1200 : 600;
|
|
3436
|
+
|
|
3437
|
+
requestAnimationFrame(function() {
|
|
3438
|
+
requestAnimationFrame(function() {
|
|
3439
|
+
var offset = circumference - (value / 100) * circumference;
|
|
3440
|
+
fill.style.strokeDashoffset = offset;
|
|
3441
|
+
|
|
3442
|
+
if (valueEl) {
|
|
3443
|
+
var start = performance.now();
|
|
3444
|
+
function tick(now) {
|
|
3445
|
+
var elapsed = now - start;
|
|
3446
|
+
var progress = Math.min(elapsed / duration, 1);
|
|
3447
|
+
var current = Math.round(progress * value);
|
|
3448
|
+
valueEl.textContent = current + '%';
|
|
3449
|
+
if (progress < 1) requestAnimationFrame(tick);
|
|
3450
|
+
}
|
|
3451
|
+
requestAnimationFrame(tick);
|
|
3452
|
+
}
|
|
3453
|
+
});
|
|
3454
|
+
});
|
|
3455
|
+
});
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
if (document.readyState === 'loading') {
|
|
3459
|
+
document.addEventListener('DOMContentLoaded', initRadialProgress);
|
|
3460
|
+
} else {
|
|
3461
|
+
initRadialProgress();
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
// =========================================
|
|
3465
|
+
// Number Input
|
|
3466
|
+
// =========================================
|
|
3467
|
+
document.addEventListener('click', function(e) {
|
|
3468
|
+
var btn = e.target.closest('.sui-number-input-btn');
|
|
3469
|
+
if (!btn) return;
|
|
3470
|
+
var wrap = btn.closest('.sui-number-input');
|
|
3471
|
+
var input = wrap.querySelector('input[type="number"]');
|
|
3472
|
+
if (!input) return;
|
|
3473
|
+
var step = parseFloat(input.step) || 1;
|
|
3474
|
+
var min = input.min !== '' ? parseFloat(input.min) : -Infinity;
|
|
3475
|
+
var max = input.max !== '' ? parseFloat(input.max) : Infinity;
|
|
3476
|
+
var val = parseFloat(input.value) || 0;
|
|
3477
|
+
if (btn.getAttribute('data-action') === 'decrement') {
|
|
3478
|
+
val = Math.max(min, val - step);
|
|
3479
|
+
} else {
|
|
3480
|
+
val = Math.min(max, val + step);
|
|
3481
|
+
}
|
|
3482
|
+
input.value = val;
|
|
3483
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
3484
|
+
});
|
|
3485
|
+
|
|
3486
|
+
// =========================================
|
|
3487
|
+
// Password Toggle
|
|
3488
|
+
// =========================================
|
|
3489
|
+
document.addEventListener('click', function(e) {
|
|
3490
|
+
var btn = e.target.closest('.sui-password-toggle');
|
|
3491
|
+
if (!btn) return;
|
|
3492
|
+
e.stopPropagation();
|
|
3493
|
+
var wrap = btn.closest('.sui-password-input');
|
|
3494
|
+
var input = wrap.querySelector('input');
|
|
3495
|
+
if (!input) return;
|
|
3496
|
+
var isPassword = input.type === 'password';
|
|
3497
|
+
input.type = isPassword ? 'text' : 'password';
|
|
3498
|
+
btn.classList.toggle('active');
|
|
3499
|
+
}, true);
|
|
3500
|
+
|
|
3501
|
+
// =========================================
|
|
3502
|
+
// Tags Input
|
|
3503
|
+
// =========================================
|
|
3504
|
+
document.addEventListener('keydown', function(e) {
|
|
3505
|
+
var input = e.target.closest('.sui-tags-input-field');
|
|
3506
|
+
if (!input) return;
|
|
3507
|
+
var wrap = input.closest('.sui-tags-input');
|
|
3508
|
+
if (e.key === 'Enter' || e.key === ',') {
|
|
3509
|
+
e.preventDefault();
|
|
3510
|
+
var val = input.value.trim().replace(/,$/, '');
|
|
3511
|
+
if (!val) return;
|
|
3512
|
+
var tag = document.createElement('span');
|
|
3513
|
+
tag.className = 'sui-chip';
|
|
3514
|
+
tag.textContent = val;
|
|
3515
|
+
var closeBtn = document.createElement('button');
|
|
3516
|
+
closeBtn.className = 'sui-chip-close';
|
|
3517
|
+
closeBtn.setAttribute('aria-label', 'Remove');
|
|
3518
|
+
tag.appendChild(closeBtn);
|
|
3519
|
+
wrap.insertBefore(tag, input);
|
|
3520
|
+
input.value = '';
|
|
3521
|
+
} else if (e.key === 'Backspace' && !input.value) {
|
|
3522
|
+
var tags = wrap.querySelectorAll('.sui-chip');
|
|
3523
|
+
if (tags.length) tags[tags.length - 1].remove();
|
|
3524
|
+
}
|
|
3525
|
+
});
|
|
3526
|
+
|
|
3527
|
+
document.addEventListener('click', function(e) {
|
|
3528
|
+
var dismiss = e.target.closest('.sui-tags-input .sui-chip-close');
|
|
3529
|
+
if (dismiss) {
|
|
3530
|
+
dismiss.closest('.sui-chip').remove();
|
|
3531
|
+
return;
|
|
3532
|
+
}
|
|
3533
|
+
var wrap = e.target.closest('.sui-tags-input');
|
|
3534
|
+
if (wrap) {
|
|
3535
|
+
var input = wrap.querySelector('.sui-tags-input-field');
|
|
3536
|
+
if (input) input.focus();
|
|
3537
|
+
}
|
|
3538
|
+
});
|
|
3539
|
+
|
|
3540
|
+
// =========================================
|
|
3541
|
+
// Swap
|
|
3542
|
+
// =========================================
|
|
3543
|
+
// Lock slide swap dimensions so absolute children don't collapse container
|
|
3544
|
+
function initSlideSwaps() {
|
|
3545
|
+
document.querySelectorAll('.sui-swap-slide, .sui-swap-slide-x').forEach(function(swap) {
|
|
3546
|
+
if (swap.dataset.suiSlideInit) return;
|
|
3547
|
+
var children = swap.querySelectorAll('.sui-swap-on, .sui-swap-off, .sui-swap-state');
|
|
3548
|
+
var maxW = 0, maxH = 0;
|
|
3549
|
+
children.forEach(function(c) {
|
|
3550
|
+
var prev = c.style.cssText;
|
|
3551
|
+
c.style.position = 'relative';
|
|
3552
|
+
c.style.opacity = '1';
|
|
3553
|
+
c.style.transform = 'none';
|
|
3554
|
+
maxW = Math.max(maxW, c.offsetWidth);
|
|
3555
|
+
maxH = Math.max(maxH, c.offsetHeight);
|
|
3556
|
+
c.style.cssText = prev;
|
|
3557
|
+
});
|
|
3558
|
+
if (maxW) swap.style.width = maxW + 'px';
|
|
3559
|
+
if (maxH) swap.style.height = maxH + 'px';
|
|
3560
|
+
swap.dataset.suiSlideInit = '1';
|
|
3561
|
+
});
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
if (document.readyState === 'loading') {
|
|
3565
|
+
document.addEventListener('DOMContentLoaded', initSlideSwaps);
|
|
3566
|
+
} else {
|
|
3567
|
+
initSlideSwaps();
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
document.addEventListener('click', function(e) {
|
|
3571
|
+
var swap = e.target.closest('.sui-swap');
|
|
3572
|
+
if (!swap) return;
|
|
3573
|
+
if (swap.classList.contains('sui-swap-cycle')) {
|
|
3574
|
+
var states = Array.from(swap.querySelectorAll('.sui-swap-state'));
|
|
3575
|
+
var current = states.findIndex(function(s) { return s.classList.contains('active'); });
|
|
3576
|
+
var next = (current + 1) % states.length;
|
|
3577
|
+
states.forEach(function(s) { s.classList.remove('active'); });
|
|
3578
|
+
states[next].classList.add('active');
|
|
3579
|
+
swap.setAttribute('data-state', next);
|
|
3580
|
+
swap.dispatchEvent(new CustomEvent('sui-swap-change', { detail: { state: next, total: states.length } }));
|
|
3581
|
+
} else {
|
|
3582
|
+
swap.classList.toggle('active');
|
|
3583
|
+
swap.dispatchEvent(new CustomEvent('sui-swap-change', { detail: { active: swap.classList.contains('active') } }));
|
|
3584
|
+
}
|
|
3585
|
+
});
|
|
3586
|
+
|
|
3587
|
+
// =========================================
|
|
3588
|
+
// Dock — magnification effect
|
|
3589
|
+
// =========================================
|
|
3590
|
+
var dockMaxScale = 1.5;
|
|
3591
|
+
var dockRange = 3;
|
|
3592
|
+
|
|
3593
|
+
document.addEventListener('mousemove', function(e) {
|
|
3594
|
+
var dock = e.target.closest('.sui-dock');
|
|
3595
|
+
if (!dock) return;
|
|
3596
|
+
if (dock.classList.contains('sui-dock-no-scale')) return;
|
|
3597
|
+
var iconOnly = dock.classList.contains('sui-dock-icon-scale');
|
|
3598
|
+
var items = Array.from(dock.querySelectorAll('.sui-dock-item'));
|
|
3599
|
+
var isVertical = dock.classList.contains('sui-dock-vertical');
|
|
3600
|
+
|
|
3601
|
+
items.forEach(function(item) {
|
|
3602
|
+
var rect = item.getBoundingClientRect();
|
|
3603
|
+
var center = isVertical
|
|
3604
|
+
? rect.top + rect.height / 2
|
|
3605
|
+
: rect.left + rect.width / 2;
|
|
3606
|
+
var mouse = isVertical ? e.clientY : e.clientX;
|
|
3607
|
+
var baseSize = dock.classList.contains('sui-dock-sm') ? 32
|
|
3608
|
+
: dock.classList.contains('sui-dock-lg') ? 52 : 40;
|
|
3609
|
+
var dist = Math.abs(mouse - center) / baseSize;
|
|
3610
|
+
|
|
3611
|
+
if (dist < dockRange) {
|
|
3612
|
+
var scale = dockMaxScale - (dist / dockRange) * (dockMaxScale - 1);
|
|
3613
|
+
if (iconOnly) {
|
|
3614
|
+
item.style.width = '';
|
|
3615
|
+
item.style.height = '';
|
|
3616
|
+
var svg = item.querySelector('svg');
|
|
3617
|
+
if (svg) svg.style.transform = 'scale(' + scale + ')';
|
|
3618
|
+
} else {
|
|
3619
|
+
var newSize = Math.round(baseSize * scale);
|
|
3620
|
+
item.style.width = newSize + 'px';
|
|
3621
|
+
item.style.height = newSize + 'px';
|
|
3622
|
+
}
|
|
3623
|
+
} else {
|
|
3624
|
+
item.style.width = '';
|
|
3625
|
+
item.style.height = '';
|
|
3626
|
+
if (iconOnly) {
|
|
3627
|
+
var svg = item.querySelector('svg');
|
|
3628
|
+
if (svg) svg.style.transform = '';
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
});
|
|
3632
|
+
});
|
|
3633
|
+
|
|
3634
|
+
document.addEventListener('mouseleave', function(e) {
|
|
3635
|
+
if (!e.target.classList || !e.target.classList.contains('sui-dock')) return;
|
|
3636
|
+
var iconOnly = e.target.classList.contains('sui-dock-icon-scale');
|
|
3637
|
+
var items = e.target.querySelectorAll('.sui-dock-item');
|
|
3638
|
+
items.forEach(function(item) {
|
|
3639
|
+
item.style.width = '';
|
|
3640
|
+
item.style.height = '';
|
|
3641
|
+
if (iconOnly) {
|
|
3642
|
+
var svg = item.querySelector('svg');
|
|
3643
|
+
if (svg) svg.style.transform = '';
|
|
3644
|
+
}
|
|
3645
|
+
});
|
|
3646
|
+
}, true);
|
|
3647
|
+
|
|
3648
|
+
// =========================================
|
|
3649
|
+
// Image Lightbox
|
|
3650
|
+
// =========================================
|
|
3651
|
+
var lightboxOverlay = null;
|
|
3652
|
+
var lightboxImages = [];
|
|
3653
|
+
var lightboxIndex = 0;
|
|
3654
|
+
|
|
3655
|
+
function createLightbox() {
|
|
3656
|
+
if (lightboxOverlay) return;
|
|
3657
|
+
lightboxOverlay = document.createElement('div');
|
|
3658
|
+
lightboxOverlay.className = 'sui-lightbox-overlay';
|
|
3659
|
+
lightboxOverlay.innerHTML =
|
|
3660
|
+
'<button class="sui-lightbox-close" aria-label="Close">×</button>' +
|
|
3661
|
+
'<span class="sui-lightbox-counter"></span>' +
|
|
3662
|
+
'<button class="sui-lightbox-prev" aria-label="Previous"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></button>' +
|
|
3663
|
+
'<button class="sui-lightbox-next" aria-label="Next"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>' +
|
|
3664
|
+
'<img src="" alt="">' +
|
|
3665
|
+
'<div class="sui-lightbox-caption"></div>';
|
|
3666
|
+
document.body.appendChild(lightboxOverlay);
|
|
3667
|
+
|
|
3668
|
+
lightboxOverlay.querySelector('.sui-lightbox-close').addEventListener('click', closeLightbox);
|
|
3669
|
+
lightboxOverlay.querySelector('.sui-lightbox-prev').addEventListener('click', function() { showLightboxImage(lightboxIndex - 1); });
|
|
3670
|
+
lightboxOverlay.querySelector('.sui-lightbox-next').addEventListener('click', function() { showLightboxImage(lightboxIndex + 1); });
|
|
3671
|
+
lightboxOverlay.addEventListener('click', function(e) {
|
|
3672
|
+
if (e.target === lightboxOverlay) closeLightbox();
|
|
3673
|
+
if (e.target.tagName === 'IMG') {
|
|
3674
|
+
lightboxOverlay.classList.toggle('zoomed');
|
|
3675
|
+
}
|
|
3676
|
+
});
|
|
3677
|
+
document.addEventListener('keydown', function(e) {
|
|
3678
|
+
if (!lightboxOverlay || !lightboxOverlay.classList.contains('open')) return;
|
|
3679
|
+
if (e.key === 'Escape') closeLightbox();
|
|
3680
|
+
if (e.key === 'ArrowLeft') showLightboxImage(lightboxIndex - 1);
|
|
3681
|
+
if (e.key === 'ArrowRight') showLightboxImage(lightboxIndex + 1);
|
|
3682
|
+
});
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
function openLightbox(images, index) {
|
|
3686
|
+
createLightbox();
|
|
3687
|
+
lightboxImages = images;
|
|
3688
|
+
lightboxIndex = index || 0;
|
|
3689
|
+
showLightboxImage(lightboxIndex);
|
|
3690
|
+
lightboxOverlay.classList.add('open');
|
|
3691
|
+
lightboxOverlay.classList.remove('zoomed');
|
|
3692
|
+
document.body.style.overflow = 'hidden';
|
|
3693
|
+
var hasMultiple = images.length > 1;
|
|
3694
|
+
lightboxOverlay.querySelector('.sui-lightbox-prev').style.display = hasMultiple ? '' : 'none';
|
|
3695
|
+
lightboxOverlay.querySelector('.sui-lightbox-next').style.display = hasMultiple ? '' : 'none';
|
|
3696
|
+
lightboxOverlay.querySelector('.sui-lightbox-counter').style.display = hasMultiple ? '' : 'none';
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3699
|
+
function closeLightbox() {
|
|
3700
|
+
if (lightboxOverlay) {
|
|
3701
|
+
lightboxOverlay.classList.remove('open', 'zoomed');
|
|
3702
|
+
document.body.style.overflow = '';
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
function showLightboxImage(idx) {
|
|
3707
|
+
if (lightboxImages.length === 0) return;
|
|
3708
|
+
lightboxIndex = (idx + lightboxImages.length) % lightboxImages.length;
|
|
3709
|
+
var item = lightboxImages[lightboxIndex];
|
|
3710
|
+
var img = lightboxOverlay.querySelector('img');
|
|
3711
|
+
var caption = lightboxOverlay.querySelector('.sui-lightbox-caption');
|
|
3712
|
+
var counter = lightboxOverlay.querySelector('.sui-lightbox-counter');
|
|
3713
|
+
img.src = item.src;
|
|
3714
|
+
img.alt = item.alt || '';
|
|
3715
|
+
caption.textContent = item.caption || '';
|
|
3716
|
+
caption.style.display = item.caption ? '' : 'none';
|
|
3717
|
+
counter.textContent = (lightboxIndex + 1) + ' / ' + lightboxImages.length;
|
|
3718
|
+
lightboxOverlay.classList.remove('zoomed');
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3721
|
+
// Vertical gallery — click side thumb to update main
|
|
3722
|
+
document.addEventListener('click', function(e) {
|
|
3723
|
+
var thumb = e.target.closest('.sui-lightbox-vertical-strip .sui-lightbox-thumb');
|
|
3724
|
+
if (!thumb) return;
|
|
3725
|
+
var gallery = thumb.closest('.sui-lightbox-vertical');
|
|
3726
|
+
var main = gallery.querySelector('.sui-lightbox-vertical-main img');
|
|
3727
|
+
var img = thumb.querySelector('img');
|
|
3728
|
+
if (main && img) {
|
|
3729
|
+
main.src = thumb.getAttribute('data-src') || img.src;
|
|
3730
|
+
main.alt = thumb.getAttribute('data-alt') || img.alt;
|
|
3731
|
+
}
|
|
3732
|
+
gallery.querySelectorAll('.sui-lightbox-vertical-strip .sui-lightbox-thumb').forEach(function(t) { t.classList.remove('active'); });
|
|
3733
|
+
thumb.classList.add('active');
|
|
3734
|
+
});
|
|
3735
|
+
|
|
3736
|
+
// Click main image in vertical gallery to open lightbox
|
|
3737
|
+
document.addEventListener('click', function(e) {
|
|
3738
|
+
var main = e.target.closest('.sui-lightbox-vertical-main');
|
|
3739
|
+
if (!main) return;
|
|
3740
|
+
var gallery = main.closest('.sui-lightbox-vertical');
|
|
3741
|
+
var thumbs = Array.from(gallery.querySelectorAll('.sui-lightbox-vertical-strip .sui-lightbox-thumb'));
|
|
3742
|
+
var images = thumbs.map(function(t) {
|
|
3743
|
+
var img = t.querySelector('img');
|
|
3744
|
+
return {
|
|
3745
|
+
src: t.getAttribute('data-src') || (img ? img.src : ''),
|
|
3746
|
+
alt: t.getAttribute('data-alt') || (img ? img.alt : ''),
|
|
3747
|
+
caption: t.getAttribute('data-caption') || ''
|
|
3748
|
+
};
|
|
3749
|
+
});
|
|
3750
|
+
var activeIdx = thumbs.findIndex(function(t) { return t.classList.contains('active'); });
|
|
3751
|
+
openLightbox(images, activeIdx >= 0 ? activeIdx : 0);
|
|
3752
|
+
});
|
|
3753
|
+
|
|
3754
|
+
// Click on thumbnail
|
|
3755
|
+
document.addEventListener('click', function(e) {
|
|
3756
|
+
var thumb = e.target.closest('.sui-lightbox-thumb');
|
|
3757
|
+
if (!thumb) return;
|
|
3758
|
+
// Skip if inside vertical strip (handled above)
|
|
3759
|
+
if (thumb.closest('.sui-lightbox-vertical-strip')) return;
|
|
3760
|
+
var grid = thumb.closest('.sui-lightbox-grid');
|
|
3761
|
+
var thumbs = grid ? Array.from(grid.querySelectorAll('.sui-lightbox-thumb')) : [thumb];
|
|
3762
|
+
var images = thumbs.map(function(t) {
|
|
3763
|
+
var img = t.querySelector('img');
|
|
3764
|
+
return {
|
|
3765
|
+
src: t.getAttribute('data-src') || (img ? img.src : ''),
|
|
3766
|
+
alt: t.getAttribute('data-alt') || (img ? img.alt : ''),
|
|
3767
|
+
caption: t.getAttribute('data-caption') || ''
|
|
3768
|
+
};
|
|
3769
|
+
});
|
|
3770
|
+
var index = thumbs.indexOf(thumb);
|
|
3771
|
+
openLightbox(images, index);
|
|
3772
|
+
});
|
|
3773
|
+
|
|
3774
|
+
// =========================================
|
|
3775
|
+
// Diff — Image Compare Slider
|
|
3776
|
+
// =========================================
|
|
3777
|
+
function initDiffSliders() {
|
|
3778
|
+
document.querySelectorAll('.sui-diff[data-sui-diff]').forEach(function(diff) {
|
|
3779
|
+
if (diff.dataset.suiDiffInit) return;
|
|
3780
|
+
diff.dataset.suiDiffInit = '1';
|
|
3781
|
+
var handle = diff.querySelector('.sui-diff-handle');
|
|
3782
|
+
var before = diff.querySelector('.sui-diff-before');
|
|
3783
|
+
if (!handle || !before) return;
|
|
3784
|
+
var isVertical = diff.classList.contains('sui-diff-vertical');
|
|
3785
|
+
|
|
3786
|
+
function onMove(e) {
|
|
3787
|
+
e.preventDefault();
|
|
3788
|
+
var rect = diff.getBoundingClientRect();
|
|
3789
|
+
var pos;
|
|
3790
|
+
if (isVertical) {
|
|
3791
|
+
var clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
|
3792
|
+
pos = Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
|
|
3793
|
+
var pct = (pos * 100);
|
|
3794
|
+
before.style.clipPath = 'inset(0 0 ' + (100 - pct) + '% 0)';
|
|
3795
|
+
handle.style.top = pct + '%';
|
|
3796
|
+
} else {
|
|
3797
|
+
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
|
3798
|
+
pos = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
3799
|
+
var pct = (pos * 100);
|
|
3800
|
+
before.style.clipPath = 'inset(0 ' + (100 - pct) + '% 0 0)';
|
|
3801
|
+
handle.style.left = pct + '%';
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
function onDown(e) {
|
|
3806
|
+
e.preventDefault();
|
|
3807
|
+
onMove(e);
|
|
3808
|
+
document.addEventListener('mousemove', onMove);
|
|
3809
|
+
document.addEventListener('mouseup', onUp);
|
|
3810
|
+
document.addEventListener('touchmove', onMove, { passive: false });
|
|
3811
|
+
document.addEventListener('touchend', onUp);
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3814
|
+
function onUp() {
|
|
3815
|
+
document.removeEventListener('mousemove', onMove);
|
|
3816
|
+
document.removeEventListener('mouseup', onUp);
|
|
3817
|
+
document.removeEventListener('touchmove', onMove);
|
|
3818
|
+
document.removeEventListener('touchend', onUp);
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
diff.addEventListener('mousedown', onDown);
|
|
3822
|
+
diff.addEventListener('touchstart', onDown, { passive: false });
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
|
|
3826
|
+
if (document.readyState === 'loading') {
|
|
3827
|
+
document.addEventListener('DOMContentLoaded', initDiffSliders);
|
|
3828
|
+
} else {
|
|
3829
|
+
initDiffSliders();
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// =========================================
|
|
3833
|
+
// Speed Dial
|
|
3834
|
+
// =========================================
|
|
3835
|
+
document.addEventListener('click', function(e) {
|
|
3836
|
+
var trigger = e.target.closest('.sui-speed-dial-trigger');
|
|
3837
|
+
if (trigger) {
|
|
3838
|
+
var dial = trigger.closest('.sui-speed-dial');
|
|
3839
|
+
dial.classList.toggle('open');
|
|
3840
|
+
return;
|
|
3841
|
+
}
|
|
3842
|
+
var action = e.target.closest('.sui-speed-dial-action');
|
|
3843
|
+
if (action) {
|
|
3844
|
+
var dial = action.closest('.sui-speed-dial');
|
|
3845
|
+
dial.classList.remove('open');
|
|
3846
|
+
return;
|
|
3847
|
+
}
|
|
3848
|
+
// Close all open dials when clicking outside
|
|
3849
|
+
document.querySelectorAll('.sui-speed-dial.open').forEach(function(d) {
|
|
3850
|
+
d.classList.remove('open');
|
|
3851
|
+
});
|
|
3852
|
+
});
|
|
3853
|
+
|
|
3854
|
+
// Hover mode
|
|
3855
|
+
document.addEventListener('mouseenter', function(e) {
|
|
3856
|
+
var dial = e.target.closest('.sui-speed-dial-hover');
|
|
3857
|
+
if (dial) dial.classList.add('open');
|
|
3858
|
+
}, true);
|
|
3859
|
+
|
|
3860
|
+
document.addEventListener('mouseleave', function(e) {
|
|
3861
|
+
var dial = e.target.closest('.sui-speed-dial-hover');
|
|
3862
|
+
if (dial) dial.classList.remove('open');
|
|
3863
|
+
}, true);
|
|
3864
|
+
|
|
3865
|
+
// =========================================
|
|
3866
|
+
// Tree View
|
|
3867
|
+
// =========================================
|
|
3868
|
+
document.addEventListener('click', function(e) {
|
|
3869
|
+
var label = e.target.closest('.sui-tree-label');
|
|
3870
|
+
if (!label) return;
|
|
3871
|
+
if (e.target.closest('.sui-checkbox')) return;
|
|
3872
|
+
var item = label.closest('.sui-tree-item');
|
|
3873
|
+
var children = item.querySelector('.sui-tree-children');
|
|
3874
|
+
if (children) {
|
|
3875
|
+
item.classList.toggle('expanded');
|
|
3876
|
+
}
|
|
3877
|
+
});
|
|
3878
|
+
|
|
3879
|
+
// Tree checkbox propagation
|
|
3880
|
+
document.addEventListener('change', function(e) {
|
|
3881
|
+
if (!e.target.closest('.sui-tree .sui-checkbox input')) return;
|
|
3882
|
+
var checkbox = e.target;
|
|
3883
|
+
var item = checkbox.closest('.sui-tree-item');
|
|
3884
|
+
var checked = checkbox.checked;
|
|
3885
|
+
|
|
3886
|
+
// Propagate down — check/uncheck all children
|
|
3887
|
+
var childBoxes = item.querySelectorAll('.sui-tree-children .sui-checkbox input');
|
|
3888
|
+
childBoxes.forEach(function(cb) {
|
|
3889
|
+
cb.checked = checked;
|
|
3890
|
+
cb.indeterminate = false;
|
|
3891
|
+
});
|
|
3892
|
+
|
|
3893
|
+
// Propagate up — update parent state
|
|
3894
|
+
updateTreeParent(item);
|
|
3895
|
+
});
|
|
3896
|
+
|
|
3897
|
+
function updateTreeParent(item) {
|
|
3898
|
+
var parentChildren = item.closest('.sui-tree-children');
|
|
3899
|
+
if (!parentChildren) return;
|
|
3900
|
+
var parentItem = parentChildren.closest('.sui-tree-item');
|
|
3901
|
+
if (!parentItem) return;
|
|
3902
|
+
var parentCb = parentItem.querySelector(':scope > .sui-tree-label .sui-checkbox input');
|
|
3903
|
+
if (!parentCb) return;
|
|
3904
|
+
|
|
3905
|
+
var siblings = parentChildren.querySelectorAll(':scope > .sui-tree-item > .sui-tree-label .sui-checkbox input');
|
|
3906
|
+
var total = siblings.length;
|
|
3907
|
+
var checkedCount = 0;
|
|
3908
|
+
siblings.forEach(function(cb) { if (cb.checked) checkedCount++; });
|
|
3909
|
+
|
|
3910
|
+
if (checkedCount === 0) {
|
|
3911
|
+
parentCb.checked = false;
|
|
3912
|
+
parentCb.indeterminate = false;
|
|
3913
|
+
} else if (checkedCount === total) {
|
|
3914
|
+
parentCb.checked = true;
|
|
3915
|
+
parentCb.indeterminate = false;
|
|
3916
|
+
} else {
|
|
3917
|
+
parentCb.checked = false;
|
|
3918
|
+
parentCb.indeterminate = true;
|
|
3919
|
+
}
|
|
3920
|
+
|
|
3921
|
+
// Continue up the tree
|
|
3922
|
+
updateTreeParent(parentItem);
|
|
3923
|
+
}
|
|
3924
|
+
|
|
2986
3925
|
return { modal, sheet, toast, carousel, sidebar };
|
|
2987
3926
|
})();
|