Files
MyFastHtml/examples/profiler_mockup.html

641 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Profiler — UI Mockup</title>
<style>
/* ------------------------------------------------------------------ */
/* Base — mirrors DaisyUI dark theme CSS variables */
/* ------------------------------------------------------------------ */
:root {
--hcg-bg-main: #0d1117;
--hcg-bg-button: rgba(22, 27, 34, 0.92);
--hcg-border: #30363d;
--hcg-text-muted: rgba(230, 237, 243, 0.5);
--hcg-text-primary: #e6edf3;
--hcg-node-bg: #1c2128;
--hcg-node-bg-selected: color-mix(in oklab, #1c2128 70%, #f0883e 30%);
--profiler-danger: #f85149;
--profiler-warn: #e3b341;
--profiler-ok: #3fb950;
--profiler-accent: #58a6ff;
--profiler-muted: rgba(230, 237, 243, 0.35);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background: var(--hcg-bg-main);
color: var(--hcg-text-primary);
font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, monospace;
font-size: 13px;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* ------------------------------------------------------------------ */
/* Toolbar */
/* ------------------------------------------------------------------ */
.mf-profiler-toolbar {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 14px;
background: var(--hcg-node-bg);
border-bottom: 1px solid var(--hcg-border);
flex-shrink: 0;
}
.mf-profiler-toolbar-title {
font-size: 13px;
font-weight: 600;
color: var(--hcg-text-primary);
letter-spacing: 0.05em;
text-transform: uppercase;
margin-right: 4px;
}
.mf-profiler-btn {
padding: 4px 12px;
border-radius: 6px;
border: 1px solid var(--hcg-border);
background: var(--hcg-bg-button);
color: var(--hcg-text-primary);
cursor: pointer;
font-size: 12px;
font-family: inherit;
transition: background 0.15s, border-color 0.15s;
}
.mf-profiler-btn:hover {
background: color-mix(in oklab, var(--hcg-node-bg) 80%, var(--profiler-accent) 20%);
border-color: var(--profiler-accent);
}
.mf-profiler-btn.active {
background: color-mix(in oklab, var(--hcg-node-bg) 60%, var(--profiler-ok) 40%);
border-color: var(--profiler-ok);
color: var(--profiler-ok);
}
.mf-profiler-btn.danger {
border-color: var(--profiler-danger);
color: var(--profiler-danger);
}
.mf-profiler-btn.danger:hover {
background: color-mix(in oklab, var(--hcg-node-bg) 70%, var(--profiler-danger) 30%);
}
.mf-profiler-overhead {
margin-left: auto;
color: var(--hcg-text-muted);
font-size: 11px;
display: flex;
gap: 16px;
}
.mf-profiler-overhead span b {
color: var(--profiler-warn);
}
/* ------------------------------------------------------------------ */
/* Split layout */
/* ------------------------------------------------------------------ */
.mf-profiler-body {
display: flex;
flex: 1;
overflow: hidden;
}
/* ------------------------------------------------------------------ */
/* Trace list (left) */
/* ------------------------------------------------------------------ */
.mf-profiler-list {
width: 380px;
flex-shrink: 0;
border-right: 1px solid var(--hcg-border);
display: flex;
flex-direction: column;
overflow: hidden;
}
.mf-profiler-list-header {
display: grid;
grid-template-columns: 1fr 80px 110px;
padding: 6px 12px;
border-bottom: 1px solid var(--hcg-border);
color: var(--hcg-text-muted);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
background: var(--hcg-node-bg);
}
.mf-profiler-list-body {
overflow-y: auto;
flex: 1;
}
.mf-profiler-row {
display: grid;
grid-template-columns: 1fr 80px 110px;
padding: 7px 12px;
border-bottom: 1px solid rgba(48, 54, 61, 0.5);
cursor: pointer;
transition: background 0.1s;
align-items: center;
}
.mf-profiler-row:hover {
background: color-mix(in oklab, var(--hcg-node-bg) 60%, var(--profiler-accent) 5%);
}
.mf-profiler-row.selected {
background: var(--hcg-node-bg-selected);
border-left: 2px solid #f0883e;
padding-left: 10px;
}
.mf-profiler-cmd {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--hcg-text-primary);
}
.mf-profiler-duration {
text-align: right;
font-variant-numeric: tabular-nums;
font-size: 12px;
}
.mf-profiler-duration.fast {
color: var(--profiler-ok);
}
.mf-profiler-duration.medium {
color: var(--profiler-warn);
}
.mf-profiler-duration.slow {
color: var(--profiler-danger);
}
.mf-profiler-ts {
text-align: right;
color: var(--hcg-text-muted);
font-size: 11px;
}
/* ------------------------------------------------------------------ */
/* Detail panel (right) — Properties-style */
/* ------------------------------------------------------------------ */
.mf-profiler-detail {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.mf-profiler-detail-header {
padding: 8px 14px;
border-bottom: 1px solid var(--hcg-border);
background: var(--hcg-node-bg);
color: var(--hcg-text-muted);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.mf-profiler-detail-header b {
color: var(--hcg-text-primary);
font-size: 13px;
text-transform: none;
letter-spacing: 0;
}
.mf-profiler-detail-body {
flex: 1;
overflow-y: auto;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
/* Properties-style cards */
.mf-properties-group-card {
border: 1px solid var(--hcg-border);
border-radius: 6px;
overflow: hidden;
}
.mf-properties-group-header {
padding: 5px 10px;
background: var(--hcg-node-bg);
color: var(--hcg-text-muted);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
border-bottom: 1px solid var(--hcg-border);
}
.mf-properties-row {
display: grid;
grid-template-columns: 140px 1fr;
border-bottom: 1px solid rgba(48, 54, 61, 0.4);
}
.mf-properties-row:last-child {
border-bottom: none;
}
.mf-properties-key {
padding: 5px 10px;
color: var(--hcg-text-muted);
border-right: 1px solid var(--hcg-border);
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mf-properties-value {
padding: 5px 10px;
color: var(--hcg-text-primary);
font-size: 12px;
word-break: break-all;
}
/* Span tree */
.mf-profiler-span-tree {
border: 1px solid var(--hcg-border);
border-radius: 6px;
overflow: hidden;
}
.mf-profiler-span-tree-header {
padding: 5px 10px;
background: var(--hcg-node-bg);
color: var(--hcg-text-muted);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
border-bottom: 1px solid var(--hcg-border);
}
.mf-profiler-span-row {
display: flex;
align-items: center;
padding: 5px 10px;
border-bottom: 1px solid rgba(48, 54, 61, 0.4);
gap: 6px;
}
.mf-profiler-span-row:last-child {
border-bottom: none;
}
.mf-profiler-span-indent {
flex-shrink: 0;
}
.mf-profiler-span-bar-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
}
.mf-profiler-span-name {
min-width: 140px;
font-size: 12px;
white-space: nowrap;
}
.mf-profiler-span-bar-bg {
flex: 1;
height: 6px;
background: rgba(48, 54, 61, 0.6);
border-radius: 3px;
overflow: hidden;
}
.mf-profiler-span-bar {
height: 100%;
border-radius: 3px;
background: var(--profiler-accent);
transition: width 0.2s;
}
.mf-profiler-span-bar.slow {
background: var(--profiler-danger);
}
.mf-profiler-span-bar.medium {
background: var(--profiler-warn);
}
.mf-profiler-span-ms {
font-variant-numeric: tabular-nums;
font-size: 11px;
color: var(--hcg-text-muted);
min-width: 60px;
text-align: right;
}
/* Cumulative span badge */
.mf-profiler-cumulative-badge {
font-size: 10px;
padding: 1px 5px;
border-radius: 3px;
background: rgba(88, 166, 255, 0.15);
border: 1px solid rgba(88, 166, 255, 0.3);
color: var(--profiler-accent);
flex-shrink: 0;
}
/* Empty state */
.mf-profiler-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--hcg-text-muted);
font-size: 13px;
}
/* Scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--hcg-border);
border-radius: 3px;
}
</style>
</head>
<body>
<!-- ================================================================== -->
<!-- Toolbar -->
<!-- ================================================================== -->
<div class="mf-profiler-toolbar">
<span class="mf-profiler-toolbar-title">Profiler</span>
<button class="mf-profiler-btn active" onclick="toggleEnabled(this)">● Enabled</button>
<button class="mf-profiler-btn danger" onclick="clearTraces()">Clear</button>
<div class="mf-profiler-overhead">
<span>Overhead/span: <b>1.2 µs</b></span>
<span>Total overhead: <b>0.04 ms</b></span>
<span>Traces: <b id="trace-count">8</b> / 500</span>
</div>
</div>
<!-- ================================================================== -->
<!-- Body: list + detail -->
<!-- ================================================================== -->
<div class="mf-profiler-body">
<!-- ---------------------------------------------------------------- -->
<!-- Trace list -->
<!-- ---------------------------------------------------------------- -->
<div class="mf-profiler-list">
<div class="mf-profiler-list-header">
<span>Command</span>
<span style="text-align:right">Duration</span>
<span style="text-align:right">Time</span>
</div>
<div class="mf-profiler-list-body" id="trace-list">
<div class="mf-profiler-row selected" onclick="selectRow(this, 0)">
<span class="mf-profiler-cmd">NavigateCell</span>
<span class="mf-profiler-duration slow">173.4 ms</span>
<span class="mf-profiler-ts">14:32:07.881</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 1)">
<span class="mf-profiler-cmd">NavigateCell</span>
<span class="mf-profiler-duration slow">168.1 ms</span>
<span class="mf-profiler-ts">14:32:07.712</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 2)">
<span class="mf-profiler-cmd">SelectRow</span>
<span class="mf-profiler-duration medium">42.7 ms</span>
<span class="mf-profiler-ts">14:32:06.501</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 3)">
<span class="mf-profiler-cmd">FilterChanged</span>
<span class="mf-profiler-duration medium">38.2 ms</span>
<span class="mf-profiler-ts">14:32:05.334</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 4)">
<span class="mf-profiler-cmd">NavigateCell</span>
<span class="mf-profiler-duration fast">12.0 ms</span>
<span class="mf-profiler-ts">14:32:04.102</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 5)">
<span class="mf-profiler-cmd">SortColumn</span>
<span class="mf-profiler-duration fast">8.4 ms</span>
<span class="mf-profiler-ts">14:32:03.770</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 6)">
<span class="mf-profiler-cmd">SelectRow</span>
<span class="mf-profiler-duration fast">5.1 ms</span>
<span class="mf-profiler-ts">14:32:02.441</span>
</div>
<div class="mf-profiler-row" onclick="selectRow(this, 7)">
<span class="mf-profiler-cmd">NavigateCell</span>
<span class="mf-profiler-duration fast">4.8 ms</span>
<span class="mf-profiler-ts">14:32:01.003</span>
</div>
</div>
</div>
<!-- ---------------------------------------------------------------- -->
<!-- Detail panel -->
<!-- ---------------------------------------------------------------- -->
<div class="mf-profiler-detail">
<div class="mf-profiler-detail-header">
Trace detail — <b>NavigateCell</b>
</div>
<div class="mf-profiler-detail-body">
<!-- Metadata (Properties-style) -->
<div class="mf-properties-group-card">
<div class="mf-properties-group-header">Metadata</div>
<div class="mf-properties-row">
<div class="mf-properties-key">command</div>
<div class="mf-properties-value">NavigateCell</div>
</div>
<div class="mf-properties-row">
<div class="mf-properties-key">total_duration_ms</div>
<div class="mf-properties-value" style="color:var(--profiler-danger)">173.4</div>
</div>
<div class="mf-properties-row">
<div class="mf-properties-key">timestamp</div>
<div class="mf-properties-value">2026-03-21 14:32:07.881</div>
</div>
</div>
<!-- kwargs (Properties-style) -->
<div class="mf-properties-group-card">
<div class="mf-properties-group-header">kwargs</div>
<div class="mf-properties-row">
<div class="mf-properties-key">row</div>
<div class="mf-properties-value">12</div>
</div>
<div class="mf-properties-row">
<div class="mf-properties-key">col</div>
<div class="mf-properties-value">3</div>
</div>
<div class="mf-properties-row">
<div class="mf-properties-key">direction</div>
<div class="mf-properties-value">down</div>
</div>
</div>
<!-- Span tree -->
<div class="mf-profiler-span-tree">
<div class="mf-profiler-span-tree-header">Span breakdown</div>
<!-- Root span -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent" style="width:0"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name" style="color:var(--hcg-text-primary);font-weight:600">NavigateCell</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar slow" style="width:100%"></div>
</div>
<span class="mf-profiler-span-ms" style="color:var(--profiler-danger)">173.4 ms</span>
</div>
</div>
<!-- before_commands -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:16px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">before_commands</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar" style="width:1%"></div>
</div>
<span class="mf-profiler-span-ms">0.8 ms</span>
</div>
</div>
<!-- callback -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:16px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">callback</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar slow" style="width:88%"></div>
</div>
<span class="mf-profiler-span-ms" style="color:var(--profiler-danger)">152.6 ms</span>
</div>
</div>
<!-- navigate_cell (child of callback) -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:32px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">navigate_cell</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar slow" style="width:86%"></div>
</div>
<span class="mf-profiler-span-ms" style="color:var(--profiler-danger)">149.0 ms</span>
</div>
</div>
<!-- process_row (cumulative, child of navigate_cell) -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:48px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">process_row</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar medium" style="width:80%"></div>
</div>
<span class="mf-profiler-span-ms" style="color:var(--profiler-warn)">138.5 ms</span>
</div>
<span class="mf-profiler-cumulative-badge">×1000 · min 0.1 · avg 0.14 · max 0.4 ms</span>
</div>
<!-- after_commands -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:16px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">after_commands</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar" style="width:6%"></div>
</div>
<span class="mf-profiler-span-ms">10.3 ms</span>
</div>
</div>
<!-- oob_swap -->
<div class="mf-profiler-span-row">
<div class="mf-profiler-span-indent"
style="width:16px; border-left:1px solid var(--hcg-border)"></div>
<div class="mf-profiler-span-bar-wrap">
<span class="mf-profiler-span-name">oob_swap</span>
<div class="mf-profiler-span-bar-bg">
<div class="mf-profiler-span-bar" style="width:5%"></div>
</div>
<span class="mf-profiler-span-ms">9.7 ms</span>
</div>
</div>
</div><!-- /.mf-profiler-span-tree -->
</div><!-- /.mf-profiler-detail-body -->
</div><!-- /.mf-profiler-detail -->
</div><!-- /.mf-profiler-body -->
<script>
function selectRow(el, index) {
document.querySelectorAll('.mf-profiler-row').forEach(r => r.classList.remove('selected'));
el.classList.add('selected');
}
function toggleEnabled(btn) {
const enabled = btn.classList.toggle('active');
btn.textContent = enabled ? '● Enabled' : '○ Disabled';
}
function clearTraces() {
document.getElementById('trace-list').innerHTML =
'<div class="mf-profiler-empty">No traces recorded.</div>';
document.getElementById('trace-count').textContent = '0';
}
</script>
</body>
</html>