Created
April 8, 2025 16:34
-
-
Save benallfree/1e20b4e2c0200fb25a22581b65c4e68d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en" data-theme="light"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>Debug View</title> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.min.css" rel="stylesheet" type="text/css" /> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script> | |
tailwind.config = { | |
theme: { | |
extend: {}, | |
}, | |
daisyui: { | |
themes: ['light'], | |
}, | |
} | |
</script> | |
<style> | |
.phone-notch::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 50%; | |
transform: translateX(-50%); | |
width: 60px; | |
height: 12px; | |
background: #1a1a1a; | |
border-bottom-left-radius: 12px; | |
border-bottom-right-radius: 12px; | |
} | |
.error-log { | |
opacity: 0; | |
transition: opacity 0.3s; | |
} | |
.error-log.has-error { | |
opacity: 1; | |
} | |
#phoneContainer { | |
margin-top: 96px; | |
padding: 1rem; | |
display: flex; | |
flex-wrap: wrap; | |
align-items: flex-start; | |
gap: 1rem; | |
} | |
.phone-wrapper { | |
width: 393px; | |
height: 852px; | |
transform-origin: top left; | |
display: inline-block; | |
transition: all 0.2s ease; | |
} | |
.phone-frame { | |
width: 393px; | |
height: 852px; | |
} | |
.phone-frame iframe { | |
width: 393px; | |
height: 852px; | |
border: none; | |
} | |
.scale-controls { | |
display: flex; | |
gap: 0.5rem; | |
align-items: center; | |
} | |
.scale-display { | |
min-width: 4rem; | |
text-align: center; | |
} | |
</style> | |
</head> | |
<body class="bg-base-200 min-h-screen"> | |
<div class="fixed top-0 left-0 right-0 bg-base-100 shadow-lg z-50"> | |
<div class="container mx-auto p-4 flex gap-4 items-center"> | |
<input | |
type="text" | |
id="urlInput" | |
placeholder="Enter URL to debug (default: index.html)" | |
value="index.html" | |
class="input input-bordered flex-1 max-w-md" | |
/> | |
<button onclick="addPhone()" class="btn btn-primary">Add Phone</button> | |
<button onclick="clearAll()" class="btn btn-ghost">Clear All</button> | |
<div class="scale-controls"> | |
<button onclick="adjustScale(-0.1)" class="btn btn-sm">-</button> | |
<span id="scaleDisplay" class="scale-display">100%</span> | |
<button onclick="adjustScale(0.1)" class="btn btn-sm">+</button> | |
</div> | |
</div> | |
</div> | |
<div id="phoneContainer" class="container mx-auto"></div> | |
<script> | |
let currentScale = 1.0 | |
function adjustScale(delta) { | |
currentScale = Math.max(0.1, Math.min(1, currentScale + delta)) | |
document.getElementById('scaleDisplay').textContent = Math.round(currentScale * 100) + '%' | |
updatePhoneScales() | |
} | |
function updatePhoneScales() { | |
const phones = document.getElementsByClassName('phone-wrapper') | |
Array.from(phones).forEach((phone) => { | |
phone.style.transform = `scale(${currentScale})` | |
phone.style.width = `${393 * currentScale}px` | |
phone.style.height = `${852 * currentScale}px` | |
}) | |
} | |
function createPhoneFrame(url) { | |
const phoneWrapper = document.createElement('div') | |
phoneWrapper.className = 'phone-wrapper' | |
phoneWrapper.style.transform = `scale(${currentScale})` | |
phoneWrapper.style.width = `${393 * currentScale}px` | |
phoneWrapper.style.height = `${852 * currentScale}px` | |
const phoneDiv = document.createElement('div') | |
phoneDiv.className = 'relative phone-notch phone-frame' | |
// Phone frame with bezel effect | |
const frameOuter = document.createElement('div') | |
frameOuter.className = 'absolute inset-0 rounded-[2rem] bg-neutral shadow-xl' | |
const frameInner = document.createElement('div') | |
frameInner.className = 'absolute inset-[0.5rem] rounded-[1.5rem] bg-base-100 flex flex-col overflow-hidden' | |
const iframe = document.createElement('iframe') | |
iframe.src = url | |
const errorLog = document.createElement('div') | |
errorLog.className = | |
'error-log absolute -bottom-12 left-0 right-0 bg-error text-error-content p-2 text-sm rounded-lg truncate' | |
frameInner.appendChild(iframe) | |
frameOuter.appendChild(frameInner) | |
phoneDiv.appendChild(frameOuter) | |
phoneDiv.appendChild(errorLog) | |
phoneWrapper.appendChild(phoneDiv) | |
// Monitor console errors in the iframe | |
iframe.onload = () => { | |
const iframeWindow = iframe.contentWindow | |
const originalConsoleError = iframeWindow.console.error | |
iframeWindow.console.error = function (...args) { | |
errorLog.textContent = args.join(' ') | |
errorLog.classList.add('has-error') | |
originalConsoleError.apply(this, args) | |
} | |
iframeWindow.addEventListener('error', (event) => { | |
errorLog.textContent = `${event.message} (${event.filename}:${event.lineno})` | |
errorLog.classList.add('has-error') | |
}) | |
iframeWindow.addEventListener('unhandledrejection', (event) => { | |
errorLog.textContent = `Unhandled Promise: ${event.reason}` | |
errorLog.classList.add('has-error') | |
}) | |
} | |
return phoneWrapper | |
} | |
function addPhone() { | |
const url = document.getElementById('urlInput').value || 'index.html' | |
const container = document.getElementById('phoneContainer') | |
container.appendChild(createPhoneFrame(url)) | |
} | |
function clearAll() { | |
const container = document.getElementById('phoneContainer') | |
container.innerHTML = '' | |
} | |
// Initialize with one phone | |
addPhone() | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment