// ───────────────────────────────────────────────── // PREVIEW IMAGES // Legt auf der Webflow-Seite ein Element mit data-lightbox-demo-assets an, // darin direkt 5 Elemente — deren src wird automatisch übernommen. // Beispiel:
// ... //
// ───────────────────────────────────────────────── (function() { const assetEl = document.querySelector('[data-lightbox-demo-assets]'); if (!assetEl) return; const srcs = Array.from(assetEl.querySelectorAll('img')).map(i => i.src).filter(Boolean); if (!srcs.length) return; // Main image: erstes Bild const mainImg = document.getElementById('main-img'); if (mainImg && srcs[0]) mainImg.src = srcs[0]; // Thumbnails const thumbImgs = document.querySelectorAll('#lightbox-preview .w-lightbox-thumbnail-image'); thumbImgs.forEach((img, i) => { if (srcs[i]) img.src = srcs[i]; }); })(); // ───────────────────────────────────────────────── // ── State ── const state = { color: '#000000', opacity: 90, blur: 0, thumbWidth: 10, thumbHeight: 10, thumbRadius: 0, thumbMargin: 1, thumbPaddingTB: 2, frameRadius: 0, fullSize: false, objectFit: 'cover', arrowPreset: 'Default', arrowPosition: 0, arrowSize: 1.5, arrowOpacity: 50, arrowMirror: true, arrowSvgRight: '', arrowSvgLeft: '', arrowColor: '#ffffff', closePreset: 'Default', closeSide: 'right', closeOffsetX: 0, closeOffsetY: 0, closeSize: 1, closeOpacity: 80, closeColor: '#ffffff', closeSvg: '', stripHide: false, stripAlign: 'center', stripBgEnable: false, stripBgType: 'solid', stripGradFrom: '#000000', stripGradFromOpacity: 50, stripGradTo: 'transparent', stripGradDir: 'to top', stripBgColor: '#000000', stripBgOpacity: 100, activeOpacity: 30, activeBorderWidth: 0, activeBorderColor: '#ffffff', }; let activeTab = 'backdrop'; const backdrop = document.getElementById('preview-backdrop'); // ── Controls wiring ── function wire(id, stateKey, displayId) { const slider = document.getElementById(id); const disp = document.getElementById(displayId); slider.addEventListener('input', () => { const v = parseFloat(slider.value); state[stateKey] = v; if (disp) disp.value = v; applyStyles(); }); if (disp) { disp.addEventListener('change', () => { const raw = parseFloat(disp.value); if (isNaN(raw)) { disp.value = state[stateKey]; return; } state[stateKey] = raw; const mn = parseFloat(slider.min), mx = parseFloat(slider.max); slider.value = Math.min(mx, Math.max(mn, raw)); applyStyles(); }); } } wire('ctrl-opacity', 'opacity', 'val-opacity'); wire('ctrl-blur', 'blur', 'val-blur'); // ── Color picker ── const colorPicker = document.getElementById('ctrl-color'); const hexInput = document.getElementById('ctrl-hex'); function setColor(hex) { hex = hex.replace(/[^#0-9a-fA-F]/g, ''); if (!hex.startsWith('#')) hex = '#' + hex; if (hex.length === 7) { state.color = hex.toLowerCase(); colorPicker.value = hex; hexInput.value = hex.toLowerCase(); applyStyles(); } } colorPicker.addEventListener('input', e => setColor(e.target.value)); hexInput.addEventListener('input', e => setColor(e.target.value)); hexInput.addEventListener('keydown', e => { if (e.key === 'Enter') setColor(hexInput.value); }); // ── Thumbnail click — preload + instant swap ── const mainImg = document.getElementById('main-img'); // Alle Thumbnail-Bilder vorladen damit der Wechsel aus dem Cache kommt function preloadThumbImages() { document.querySelectorAll('#lightbox-preview .w-lightbox-thumbnail-image').forEach(img => { if (img.src && !img.src.startsWith('data:')) { const pre = new Image(); pre.src = img.src; } }); } // Nach kurzem Delay preloaden (damit data-lightbox-demo-assets zuerst gesetzt wird) setTimeout(preloadThumbImages, 300); document.querySelectorAll('.w-lightbox-item').forEach(item => { item.addEventListener('click', () => { document.querySelectorAll('.w-lightbox-item').forEach(i => i.classList.remove('w-lightbox-active')); item.classList.add('w-lightbox-active'); const thumbImg = item.querySelector('.w-lightbox-thumbnail-image'); if (!thumbImg) return; // Bild ist im Cache → kein Fade nötig, direkt wechseln mainImg.src = thumbImg.src; }); }); // ── Apply styles to preview ── function applyStyles() { const r = parseInt(state.color.slice(1,3), 16); const g = parseInt(state.color.slice(3,5), 16); const b = parseInt(state.color.slice(5,7), 16); const a = (state.opacity / 100).toFixed(2); const filters = []; if (state.blur > 0) filters.push('blur(' + state.blur + 'px)'); backdrop.style.backgroundColor = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; backdrop.style.backdropFilter = filters.length ? filters.join(' ') : ''; backdrop.style.webkitBackdropFilter = backdrop.style.backdropFilter; backdrop.style.transition = 'all, opacity ' + state.duration + 'ms ' + state.easing + ', transform ' + state.duration + 'ms ' + state.easing; } // ── Thumb styles ── const thumbDynamicStyle = document.createElement('style'); document.head.appendChild(thumbDynamicStyle); function applyThumbStyles() { const viewH = 96 - state.thumbHeight - 2; if (state.fullSize) { thumbDynamicStyle.textContent = '#lightbox-preview .w-lightbox-content { height: 100vh; margin-top: 0; }' + '#lightbox-preview .w-lightbox-group,' + '#lightbox-preview .w-lightbox-group .w-lightbox-view,' + '#lightbox-preview .w-lightbox-group .w-lightbox-view:before { height: 100vh; }' + '#lightbox-preview .w-lightbox-view:before { display: none; }' + '#lightbox-preview .w-lightbox-frame { display: block; width: 100%; height: 100vh; vertical-align: top; }' + '#lightbox-preview .w-lightbox-figure { width: 100%; height: 100%; margin: 0; }' + '#lightbox-preview .w-lightbox-image:not(.w-lightbox-thumbnail-image) { display: block; width: 100%; height: 100%; max-height: none; max-width: none; float: none; object-fit: ' + state.objectFit + '; }'; } else { thumbDynamicStyle.textContent = '@media (min-width: 768px) {' + ' #lightbox-preview .w-lightbox-group,' + ' #lightbox-preview .w-lightbox-group .w-lightbox-view,' + ' #lightbox-preview .w-lightbox-group .w-lightbox-view:before' + ' { height: ' + viewH + 'vh; }' + ' #lightbox-preview .w-lightbox-group .w-lightbox-image' + ' { max-height: ' + viewH + 'vh; }' + '}'; } document.querySelectorAll('.w-lightbox-thumbnail').forEach(function(el) { el.style.height = state.thumbHeight + 'vh'; el.style.borderRadius = state.thumbRadius > 0 ? state.thumbRadius + 'rem' : ''; }); const strip = document.querySelector('#lightbox-preview .w-lightbox-strip'); if (strip) { strip.style.fontSize = '0'; strip.style.display = state.stripHide ? 'none' : ''; strip.style.textAlign = state.stripAlign; if (state.stripBgEnable) { if (state.stripBgType === 'gradient') { const fromHex = state.stripGradFrom; const fR = parseInt(fromHex.slice(1,3),16), fG = parseInt(fromHex.slice(3,5),16), fB = parseInt(fromHex.slice(5,7),16); const fromRgba = 'rgba(' + fR + ',' + fG + ',' + fB + ',' + (state.stripGradFromOpacity/100).toFixed(2) + ')'; strip.style.background = 'linear-gradient(' + state.stripGradDir + ', ' + fromRgba + ', ' + state.stripGradTo + ')'; strip.style.backgroundColor = ''; } else if (state.stripBgOpacity > 0) { const r = parseInt(state.stripBgColor.slice(1,3),16); const g = parseInt(state.stripBgColor.slice(3,5),16); const b = parseInt(state.stripBgColor.slice(5,7),16); strip.style.background = ''; strip.style.backgroundColor = 'rgba(' + r + ',' + g + ',' + b + ',' + (state.stripBgOpacity/100).toFixed(2) + ')'; } } else { strip.style.background = ''; strip.style.backgroundColor = ''; } } document.querySelectorAll('.w-lightbox-item').forEach(function(el) { el.style.width = state.thumbWidth + 'vh'; el.style.marginLeft = state.thumbMargin > 0 ? state.thumbMargin + 'vh' : ''; el.style.marginRight = state.thumbMargin > 0 ? state.thumbMargin + 'vh' : ''; el.style.paddingLeft = '0'; el.style.paddingRight = '0'; el.style.paddingTop = state.thumbPaddingTB + 'vh'; el.style.paddingBottom = state.thumbPaddingTB + 'vh'; }); // Active thumb const activeStyle = document.getElementById('active-thumb-style') || (() => { const s = document.createElement('style'); s.id = 'active-thumb-style'; document.head.appendChild(s); return s; })(); let activeRules = '#lightbox-preview .w-lightbox-active { opacity: ' + (state.activeOpacity / 100).toFixed(2) + '; }'; if (state.activeBorderWidth > 0) { activeRules += ' #lightbox-preview .w-lightbox-active .w-lightbox-thumbnail { border: ' + state.activeBorderWidth + 'rem solid ' + state.activeBorderColor + '; box-sizing: border-box; }'; } else { activeRules += ' #lightbox-preview .w-lightbox-active .w-lightbox-thumbnail { border: none; }'; } activeStyle.textContent = activeRules; } // ── Frame styles ── const frameDynamicStyle = document.createElement('style'); document.head.appendChild(frameDynamicStyle); function applyFrameStyles() { const frame = document.querySelector('#lightbox-preview .w-lightbox-frame'); const img = document.querySelector('#lightbox-preview .w-lightbox-img'); if (!frame) return; frame.style.borderRadius = state.frameRadius > 0 ? state.frameRadius + 'rem' : ''; frame.style.overflow = (state.frameRadius > 0 || state.fullSize) ? 'hidden' : ''; // fullSize layout is handled via thumbDynamicStyle in applyThumbStyles applyThumbStyles(); updateModified(); } const arrowPresets = [ { name: "Default", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii00IDAgMjQgNDAiIHdpZHRoPSIyNCIgaGVpZ2h0PSI0MCI+PGcgdHJhbnNmb3JtPSJyb3RhdGUoNDUpIj48cGF0aCBkPSJtMC0waDI4djI4aC01di0yM2gtMjN6IiBvcGFjaXR5PSIuNCIvPjxwYXRoIGQ9Im0xIDFoMjZ2MjZoLTN2LTIzaC0yM3oiIGZpbGw9IiNmZmYiLz48L2c+PC9zdmc+", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii00IDAgMjQgNDAiIHdpZHRoPSIyNCIgaGVpZ2h0PSI0MCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjQsMCkgc2NhbGUoLTEsMSkiPjxnIHRyYW5zZm9ybT0icm90YXRlKDQ1KSI+PHBhdGggZD0ibTAtMGgyOHYyOGgtNXYtMjNoLTIzeiIgb3BhY2l0eT0iLjQiLz48cGF0aCBkPSJtMSAxaDI2djI2aC0zdi0yM2gtMjN6IiBmaWxsPSIjZmZmIi8+PC9nPjwvZz48L3N2Zz4=", svg: '', svgLeft: '' }, { name: "Chevron", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48cG9seWxpbmUgcG9pbnRzPSI1LDQgMTksMjAgNSwzNiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNCwwKSBzY2FsZSgtMSwxKSI+PHBvbHlsaW5lIHBvaW50cz0iNSw0IDE5LDIwIDUsMzYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvZz48L3N2Zz4=", svg: '' }, { name: "Arrow", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48bGluZSB4MT0iMiIgeTE9IjIwIiB4Mj0iMjEiIHkyPSIyMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBvbHlsaW5lIHBvaW50cz0iMTMsMTEgMjEsMjAgMTMsMjkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg==", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNCwwKSBzY2FsZSgtMSwxKSI+PGxpbmUgeDE9IjIiIHkxPSIyMCIgeDI9IjIxIiB5Mj0iMjAiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwb2x5bGluZSBwb2ludHM9IjEzLDExIDIxLDIwIDEzLDI5IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L2c+PC9zdmc+", svg: '' }, { name: "Triangle", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48cG9seWdvbiBwb2ludHM9IjYsOCAyMCwyMCA2LDMyIiBmaWxsPSIjZmZmIiBvcGFjaXR5PSIwLjkiLz48L3N2Zz4=", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNCwwKSBzY2FsZSgtMSwxKSI+PHBvbHlnb24gcG9pbnRzPSI2LDggMjAsMjAgNiwzMiIgZmlsbD0iI2ZmZiIgb3BhY2l0eT0iMC45Ii8+PC9nPjwvc3ZnPg==", svg: '' }, { name: "Thin", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48cG9seWxpbmUgcG9pbnRzPSI3LDYgMTcsMjAgNywzNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCA0MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjQwIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNCwwKSBzY2FsZSgtMSwxKSI+PHBvbHlsaW5lIHBvaW50cz0iNyw2IDE3LDIwIDcsMzQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvZz48L3N2Zz4=", svg: '' }, { name: "Double", right: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCA0MCIgd2lkdGg9IjI4IiBoZWlnaHQ9IjQwIj48cG9seWxpbmUgcG9pbnRzPSI0LDYgMTQsMjAgNCwzNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwb2x5bGluZSBwb2ludHM9IjEzLDYgMjMsMjAgMTMsMzQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=", left: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCA0MCIgd2lkdGg9IjI4IiBoZWlnaHQ9IjQwIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyOCwwKSBzY2FsZSgtMSwxKSI+PHBvbHlsaW5lIHBvaW50cz0iNCw2IDE0LDIwIDQsMzQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cG9seWxpbmUgcG9pbnRzPSIxMyw2IDIzLDIwIDEzLDM0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9nPjwvc3ZnPg==", svg: '' }, ]; // ── Arrow styles ── function svgToDataUri(svg) { svg = svg.trim(); if (!svg.startsWith(']*>)/, '$1'); mirrored = mirrored.replace('', ''); return svgToDataUri(mirrored); } function colorizeArrowSvg(svg) { const c = state.arrowColor; return svg .replace(/fill="[^"none][^"]*"/gi, 'fill="' + c + '"') .replace(/stroke="[^"none][^"]*"/gi, 'stroke="' + c + '"') .replace(/fill='[^'none][^']*'/gi, "fill='" + c + "'") .replace(/stroke='[^'none][^']*'/gi, "stroke='" + c + "'") .replace(/fill="currentColor"/gi, 'fill="' + c + '"') .replace(/stroke="currentColor"/gi, 'stroke="' + c + '"'); } function applyArrowStyles() { const leftEl = document.querySelector('#lightbox-preview .w-lightbox-left'); const rightEl = document.querySelector('#lightbox-preview .w-lightbox-right'); if (!leftEl || !rightEl) return; let uriRight, uriLeft; if (state.arrowSvgRight.trim()) { const colored = colorizeArrowSvg(state.arrowSvgRight); uriRight = svgToDataUri(colored); if (state.arrowMirror) { uriLeft = mirrorSvgUri(colored); } else { const coloredLeft = state.arrowSvgLeft.trim() ? colorizeArrowSvg(state.arrowSvgLeft) : colored; uriLeft = svgToDataUri(coloredLeft); } } else { const preset = arrowPresets.find(p => p.name === state.arrowPreset) || arrowPresets[0]; if (preset.name === 'Default' && state.arrowColor === '#ffffff') { // Restore Webflow originals — remove overrides rightEl.style.backgroundImage = ''; leftEl.style.backgroundImage = ''; } else { const coloredRight = colorizeArrowSvg(preset.svg); uriRight = svgToDataUri(coloredRight); uriLeft = preset.svgLeft ? svgToDataUri(colorizeArrowSvg(preset.svgLeft)) : mirrorSvgUri(coloredRight); } } if (uriRight) rightEl.style.backgroundImage = 'url("' + uriRight + '")'; if (uriLeft) leftEl.style.backgroundImage = 'url("' + uriLeft + '")'; const sizePx = state.arrowSize + 'rem'; rightEl.style.backgroundSize = sizePx; leftEl.style.backgroundSize = sizePx; // Expand hit area when icon exceeds default 1.5rem — only on left/right, never close const extra = state.arrowSize - 1.5; const arrowWidth = extra > 0 ? 'calc(4em + ' + extra.toFixed(4) + 'rem)' : ''; rightEl.style.width = arrowWidth; leftEl.style.width = arrowWidth; rightEl.style.right = state.arrowPosition !== 0 ? state.arrowPosition + 'rem' : ''; leftEl.style.left = state.arrowPosition !== 0 ? state.arrowPosition + 'rem' : ''; // Opacity via dynamic style to override media query const opacityStyle = document.getElementById('arrow-opacity-style') || (() => { const s = document.createElement('style'); s.id = 'arrow-opacity-style'; document.head.appendChild(s); return s; })(); const op = (state.arrowOpacity / 100).toFixed(2); opacityStyle.textContent = '#lightbox-preview .w-lightbox-left, #lightbox-preview .w-lightbox-right { opacity: ' + op + '; }' + '#lightbox-preview .w-lightbox-control:hover { opacity: 1; }'; updateModified(); } // Preset tile clicks document.querySelectorAll('.arrow-preset-tile').forEach(tile => { tile.addEventListener('click', () => { document.querySelectorAll('.arrow-preset-tile').forEach(t => t.classList.remove('active')); tile.classList.add('active'); state.arrowPreset = tile.dataset.preset; // Clear custom SVG state.arrowSvgRight = ''; state.arrowSvgLeft = ''; document.getElementById('ctrl-arrow-svg-right').value = ''; document.getElementById('ctrl-arrow-svg-left').value = ''; applyArrowStyles(); }); }); // Set first preset active const firstTile = document.querySelector('.arrow-preset-tile'); if (firstTile) firstTile.classList.add('active'); // Arrow size + opacity wires function wireArrow(id, stateKey, displayId) { const slider = document.getElementById(id); const disp = document.getElementById(displayId); if (!slider) return; slider.addEventListener('input', () => { state[stateKey] = parseFloat(slider.value); if (disp) disp.value = slider.value; applyArrowStyles(); }); if (disp) { disp.addEventListener('change', () => { const raw = parseFloat(disp.value); if (isNaN(raw)) { disp.value = state[stateKey]; return; } state[stateKey] = raw; const mn = parseFloat(slider.min), mx = parseFloat(slider.max); slider.value = Math.min(mx, Math.max(mn, raw)); applyArrowStyles(); }); } } wireArrow('ctrl-arrow-position', 'arrowPosition', 'val-arrow-position'); wireArrow('ctrl-arrow-size', 'arrowSize', 'val-arrow-size'); wireArrow('ctrl-arrow-opacity', 'arrowOpacity', 'val-arrow-opacity'); // Arrow color picker const arrowColorPicker = document.getElementById('ctrl-arrow-color'); const arrowHexInput = document.getElementById('ctrl-arrow-hex'); function setArrowColor(hex) { hex = hex.replace(/[^#0-9a-fA-F]/g, ''); if (!hex.startsWith('#')) hex = '#' + hex; if (hex.length === 7) { state.arrowColor = hex.toLowerCase(); arrowColorPicker.value = hex; arrowHexInput.value = hex.toLowerCase(); applyArrowStyles(); } } arrowColorPicker.addEventListener('input', e => setArrowColor(e.target.value)); arrowHexInput.addEventListener('input', e => setArrowColor(e.target.value)); arrowHexInput.addEventListener('keydown', e => { if (e.key === 'Enter') setArrowColor(arrowHexInput.value); }); // Mirror toggle document.getElementById('ctrl-arrow-mirror').addEventListener('change', function() { state.arrowMirror = this.checked; document.getElementById('wrap-arrow-left').style.display = this.checked ? 'none' : ''; applyArrowStyles(); }); // Hide left input initially (mirror on by default) document.getElementById('wrap-arrow-left').style.display = 'none'; // Custom SVG inputs function handleSvgInput(id, errId, isRight) { const ta = document.getElementById(id); const err = document.getElementById(errId); ta.addEventListener('input', () => { const val = ta.value.trim(); if (!val) { err.textContent = ''; if (isRight) state.arrowSvgRight = ''; else state.arrowSvgLeft = ''; applyArrowStyles(); return; } if (!val.startsWith(' t.classList.remove('active')); state.arrowPreset = ''; applyArrowStyles(); }); } handleSvgInput('ctrl-arrow-svg-right', 'err-arrow-right', true); handleSvgInput('ctrl-arrow-svg-left', 'err-arrow-left', false); const closePresets = [ { name: "Default", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii00IDAgMTggMTciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxNyI+PGcgdHJhbnNmb3JtPSJyb3RhdGUoNDUpIj48cGF0aCBkPSJtMCAwaDd2LTdoNXY3aDd2NWgtN3Y3aC01di03aC03eiIgb3BhY2l0eT0iLjQiLz48cGF0aCBkPSJtMSAxaDd2LTdoM3Y3aDd2M2gtN3Y3aC0zdi03aC03eiIgZmlsbD0iI2ZmZiIvPjwvZz48L3N2Zz4=", svg: '' }, { name: "Cross", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48bGluZSB4MT0iMiIgeTE9IjIiIHgyPSIxNiIgeTI9IjE2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PGxpbmUgeDE9IjE2IiB5MT0iMiIgeDI9IjIiIHkyPSIxNiIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==", svg: '' }, { name: "Thin", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48bGluZSB4MT0iMiIgeTE9IjIiIHgyPSIxNiIgeTI9IjE2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PGxpbmUgeDE9IjE2IiB5MT0iMiIgeDI9IjIiIHkyPSIxNiIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==", svg: '' }, { name: "Circle", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48Y2lyY2xlIGN4PSI5IiBjeT0iOSIgcj0iOCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxsaW5lIHgxPSI1LjUiIHkxPSI1LjUiIHgyPSIxMi41IiB5Mj0iMTIuNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PGxpbmUgeDE9IjEyLjUiIHkxPSI1LjUiIHgyPSI1LjUiIHkyPSIxMi41IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48L3N2Zz4=", svg: '' }, { name: "Square", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48cmVjdCB4PSIxIiB5PSIxIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIyIiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjUuNSIgeTE9IjUuNSIgeDI9IjEyLjUiIHkyPSIxMi41IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48bGluZSB4MT0iMTIuNSIgeTE9IjUuNSIgeDI9IjUuNSIgeTI9IjEyLjUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==", svg: '' }, { name: "Plus", uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48bGluZSB4MT0iMiIgeTE9IjIiIHgyPSIxNiIgeTI9IjE2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48bGluZSB4MT0iMTYiIHkxPSIyIiB4Mj0iMiIgeTI9IjE2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48L3N2Zz4=", svg: '' }, ]; function colorizeCloseSvg(svg) { const c = state.closeColor; return svg .replace(/fill="[^"none][^"]*"/gi, 'fill="' + c + '"') .replace(/stroke="[^"none][^"]*"/gi, 'stroke="' + c + '"') .replace(/fill='[^'none][^']*'/gi, "fill='" + c + "'") .replace(/stroke='[^'none][^']*'/gi, "stroke='" + c + "'") .replace(/fill="currentColor"/gi, 'fill="' + c + '"') .replace(/stroke="currentColor"/gi, 'stroke="' + c + '"'); } function applyCloseStyles() { const el = document.querySelector('#lightbox-preview .w-lightbox-close'); if (!el) return; // SVG / preset if (state.closeSvg.trim()) { const uri = svgToDataUri(colorizeCloseSvg(state.closeSvg)); if (uri) el.style.backgroundImage = 'url("' + uri + '")'; } else { const preset = closePresets.find(p => p.name === state.closePreset) || closePresets[0]; if (preset.name === 'Default' && state.closeColor === '#ffffff') { el.style.backgroundImage = ''; } else { const uri = svgToDataUri(colorizeCloseSvg(preset.svg)); if (uri) el.style.backgroundImage = 'url("' + uri + '")'; } } // Size el.style.backgroundSize = state.closeSize + 'rem'; el.style.height = (state.closeSize * 2.3).toFixed(4) + 'rem'; // Opacity via dynamic style const opStyle = document.getElementById('close-opacity-style') || (() => { const s = document.createElement('style'); s.id = 'close-opacity-style'; document.head.appendChild(s); return s; })(); opStyle.textContent = '#lightbox-preview .w-lightbox-close { opacity: ' + (state.closeOpacity/100).toFixed(2) + '; }'; // Position — reset both sides first, then set el.style.right = ''; el.style.left = ''; if (state.closeSide === 'right') { el.style.right = state.closeOffsetX !== 0 ? state.closeOffsetX + 'rem' : ''; el.style.left = 'auto'; } else { el.style.left = state.closeOffsetX !== 0 ? state.closeOffsetX + 'rem' : '0'; el.style.right = 'auto'; } el.style.top = state.closeOffsetY !== 0 ? state.closeOffsetY + 'rem' : ''; updateModified(); } // Close preset tiles document.querySelectorAll('.close-preset-tile').forEach(tile => { tile.addEventListener('click', () => { document.querySelectorAll('.close-preset-tile').forEach(t => t.classList.remove('active')); tile.classList.add('active'); state.closePreset = tile.dataset.closePreset; state.closeSvg = ''; document.getElementById('ctrl-close-svg').value = ''; applyCloseStyles(); }); }); const firstCloseTile = document.querySelector('.close-preset-tile'); if (firstCloseTile) firstCloseTile.classList.add('active'); // Position quick-select buttons document.querySelectorAll('.close-pos-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.close-pos-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); state.closeSide = btn.dataset.pos === 'top-left' ? 'left' : 'right'; applyCloseStyles(); }); }); // Set top-right active by default const defaultPosBtn = document.querySelector('.close-pos-btn[data-pos="top-right"]'); if (defaultPosBtn) defaultPosBtn.classList.add('active'); // Wire sliders function wireClose(id, stateKey, displayId) { const slider = document.getElementById(id); const disp = document.getElementById(displayId); if (!slider) return; slider.addEventListener('input', () => { state[stateKey] = parseFloat(slider.value); if (disp) disp.value = slider.value; applyCloseStyles(); }); if (disp) { disp.addEventListener('change', () => { const raw = parseFloat(disp.value); if (isNaN(raw)) { disp.value = state[stateKey]; return; } state[stateKey] = raw; slider.value = Math.min(parseFloat(slider.max), Math.max(parseFloat(slider.min), raw)); applyCloseStyles(); }); } } wireClose('ctrl-close-x', 'closeOffsetX', 'val-close-x'); wireClose('ctrl-close-y', 'closeOffsetY', 'val-close-y'); wireClose('ctrl-close-size', 'closeSize', 'val-close-size'); wireClose('ctrl-close-opacity', 'closeOpacity', 'val-close-opacity'); // Active border color picker const activeBorderColorPicker = document.getElementById('ctrl-active-border-color'); const activeBorderHexInput = document.getElementById('ctrl-active-border-hex'); function setActiveBorderColor(hex) { hex = hex.replace(/[^#0-9a-fA-F]/g, ''); if (!hex.startsWith('#')) hex = '#' + hex; if (hex.length === 7) { state.activeBorderColor = hex.toLowerCase(); activeBorderColorPicker.value = hex; activeBorderHexInput.value = hex.toLowerCase(); applyThumbStyles(); } } activeBorderColorPicker.addEventListener('input', e => setActiveBorderColor(e.target.value)); activeBorderHexInput.addEventListener('input', e => setActiveBorderColor(e.target.value)); // Close color picker const closeColorPicker = document.getElementById('ctrl-close-color'); const closeHexInput = document.getElementById('ctrl-close-hex'); function setCloseColor(hex) { hex = hex.replace(/[^#0-9a-fA-F]/g, ''); if (!hex.startsWith('#')) hex = '#' + hex; if (hex.length === 7) { state.closeColor = hex.toLowerCase(); closeColorPicker.value = hex; closeHexInput.value = hex.toLowerCase(); applyCloseStyles(); } } closeColorPicker.addEventListener('input', e => setCloseColor(e.target.value)); closeHexInput.addEventListener('input', e => setCloseColor(e.target.value)); // Custom SVG document.getElementById('ctrl-close-svg').addEventListener('input', function() { const val = this.value.trim(); const err = document.getElementById('err-close-svg'); if (!val) { err.textContent = ''; state.closeSvg = ''; applyCloseStyles(); return; } if (!val.startsWith(' t.classList.remove('active')); state.closePreset = ''; applyCloseStyles(); }); // ── Tab switching ── const backdropPanel = document.querySelector('.sidebar-scroll > .section:first-child, #panel-backdrop'); const allSections = document.querySelectorAll('.sidebar-scroll > .section, .sidebar-scroll > #panel-thumbs'); document.querySelectorAll('.sidebar-tab:not(.disabled)').forEach(tab => { tab.addEventListener('click', () => { document.querySelectorAll('.sidebar-tab').forEach(t => t.classList.remove('active')); tab.classList.add('active'); activeTab = tab.dataset.tab; // Show/hide panels const scroll = document.querySelector('.sidebar-scroll'); // Hide all direct section children and named panels scroll.querySelectorAll(':scope > .section, :scope > div[id^="panel-"]').forEach(el => el.style.display = 'none'); if (activeTab === 'backdrop') { scroll.querySelectorAll(':scope > .section').forEach(el => el.style.display = ''); } else if (activeTab === 'close') { document.getElementById('panel-close').style.display = ''; } else if (activeTab === 'arrows') { document.getElementById('panel-arrows').style.display = ''; } else if (activeTab === 'thumbs') { document.getElementById('panel-thumbs').style.display = ''; } else if (activeTab === 'frame') { document.getElementById('panel-frame').style.display = ''; } }); }); // ── Thumb controls ── function wireThumb(id, stateKey, displayId) { const slider = document.getElementById(id); const disp = document.getElementById(displayId); const mn = parseFloat(slider.min), mx = parseFloat(slider.max); slider.addEventListener('input', () => { const v = parseFloat(slider.value); state[stateKey] = v; disp.value = v; applyThumbStyles(); }); disp.addEventListener('change', () => { const raw = parseFloat(disp.value); if (isNaN(raw)) { disp.value = state[stateKey]; return; } state[stateKey] = raw; slider.value = Math.min(mx, Math.max(mn, raw)); applyThumbStyles(); }); } // Strip alignment document.getElementById('ctrl-strip-align').addEventListener('change', function() { state.stripAlign = this.value; applyThumbStyles(); }); // Strip hide toggle document.getElementById('ctrl-strip-hide').addEventListener('change', function() { state.stripHide = this.checked; applyThumbStyles(); }); // Strip bg color const stripBgPicker = document.getElementById('ctrl-strip-bg-color'); const stripBgHex = document.getElementById('ctrl-strip-bg-hex'); function setStripBgColor(hex) { hex = hex.replace(/[^#0-9a-fA-F]/g, ''); if (!hex.startsWith('#')) hex = '#' + hex; if (hex.length === 7) { state.stripBgColor = hex.toLowerCase(); stripBgPicker.value = hex; stripBgHex.value = hex.toLowerCase(); applyThumbStyles(); } } stripBgPicker.addEventListener('input', e => setStripBgColor(e.target.value)); stripBgHex.addEventListener('input', e => setStripBgColor(e.target.value)); wireThumb('ctrl-strip-bg-opacity', 'stripBgOpacity', 'val-strip-bg-opacity'); document.getElementById('ctrl-strip-bg-enable').addEventListener('change', function() { state.stripBgEnable = this.checked; document.getElementById('strip-bg-controls').style.display = this.checked ? '' : 'none'; applyThumbStyles(); }); // Strip BG type toggle document.querySelectorAll('.strip-bg-type-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.strip-bg-type-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); state.stripBgType = btn.dataset.type; document.getElementById('strip-solid-controls').style.display = state.stripBgType === 'solid' ? '' : 'none'; document.getElementById('strip-gradient-controls').style.display = state.stripBgType === 'gradient' ? '' : 'none'; applyThumbStyles(); }); }); // Gradient pickers function wireGradientPickerReset(pickerId, hexId, val) { const picker = document.getElementById(pickerId); const hex = document.getElementById(hexId); if (hex) hex.value = val; if (picker && val.startsWith('#') && val.length === 7) picker.value = val; } function wireGradientPicker(pickerId, hexId, stateKey) { const picker = document.getElementById(pickerId); const hex = document.getElementById(hexId); function apply(val) { state[stateKey] = val; if (picker && val.startsWith('#') && val.length === 7) { picker.value = val; picker.style.visibility = ''; picker.style.width = ''; } if (hex) hex.value = val; applyThumbStyles(); } if (picker) picker.addEventListener('input', e => apply(e.target.value)); if (hex) hex.addEventListener('input', e => apply(e.target.value)); } wireGradientPicker('ctrl-strip-grad-from', 'ctrl-strip-grad-from-hex', 'stripGradFrom'); wireGradientPicker('ctrl-strip-grad-to', 'ctrl-strip-grad-to-hex', 'stripGradTo'); // From opacity (function() { const slider = document.getElementById('ctrl-strip-grad-from-opacity'); const disp = document.getElementById('val-strip-grad-from-opacity'); slider.addEventListener('input', () => { state.stripGradFromOpacity = parseFloat(slider.value); disp.value = slider.value; applyThumbStyles(); }); disp.addEventListener('change', () => { const v = parseFloat(disp.value); if (!isNaN(v)) { state.stripGradFromOpacity = v; slider.value = Math.min(100,Math.max(0,v)); applyThumbStyles(); } }); })(); document.getElementById('ctrl-strip-grad-dir').addEventListener('change', function() { state.stripGradDir = this.value; applyThumbStyles(); }); wireThumb('ctrl-thumb-width', 'thumbWidth', 'val-thumb-width'); wireThumb('ctrl-thumb-height', 'thumbHeight', 'val-thumb-height'); wireThumb('ctrl-thumb-radius', 'thumbRadius', 'val-thumb-radius'); wireThumb('ctrl-thumb-margin', 'thumbMargin', 'val-thumb-margin'); wireThumb('ctrl-thumb-paddingtb', 'thumbPaddingTB', 'val-thumb-paddingtb'); wireThumb('ctrl-active-opacity', 'activeOpacity', 'val-active-opacity'); wireThumb('ctrl-active-border-width', 'activeBorderWidth', 'val-active-border-width'); // ── Frame wires ── function wireFrame(id, stateKey, displayId) { const slider = document.getElementById(id); const disp = document.getElementById(displayId); if (!slider) return; slider.addEventListener('input', () => { state[stateKey] = parseFloat(slider.value); if (disp) disp.value = slider.value; applyFrameStyles(); }); if (disp) { disp.addEventListener('change', () => { const raw = parseFloat(disp.value); if (isNaN(raw)) { disp.value = state[stateKey]; return; } state[stateKey] = raw; const mn = parseFloat(slider.min), mx = parseFloat(slider.max); slider.value = Math.min(mx, Math.max(mn, raw)); applyFrameStyles(); }); } } wireFrame('ctrl-frame-radius', 'frameRadius', 'val-frame-radius'); document.getElementById('ctrl-full-size').addEventListener('change', function() { state.fullSize = this.checked; document.getElementById('full-size-fit-wrap').style.display = this.checked ? '' : 'none'; applyFrameStyles(); }); document.getElementById('ctrl-object-fit').addEventListener('change', function() { state.objectFit = this.value; applyThumbStyles(); }); // ── Export ── function buildCSS() { const sections = []; // ── Arrows ── const arrowPreset = arrowPresets.find(p => p.name === state.arrowPreset); const hasCustomRight = state.arrowSvgRight.trim().length > 0; let uriRight, uriLeft; if (hasCustomRight) { const cr = colorizeArrowSvg(state.arrowSvgRight); uriRight = svgToDataUri(cr); uriLeft = (!state.arrowMirror && state.arrowSvgLeft.trim()) ? svgToDataUri(colorizeArrowSvg(state.arrowSvgLeft)) : mirrorSvgUri(cr); } else if (arrowPreset) { const cr = colorizeArrowSvg(arrowPreset.svg); uriRight = svgToDataUri(cr); uriLeft = arrowPreset.svgLeft ? svgToDataUri(colorizeArrowSvg(arrowPreset.svgLeft)) : mirrorSvgUri(cr); } { let arrows = '/* Arrows */\n'; let hasArrow = false; if (state.arrowSize !== 1.5) { arrows += '.w-lightbox-control { background-size: ' + state.arrowSize + 'rem; }\n'; hasArrow = true; } const extra = state.arrowSize - 1.5; if (extra > 0) { const w = 'calc(4em + ' + extra.toFixed(4) + 'rem)'; arrows += '.w-lightbox-left, .w-lightbox-right { width: ' + w + '; }\n'; hasArrow = true; } if (state.arrowPosition !== 0) { arrows += '.w-lightbox-right { right: ' + state.arrowPosition + 'rem; }\n'; arrows += '.w-lightbox-left { left: ' + state.arrowPosition + 'rem; }\n'; hasArrow = true; } if (uriRight && !(arrowPreset && arrowPreset.name === 'Default' && state.arrowColor === '#ffffff')) { arrows += '.w-lightbox-right { background-image: url("' + uriRight + '"); }\n'; arrows += '.w-lightbox-left { background-image: url("' + uriLeft + '"); }\n'; hasArrow = true; } const op = (state.arrowOpacity / 100).toFixed(2); if (state.arrowOpacity !== 50) { arrows += '@media (min-width: 768px) {\n'; arrows += ' .w-lightbox-left, .w-lightbox-right { opacity: ' + op + '; }\n'; arrows += ' .w-lightbox-inactive, .w-lightbox-inactive:hover { opacity: 0; }\n}\n'; hasArrow = true; } if (hasArrow) sections.push(arrows.trim()); } // ── Close ── { const preset = closePresets.find(p => p.name === state.closePreset); const hasCustom = state.closeSvg.trim().length > 0; let closeRules = ''; if (hasCustom) { const uri = svgToDataUri(colorizeCloseSvg(state.closeSvg)); if (uri) closeRules += '.w-lightbox-close { background-image: url("' + uri + '"); }\n'; } else if (preset && !(preset.name === 'Default' && state.closeColor === '#ffffff')) { const uri = svgToDataUri(colorizeCloseSvg(preset.svg)); if (uri) closeRules += '.w-lightbox-close { background-image: url("' + uri + '"); }\n'; } if (state.closeSize !== 1) closeRules += '.w-lightbox-close { background-size: ' + state.closeSize + 'rem; height: ' + (state.closeSize * 2.3).toFixed(4) + 'rem; }\n'; if (state.closeOpacity !== 80) closeRules += '@media (min-width: 768px) { .w-lightbox-close { opacity: ' + (state.closeOpacity/100).toFixed(2) + '; } }\n'; if (state.closeSide === 'left') { closeRules += '.w-lightbox-close { left: ' + (state.closeOffsetX !== 0 ? state.closeOffsetX + 'rem' : '0') + '; right: auto; }\n'; } else if (state.closeOffsetX !== 0) { closeRules += '.w-lightbox-close { right: ' + state.closeOffsetX + 'rem; }\n'; } if (state.closeOffsetY !== 0) closeRules += '.w-lightbox-close { top: ' + state.closeOffsetY + 'rem; }\n'; if (closeRules) sections.push('/* Close button */\n' + closeRules.trim()); } // ── Backdrop ── { const r = parseInt(state.color.slice(1,3), 16); const g = parseInt(state.color.slice(3,5), 16); const b = parseInt(state.color.slice(5,7), 16); const a = (state.opacity / 100).toFixed(2); let backdrop = '/* Backdrop */\n.w-lightbox-backdrop {\n'; backdrop += ' background: rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ');\n'; if (state.blur > 0) { backdrop += ' backdrop-filter: blur(' + state.blur + 'px);\n'; backdrop += ' -webkit-backdrop-filter: blur(' + state.blur + 'px);\n'; } backdrop += '}'; sections.push(backdrop); } // ── Thumbnails + Strip (all together before push) ── { const viewH = 96 - state.thumbHeight - 2; const thumbRem = parseFloat(state.thumbRadius.toFixed(4)); let thumbs = '/* Thumbnails */\n'; thumbs += '/* viewHeight = 96 - ' + state.thumbHeight + 'vh(thumb) - 2vh(padding) = ' + viewH + 'vh */\n'; thumbs += '@media (min-width: 768px) {\n'; thumbs += ' .w-lightbox-group,\n'; thumbs += ' .w-lightbox-group .w-lightbox-view,\n'; thumbs += ' .w-lightbox-group .w-lightbox-view:before { height: ' + viewH + 'vh; }\n'; thumbs += ' .w-lightbox-group .w-lightbox-image { max-height: ' + viewH + 'vh; }\n'; thumbs += '}\n'; // Thumb item/thumbnail sizing thumbs += '.w-lightbox-strip { font-size: 0; }\n'; let itemRules = ' width: ' + state.thumbWidth + 'vh;\n padding-left: 0;\n padding-right: 0;\n'; if (state.thumbMargin !== 1) { if (state.thumbMargin > 0) { itemRules += ' margin-left: ' + state.thumbMargin + 'vh;\n'; itemRules += ' margin-right: ' + state.thumbMargin + 'vh;\n'; } } itemRules += ' padding-top: ' + state.thumbPaddingTB + 'vh;\n'; itemRules += ' padding-bottom: ' + state.thumbPaddingTB + 'vh;\n'; thumbs += '.w-lightbox-item {\n' + itemRules + '}\n'; thumbs += '.w-lightbox-thumbnail {\n'; thumbs += ' height: ' + state.thumbHeight + 'vh;\n'; if (state.thumbRadius > 0) thumbs += ' border-radius: ' + thumbRem + 'rem;\n'; thumbs += '}\n'; thumbs += '.w-lightbox-thumbnail-image { object-fit: cover; width: 100%; height: 100%; }'; if (state.activeOpacity !== 30) thumbs += '\n.w-lightbox-active { opacity: ' + (state.activeOpacity/100).toFixed(2) + '; }'; if (state.activeBorderWidth > 0) thumbs += '\n.w-lightbox-active .w-lightbox-thumbnail { border: ' + state.activeBorderWidth + 'rem solid ' + state.activeBorderColor + '; box-sizing: border-box; }'; // Strip alignment if (state.stripAlign && state.stripAlign !== 'center') { thumbs += '\n.w-lightbox-strip { text-align: ' + state.stripAlign + '; }'; } // Strip hide / background if (state.stripHide) { thumbs += '\n.w-lightbox-strip { display: none; }'; } else if (state.stripBgEnable) { if (state.stripBgType === 'gradient') { const fromHex = state.stripGradFrom; const fR = parseInt(fromHex.slice(1,3),16), fG = parseInt(fromHex.slice(3,5),16), fB = parseInt(fromHex.slice(5,7),16); const fromRgba = 'rgba(' + fR + ',' + fG + ',' + fB + ',' + (state.stripGradFromOpacity/100).toFixed(2) + ')'; thumbs += '\n.w-lightbox-strip { background: linear-gradient(' + state.stripGradDir + ', ' + fromRgba + ', ' + state.stripGradTo + '); }'; } else if (state.stripBgOpacity > 0) { const sr = parseInt(state.stripBgColor.slice(1,3),16); const sg = parseInt(state.stripBgColor.slice(3,5),16); const sb = parseInt(state.stripBgColor.slice(5,7),16); thumbs += '\n.w-lightbox-strip { background-color: rgba(' + sr + ',' + sg + ',' + sb + ',' + (state.stripBgOpacity/100).toFixed(2) + '); }'; } } sections.push(thumbs); } // ── Full size ── if (state.fullSize) { let fs = '/* Full size */\n'; fs += '.w-lightbox-content { height: 100vh; margin-top: 0; }\n'; fs += '.w-lightbox-group,\n.w-lightbox-group .w-lightbox-view,\n.w-lightbox-group .w-lightbox-view:before { height: 100vh; }\n'; fs += '.w-lightbox-view:before { display: none; }\n'; fs += '.w-lightbox-frame { display: block; width: 100%; height: 100vh; vertical-align: top; }\n'; fs += '.w-lightbox-figure { width: 100%; height: 100%; margin: 0; }\n'; fs += '.w-lightbox-image:not(.w-lightbox-thumbnail-image) { display: block; width: 100%; height: 100%; max-height: none; max-width: none; float: none; object-fit: ' + state.objectFit + '; }'; sections.push(fs); } // ── Frame ── if (state.frameRadius > 0) { let frame = '/* Frame */\n.w-lightbox-frame {\n'; frame += ' border-radius: ' + state.frameRadius + 'rem;\n'; frame += ' overflow: hidden;\n}'; sections.push(frame); } sections.unshift('/* Built with Lightbox Customizer by formburg.com */'); return sections.join('\n\n'); } function syntaxHighlight(css) { return css .replace(/(\/\*[^*]*\*\/)/g, '$1') .replace(/(\.[\w-]+\s*\{)/g, '$1') .replace(/(\})/g, '$1') .replace(/([\w-]+)(\s*:)/g, '$1$2') .replace(/:\s*([^;{}\n]+)(;)/g, ': $1;'); } function openExport() { const css = buildCSS(); const wrapped = ''; // Display: escape < > so browser renders them as text const display = wrapped.replace(//g, '>'); document.getElementById('export-code').innerHTML = syntaxHighlight(display); document.getElementById('modal').classList.add('open'); document.getElementById('copy-btn').innerHTML = ' Copy code'; document.getElementById('copy-btn').classList.remove('copied'); } function closeExport() { document.getElementById('modal').classList.remove('open'); } function handleModalClick(e) { if (e.target === document.getElementById('modal')) closeExport(); } function copyCode() { const css = ''; const btn = document.getElementById('copy-btn'); function onSuccess() { btn.innerHTML = '✓ Copied to clipboard!'; btn.classList.add('copied'); setTimeout(() => { btn.innerHTML = ' Copy code'; btn.classList.remove('copied'); }, 2500); } // Try modern clipboard API first if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(css).then(onSuccess).catch(() => fallbackCopy(css, onSuccess)); } else { fallbackCopy(css, onSuccess); } } function fallbackCopy(text, onSuccess) { const ta = document.createElement('textarea'); ta.value = text; ta.style.cssText = 'position:fixed;top:-9999px;left:-9999px;opacity:0;'; document.body.appendChild(ta); ta.focus(); ta.select(); try { document.execCommand('copy'); onSuccess(); } catch(e) { alert('Copy failed — please select and copy the code manually.'); } document.body.removeChild(ta); } // ── Modified indicators + label reset ── function updateModified() { document.querySelectorAll('.prop-label[data-key]').forEach(lbl => { const key = lbl.dataset.key; const def = lbl.dataset.default; const cur = state[key]; const changed = def.startsWith('#') ? cur.toLowerCase() !== def.toLowerCase() : isNaN(parseFloat(def)) ? String(cur) !== String(def) : Math.abs(parseFloat(cur) - parseFloat(def)) > 0.001; lbl.classList.toggle('modified', changed); }); } document.querySelectorAll('.prop-label[data-key]').forEach(lbl => { lbl.title = 'Click to reset to default'; lbl.addEventListener('click', () => { const key = lbl.dataset.key; const def = lbl.dataset.default; const prop = lbl.closest('.prop'); if (def.startsWith('#')) { state[key] = def; if (key === 'arrowColor') setArrowColor(def); else if (key === 'closeColor') setCloseColor(def); else if (key === 'activeBorderColor') setActiveBorderColor(def); else if (key === 'stripBgColor') setStripBgColor(def); } else if (isNaN(parseFloat(def))) { // String/select value (including color strings like 'transparent') state[key] = def; const sel = prop ? prop.querySelector('select') : null; if (sel) sel.value = def; // Color fields that are strings if (key === 'color') { setColor(def); } else if (key === 'stripGradFrom') { wireGradientPickerReset('ctrl-strip-grad-from', 'ctrl-strip-grad-from-hex', def); applyThumbStyles(); } else if (key === 'stripGradTo') { wireGradientPickerReset('ctrl-strip-grad-to', 'ctrl-strip-grad-to-hex', def); applyThumbStyles(); } else if (key === 'stripGradDir') { applyThumbStyles(); } else if (['objectFit'].includes(key)) applyFrameStyles(); else if (['stripAlign'].includes(key)) applyThumbStyles(); else applyStyles(); } else { state[key] = parseFloat(def); const slider = prop ? prop.querySelector('input[type="range"]') : null; const numInput = prop ? prop.querySelector('input[type="number"]') : null; if (slider) slider.value = def; if (numInput) numInput.value = def; const thumbKeys = ['thumbWidth','thumbHeight','thumbRadius','thumbMargin','thumbPaddingTB','stripBgOpacity','activeOpacity','activeBorderWidth','stripGradFromOpacity']; const closeKeys = ['closeOffsetX','closeOffsetY','closeSize','closeOpacity']; const arrowKeys = ['arrowPosition','arrowSize','arrowOpacity']; const frameKeys = ['frameRadius']; if (thumbKeys.includes(key)) { if (key === 'stripGradFromOpacity') { const sl = document.getElementById('ctrl-strip-grad-from-opacity'); const dv = document.getElementById('val-strip-grad-from-opacity'); if (sl) sl.value = def; if (dv) dv.value = def; } applyThumbStyles(); } else if (closeKeys.includes(key)) applyCloseStyles(); else if (arrowKeys.includes(key)) applyArrowStyles(); else if (frameKeys.includes(key)) applyFrameStyles(); else applyStyles(); } updateModified(); }); }); // Patch applyStyles + applyThumbStyles to call updateModified const _origApplyStyles = applyStyles; applyStyles = function() { _origApplyStyles(); updateModified(); }; const _origApplyThumb = applyThumbStyles; applyThumbStyles = function() { _origApplyThumb(); updateModified(); }; const _origApplyFrame = applyFrameStyles; applyFrameStyles = function() { _origApplyFrame(); updateModified(); }; // ── Init ── applyStyles();