refactor(dashboard): overhaul UI styling, typography, layout and fix JS string syntax error
This commit is contained in:
1 parent
5d37af1d74
commit
bd4622bbb5
1 file changed
+270
-64
+270
-64
@@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user