Skip to content

Commit 35d313b

Browse files
aksOpsclaude
andcommitted
Redesign flow UI with Tailwind CSS — premium look + working edges
- Tailwind CDN for styling (no build step needed) - Sticky header with brand logo, node/edge stats - Icon-based navigation with active state highlighting - Breadcrumb with clickable back navigation - Pill-style view stats - Proper dark/light theme toggle with Mermaid re-render - Mermaid configured with curve:basis, proper spacing - Footer with generation timestamp - Renamed to Code IQ branding throughout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 29682a8 commit 35d313b

2 files changed

Lines changed: 99 additions & 87 deletions

File tree

src/code_intelligence/flow/templates/interactive.html

Lines changed: 98 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,105 @@
11
<!DOCTYPE html>
2-
<html lang="en">
2+
<html lang="en" class="dark">
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<title>Code Intelligence — Architecture Flow</title>
7-
<style>
8-
* { box-sizing: border-box; margin: 0; padding: 0; }
9-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0d1117; color: #c9d1d9; }
10-
.header { padding: 20px 24px; border-bottom: 1px solid #21262d; display: flex; align-items: center; justify-content: space-between; }
11-
.header h1 { font-size: 20px; font-weight: 600; color: #f0f6fc; }
12-
.stats { display: flex; gap: 16px; }
13-
.stat { text-align: center; padding: 4px 12px; background: #161b22; border-radius: 6px; border: 1px solid #21262d; }
14-
.stat-val { font-size: 18px; font-weight: 700; color: #58a6ff; }
15-
.stat-label { font-size: 11px; color: #8b949e; text-transform: uppercase; }
16-
.nav { padding: 12px 24px; display: flex; gap: 8px; border-bottom: 1px solid #21262d; flex-wrap: wrap; }
17-
.nav-btn { padding: 6px 16px; border-radius: 6px; border: 1px solid #30363d; background: #161b22; color: #c9d1d9; cursor: pointer; font-size: 13px; transition: all 0.15s; }
18-
.nav-btn:hover { background: #21262d; border-color: #58a6ff; }
19-
.nav-btn.active { background: #1f6feb; border-color: #1f6feb; color: #fff; }
20-
.breadcrumb { padding: 8px 24px; font-size: 13px; color: #8b949e; }
21-
.breadcrumb a { color: #58a6ff; text-decoration: none; cursor: pointer; }
22-
.diagram { padding: 24px; display: flex; justify-content: center; min-height: 400px; }
23-
.diagram .mermaid { background: #161b22; padding: 24px; border-radius: 8px; border: 1px solid #21262d; max-width: 100%; overflow-x: auto; }
24-
.view-stats { padding: 12px 24px; display: flex; gap: 12px; flex-wrap: wrap; }
25-
.view-stat { font-size: 12px; color: #8b949e; padding: 4px 8px; background: #161b22; border-radius: 4px; }
26-
.footer { padding: 16px 24px; border-top: 1px solid #21262d; text-align: center; font-size: 12px; color: #484f58; }
27-
/* Light theme */
28-
body.light { background: #fff; color: #24292f; }
29-
body.light .header { border-color: #d0d7de; }
30-
body.light .header h1 { color: #24292f; }
31-
body.light .stat { background: #f6f8fa; border-color: #d0d7de; }
32-
body.light .stat-val { color: #0969da; }
33-
body.light .stat-label { color: #57606a; }
34-
body.light .nav { border-color: #d0d7de; }
35-
body.light .nav-btn { background: #f6f8fa; border-color: #d0d7de; color: #24292f; }
36-
body.light .nav-btn:hover { border-color: #0969da; }
37-
body.light .nav-btn.active { background: #0969da; color: #fff; }
38-
body.light .breadcrumb { color: #57606a; }
39-
body.light .breadcrumb a { color: #0969da; }
40-
body.light .diagram .mermaid { background: #f6f8fa; border-color: #d0d7de; }
41-
body.light .view-stat { background: #f6f8fa; color: #57606a; }
42-
body.light .footer { border-color: #d0d7de; color: #8c959f; }
43-
</style>
6+
<title>Code IQ — Architecture Flow</title>
7+
<script src="https://cdn.tailwindcss.com"></script>
8+
<script>
9+
tailwind.config = {
10+
darkMode: 'class',
11+
theme: { extend: {
12+
colors: { brand: { 50:'#eff6ff', 100:'#dbeafe', 500:'#3b82f6', 600:'#2563eb', 700:'#1d4ed8', 900:'#1e3a5f' }}
13+
}}
14+
}
15+
</script>
16+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
4417
</head>
45-
<body>
46-
<div class="header">
47-
<h1>Code Intelligence — Architecture Flow</h1>
48-
<div class="stats" id="global-stats"></div>
49-
<button class="nav-btn" onclick="toggleTheme()" style="font-size:16px">theme</button>
18+
<body class="bg-gray-950 text-gray-200 min-h-screen flex flex-col transition-colors duration-200">
19+
20+
<!-- Header -->
21+
<header class="border-b border-gray-800 bg-gray-900/80 backdrop-blur-sm sticky top-0 z-10">
22+
<div class="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between flex-wrap gap-4">
23+
<div class="flex items-center gap-3">
24+
<div class="w-9 h-9 rounded-lg bg-brand-600 flex items-center justify-center text-white font-bold text-sm">IQ</div>
25+
<div>
26+
<h1 class="text-lg font-semibold text-white tracking-tight">Code IQ</h1>
27+
<p class="text-xs text-gray-500">Architecture Flow — Deterministic Analysis</p>
28+
</div>
29+
</div>
30+
<div class="flex items-center gap-3" id="global-stats"></div>
31+
<button onclick="toggleTheme()" class="p-2 rounded-lg border border-gray-700 hover:border-gray-500 text-gray-400 hover:text-white transition" title="Toggle theme">
32+
<svg id="theme-icon-dark" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/></svg>
33+
<svg id="theme-icon-light" class="w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>
34+
</button>
35+
</div>
36+
</header>
37+
38+
<!-- Navigation -->
39+
<nav class="border-b border-gray-800 bg-gray-900/50">
40+
<div class="max-w-7xl mx-auto px-6 py-3 flex items-center gap-2 flex-wrap" id="nav"></div>
41+
</nav>
42+
43+
<!-- Breadcrumb + View Stats -->
44+
<div class="max-w-7xl mx-auto px-6 pt-4 flex items-center justify-between flex-wrap gap-2">
45+
<div class="text-sm text-gray-500" id="breadcrumb"></div>
46+
<div class="flex gap-2 flex-wrap" id="view-stats"></div>
5047
</div>
51-
<div class="nav" id="nav"></div>
52-
<div class="breadcrumb" id="breadcrumb"></div>
53-
<div class="view-stats" id="view-stats"></div>
54-
<div class="diagram"><pre class="mermaid" id="mermaid-container"></pre></div>
55-
<div class="footer">Generated by Code Intelligence — No AI, pure deterministic analysis</div>
5648

57-
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
49+
<!-- Diagram -->
50+
<main class="flex-1 max-w-7xl mx-auto w-full px-6 py-6">
51+
<div class="rounded-xl border border-gray-800 bg-gray-900/50 p-6 min-h-[500px] flex items-center justify-center overflow-x-auto">
52+
<pre class="mermaid w-full" id="mermaid-container"></pre>
53+
</div>
54+
</main>
55+
56+
<!-- Footer -->
57+
<footer class="border-t border-gray-800 bg-gray-900/30">
58+
<div class="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between text-xs text-gray-600">
59+
<span>Generated by <strong class="text-gray-400">Code IQ</strong> — No AI, pure deterministic analysis</span>
60+
<span id="gen-time"></span>
61+
</div>
62+
</footer>
63+
5864
<script>
59-
/* Data injected by renderer — all values are deterministically generated, not user input */
65+
/* Data injected by renderer — all values are deterministically generated */
6066
const VIEWS_MERMAID = {{VIEWS_MERMAID}};
6167
const VIEWS_DATA = {{VIEWS_DATA}};
6268
const STATS = {{STATS}};
6369

6470
const VIEW_LABELS = {overview:"Overview", ci:"CI/CD Pipeline", deploy:"Deployment", runtime:"Runtime", auth:"Security"};
71+
const VIEW_ICONS = {overview:"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z", ci:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15", deploy:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2", runtime:"M13 10V3L4 14h7v7l9-11h-7z", auth:"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"};
6572
let currentView = "overview";
73+
let isDark = true;
6674

6775
function init() {
68-
mermaid.initialize({startOnLoad:false, theme:"dark", securityLevel:"loose"});
76+
mermaid.initialize({startOnLoad:false, theme:"dark", securityLevel:"loose", flowchart:{curve:"basis", padding:20, nodeSpacing:40, rankSpacing:60}});
6977
renderGlobalStats();
7078
renderNav();
7179
switchView("overview");
72-
}
73-
74-
function createStatElement(label, val) {
75-
var stat = document.createElement("div");
76-
stat.className = "stat";
77-
var valDiv = document.createElement("div");
78-
valDiv.className = "stat-val";
79-
valDiv.textContent = val.toLocaleString();
80-
var labelDiv = document.createElement("div");
81-
labelDiv.className = "stat-label";
82-
labelDiv.textContent = label;
83-
stat.appendChild(valDiv);
84-
stat.appendChild(labelDiv);
85-
return stat;
80+
document.getElementById("gen-time").textContent = new Date().toLocaleDateString();
8681
}
8782

8883
function renderGlobalStats() {
8984
var el = document.getElementById("global-stats");
90-
while (el.firstChild) el.removeChild(el.firstChild);
91-
var items = [
92-
{label:"Nodes", val:STATS.total_nodes||0},
93-
{label:"Edges", val:STATS.total_edges||0},
94-
];
95-
items.forEach(function(s) { el.appendChild(createStatElement(s.label, s.val)); });
85+
el.innerHTML = "";
86+
[{l:"Nodes",v:STATS.total_nodes||0,c:"text-brand-500"},{l:"Edges",v:STATS.total_edges||0,c:"text-emerald-500"}].forEach(function(s){
87+
var d = document.createElement("div");
88+
d.className = "flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gray-800/50 border border-gray-700/50";
89+
d.innerHTML = '<span class="text-base font-bold '+s.c+'">'+s.v.toLocaleString()+'</span><span class="text-xs text-gray-500 uppercase tracking-wider">'+s.l+'</span>';
90+
el.appendChild(d);
91+
});
9692
}
9793

9894
function renderNav() {
9995
var el = document.getElementById("nav");
100-
while (el.firstChild) el.removeChild(el.firstChild);
96+
el.innerHTML = "";
10197
Object.keys(VIEW_LABELS).forEach(function(v) {
10298
var btn = document.createElement("button");
103-
btn.className = "nav-btn" + (v === currentView ? " active" : "");
104-
btn.textContent = VIEW_LABELS[v];
99+
var isActive = v === currentView;
100+
btn.className = "flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-150 " +
101+
(isActive ? "bg-brand-600 text-white shadow-lg shadow-brand-600/20" : "text-gray-400 hover:text-white hover:bg-gray-800 border border-transparent hover:border-gray-700");
102+
btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="'+(VIEW_ICONS[v]||VIEW_ICONS.overview)+'"/></svg>' + VIEW_LABELS[v];
105103
btn.addEventListener("click", function() { switchView(v); });
106104
el.appendChild(btn);
107105
});
@@ -112,29 +110,33 @@ <h1>Code Intelligence — Architecture Flow</h1>
112110
renderNav();
113111

114112
var bcEl = document.getElementById("breadcrumb");
115-
while (bcEl.firstChild) bcEl.removeChild(bcEl.firstChild);
113+
bcEl.innerHTML = "";
116114
if (view === "overview") {
117-
bcEl.textContent = "Architecture Overview";
115+
bcEl.innerHTML = '<span class="text-gray-300 font-medium">Architecture Overview</span>';
118116
} else {
119117
var link = document.createElement("a");
118+
link.className = "text-brand-500 hover:text-brand-400 cursor-pointer transition";
120119
link.textContent = "Overview";
121120
link.addEventListener("click", function() { switchView("overview"); });
122121
bcEl.appendChild(link);
123-
var sep = document.createTextNode(" > " + VIEW_LABELS[view]);
124-
bcEl.appendChild(sep);
122+
bcEl.appendChild(document.createTextNode(" / "));
123+
var span = document.createElement("span");
124+
span.className = "text-gray-300 font-medium";
125+
span.textContent = VIEW_LABELS[view];
126+
bcEl.appendChild(span);
125127
}
126128

127129
/* View-specific stats */
128130
var data = VIEWS_DATA[view];
129131
var statsEl = document.getElementById("view-stats");
130-
while (statsEl.firstChild) statsEl.removeChild(statsEl.firstChild);
132+
statsEl.innerHTML = "";
131133
if (data && data.stats) {
132134
Object.keys(data.stats).forEach(function(k) {
133-
var span = document.createElement("span");
134-
span.className = "view-stat";
135-
var v = data.stats[k];
136-
span.textContent = k.replace(/_/g, " ") + ": " + (typeof v === "number" ? v.toLocaleString() : v);
137-
statsEl.appendChild(span);
135+
var val = data.stats[k];
136+
var pill = document.createElement("span");
137+
pill.className = "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-gray-800 border border-gray-700 text-gray-300";
138+
pill.innerHTML = '<span class="text-gray-500">'+k.replace(/_/g," ")+'</span> <span class="text-white font-semibold">'+(typeof val==="number"?val.toLocaleString():val)+'</span>';
139+
statsEl.appendChild(pill);
138140
});
139141
}
140142

@@ -143,10 +145,20 @@ <h1>Code Intelligence — Architecture Flow</h1>
143145
var mermaidSrc = VIEWS_MERMAID[view] || "graph LR\n empty[No data for this view]";
144146
container.removeAttribute("data-processed");
145147
container.textContent = mermaidSrc;
148+
mermaid.initialize({startOnLoad:false, theme: isDark ? "dark" : "default", securityLevel:"loose", flowchart:{curve:"basis", padding:20, nodeSpacing:40, rankSpacing:60}});
146149
mermaid.run({nodes:[container]});
147150
}
148151

149-
function toggleTheme() { document.body.classList.toggle("light"); }
152+
function toggleTheme() {
153+
isDark = !isDark;
154+
document.documentElement.classList.toggle("dark");
155+
document.body.classList.toggle("bg-gray-950"); document.body.classList.toggle("bg-white");
156+
document.body.classList.toggle("text-gray-200"); document.body.classList.toggle("text-gray-800");
157+
document.getElementById("theme-icon-dark").classList.toggle("hidden");
158+
document.getElementById("theme-icon-light").classList.toggle("hidden");
159+
/* Re-render mermaid with correct theme */
160+
switchView(currentView);
161+
}
150162

151163
document.addEventListener("DOMContentLoaded", init);
152164
</script>

tests/flow/test_renderer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def test_render_html():
6868
views = {"overview": _sample_diagram()}
6969
html = render_html(views, {"total_nodes": 100, "total_edges": 200})
7070
assert "<!DOCTYPE html>" in html
71-
assert "Code Intelligence" in html
71+
assert "Code IQ" in html
7272
assert "VIEWS_MERMAID" in html or "graph LR" in html
7373
assert "100" in html
7474

0 commit comments

Comments
 (0)