1
0

polish: extract inline CSS, add connection status, panel macro, favicon, ollama cache, toast system (#164)

Major:
- Extract all inline <style> blocks from 22 Jinja2 templates into
  static/css/mission-control.css — single cacheable stylesheet
- Add tox lint check that fails on inline <style> in templates

Minor:
1. Connection status indicator in topbar (green/amber/red dot) reflecting
   WebSocket + Ollama reachability, with auto-reconnect
2. Jinja2 {% macro panel(title) %} in macros.html — eliminates repeated
   .card.mc-panel markup; index.html converted as example
3. SVG favicon (purple T + orange dot)
4. 30-second TTL cache on _check_ollama() to avoid blocking the event loop
   on every health poll (asyncio.to_thread was already in place)
5. Toast notification system (McToast.show) for transient status messages —
   wired into connection status for Ollama/WebSocket state changes

Enforcement:
- CLAUDE.md updated with conventions 11-14 (no inline CSS, use panel macro,
  use toasts, never block the event loop)
- tox lint + pre-push environments now fail on inline <style> blocks

https://claude.ai/code/session_014FQ785MQdyJQ4BAXrRSo9w

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Alexander Whitestone
2026-03-11 09:52:57 -04:00
committed by GitHub
parent 07f2c1b41e
commit 622a6a9204
30 changed files with 2171 additions and 2065 deletions

View File

@@ -12,7 +12,9 @@
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous" />
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml" />
<link rel="stylesheet" href="/static/style.css?v=5" />
<link rel="stylesheet" href="/static/css/mission-control.css?v=1" />
{% block extra_styles %}{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.3/dist/htmx.min.js" crossorigin="anonymous"></script>
<script>
@@ -31,6 +33,10 @@
<div class="mc-header-left">
<a href="/" class="mc-title">MISSION CONTROL</a>
<span class="mc-subtitle">MISSION CONTROL</span>
<span class="mc-conn-status" id="conn-status">
<span class="mc-conn-dot red" id="conn-dot"></span>
<span id="conn-label">OFFLINE</span>
</span>
</div>
<!-- Desktop nav -->
@@ -121,6 +127,9 @@
</div>
</nav>
<!-- Toast container -->
<div class="mc-toast-container" id="toast-container"></div>
<main class="mc-main">
{% block content %}{% endblock %}
</main>
@@ -206,6 +215,100 @@
.catch(function() {});
}
</script>
<!-- Toast + connection status system -->
<script>
// ── Toast notifications ──
window.McToast = {
show: function(message, level) {
level = level || 'info';
var container = document.getElementById('toast-container');
if (!container) return;
var toast = document.createElement('div');
toast.className = 'mc-toast ' + level;
toast.textContent = message;
container.appendChild(toast);
requestAnimationFrame(function() {
toast.classList.add('show');
});
setTimeout(function() {
toast.classList.remove('show');
setTimeout(function() { toast.remove(); }, 300);
}, 4000);
}
};
// ── Global connection status ──
(function() {
var dot = document.getElementById('conn-dot');
var label = document.getElementById('conn-label');
var wsConnected = false;
var ollamaOk = null; // null = unknown, true/false
function updateIndicator() {
if (!dot || !label) return;
if (!wsConnected) {
dot.className = 'mc-conn-dot red';
label.textContent = 'OFFLINE';
} else if (ollamaOk === false) {
dot.className = 'mc-conn-dot amber';
label.textContent = 'NO LLM';
} else {
dot.className = 'mc-conn-dot green';
label.textContent = 'LIVE';
}
}
function checkOllama() {
fetch('/health')
.then(function(r) { return r.json(); })
.then(function(data) {
var prev = ollamaOk;
ollamaOk = data.services && data.services.ollama === 'up';
updateIndicator();
if (prev === false && ollamaOk) {
McToast.show('Ollama reconnected', 'info');
} else if (prev === true && !ollamaOk) {
McToast.show('Ollama unreachable', 'warn');
}
})
.catch(function() {
ollamaOk = false;
updateIndicator();
});
}
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
var reconnectDelay = 1000;
function connectStatusWs() {
var ws;
try {
ws = new WebSocket(protocol + '//' + window.location.host + '/swarm/live');
} catch(e) { return; }
ws.onopen = function() {
wsConnected = true;
reconnectDelay = 1000;
updateIndicator();
checkOllama();
};
ws.onclose = function() {
if (wsConnected) {
McToast.show('WebSocket disconnected', 'error');
}
wsConnected = false;
updateIndicator();
setTimeout(connectStatusWs, reconnectDelay);
reconnectDelay = Math.min(reconnectDelay * 2, 30000);
};
ws.onerror = function() {};
}
connectStatusWs();
// Poll Ollama health every 30s
setInterval(checkOllama, 30000);
})();
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script src="/static/notifications.js"></script>
</body>