Microsoft Store Lightbox Gallery

A minimalist lightbox gallery for Google Play Store with multi-image panorama viewing, dynamic resolution, gap controls, and saved settings.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Microsoft Store Lightbox Gallery
// @namespace    MSStoreImageViewer
// @version      4.1
// @description  A minimalist lightbox gallery for Google Play Store with multi-image panorama viewing, dynamic resolution, gap controls, and saved settings.
// @author       MochAdiMR
// @match        https://apps.microsoft.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=apps.microsoft.com
// @grant        none
// @connect      none
// @supportURL   https://buymeacoffee.com/mochadimr
// @homepageURL  https://github.com/adimuhamad/
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let albumImages = [], currentIndex = 0;
    let scale = 1, translateX = 0, translateY = 0;
    let isDragging = false, wasDragged = false;
    let startX = 0, startY = 0, downX = 0, downY = 0;

    const icoExpand = '<svg viewBox="0 0 448 512"><path d="M32 32C14 32 0 46 0 64v96a32 32 0 1 0 64 0V96h64a32 32 0 1 0 0-64zm32 320a32 32 0 1 0-64 0v96c0 18 14 32 32 32h96a32 32 0 1 0 0-64H64zM320 32a32 32 0 1 0 0 64h64v64a32 32 0 1 0 64 0V64c0-18-14-32-32-32zm128 320a32 32 0 1 0-64 0v64h-64a32 32 0 1 0 0 64h96c18 0 32-14 32-32z"/></svg>';
    const icoCompress = '<svg viewBox="0 0 448 512"><path d="M160 64a32 32 0 1 0-64 0v64H32a32 32 0 1 0 0 64h96c18 0 32-14 32-32zM32 320a32 32 0 1 0 0 64h64v64a32 32 0 1 0 0 64v-96c0-18-14-32-32-32zM352 64a32 32 0 1 0-64 0v96c0 18 14 32 32 32h96a32 32 0 1 0 0-64h-64zm-32 256c-18 0-32 14-32 32v96a32 32 0 1 0 64 0v-64h64a32 32 0 1 0 0-64z"/></svg>';
    const icoKeyboard = '<svg viewBox="0 0 576 512"><path d="M64 64C29 64 0 93 0 128v256c0 35 29 64 64 64h448c35 0 64-29 64-64V128c0-35-29-64-64-64zm16 64h32q15 1 16 16v32q-1 15-16 16H80q-15-1-16-16v-32q1-15 16-16M64 240q1-15 16-16h32q15 1 16 16v32q-1 15-16 16H80q-15-1-16-16zm112-112h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16v-32q1-15 16-16m-16 112q1-15 16-16h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16zm16 80h224q15 1 16 16v32q-1 15-16 16H176q-15-1-16-16v-32q1-15 16-16m80-176q1-15 16-16h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16zm16 80h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16v-32q1-15 16-16m80-80q1-15 16-16h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16zm16 80h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16m80-80q1-15 16-16h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16zm16 80h32q15 1 16 16v32q-1 15-16 16h-32q-15-1-16-16v-32q1-15 16-16"/></svg>';
    const icoEye = '<svg viewBox="0 0 576 512"><path d="M288 32c-81 0-145 37-193 81-46 43-78 95-93 131q-4 12 0 24c15 36 47 88 93 131 48 44 112 81 193 81s146-37 193-81c46-43 78-95 93-131q5-12 0-24c-15-36-47-88-93-131-47-44-112-81-193-81M144 256a144 144 0 1 1 288 0 144 144 0 1 1-288 0m144-64a64 64 0 0 1-96 56q-1 16 3 33a96 96 0 1 0 85-121q8 15 8 32"/></svg>';
    const icoEyeSlash = '<svg viewBox="0 0 576 512"><path d="M41-25c-9-9-25-9-34 0S-2 0 7 9l528 528c9 10 25 10 34 0s9-24 0-34l-97-96 9-7c46-44 78-96 93-131q5-12 0-25c-15-36-47-88-93-131-48-44-112-81-193-81-57 0-106 18-146 44zm164 164q36-26 83-27a144 144 0 0 1 117 228l-34-35a96 96 0 0 0-108-142l-24 10zm120 256a143 143 0 0 1-181-139q0-19 5-37l-80-80c-32 37-55 76-66 105q-6 12 0 24c14 36 46 88 93 131 47 44 111 81 192 81q56-1 102-21z"/></svg>';
    const icoXmark = '<svg viewBox="0 0 384 512"><path d="M55 73a32 32 0 0 0-45 46l137 137L10 393a32 32 0 0 0 45 46l138-138 137 138a32 32 0 0 0 45-46L238 256l137-137a32 32 0 0 0-45-46L193 211z"/></svg>';
    const icoAngleLeft = '<svg viewBox="0 0 320 512"><path d="M9 233a32 32 0 0 0 0 46l192 192a32 32 0 0 0 46-46L77 256 247 87a32 32 0 0 0-46-46z"/></svg>';
    const icoAngleRight = '<svg viewBox="0 0 320 512"><path d="M311 233c13 13 13 33 0 46L119 471a32 32 0 0 1-45-46l169-169L74 87a32 32 0 0 1 45-46z"/></svg>';
    const icoGear = '<svg viewBox="0 0 512 512"><path d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"/></svg>';

    // Inject Stylesheet
    const style = document.createElement('style');
    style.innerHTML = `.ms-lb-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; height: 100dvh; background: rgba(10,12,16,0.97); z-index: 999999; opacity: 0; pointer-events: none; transition: opacity 0.3s; font-family: "Segoe UI", Roboto, Arial, sans-serif; color: #c9d1d9; user-select: none; } .ms-lb-overlay.active { pointer-events: auto; opacity: 1; } .ms-lb-topbar, .ms-lb-thumbs-window { transition: opacity 0.25s, visibility 0.25s; opacity: 1; visibility: visible; position: absolute; left: 0; width: 100%; z-index: 1000002; } .ms-lb-topbar { top: 0; display: flex; justify-content: space-between; align-items: center; padding: 5px 12px; background: rgba(0,0,0,0.88); box-sizing: border-box; } .ms-lb-thumbs-window { bottom: 0; background: rgba(13,17,23,0.95); border-top: 1px solid #30363d; padding: 4px 0; display: flex; justify-content: center; } .ms-lb-overlay.zoomed-mode .ms-lb-topbar, .ms-lb-overlay.zoomed-mode .ms-lb-thumbs-window, .ms-lb-overlay.ui-hidden .ms-lb-topbar, .ms-lb-overlay.ui-hidden .ms-lb-thumbs-window { opacity: 0; visibility: hidden; pointer-events: none; } .ms-lb-meta { display: flex; flex-direction: column; max-width: 50%; } #ms-lb-caption { font-size: 13px; font-weight: 500; color: #fff; line-height: 1.2; } .ms-lb-tech-info { font-size: 11px; color: #8b949e; display: flex; gap: 6px; margin-top: 3px; } .ms-lb-tech-info span { background: #21262d; padding: 0px 4px; border-radius: 4px; border: 1px solid #30363d; } .ms-lb-controls { display: flex; align-items: center; gap: 6px; } .ms-lb-main-view { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; z-index: 1000000; display: flex; justify-content: center; align-items: center; box-sizing: border-box; padding-top: 38px; padding-bottom: 54px; transition: padding 0.2s ease; touch-action: none; } .ms-lb-overlay.zoomed-mode .ms-lb-main-view, .ms-lb-overlay.ui-hidden .ms-lb-main-view { padding: 0; } .ms-lb-img-container { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; gap: 0px; transition: transform 0.1s ease-out; } .ms-lb-img-container img { max-width: 100%; height: 100%; object-fit: contain; cursor: zoom-in; margin: 0; padding: 0; display: block; } .ms-lb-btn svg { width: 11px; height: 11px; fill: currentColor; display: inline-block; vertical-align: middle; } .ms-lb-nav svg { width: 15px; height: 15px; } .ms-lb-btn { background: rgba(255, 255, 255, 0.1); color: #fff; border: none; border-radius: 4px; padding: 0 8px; height: 24px; font-size: 11px; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 5px; box-sizing: border-box; transition: background 0.2s; } .ms-lb-btn:hover, #ms-lb-unhide-btn:hover { background: rgba(255, 255, 255, 0.2); } #ms-lb-close-btn { width: 24px; padding: 0; background: rgba(255,0,0,0.2); } #ms-lb-close-btn:hover { background: rgba(255,0,0,0.5); } #ms-lb-close-btn svg { width: 10px; height: 10px; } .ms-lb-select { background: #202124; color: #fff; border: 1px solid #3c4043; border-radius: 4px; padding: 0 4px; height: 24px; font-size: 11px; cursor: pointer; outline: none; box-sizing: border-box; } .ms-lb-select:hover { border-color: #8b949e; background: #2d2e30; } .ms-lb-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 38px; height: 38px; border-radius: 50%; z-index: 1000001; padding: 0; background: rgba(0,0,0,0.5); } .ms-lb-nav:hover { background: rgba(0,0,0,0.8); } .ms-lb-prev { left: 12px; } .ms-lb-next { right: 12px; } .ms-lb-thumbs-container { display: flex; gap: 6px; overflow-x: auto; max-width: 95%; padding: 2px; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; } .ms-lb-thumbs-container::-webkit-scrollbar { height: 3px; } .ms-lb-thumbs-container::-webkit-scrollbar-thumb { background: #5f6368; border-radius: 2px; } .ms-lb-thumb { height: 38px; min-width: 24px; max-width: 70px; border-radius: 4px; border: 2px solid transparent; cursor: pointer; opacity: 0.5; transition: 0.2s; flex-shrink: 0; box-sizing: border-box; object-fit: contain; background: #000; } .ms-lb-thumb:hover, .ms-lb-thumb.active { opacity: 1; border-color: #0078d4; } #ms-lb-unhide-btn { position: absolute; top: 6px; right: 12px; z-index: 1000007; display: none; } .ms-lb-overlay.ui-hidden #ms-lb-unhide-btn { display: flex; } .ms-lb-modal { position: absolute; top: 45px; right: 20px; background: #202124; border: 1px solid #3c4043; border-radius: 8px; padding: 12px; width: 220px; box-shadow: 0 6px 24px rgba(0,0,0,0.6); display: none; z-index: 1000006; font-size: 12px; } .ms-lb-modal.active { display: block; } .ms-lb-modal-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; border-bottom: 1px dashed #3c4043; padding-bottom: 6px; } .ms-lb-modal-row:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } .ms-lb-key { background: #3c4043; border-radius: 4px; padding: 1px 5px; font-weight: bold; font-family: monospace; color: #fff; } `;
    document.head.appendChild(style);

    // Build DOM
    const overlay = document.createElement('div');
    overlay.className = 'ms-lb-overlay';
    overlay.innerHTML = `<div class="ms-lb-main-view"><button class="ms-lb-btn ms-lb-nav ms-lb-prev">${icoAngleLeft}</button><div class="ms-lb-img-container"></div><button class="ms-lb-btn ms-lb-nav ms-lb-next">${icoAngleRight}</button></div><div class="ms-lb-topbar"><div class="ms-lb-meta"><div id="ms-lb-caption">Loading...</div><div class="ms-lb-tech-info"><span id="ms-lb-dims">-</span><span id="ms-lb-format">-</span><span id="ms-lb-size">-</span></div></div><div class="ms-lb-controls"><button class="ms-lb-btn" id="ms-lb-toggle-ui-btn">${icoEyeSlash} Hide UI</button><button class="ms-lb-btn" id="ms-lb-fs-btn">${icoExpand} Expand</button><button class="ms-lb-btn" id="ms-lb-settings-btn">${icoGear} Settings</button><button class="ms-lb-btn" id="ms-lb-help-btn">${icoKeyboard} Shortcuts</button><button class="ms-lb-btn" id="ms-lb-close-btn">${icoXmark}</button></div></div><div class="ms-lb-thumbs-window"><div class="ms-lb-thumbs-container"></div></div><button class="ms-lb-btn" id="ms-lb-unhide-btn">${icoEye} Show UI</button><div class="ms-lb-modal" id="ms-lb-help-modal"><div style="font-weight:700;margin-bottom:10px;color:#0078d4;text-align:center">Keyboard Shortcuts</div><div class="ms-lb-modal-row"><span>Next Image</span><span class="ms-lb-key">→</span></div><div class="ms-lb-modal-row"><span>Prev Image</span><span class="ms-lb-key">←</span></div><div class="ms-lb-modal-row"><span>Fullscreen</span><span class="ms-lb-key">F</span></div><div class="ms-lb-modal-row"><span>Toggle UI</span><span class="ms-lb-key">H</span></div><div class="ms-lb-modal-row"><span>Close Gallery</span><span class="ms-lb-key">ESC</span></div></div><div class="ms-lb-modal" id="ms-lb-settings-modal"><div style="font-weight:700;margin-bottom:12px;color:#0078d4;text-align:center">Gallery Settings</div><div class="ms-lb-modal-row"><span>View Layout</span><select id="ms-lb-view-count" class="ms-lb-select"><option value="1">1 Image</option><option value="2">2 Images</option><option value="3">3 Images</option></select></div><div class="ms-lb-modal-row"><span>Resolution</span><select id="ms-lb-res-toggle" class="ms-lb-select"><option value="high">High Res</option><option value="med">Med Res</option><option value="low">Low Res</option></select></div><div class="ms-lb-modal-row"><span>Image Gap</span><select id="ms-lb-gap-toggle" class="ms-lb-select"><option value="none">No Gap</option><option value="default">Default Gap</option></select></div></div>`;
    document.body.appendChild(overlay);

    const imgContainer = overlay.querySelector('.ms-lb-img-container');
    const thumbContainer = overlay.querySelector('.ms-lb-thumbs-container');
    const helpModal = document.getElementById('ms-lb-help-modal');
    const settingsModal = document.getElementById('ms-lb-settings-modal');
    const unhideBtn = document.getElementById('ms-lb-unhide-btn');
    const viewCountSelect = document.getElementById('ms-lb-view-count');
    const resToggleSelect = document.getElementById('ms-lb-res-toggle');
    const gapToggleSelect = document.getElementById('ms-lb-gap-toggle');

    // Retrieve saved user preferences
    const savedViewCount = localStorage.getItem('ms_lb_view_count') || '1';
    const savedResToggle = localStorage.getItem('ms_lb_res_toggle') || 'high';
    const savedGapToggle = localStorage.getItem('ms_lb_gap_toggle') || 'none';

    viewCountSelect.value = savedViewCount;
    resToggleSelect.value = savedResToggle;
    gapToggleSelect.value = savedGapToggle;

    function saveSettings() {
        localStorage.setItem('ms_lb_view_count', viewCountSelect.value);
        localStorage.setItem('ms_lb_res_toggle', resToggleSelect.value);
        localStorage.setItem('ms_lb_gap_toggle', gapToggleSelect.value);
        updateLightbox();
    }

    viewCountSelect.addEventListener('change', saveSettings);
    resToggleSelect.addEventListener('change', saveSettings);
    gapToggleSelect.addEventListener('change', saveSettings);

    overlay.querySelector('.ms-lb-topbar').addEventListener('click', (e) => e.stopPropagation());
    overlay.querySelector('.ms-lb-thumbs-window').addEventListener('click', (e) => e.stopPropagation());
    helpModal.addEventListener('click', (e) => e.stopPropagation());
    settingsModal.addEventListener('click', (e) => e.stopPropagation());
    unhideBtn.addEventListener('click', (e) => { e.stopPropagation(); toggleUIVisibility(); });

    // Build dynamic high-resolution URLs for Microsoft Store CDN
    function getDynamicResUrl(url, resLevel) {
        if (!url) return "";
        let base = url.split('?')[0];
        if (resLevel === 'high') return base + '?h=1080';
        if (resLevel === 'med') return base + '?h=720';
        return base + '?h=380';
    }

    function updateLightbox() {
        if (albumImages.length === 0) return;
        resetZoomAndDrag();

        imgContainer.innerHTML = '';
        const maxPhotosToShow = parseInt(viewCountSelect.value) || 1;
        const resMode = resToggleSelect.value;
        const gapMode = gapToggleSelect.value;

        imgContainer.style.gap = gapMode === 'default' ? '8px' : '0px';

        document.getElementById('ms-lb-caption').textContent = `Screenshot ${currentIndex + 1} (${currentIndex + 1} / ${albumImages.length})`;
        document.getElementById('ms-lb-dims').textContent = '-';
        document.getElementById('ms-lb-format').textContent = '-';
        document.getElementById('ms-lb-size').textContent = '...';

        for (let i = 0; i < maxPhotosToShow; i++) {
            let targetIdx = (currentIndex + i) % albumImages.length;
            if (i > 0 && targetIdx === currentIndex) break;

            const baseSource = albumImages[targetIdx];
            const imgEl = document.createElement('img');
            imgEl.draggable = false;

            imgEl.src = getDynamicResUrl(baseSource, resMode);
            imgEl.style.width = maxPhotosToShow === 1 ? '100%' : 'auto';

            if (i === 0) {
                imgEl.onload = () => {
                    document.getElementById('ms-lb-dims').textContent = `${imgEl.naturalWidth}x${imgEl.naturalHeight}`;
                    let detectedFormat = "JPG";
                    if (imgEl.src.toLowerCase().includes('.png')) detectedFormat = "PNG";
                    else if (imgEl.src.toLowerCase().includes('.webp')) detectedFormat = "WEBP";
                    document.getElementById('ms-lb-format').textContent = detectedFormat;
                };

                fetch(imgEl.src, { method: 'HEAD' }).then(res => {
                    const bytes = res.headers.get('content-length');
                    const contentType = res.headers.get('content-type');

                    if (contentType) {
                        if (contentType.includes('png')) document.getElementById('ms-lb-format').textContent = "PNG";
                        else if (contentType.includes('webp')) document.getElementById('ms-lb-format').textContent = "WEBP";
                        else if (contentType.includes('jpeg') || contentType.includes('jpg')) document.getElementById('ms-lb-format').textContent = "JPG";
                    }

                    if (bytes) {
                        const mb = bytes / (1024 * 1024);
                        if (mb >= 1) {
                            document.getElementById('ms-lb-size').textContent = mb.toFixed(2) + " MB";
                        } else {
                            document.getElementById('ms-lb-size').textContent = (bytes / 1024).toFixed(0) + " KB";
                        }
                    } else {
                        document.getElementById('ms-lb-size').textContent = '-';
                    }
                }).catch(() => {
                    document.getElementById('ms-lb-size').textContent = '-';
                });
            }

            imgContainer.appendChild(imgEl);
        }

        overlay.querySelector('.ms-lb-prev').style.display = albumImages.length <= 1 ? 'none' : 'flex';
        overlay.querySelector('.ms-lb-next').style.display = albumImages.length <= 1 ? 'none' : 'flex';

        updateThumbnails();
    }

    function applyTransform() {
        imgContainer.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`;
        if (scale > 1) overlay.classList.add('zoomed-mode'); else overlay.classList.remove('zoomed-mode');
    }

    function resetZoomAndDrag() { scale = 1; translateX = 0; translateY = 0; imgContainer.style.cursor = 'zoom-in'; applyTransform(); }

    imgContainer.addEventListener('pointerdown', (e) => {
        e.preventDefault(); e.stopPropagation(); downX = e.clientX; downY = e.clientY; wasDragged = false;
        if (scale > 1) { isDragging = true; startX = e.clientX - translateX; startY = e.clientY - translateY; imgContainer.style.cursor = 'grabbing'; imgContainer.setPointerCapture(e.pointerId); }
    });
    imgContainer.addEventListener('pointermove', (e) => {
        if (!isDragging) return;
        if (Math.abs(e.clientX - downX) > 5 || Math.abs(e.clientY - downY) > 5) wasDragged = true;
        translateX = e.clientX - startX; translateY = e.clientY - startY; applyTransform();
    });
    imgContainer.addEventListener('pointerup', (e) => { if (isDragging) { isDragging = false; imgContainer.style.cursor = 'grab'; imgContainer.releasePointerCapture(e.pointerId); } });
    imgContainer.addEventListener('click', (e) => { e.stopPropagation(); if (wasDragged) { wasDragged = false; return; } if (scale === 1) { scale = 2.5; imgContainer.style.cursor = 'grab'; } else { resetZoomAndDrag(); } applyTransform(); });

    overlay.addEventListener('wheel', (e) => {
        if (!overlay.classList.contains('active')) return;
        e.preventDefault(); scale = e.deltaY < 0 ? Math.min(scale + 0.15, 6) : Math.max(scale - 0.15, 1);
        if (scale === 1) { translateX = 0; translateY = 0; }
        imgContainer.style.cursor = scale > 1 ? 'grab' : 'zoom-in'; applyTransform();
    }, { passive: false });

    function buildThumbnails() {
        thumbContainer.innerHTML = '';
        albumImages.forEach((sourceUrl, index) => {
            const thumb = document.createElement('img');
            thumb.src = sourceUrl;
            thumb.className = 'ms-lb-thumb';
            thumb.addEventListener('click', (e) => { e.stopPropagation(); currentIndex = index; updateLightbox(); });
            thumbContainer.appendChild(thumb);
        });
    }

    function updateThumbnails() {
        const thumbs = thumbContainer.querySelectorAll('.ms-lb-thumb');
        thumbs.forEach((t, idx) => {
            if (idx === currentIndex) { t.classList.add('active'); t.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); }
            else { t.classList.remove('active'); }
        });
    }

    function toggleUIVisibility() {
        const isHidden = overlay.classList.toggle('ui-hidden');
        document.getElementById('ms-lb-toggle-ui-btn').innerHTML = isHidden ? icoEye + ' Show UI' : icoEyeSlash + ' Hide UI';
    }

    function toggleFullscreen(e) {
        if(e) e.stopPropagation();
        const fsBtn = document.getElementById('ms-lb-fs-btn');
        if (!document.fullscreenElement) {
            overlay.requestFullscreen();
            fsBtn.innerHTML = icoCompress + ' Collapse';
        } else {
            document.exitFullscreen();
            fsBtn.innerHTML = icoExpand + ' Expand';
        }
    }

    function openLightbox() {
        overlay.classList.add('active');
        document.body.style.overflow = 'hidden';
    }

    function closeLightbox() {
        helpModal.classList.remove('active');
        settingsModal.classList.remove('active');

        if (overlay.classList.contains('ui-hidden')) { toggleUIVisibility(); return; }
        overlay.classList.remove('active');
        overlay.classList.remove('ui-hidden');

        document.getElementById('ms-lb-toggle-ui-btn').innerHTML = icoEyeSlash + ' Hide UI';
        document.body.style.overflow = ''; if (document.fullscreenElement) document.exitFullscreen();
        imgContainer.innerHTML = '';
    }

    document.addEventListener('click', function(event) {
        const path = event.composedPath();

        let targetImg = null;
        let viewerHost = null;

        for (let i = 0; i < path.length; i++) {
            const el = path[i];

            if (el && el.tagName === 'IMG' && el.classList.contains('screenshot')) {
                targetImg = el;
            }

            if (el && el.tagName === 'SCREENSHOT-VIEWER') {
                viewerHost = el;
                break;
            }
        }

        if (targetImg && viewerHost && viewerHost.shadowRoot) {
            event.preventDefault();
            event.stopPropagation();
            event.stopImmediatePropagation();

            const rawImages = Array.from(viewerHost.shadowRoot.querySelectorAll('img.screenshot, .carousel-item img'));

            if (rawImages.length === 0) return;

            albumImages = rawImages.map(img => img.src || img.getAttribute('data-src') || "");

            currentIndex = rawImages.indexOf(targetImg);
            if (currentIndex === -1) currentIndex = 0;

            openLightbox();
            buildThumbnails();
            updateLightbox();
        }
    }, true); // Tetap pertahankan fase penangkapan (true)

    document.getElementById('ms-lb-close-btn').addEventListener('click', (e) => { e.stopPropagation(); overlay.classList.remove('ui-hidden'); closeLightbox(); });
    document.getElementById('ms-lb-toggle-ui-btn').addEventListener('click', (e) => { e.stopPropagation(); toggleUIVisibility(); });
    document.getElementById('ms-lb-fs-btn').addEventListener('click', toggleFullscreen);

    document.getElementById('ms-lb-settings-btn').addEventListener('click', (e) => {
        e.stopPropagation();
        settingsModal.classList.toggle('active');
        helpModal.classList.remove('active');
    });
    document.getElementById('ms-lb-help-btn').addEventListener('click', (e) => {
        e.stopPropagation();
        helpModal.classList.toggle('active');
        settingsModal.classList.remove('active');
    });

    overlay.addEventListener('click', (e) => {
        if (e.target === overlay || e.target.classList.contains('ms-lb-main-view') || e.target.classList.contains('ms-lb-img-container')) {
            closeLightbox();
        } else {
            helpModal.classList.remove('active');
            settingsModal.classList.remove('active');
        }
    });

    overlay.querySelector('.ms-lb-prev').addEventListener('click', (e) => { e.stopPropagation(); currentIndex = (currentIndex - 1 + albumImages.length) % albumImages.length; updateLightbox(); });
    overlay.querySelector('.ms-lb-next').addEventListener('click', (e) => { e.stopPropagation(); currentIndex = (currentIndex + 1) % albumImages.length; updateLightbox(); });

    document.addEventListener('keydown', function(event) {
        if (!overlay.classList.contains('active')) return;
        if ([' ', 'Enter'].includes(event.key)) { event.preventDefault(); return; }
        const key = event.key.toLowerCase();

        if (event.key === 'Escape') {
            if (settingsModal.classList.contains('active') || helpModal.classList.contains('active')) {
                settingsModal.classList.remove('active'); helpModal.classList.remove('active'); return;
            }
            overlay.classList.remove('ui-hidden'); closeLightbox();
        }
        else if (key === 'h') { toggleUIVisibility(); }
        else if (key === 'f') { toggleFullscreen(event); }
        else if (event.key === 'ArrowRight') { currentIndex = (currentIndex + 1) % albumImages.length; updateLightbox(); }
        else if (event.key === 'ArrowLeft') { currentIndex = (currentIndex - 1 + albumImages.length) % albumImages.length; updateLightbox(); }
    });
})();