HackAPrompt - Focus Mode 🎯

Youtube Full Screen like Zooming for HackAPrompt Challenges

// ==UserScript==
// @name         HackAPrompt - Focus Mode 🎯
// @namespace    KarthiDreamr.AI.RedTeam.Tools
// @version      2.2
// @description  Youtube Full Screen like Zooming for HackAPrompt Challenges 
// @author       KarthiDreamr & Perplexity (Logic updated by Gemini)
// @match        https://www.hackaprompt.com/*
// @grant        GM_addStyle
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

     // --- URL Validation: Only run on URLs with exactly 2 segments after /track/ ---
    function isValidURL() {
        const pathname = window.location.pathname;
        // Regex pattern: /track/[segment1]/[segment2] (with optional trailing slash)
        const pattern = /^\/track\/[^\/]+\/[^\/]+\/?$/;
        return pattern.test(pathname);
    }

    // Early exit if URL doesn't match the required pattern
    if (!isValidURL()) {
        console.log('HackAPrompt Script: URL does not match required pattern. Script will not run.');
        return;
    }

    console.log('HackAPrompt Script: Valid URL detected. Initializing...');

    // --- Configuration ---
    const TOGGLE_BUTTON_ID = "hap-isolate-toggle-button";
    const ISOLATED_BODY_CLASS = "hap-isolated-view-active";

    // --- State Variables ---
    let isIsolated = false;
    let targetElement = null;
    let intervalId = null;

    // --- CSS Injection ---
    GM_addStyle(`

        /* --- FIX: Ensure the TabList remains visible --- */
        /* This tells the row of tab buttons not to shrink, even when its container is in flex mode. */
          body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] [role="tablist"] {
          flex-shrink: 0 !important;
          }

    /* --- FIX: Ensure the bottom 'Points/Button' div remains visible --- */
    /* This targets the div with the 'sm:mt-auto' class and tells it not to shrink. */
    body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] .sm\\:mt-auto {
        flex-shrink: 0 !important;
        padding-bottom: 2.3rem !important; /* Adds a little space at the bottom */
    }

        /* --- Toggle Button Styles (unchanged) --- */
        #${TOGGLE_BUTTON_ID} {
            position: fixed;
            bottom: 20px;
            left: 20px;
            z-index: 999999; /* Must be higher than the focused element */
            background-color: #1a202c;
            color: #e2e8f0;
            border: 1px solid #4a5568;
            border-radius: 25px;
            padding: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.4);
            transition: all 0.3s ease;
            overflow: hidden;
            width: 40px;
            height: 40px;
        }
        #${TOGGLE_BUTTON_ID}:hover { width: 170px; }
        #${TOGGLE_BUTTON_ID} .toggle-icon { flex-shrink: 0; width: 24px; height: 24px; margin: 0; transition: transform 0.3s ease; }
        #${TOGGLE_BUTTON_ID} .toggle-text { white-space: nowrap; opacity: 0; transition: opacity 0.2s ease 0.1s; font-family: sans-serif; font-size: 14px; margin-left: 8px; }
        #${TOGGLE_BUTTON_ID}:hover .toggle-text { opacity: 1; }

        /**************************************************************
         * NEW LOGIC: Promote the target element instead of hiding others
         **************************************************************/

        /* 1. When active, lift the target element and make it a full-screen overlay */
        body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] {
             position: fixed !important;
             top: 0 !important;
             left: 0 !important;
             width: 100vw !important;
             height: 100vh !important;
             z-index: 999990 !important; /* High z-index to cover page content */
             background: #0F172A !important; /* Add a background color to hide content underneath */
             padding: 0 !important;
             margin-top: 0 !important;
             display: flex !important;
             flex-direction: row !important;
        }

        /* 2. Prevent the body from scrolling while in focus mode */
        body.${ISOLATED_BODY_CLASS} {
            overflow: hidden !important;
        }


        /**************************************************************
         * FULL HEIGHT STYLES (These are still needed for the internals)
         **************************************************************/

        body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] .flex-1 {
            flex-grow: 1 !important;
            min-height: 0 !important;
            display: flex !important;
            flex-direction: column !important;
        }

        body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] [role="tabpanel"],
        body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] .overflow-y-auto {
            height: 100% !important;
            max-height: none !important;
            flex: 1 !important;
        }

        body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] textarea {
            min-height: 200px !important;
            flex-grow: 1 !important;
        }

        body.${ISOLATED_BODY_CLASS} .h-\\[calc\\(100dvh-8rem\\)\\] { height: 100% !important; }
        body.${ISOLATED_BODY_CLASS} .h-\\[calc\\(100dvh-13rem\\)\\] { height: 100% !important; flex: 1 !important; }
        body.${ISOLATED_BODY_CLASS} .lg\\:h-\\[calc\\(100dvh-8rem\\)\\] { height: 100% !important; }
    `);

    // --- Core Logic ---
    function createToggleButton() {
        const button = document.createElement('div');
        button.id = TOGGLE_BUTTON_ID;
        button.title = "Toggle Focus View";
        button.innerHTML = `
            <svg class="toggle-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>
            </svg>
            <span class="toggle-text">Focus View</span>`;
        document.body.appendChild(button);
        button.addEventListener('click', toggleView);
    }

    // --- UPDATED toggleView Function (Much Simpler) ---
    function toggleView() {
        if (!targetElement) {
            console.warn('HackAPrompt Script: Cannot toggle, target element not found.');
            return;
        }
        isIsolated = !isIsolated;
        const button = document.getElementById(TOGGLE_BUTTON_ID);
        const buttonText = button.querySelector('.toggle-text');
        const buttonIcon = button.querySelector('.toggle-icon');

        if (isIsolated) {
            // --- ISOLATE ---
            // No more moving elements! Just add classes and attributes.
            targetElement.setAttribute('data-hap-target', 'true');
            document.body.classList.add(ISOLATED_BODY_CLASS);

            buttonText.textContent = "Restore View";
            buttonIcon.innerHTML = `<path d="M15 3h6v6m-11 5L21 3m-3 18h-6v-6m-1-5L3 21"/>`; // Contract icon
            console.log('HackAPrompt Script: View Focused.');
        } else {
            // --- RESTORE ---
            // Just remove the classes and attributes.
            targetElement.removeAttribute('data-hap-target');
            document.body.classList.remove(ISOLATED_BODY_CLASS);

            buttonText.textContent = "Focus View";
            buttonIcon.innerHTML = `<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>`; // Expand icon
            console.log('HackAPrompt Script: View Restored.');
        }
    }

    function initialize() {
        if (document.getElementById(TOGGLE_BUTTON_ID)) {
            if (intervalId) clearInterval(intervalId);
            return;
        }

        // Finding logic is unchanged
        const allFlexRows = document.querySelectorAll('div.lg\\:flex-row');
        let foundElement = null;
        for (const container of allFlexRows) {
            const leftPanel = container.querySelector(':scope > div[class*="lg:w-[40%]"]');
            const rightPanel = container.querySelector(':scope > div[class*="lg:w-[58%]"]');

            if (leftPanel && rightPanel) {
                foundElement = container;
                break;
            }
        }

        targetElement = foundElement;
        if (targetElement) {
            console.log('HackAPrompt Isolate Script: Target element located. Initializing controls.');
            createToggleButton();
            if (intervalId) clearInterval(intervalId);
        }
    }

    // Polling mechanism (unchanged)
    intervalId = setInterval(initialize, 500);
    setTimeout(() => {
        if (intervalId) {
            clearInterval(intervalId);
            if (!targetElement) {
                console.warn('HackAPrompt Script: Target element could not be found after 20 seconds.');
            }
        }
    }, 20000);
})();