Add responsive preview, editor themes, template gallery, devtools, and autocomplete
- 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
This commit is contained in:
70
public/js/network-panel.js
Normal file
70
public/js/network-panel.js
Normal file
@@ -0,0 +1,70 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user