Skip to content

Instantly share code, notes, and snippets.

@benallfree
Created April 8, 2025 16:34
Show Gist options
  • Save benallfree/1e20b4e2c0200fb25a22581b65c4e68d to your computer and use it in GitHub Desktop.
Save benallfree/1e20b4e2c0200fb25a22581b65c4e68d to your computer and use it in GitHub Desktop.
<!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