mnoorchenar's picture
Update 2026-03-20 21:52:49
b9370c4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ExperimentLab — {% block title %}{% endblock %}</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>
</head>
<body>
<div class="toast-container" id="toast-container"></div>
<div class="app-shell">
<!-- Sidebar -->
<nav class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="brand-icon">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#a5b4fc" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 3h6"/>
<path d="M9 3v8l-5 7a2 2 0 0 0 1.8 3h12.4A2 2 0 0 0 20 18l-5-7V3"/>
<line x1="6.5" y1="16" x2="17.5" y2="16"/>
</svg>
</div>
<div>
<div class="brand-name">ExperimentLab</div>
<div class="brand-sub">Statistical Experimentation Suite</div>
</div>
</div>
<div class="nav-section-label">Modules</div>
<ul class="nav-list">
<li>
<a href="/power" class="nav-link {% if active == 'power' %}active{% endif %}">
<span class="nav-icon">
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
</svg>
</span>
<div class="nav-text">
<span class="nav-title">Power Calculator</span>
<span class="nav-desc">Sample size planning</span>
</div>
</a>
</li>
<li>
<a href="/ab-test" class="nav-link {% if active == 'ab_test' %}active{% endif %}">
<span class="nav-icon">
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="8" height="18" rx="1.5"/>
<rect x="13" y="3" width="8" height="18" rx="1.5"/>
</svg>
</span>
<div class="nav-text">
<span class="nav-title">A/B Test Analyzer</span>
<span class="nav-desc">Significance &amp; effect size</span>
</div>
</a>
</li>
<li>
<a href="/doe" class="nav-link {% if active == 'doe' %}active{% endif %}">
<span class="nav-icon">
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="7" height="7" rx="1"/>
<rect x="14" y="3" width="7" height="7" rx="1"/>
<rect x="3" y="14" width="7" height="7" rx="1"/>
<rect x="14" y="14" width="7" height="7" rx="1"/>
</svg>
</span>
<div class="nav-text">
<span class="nav-title">Two-Factor DoE</span>
<span class="nav-desc">Factorial experiment analysis</span>
</div>
</a>
</li>
<li>
<a href="/sequential" class="nav-link {% if active == 'sequential' %}active{% endif %}">
<span class="nav-icon">
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/>
<polyline points="17 6 23 6 23 12"/>
</svg>
</span>
<div class="nav-text">
<span class="nav-title">Sequential Testing</span>
<span class="nav-desc">Peeking problem demo</span>
</div>
</a>
</li>
</ul>
<div class="sidebar-footer">
Built by <a href="https://mnoorchenar.github.io/" target="_blank" rel="noopener">Mohammad Noorchenarboo</a>
</div>
</nav>
<!-- Main column -->
<div class="main-col">
<!-- Top bar -->
<div class="top-bar">
<span class="top-bar-title">{% block page_title %}{% endblock %}</span>
<div class="top-bar-right">
<span class="last-run-label" id="last-run-label" style="display:none;">
Updated <span id="last-run-time">just now</span>
</span>
<span class="kbd-hint"><kbd>Ctrl</kbd><kbd>&#x23CE;</kbd> to run</span>
<span class="status-chip ready" id="status-chip">Ready</span>
<button class="hamburger" id="hamburger" aria-label="Toggle navigation">&#9776;</button>
</div>
<div class="progress-bar" id="progress-bar"></div>
</div>
<!-- Content area -->
<div class="content-area">
{% block content %}{% endblock %}
</div>
</div>
</div>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<script>
// Sidebar toggle
const hamburger = document.getElementById('hamburger');
const sidebar = document.getElementById('sidebar');
hamburger.addEventListener('click', () => sidebar.classList.toggle('open'));
document.querySelectorAll('.nav-link').forEach(l => l.addEventListener('click', () => sidebar.classList.remove('open')));
// Progress bar + status chip
const progressBar = document.getElementById('progress-bar');
const statusChip = document.getElementById('status-chip');
function showSpinner() {
progressBar.classList.add('running');
statusChip.textContent = 'Computing\u2026';
statusChip.className = 'status-chip computing';
}
function hideSpinner() {
progressBar.classList.remove('running');
statusChip.textContent = 'Ready';
statusChip.className = 'status-chip ready';
if (typeof markLastRun === 'function') markLastRun();
}
function showError(msg) {
progressBar.classList.remove('running');
statusChip.textContent = 'Error';
statusChip.className = 'status-chip error';
if (typeof showToast === 'function') showToast(msg, 'error');
}
function hideError() { /* no-op */ }
// Plotly helper
const PLOTLY_CONFIG = {
responsive: true,
displaylogo: false,
modeBarButtonsToRemove: ['lasso2d', 'select2d', 'toImage', 'resetScale2d'],
toImageButtonOptions: { format: 'png', filename: 'experimentlab_chart', scale: 2 }
};
function renderChart(divId, chartJson) {
const parsed = JSON.parse(chartJson);
Plotly.newPlot(divId, parsed.data, parsed.layout, PLOTLY_CONFIG);
}
</script>
{% block scripts %}{% endblock %}
</body>
</html>