PerfectGonzo: View Photos Popup & Carousel (High Res, Fit Entire Image, Grid Toggle)

Adds a button that opens a fullscreen grid of high-res photos. Clicking a photo opens a carousel overlay that scales the image to fit without cropping. In the carousel, a "Grid View" button lets you return to the grid.

// ==UserScript==
// @name         PerfectGonzo: View Photos Popup & Carousel (High Res, Fit Entire Image, Grid Toggle)
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  Adds a button that opens a fullscreen grid of high-res photos. Clicking a photo opens a carousel overlay that scales the image to fit without cropping. In the carousel, a "Grid View" button lets you return to the grid.
// @match        *://*.perfectgonzo.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Function to create the grid popup gallery
    function createPopupGallery(imageUrls) {
        // Create overlay for grid gallery
        const overlay = document.createElement('div');
        overlay.id = 'pgPhotoOverlay';
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
        overlay.style.zIndex = '10000';
        overlay.style.overflowY = 'auto';
        overlay.style.padding = '20px';

        // Close button for grid gallery
        const closeBtn = document.createElement('button');
        closeBtn.innerText = 'X';
        closeBtn.style.position = 'fixed';
        closeBtn.style.top = '20px';
        closeBtn.style.right = '20px';
        closeBtn.style.fontSize = '24px';
        closeBtn.style.background = 'transparent';
        closeBtn.style.color = '#fff';
        closeBtn.style.border = 'none';
        closeBtn.style.cursor = 'pointer';
        closeBtn.style.zIndex = '10001';
        overlay.appendChild(closeBtn);

        closeBtn.addEventListener('click', function() {
            document.body.removeChild(overlay);
        });

        // Gallery container (grid layout)
        const galleryContainer = document.createElement('div');
        galleryContainer.style.display = 'flex';
        galleryContainer.style.flexWrap = 'wrap';
        galleryContainer.style.justifyContent = 'center';
        galleryContainer.style.gap = '20px';
        galleryContainer.style.marginTop = '60px'; // leave room for the close button
        overlay.appendChild(galleryContainer);

        imageUrls.forEach((url, index) => {
            const imgContainer = document.createElement('div');
            imgContainer.style.flex = '1 1 auto';
            imgContainer.style.maxWidth = '400px';
            imgContainer.style.cursor = 'pointer';

            const img = document.createElement('img');
            img.src = url;
            img.alt = 'Photo';
            img.style.width = '100%';
            img.style.height = 'auto';
            img.style.border = '2px solid #fff';
            img.style.boxShadow = '0 0 10px rgba(255,255,255,0.5)';
            img.style.transition = 'transform 0.2s ease-in-out';
            img.addEventListener('mouseover', () => { img.style.transform = 'scale(1.05)'; });
            img.addEventListener('mouseout', () => { img.style.transform = 'scale(1)'; });

            // When clicking the image, close the grid and open the carousel at this index.
            img.addEventListener('click', function(e) {
                e.stopPropagation();
                document.body.removeChild(overlay);
                createCarousel(index, imageUrls);
            });

            imgContainer.appendChild(img);
            galleryContainer.appendChild(imgContainer);
        });

        document.body.appendChild(overlay);
    }

    // Function to create a fullscreen carousel overlay with a "Grid View" button
    function createCarousel(currentIndex, imageUrls) {
        // Create carousel overlay
        const carouselOverlay = document.createElement('div');
        carouselOverlay.id = 'pgCarouselOverlay';
        carouselOverlay.style.position = 'fixed';
        carouselOverlay.style.top = '0';
        carouselOverlay.style.left = '0';
        carouselOverlay.style.width = '100vw';
        carouselOverlay.style.height = '100vh';
        carouselOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
        carouselOverlay.style.zIndex = '10001';
        carouselOverlay.style.display = 'flex';
        carouselOverlay.style.alignItems = 'center';
        carouselOverlay.style.justifyContent = 'center';

        // Container for image and controls
        const container = document.createElement('div');
        container.style.position = 'relative';
        container.style.width = '100vw';
        container.style.height = '100vh';
        container.style.display = 'flex';
        container.style.alignItems = 'center';
        container.style.justifyContent = 'center';
        carouselOverlay.appendChild(container);

        // Image element with scaling that preserves aspect ratio
        const carouselImg = document.createElement('img');
        carouselImg.src = imageUrls[currentIndex];
        carouselImg.style.display = 'block';
        carouselImg.style.maxWidth = '100%';
        carouselImg.style.maxHeight = '100%';
        carouselImg.style.width = 'auto';
        carouselImg.style.height = 'auto';
        carouselImg.style.objectFit = 'contain';
        container.appendChild(carouselImg);

        // Left arrow
        const leftArrow = document.createElement('div');
        leftArrow.innerHTML = '❮'; // left arrow symbol
        leftArrow.style.position = 'absolute';
        leftArrow.style.left = '20px';
        leftArrow.style.top = '50%';
        leftArrow.style.transform = 'translateY(-50%)';
        leftArrow.style.fontSize = '48px';
        leftArrow.style.color = '#fff';
        leftArrow.style.cursor = 'pointer';
        leftArrow.style.userSelect = 'none';
        container.appendChild(leftArrow);

        // Right arrow
        const rightArrow = document.createElement('div');
        rightArrow.innerHTML = '❯'; // right arrow symbol
        rightArrow.style.position = 'absolute';
        rightArrow.style.right = '20px';
        rightArrow.style.top = '50%';
        rightArrow.style.transform = 'translateY(-50%)';
        rightArrow.style.fontSize = '48px';
        rightArrow.style.color = '#fff';
        rightArrow.style.cursor = 'pointer';
        rightArrow.style.userSelect = 'none';
        container.appendChild(rightArrow);

        // Close button
        const closeBtn = document.createElement('div');
        closeBtn.innerHTML = '×';
        closeBtn.style.position = 'absolute';
        closeBtn.style.top = '20px';
        closeBtn.style.right = '30px';
        closeBtn.style.fontSize = '48px';
        closeBtn.style.color = '#fff';
        closeBtn.style.cursor = 'pointer';
        closeBtn.style.userSelect = 'none';
        container.appendChild(closeBtn);

        // New: "Grid View" button to go back to grid overlay.
        const gridViewBtn = document.createElement('button');
        gridViewBtn.innerText = 'Grid View';
        gridViewBtn.style.position = 'absolute';
        gridViewBtn.style.top = '20px';
        gridViewBtn.style.left = '30px';
        gridViewBtn.style.fontSize = '16px';
        gridViewBtn.style.padding = '8px 12px';
        gridViewBtn.style.background = '#ffa700';
        gridViewBtn.style.border = 'none';
        gridViewBtn.style.borderRadius = '5px';
        gridViewBtn.style.cursor = 'pointer';
        gridViewBtn.style.zIndex = '10002';
        container.appendChild(gridViewBtn);

        // Arrow navigation events
        leftArrow.addEventListener('click', function(e) {
            e.stopPropagation();
            currentIndex = (currentIndex - 1 + imageUrls.length) % imageUrls.length;
            carouselImg.src = imageUrls[currentIndex];
        });

        rightArrow.addEventListener('click', function(e) {
            e.stopPropagation();
            currentIndex = (currentIndex + 1) % imageUrls.length;
            carouselImg.src = imageUrls[currentIndex];
        });

        // Close carousel events
        closeBtn.addEventListener('click', function() {
            document.body.removeChild(carouselOverlay);
        });
        carouselOverlay.addEventListener('click', function(e) {
            if (e.target === carouselOverlay) {
                document.body.removeChild(carouselOverlay);
            }
        });

        // "Grid View" button: remove carousel and reopen grid overlay
        gridViewBtn.addEventListener('click', function(e) {
            e.stopPropagation();
            document.body.removeChild(carouselOverlay);
            createPopupGallery(imageUrls);
        });

        document.body.appendChild(carouselOverlay);
    }

    // When the page loads, add the "View Photos" button
    window.addEventListener('load', function() {
        const btn = document.createElement('button');
        btn.innerText = 'View Photos';
        btn.style.position = 'fixed';
        btn.style.top = '10px';
        btn.style.right = '10px';
        btn.style.zIndex = '9999';
        btn.style.padding = '10px 15px';
        btn.style.background = '#ffa700';
        btn.style.border = 'none';
        btn.style.borderRadius = '5px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '14px';
        document.body.appendChild(btn);

        // On button click, gather high-res photo URLs from the Photos section
        btn.addEventListener('click', function() {
            let imageUrls = [];
            const photoAnchors = document.querySelectorAll('.bxslider_pics_fancybox a[href]');
            photoAnchors.forEach(anchor => {
                const url = anchor.href;
                if(url) {
                    imageUrls.push(url);
                }
            });
            imageUrls = [...new Set(imageUrls)]; // Remove duplicates
            if(imageUrls.length > 0) {
                createPopupGallery(imageUrls);
            } else {
                alert('No photos found.');
            }
        });
    });
})();