refactor(dashboard): overhaul UI styling, typography, layout and fix JS string syntax error

This commit is contained in:
Riz Ashraf committed 2026-09-12 11:25:44 +01:00
1 parent 5d37af1d74
commit bd4622bbb5
1 file changed
+270 -64
+270 -64
View File
@@ -1,60 +1,245 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Antigravity Memory Hub</title>
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background-color: #f0f2f5; color: #333; display: flex; flex-direction: column; height: 100vh; box-sizing: border-box; }
.header-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
h1 { margin: 0; color: #2c3e50; }
.status-dot { display: inline-block; width: 10px; height: 10px; background-color: #2ecc71; border-radius: 50%; margin-right: 8px; box-shadow: 0 0 5px #2ecc71; }
.main-container { display: flex; gap: 20px; flex: 1; min-height: 0; }
.panel { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); display: flex; flex-direction: column; }
.panel h2 { margin-top: 0; margin-bottom: 15px; color: #34495e; font-size: 1.2em; border-bottom: 1px solid #ecf0f1; padding-bottom: 10px; }
/* Graph Panel */
.graph-panel { flex: 2; position: relative; display: flex; flex-direction: column; }
#network-container { flex: 1; min-height: 400px; position: relative; border: 1px solid #bdc3c7; border-radius: 4px; background: #fafafa; }
/* Right Column */
.right-column { flex: 1; display: flex; flex-direction: column; gap: 20px; }
/* Search Panel */
.search-panel { flex: 1; }
input[type="text"] { width: 100%; padding: 10px; border: 1px solid #bdc3c7; border-radius: 4px; box-sizing: border-box; margin-bottom: 10px; }
#search-results { overflow-y: auto; flex: 1; font-size: 0.9em; }
.search-result-item { padding: 8px; border-bottom: 1px solid #eee; }
.search-result-item strong { color: #2980b9; display: block; }
/* Kanban Panel */
.kanban-panel { flex: 1.5; display: flex; flex-direction: column; min-height: 0; }
.kanban-board { display: flex; gap: 10px; flex: 1; min-height: 0; }
.kanban-column { flex: 1; background: #f8f9fa; border-radius: 4px; padding: 10px; display: flex; flex-direction: column; min-height: 0; }
.kanban-column h3 { margin: 0 0 10px 0; font-size: 0.9em; color: #7f8c8d; text-align: center; }
.kanban-items { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; min-height: 0; padding-right: 5px; }
/* Graph Controls */
.graph-controls { position: absolute; top: 50px; right: 30px; z-index: 10; display: flex; flex-direction: column; gap: 5px; }
.graph-controls button { background: white; border: 1px solid #bdc3c7; border-radius: 4px; width: 30px; height: 30px; cursor: pointer; font-weight: bold; }
.graph-controls button:hover { background: #ecf0f1; }
.task-card { background: white; padding: 8px; border-radius: 4px; border-left: 4px solid #3498db; font-size: 0.85em; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.task-card.completed { border-left-color: #2ecc71; opacity: 0.7; }
/* Activity Feed */
.activity-panel { height: 200px; margin-top: 20px; }
#activity-feed { overflow-y: auto; flex: 1; font-family: monospace; font-size: 0.85em; background: #1e1e1e; color: #00ff00; padding: 10px; border-radius: 4px; }
.feed-entry { margin-bottom: 4px; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f7f6;
color: #2c3e50;
display: flex;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
}
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: white;
padding: 15px 25px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
margin-bottom: 20px;
}
.header-bar h1 {
margin: 0;
font-size: 1.5em;
color: #2c3e50;
display: flex;
align-items: center;
gap: 10px;
}
.status-dot {
height: 12px;
width: 12px;
background-color: #2ecc71;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
box-shadow: 0 0 5px #2ecc71;
}
.main-container {
display: flex;
flex: 1;
gap: 20px;
min-height: 0;
}
.panel {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
}
.panel h2 {
margin-top: 0;
margin-bottom: 15px;
color: #34495e;
font-size: 1.2em;
border-bottom: 2px solid #f0f2f5;
padding-bottom: 10px;
}
.graph-panel {
flex: 2;
position: relative;
}
#network-container {
flex: 1;
min-height: 400px;
position: relative;
border: 1px solid #e1e8ed;
border-radius: 6px;
background: #fafbfc;
}
.graph-controls {
position: absolute;
top: 65px;
right: 35px;
z-index: 10;
display: flex;
flex-direction: column;
gap: 5px;
}
.graph-controls button {
background: white;
border: 1px solid #dcdde1;
border-radius: 4px;
width: 32px;
height: 32px;
cursor: pointer;
font-weight: bold;
color: #34495e;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: all 0.2s ease;
}
.graph-controls button:hover {
background: #f8f9fa;
border-color: #bdc3c7;
}
.right-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
min-width: 300px;
}
.search-panel {
flex: 1;
min-height: 200px;
}
input[type="text"] {
width: 100%;
padding: 12px;
border: 1px solid #dcdde1;
border-radius: 6px;
box-sizing: border-box;
margin-bottom: 15px;
font-size: 0.95em;
transition: border-color 0.2s ease;
}
input[type="text"]:focus {
outline: none;
border-color: #3498db;
}
#search-results {
overflow-y: auto;
flex: 1;
font-size: 0.9em;
}
.search-result-item {
padding: 12px;
border-bottom: 1px solid #f0f2f5;
}
.search-result-item:last-child {
border-bottom: none;
}
.search-result-item strong {
color: #2980b9;
display: block;
margin-bottom: 4px;
}
.kanban-panel {
flex: 1.5;
min-height: 300px;
}
.kanban-board {
display: flex;
gap: 15px;
flex: 1;
min-height: 0;
}
.kanban-column {
flex: 1;
background: #f8f9fa;
border-radius: 6px;
padding: 12px;
display: flex;
flex-direction: column;
min-height: 0;
border: 1px solid #e1e8ed;
}
.kanban-column h3 {
margin: 0 0 12px 0;
font-size: 0.85em;
color: #7f8c8d;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.kanban-items {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 10px;
padding-right: 5px;
}
.kanban-items::-webkit-scrollbar {
width: 6px;
}
.kanban-items::-webkit-scrollbar-thumb {
background-color: #bdc3c7;
border-radius: 3px;
}
.task-card {
background: white;
padding: 12px;
border-radius: 6px;
border-left: 4px solid #3498db;
font-size: 0.85em;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
line-height: 1.4;
}
.task-card.completed {
border-left-color: #2ecc71;
background-color: #fcfcfc;
color: #7f8c8d;
}
.task-card strong {
color: #2c3e50;
display: block;
margin-bottom: 6px;
font-size: 1.05em;
}
.activity-panel {
height: 180px;
margin-top: 20px;
}
#activity-feed {
overflow-y: auto;
flex: 1;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 0.85em;
background: #1e272e;
color: #4cd137;
padding: 15px;
border-radius: 6px;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.2);
}
.feed-entry {
margin-bottom: 6px;
line-height: 1.4;
}
.feed-entry .time {
color: #7f8c8d;
margin-right: 8px;
}
</style>
</head>
<body>
<div class="header-bar">
<h1>🧠 Antigravity Memory Hub</h1>
<div><span class="status-dot"></span>System Online</div>
<div style="font-weight: 500;"><span class="status-dot"></span>System Online</div>
</div>
<div class="main-container">
<div class="panel graph-panel">
<div class="panel graph-panel">
<h2>Knowledge Graph</h2>
<div class="graph-controls">
<button onclick="zoomGraph(0.2)" title="Zoom In">+</button>
@@ -62,7 +247,9 @@
<button onclick="resetGraph()" title="Reset View">⌂</button>
</div>
<div id="network-container"></div>
</div><div class="right-column">
</div>
<div class="right-column">
<div class="panel search-panel">
<h2>Omni-Search</h2>
<input type="text" id="search-box" placeholder="Search memory (e.g., 'database')..." onkeyup="handleSearch(event)">
@@ -91,7 +278,7 @@
</div>
<script>
// Graph Controls
// Graph Controls
function zoomGraph(step) {
if (!network) return;
const currentScale = network.getScale();
@@ -102,7 +289,7 @@
network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
}
// Graph Initialization
// Graph Initialization
let network = null;
let nodesData = new vis.DataSet();
let edgesData = new vis.DataSet();
@@ -117,13 +304,23 @@
const nodeIds = new Set();
for (const [name, entity] of Object.entries(data.entities)) {
newNodes.push({ id: name, label: name, title: entity.observations.join('\n') });
newNodes.push({
id: name,
label: name,
title: entity.observations.join('\n')
});
nodeIds.add(name);
}
data.relations.forEach(r => {
if (nodeIds.has(r.from) && nodeIds.has(r.to)) {
newEdges.push({ id: r.from + '-' + r.to + '-' + r.relationType, from: r.from, to: r.to, label: r.relationType, arrows: 'to' });
newEdges.push({
id: r.from + '-' + r.to + '-' + r.relationType,
from: r.from,
to: r.to,
label: r.relationType,
arrows: 'to'
});
}
});
@@ -143,13 +340,30 @@
if (!network) {
const container = document.getElementById('network-container');
const options = {
nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } },
edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } },
physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } }
nodes: {
shape: 'dot',
size: 16,
font: { size: 12, color: '#333' },
color: { background: '#3498db', border: '#2980b9' },
shadow: true
},
edges: {
color: { color: '#bdc3c7' },
font: { size: 10, align: 'middle' },
smooth: { type: 'continuous' }
},
physics: {
barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 }
},
interaction: { hover: true, tooltipDelay: 100 }
};
network = new vis.Network(container, { nodes: nodesData, edges: edgesData }, options);
}
} catch (err) { console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "<div style=`"color:red;padding:20px;`">Error loading graph: " + err.message + "</div>"; } }
} catch (err) {
console.error("Failed to load graph", err);
document.getElementById("network-container").innerHTML = '<div style="color:#e74c3c;padding:20px;font-weight:bold;">Error loading graph: ' + err.message + '</div>';
}
}
// Kanban Board Initialization
async function loadTasks() {
@@ -165,7 +379,7 @@
tasks.forEach(t => {
const card = document.createElement('div');
card.className = `task-card ${t.status === 'completed' ? 'completed' : ''}`;
card.innerHTML = `<strong>${t.title}</strong><br>${t.description}`;
card.innerHTML = `<strong>${t.title}</strong>${t.description}`;
if (t.status === 'completed') {
doneContainer.appendChild(card);
@@ -193,7 +407,7 @@
<div class="search-result-item">
<strong>${r.type_name}</strong>
<div>${r.content.substring(0, 100)}...</div>
<div style="font-size:0.8em;color:#95a5a6">Score: ${r.score.toFixed(2)}</div>
<div style="font-size:0.85em;color:#95a5a6;margin-top:4px;">Score: ${r.score.toFixed(2)}</div>
</div>
`).join('');
}
@@ -211,7 +425,7 @@
const div = document.createElement('div');
div.className = 'feed-entry';
const time = new Date().toLocaleTimeString();
div.innerText = `[${time}] ${event.data}`;
div.innerHTML = `<span class="time">[${time}]</span> ${event.data}`;
feed.appendChild(div);
feed.scrollTop = feed.scrollHeight;
});
@@ -229,11 +443,3 @@
</script>
</body>
</html>