Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>360° Page Enhancer</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| /* Custom CSS for the magnifier effect */ | |
| .magnifier-glass { | |
| position: absolute; | |
| width: 150px; | |
| height: 150px; | |
| border-radius: 50%; | |
| border: 3px solid rgba(255, 255, 255, 0.8); | |
| box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); | |
| background-repeat: no-repeat; | |
| background-color: white; | |
| cursor: none; | |
| z-index: 9999; | |
| pointer-events: none; | |
| display: none; | |
| transform: translate(-50%, -50%); | |
| mix-blend-mode: multiply; | |
| } | |
| .rotate-controls { | |
| position: fixed; | |
| bottom: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background: rgba(0, 0, 0, 0.7); | |
| padding: 10px; | |
| border-radius: 20px; | |
| display: flex; | |
| gap: 10px; | |
| z-index: 10000; | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| } | |
| .rotate-controls.visible { | |
| opacity: 1; | |
| } | |
| .rotate-btn { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| background: white; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); | |
| transition: transform 0.2s; | |
| } | |
| .rotate-btn:hover { | |
| transform: scale(1.1); | |
| } | |
| .zoom-level { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: rgba(0, 0, 0, 0.7); | |
| color: white; | |
| padding: 5px 10px; | |
| border-radius: 10px; | |
| font-family: sans-serif; | |
| font-size: 14px; | |
| z-index: 10000; | |
| display: none; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100"> | |
| <div class="container mx-auto p-4"> | |
| <!-- Extension UI --> | |
| <div class="bg-white rounded-lg shadow-lg p-6 mb-6"> | |
| <h1 class="text-2xl font-bold text-gray-800 mb-4">360° Page Enhancer</h1> | |
| <p class="text-gray-600 mb-4">This extension adds a 360° zoom and rotation feature to web pages. Click on any element to activate the magnifier.</p> | |
| <div class="flex flex-wrap gap-4 mb-6"> | |
| <div class="flex-1 min-w-[200px]"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Zoom Level</label> | |
| <input type="range" id="zoomRange" min="1" max="5" step="0.5" value="2" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>1x</span> | |
| <span>2x</span> | |
| <span>3x</span> | |
| <span>4x</span> | |
| <span>5x</span> | |
| </div> | |
| </div> | |
| <div class="flex-1 min-w-[200px]"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Magnifier Size</label> | |
| <input type="range" id="sizeRange" min="100" max="300" step="50" value="150" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>100px</span> | |
| <span>200px</span> | |
| <span>300px</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex flex-wrap gap-4"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="enableRotation" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| <label for="enableRotation" class="ml-2 block text-sm text-gray-700">Enable 360° Rotation</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="showControls" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="showControls" class="ml-2 block text-sm text-gray-700">Show Rotation Controls</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="smoothZoom" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked> | |
| <label for="smoothZoom" class="ml-2 block text-sm text-gray-700">Smooth Zoom Transition</label> | |
| </div> | |
| </div> | |
| <button id="toggleExtension" class="mt-6 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200"> | |
| Activate Extension | |
| </button> | |
| </div> | |
| <!-- Demo content to test the extension --> | |
| <div class="bg-white rounded-lg shadow-lg p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Try it on this demo content</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-700 mb-2">Sample Image</h3> | |
| <img src="https://images.unsplash.com/photo-1682686580391-615b4f715f5e?w=500&auto=format&fit=crop" alt="Sample" class="w-full h-auto rounded cursor-pointer demo-target"> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-700 mb-2">Sample Text</h3> | |
| <p class="text-gray-600 cursor-pointer demo-target"> | |
| Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in dui mauris. Vivamus hendrerit arcu sed erat molestie vehicula. Sed auctor neque eu tellus rhoncus ut eleifend nibh porttitor. | |
| </p> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-700 mb-2">Sample UI Elements</h3> | |
| <div class="flex flex-wrap gap-2 cursor-pointer demo-target"> | |
| <button class="bg-blue-500 text-white px-3 py-1 rounded">Button</button> | |
| <button class="bg-green-500 text-white px-3 py-1 rounded">Another</button> | |
| <button class="bg-red-500 text-white px-3 py-1 rounded">Click Me</button> | |
| </div> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-700 mb-2">Sample Complex Content</h3> | |
| <div class="cursor-pointer demo-target"> | |
| <div class="flex items-center mb-2"> | |
| <div class="w-8 h-8 bg-purple-500 rounded-full mr-2"></div> | |
| <span class="text-gray-700">User Avatar</span> | |
| </div> | |
| <div class="border-t pt-2"> | |
| <p class="text-sm text-gray-600">This is a more complex UI element that you can zoom into.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Magnifier elements that will be added to the page --> | |
| <div id="magnifier" class="magnifier-glass"></div> | |
| <div id="zoomLevel" class="zoom-level">2x</div> | |
| <div id="rotateControls" class="rotate-controls"> | |
| <div id="rotateLeft" class="rotate-btn" title="Rotate Left">←</div> | |
| <div id="resetRotation" class="rotate-btn" title="Reset Rotation">↻</div> | |
| <div id="rotateRight" class="rotate-btn" title="Rotate Right">→</div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Extension state | |
| const state = { | |
| active: false, | |
| zoomLevel: 2, | |
| magnifierSize: 150, | |
| enableRotation: false, | |
| showControls: true, | |
| smoothZoom: true, | |
| currentRotation: 0, | |
| currentTarget: null | |
| }; | |
| // DOM elements | |
| const magnifier = document.getElementById('magnifier'); | |
| const zoomLevelDisplay = document.getElementById('zoomLevel'); | |
| const rotateControls = document.getElementById('rotateControls'); | |
| const toggleExtensionBtn = document.getElementById('toggleExtension'); | |
| const zoomRange = document.getElementById('zoomRange'); | |
| const sizeRange = document.getElementById('sizeRange'); | |
| const enableRotation = document.getElementById('enableRotation'); | |
| const showControls = document.getElementById('showControls'); | |
| const smoothZoom = document.getElementById('smoothZoom'); | |
| const rotateLeftBtn = document.getElementById('rotateLeft'); | |
| const rotateRightBtn = document.getElementById('rotateRight'); | |
| const resetRotationBtn = document.getElementById('resetRotation'); | |
| // Demo targets | |
| const demoTargets = document.querySelectorAll('.demo-target'); | |
| // Initialize UI | |
| function updateUI() { | |
| toggleExtensionBtn.textContent = state.active ? 'Deactivate Extension' : 'Activate Extension'; | |
| toggleExtensionBtn.className = state.active ? | |
| 'mt-6 bg-red-600 hover:bg-red-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200' : | |
| 'mt-6 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200'; | |
| if (state.active) { | |
| document.body.style.cursor = 'crosshair'; | |
| demoTargets.forEach(el => el.style.cursor = 'crosshair'); | |
| } else { | |
| document.body.style.cursor = ''; | |
| demoTargets.forEach(el => el.style.cursor = ''); | |
| hideMagnifier(); | |
| } | |
| } | |
| // Show magnifier | |
| function showMagnifier(e, target) { | |
| if (!state.active) return; | |
| state.currentTarget = target; | |
| magnifier.style.display = 'block'; | |
| zoomLevelDisplay.style.display = 'block'; | |
| if (state.enableRotation && state.showControls) { | |
| rotateControls.classList.add('visible'); | |
| } | |
| updateMagnifier(e); | |
| } | |
| // Hide magnifier | |
| function hideMagnifier() { | |
| magnifier.style.display = 'none'; | |
| zoomLevelDisplay.style.display = 'none'; | |
| rotateControls.classList.remove('visible'); | |
| state.currentTarget = null; | |
| state.currentRotation = 0; | |
| } | |
| // Update magnifier position and content | |
| function updateMagnifier(e) { | |
| if (!state.active || !state.currentTarget) return; | |
| const targetRect = state.currentTarget.getBoundingClientRect(); | |
| const x = e.clientX; | |
| const y = e.clientY; | |
| // Position the magnifier | |
| magnifier.style.left = `${x}px`; | |
| magnifier.style.top = `${y}px`; | |
| magnifier.style.width = `${state.magnifierSize}px`; | |
| magnifier.style.height = `${state.magnifierSize}px`; | |
| // Calculate the background position for the magnifier | |
| const bgX = ((x - targetRect.left) / targetRect.width) * 100; | |
| const bgY = ((y - targetRect.top) / targetRect.height) * 100; | |
| // Create a screenshot of the target | |
| const screenshot = createScreenshot(state.currentTarget); | |
| // Apply transformations | |
| magnifier.style.backgroundImage = `url(${screenshot})`; | |
| magnifier.style.backgroundSize = `${targetRect.width * state.zoomLevel}px ${targetRect.height * state.zoomLevel}px`; | |
| magnifier.style.backgroundPosition = `${bgX}% ${bgY}%`; | |
| if (state.enableRotation) { | |
| magnifier.style.transform = `translate(-50%, -50%) rotate(${state.currentRotation}deg)`; | |
| } | |
| // Update zoom level display | |
| zoomLevelDisplay.textContent = `${state.zoomLevel}x`; | |
| zoomLevelDisplay.style.top = '20px'; | |
| zoomLevelDisplay.style.right = '20px'; | |
| } | |
| // Create a screenshot of an element | |
| function createScreenshot(element) { | |
| // In a real extension, we would use more sophisticated methods | |
| // For this demo, we'll just create a basic representation | |
| const canvas = document.createElement('canvas'); | |
| const rect = element.getBoundingClientRect(); | |
| // Set canvas dimensions | |
| canvas.width = rect.width; | |
| canvas.height = rect.height; | |
| const ctx = canvas.getContext('2d'); | |
| // Draw a representation of the element | |
| if (element.tagName === 'IMG') { | |
| // For images, we can actually draw them | |
| ctx.drawImage(element, 0, 0, rect.width, rect.height); | |
| } else { | |
| // For other elements, create a simplified representation | |
| ctx.fillStyle = window.getComputedStyle(element).backgroundColor || 'white'; | |
| ctx.fillRect(0, 0, rect.width, rect.height); | |
| // Add text if the element contains text | |
| if (element.textContent.trim()) { | |
| ctx.fillStyle = window.getComputedStyle(element).color || 'black'; | |
| ctx.font = '14px Arial'; | |
| ctx.fillText(element.textContent.trim(), 10, 20); | |
| } | |
| } | |
| return canvas.toDataURL(); | |
| } | |
| // Event listeners | |
| toggleExtensionBtn.addEventListener('click', function() { | |
| state.active = !state.active; | |
| updateUI(); | |
| }); | |
| zoomRange.addEventListener('input', function() { | |
| state.zoomLevel = parseFloat(this.value); | |
| zoomLevelDisplay.textContent = `${state.zoomLevel}x`; | |
| }); | |
| sizeRange.addEventListener('input', function() { | |
| state.magnifierSize = parseInt(this.value); | |
| magnifier.style.width = `${state.magnifierSize}px`; | |
| magnifier.style.height = `${state.magnifierSize}px`; | |
| }); | |
| enableRotation.addEventListener('change', function() { | |
| state.enableRotation = this.checked; | |
| if (!state.enableRotation) { | |
| state.currentRotation = 0; | |
| magnifier.style.transform = 'translate(-50%, -50%)'; | |
| } | |
| }); | |
| showControls.addEventListener('change', function() { | |
| state.showControls = this.checked; | |
| if (state.showControls && state.active && state.currentTarget && state.enableRotation) { | |
| rotateControls.classList.add('visible'); | |
| } else { | |
| rotateControls.classList.remove('visible'); | |
| } | |
| }); | |
| smoothZoom.addEventListener('change', function() { | |
| state.smoothZoom = this.checked; | |
| if (state.smoothZoom) { | |
| magnifier.style.transition = 'transform 0.2s ease, width 0.2s ease, height 0.2s ease'; | |
| } else { | |
| magnifier.style.transition = 'none'; | |
| } | |
| }); | |
| // Rotation controls | |
| rotateLeftBtn.addEventListener('click', function() { | |
| if (!state.active || !state.enableRotation || !state.currentTarget) return; | |
| state.currentRotation -= 15; | |
| updateMagnifier({ clientX: parseFloat(magnifier.style.left), clientY: parseFloat(magnifier.style.top) }); | |
| }); | |
| rotateRightBtn.addEventListener('click', function() { | |
| if (!state.active || !state.enableRotation || !state.currentTarget) return; | |
| state.currentRotation += 15; | |
| updateMagnifier({ clientX: parseFloat(magnifier.style.left), clientY: parseFloat(magnifier.style.top) }); | |
| }); | |
| resetRotationBtn.addEventListener('click', function() { | |
| if (!state.active || !state.enableRotation || !state.currentTarget) return; | |
| state.currentRotation = 0; | |
| updateMagnifier({ clientX: parseFloat(magnifier.style.left), clientY: parseFloat(magnifier.style.top) }); | |
| }); | |
| // Document event listeners | |
| document.addEventListener('mousemove', function(e) { | |
| if (!state.active || !state.currentTarget) return; | |
| updateMagnifier(e); | |
| }); | |
| document.addEventListener('click', function(e) { | |
| if (!state.active) return; | |
| // Find the target element | |
| let target = e.target; | |
| // Ignore clicks on the magnifier itself or its controls | |
| if (target === magnifier || target.closest('#rotateControls')) { | |
| return; | |
| } | |
| // If we're already showing a magnifier and click outside, hide it | |
| if (state.currentTarget && !target.closest('.demo-target')) { | |
| hideMagnifier(); | |
| return; | |
| } | |
| // If clicking on a demo target, show magnifier | |
| if (target.closest('.demo-target')) { | |
| target = target.closest('.demo-target'); | |
| showMagnifier(e, target); | |
| } | |
| }); | |
| // Initialize | |
| updateUI(); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Mackin7/browser-enhancer2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |