- Device breakpoint toggles (mobile 375px / tablet 768px / desktop 100%) - Editor theme selector with 6 themes (VS Dark/Light, High Contrast, Monokai, Dracula, GitHub Dark) - Starter template gallery with 8 pre-built templates (Todo, API Fetch, CSS Animation, etc.) - Code autocomplete with DOM/React type definitions and snippet completions - Devtools panels: console, network, elements, performance - Code formatter (Prettier), diff view, and linter integration
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
import { registerClearHandler } from './devtools.js';
|
|
|
|
let entries = [];
|
|
|
|
function formatSize(bytes) {
|
|
if (bytes === 0 || bytes === undefined) return '-';
|
|
if (bytes < 1024) return bytes + ' B';
|
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
}
|
|
|
|
function typeClass(initiatorType) {
|
|
switch (initiatorType) {
|
|
case 'script': return 'net-type-script';
|
|
case 'link': case 'css': return 'net-type-link';
|
|
case 'img': return 'net-type-img';
|
|
case 'fetch': return 'net-type-fetch';
|
|
case 'xmlhttprequest': return 'net-type-xmlhttprequest';
|
|
default: return 'net-type-other';
|
|
}
|
|
}
|
|
|
|
function truncateUrl(url) {
|
|
try {
|
|
const u = new URL(url);
|
|
const path = u.pathname.split('/').pop() || u.pathname;
|
|
return path + u.search;
|
|
} catch { return url; }
|
|
}
|
|
|
|
function render() {
|
|
const out = document.getElementById('network-output');
|
|
if (!entries.length) {
|
|
out.innerHTML = '<div style="padding:12px;color:var(--text-dim);font-size:11px;">No network requests captured. Run your code to see resources.</div>';
|
|
return;
|
|
}
|
|
|
|
let totalSize = 0;
|
|
let html = '<table class="network-table"><thead><tr><th>Name</th><th>Type</th><th>Size</th><th>Time</th></tr></thead><tbody>';
|
|
for (const e of entries) {
|
|
totalSize += e.transferSize || 0;
|
|
html += `<tr>
|
|
<td title="${e.name}">${truncateUrl(e.name)}</td>
|
|
<td><span class="net-type ${typeClass(e.initiatorType)}">${e.initiatorType}</span></td>
|
|
<td>${formatSize(e.transferSize)}</td>
|
|
<td>${Math.round(e.duration)}ms</td>
|
|
</tr>`;
|
|
}
|
|
html += '</tbody></table>';
|
|
html += `<div class="network-footer"><span>${entries.length} request${entries.length !== 1 ? 's' : ''}</span><span>${formatSize(totalSize)} transferred</span></div>`;
|
|
out.innerHTML = html;
|
|
}
|
|
|
|
export function clearNetwork() {
|
|
entries = [];
|
|
const out = document.getElementById('network-output');
|
|
out.innerHTML = '';
|
|
}
|
|
|
|
export function initNetwork() {
|
|
registerClearHandler('network', clearNetwork);
|
|
|
|
window.addEventListener('message', (e) => {
|
|
if (!e.data || e.data.type !== 'devtools' || e.data.tab !== 'network') return;
|
|
if (e.data.entries) {
|
|
entries.push(...e.data.entries);
|
|
render();
|
|
}
|
|
});
|
|
}
|