Youtube Full Screen like Zooming for HackAPrompt Challenges
// ==UserScript==
// @name HackAPrompt - Focus Mode 🎯
// @namespace KarthiDreamr.AI.RedTeam.Tools
// @version 2.4
// @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; // default false; we'll explicitly apply Focus View on init
let targetElement = null;
let intervalId = null;
// --- CSS Injection ---
GM_addStyle(`
/* --- FIX: Ensure the TabList remains visible --- */
body.${ISOLATED_BODY_CLASS} [data-hap-target="true"] [role="tablist"] {
flex-shrink: 0 !important;
}
/* --- FIX: Ensure the bottom 'Points/Button' div remains visible --- */
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 --- */
#${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; }
/**************************************************************
* 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; }
`);
// --- UI helpers ---
const ICON_EXPAND = `<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"/>`;
const ICON_CONTRACT = `<path d="M15 3h6v6m-11 5L21 3m-3 18h-6v-6m-1-5L3 21"/>`;
function getButtonParts() {
const button = document.getElementById(TOGGLE_BUTTON_ID);
if (!button) return {};
return {
button,
textEl: button.querySelector('.toggle-text'),
iconEl: button.querySelector('.toggle-icon')
};
}
function setButtonState({ label, iconPath }) {
const { textEl, iconEl } = getButtonParts();
if (textEl) textEl.textContent = label;
if (iconEl) iconEl.innerHTML = iconPath;
}
// --- Core Logic: explicit apply/revert to avoid accidental untoggles ---
function applyFocus() {
if (!targetElement) return;
targetElement.setAttribute('data-hap-target', 'true');
document.body.classList.add(ISOLATED_BODY_CLASS);
isIsolated = true;
setButtonState({ label: 'Restore View', iconPath: ICON_CONTRACT });
console.log('HackAPrompt Script: View Focused.');
}
function applyNormal() {
if (!targetElement) return;
targetElement.removeAttribute('data-hap-target');
document.body.classList.remove(ISOLATED_BODY_CLASS);
isIsolated = false;
setButtonState({ label: 'Focus View', iconPath: ICON_EXPAND });
console.log('HackAPrompt Script: View Restored.');
}
function toggleView() {
if (!targetElement) {
console.warn('HackAPrompt Script: Cannot toggle, target element not found.');
return;
}
if (isIsolated) applyNormal(); else applyFocus();
}
function createToggleButton() {
if (document.getElementById(TOGGLE_BUTTON_ID)) return;
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">
${ICON_EXPAND}
</svg>
<span class="toggle-text">Focus View</span>`;
document.body.appendChild(button);
button.addEventListener('click', toggleView);
}
function initialize() {
if (document.getElementById(TOGGLE_BUTTON_ID) && targetElement) {
if (intervalId) clearInterval(intervalId);
return;
}
// Find the main two-column container
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();
// Apply Focus View by default on first init (without toggling away)
if (!isIsolated) applyFocus();
if (intervalId) clearInterval(intervalId);
}
}
// Polling mechanism
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);
})();