Spaces:
Runtime error
feat(demo): unified mission-status color scheme across all UI elements
Browse filesRedesigned colors around three mission states:
- Match (satisfies=true): #34d399 emerald green
- No Match (satisfies=false): #f87171 soft red
- Unassessed (no verdict): #64748b slate gray
Unified across:
- CSS variables (--mission-match/nomatch/unassessed)
- Track card dots (was type-based color, now mission status)
- SVG overlay strokes (was hardcoded rgba, now MISSION_COLORS)
- Status badges (now reference CSS vars)
- Timeline event markers (critical=match green, low=nomatch red)
- Event log entries (same mapping)
- Waveform density bars (green=high activity, gray=low)
- Inspect panel header label color
- Timeline legend dots
Added MISSION_COLORS constant + getMissionColor(track) helper in
helpers.js as single source of truth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- demo/js/helpers.js +18 -0
- demo/js/inspect.js +1 -1
- demo/js/real-backend.js +18 -20
- demo/styles/components.css +5 -5
- demo/styles/variables.css +11 -0
|
@@ -19,6 +19,22 @@ function buildFeatures(gptRaw) {
|
|
| 19 |
return features;
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
// ββ Status Badge Helper ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 23 |
|
| 24 |
function getStatusBadgeHTML(track) {
|
|
@@ -225,6 +241,8 @@ function matchAICommand(question) {
|
|
| 225 |
// ββ Export to namespace βββββββββββββββββββββββββββββββββββββββββ
|
| 226 |
|
| 227 |
Object.assign(window.ISR, {
|
|
|
|
|
|
|
| 228 |
buildFeatures,
|
| 229 |
getStatusBadgeHTML,
|
| 230 |
formatTime,
|
|
|
|
| 19 |
return features;
|
| 20 |
}
|
| 21 |
|
| 22 |
+
// ββ Mission Status Color Helper ββββββββββββββββββββββββββββββββββββββ
|
| 23 |
+
// Single source of truth for mission-status-based colors.
|
| 24 |
+
// Used by track card dots, SVG overlays, timeline events, etc.
|
| 25 |
+
|
| 26 |
+
const MISSION_COLORS = {
|
| 27 |
+
match: { solid: '#34d399', bg: 'rgba(52, 211, 153, 0.15)', stroke: 'rgba(52, 211, 153, 0.8)' },
|
| 28 |
+
nomatch: { solid: '#f87171', bg: 'rgba(248, 113, 113, 0.12)', stroke: 'rgba(248, 113, 113, 0.8)' },
|
| 29 |
+
unassessed: { solid: '#64748b', bg: 'rgba(100, 116, 139, 0.12)', stroke: 'rgba(100, 116, 139, 0.5)' },
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
function getMissionColor(track) {
|
| 33 |
+
if (track.satisfies === true) return MISSION_COLORS.match;
|
| 34 |
+
if (track.satisfies === false) return MISSION_COLORS.nomatch;
|
| 35 |
+
return MISSION_COLORS.unassessed;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
// ββ Status Badge Helper ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
|
| 40 |
function getStatusBadgeHTML(track) {
|
|
|
|
| 241 |
// ββ Export to namespace βββββββββββββββββββββββββββββββββββββββββ
|
| 242 |
|
| 243 |
Object.assign(window.ISR, {
|
| 244 |
+
MISSION_COLORS,
|
| 245 |
+
getMissionColor,
|
| 246 |
buildFeatures,
|
| 247 |
getStatusBadgeHTML,
|
| 248 |
formatTime,
|
|
@@ -39,7 +39,7 @@ function enterInspectState(trackId) {
|
|
| 39 |
|
| 40 |
// Normalize track properties for display
|
| 41 |
const trackLabel = realTrack ? (realTrack.label || 'object').toUpperCase() : mockTrack.label.toUpperCase();
|
| 42 |
-
const trackColor = realTrack ? (realTrack.
|
| 43 |
const trackConf = realTrack ? (realTrack.score || 0).toFixed(2) : mockTrack.confidence.toFixed(2);
|
| 44 |
|
| 45 |
// Mission status badge for inspect header
|
|
|
|
| 39 |
|
| 40 |
// Normalize track properties for display
|
| 41 |
const trackLabel = realTrack ? (realTrack.label || 'object').toUpperCase() : mockTrack.label.toUpperCase();
|
| 42 |
+
const trackColor = realTrack ? ISR.getMissionColor(realTrack).solid : mockTrack.color;
|
| 43 |
const trackConf = realTrack ? (realTrack.score || 0).toFixed(2) : mockTrack.confidence.toFixed(2);
|
| 44 |
|
| 45 |
// Mission status badge for inspect header
|
|
@@ -772,8 +772,9 @@ function renderTrackListFromData(tracks) {
|
|
| 772 |
'</div>';
|
| 773 |
}
|
| 774 |
|
|
|
|
| 775 |
card.innerHTML = `
|
| 776 |
-
<div class="track-dot" style="background: ${
|
| 777 |
<div class="track-info">
|
| 778 |
<div class="track-label" style="display:flex;align-items:center;gap:6px;">
|
| 779 |
<span>${t.label}</span>
|
|
@@ -913,13 +914,9 @@ function renderSvgOverlay(tracks) {
|
|
| 913 |
const nw = nx2 - nx1;
|
| 914 |
const nh = ny2 - ny1;
|
| 915 |
|
| 916 |
-
// Determine color by mission status
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
strokeColor = 'rgba(40, 167, 69, 0.8)';
|
| 920 |
-
} else if (t.satisfies === false) {
|
| 921 |
-
strokeColor = 'rgba(220, 53, 69, 0.8)';
|
| 922 |
-
}
|
| 923 |
|
| 924 |
const isSelected = ISR.STATE.selectedTrackId === t.track_id;
|
| 925 |
const isHighlighted = ISR.STATE.highlightTrackId === t.track_id;
|
|
@@ -1086,7 +1083,8 @@ function renderWaveformFromDensity(canvas, densityData) {
|
|
| 1086 |
|
| 1087 |
// Color gradient based on density value
|
| 1088 |
const hue = 220 - val * 180; // blue(220) β amber range
|
| 1089 |
-
|
|
|
|
| 1090 |
ctx.fillRect(x, y, Math.max(barW - 1, 1), barH);
|
| 1091 |
}
|
| 1092 |
}
|
|
@@ -1211,10 +1209,10 @@ function renderEventMarkersFromData(events) {
|
|
| 1211 |
container.innerHTML = '';
|
| 1212 |
|
| 1213 |
const PRIORITY_COLORS = {
|
| 1214 |
-
critical:
|
| 1215 |
-
high: '#f59e0b',
|
| 1216 |
-
normal:
|
| 1217 |
-
low:
|
| 1218 |
};
|
| 1219 |
|
| 1220 |
for (const evt of events) {
|
|
@@ -1261,10 +1259,10 @@ function renderEventLogFromData(events) {
|
|
| 1261 |
if (!log) return;
|
| 1262 |
|
| 1263 |
const PRIORITY_STYLES = {
|
| 1264 |
-
critical: { bg:
|
| 1265 |
high: { bg: 'rgba(245,158,11,0.12)', color: '#f59e0b' },
|
| 1266 |
-
normal: { bg:
|
| 1267 |
-
low: { bg:
|
| 1268 |
};
|
| 1269 |
|
| 1270 |
log.innerHTML = events.map(evt => {
|
|
@@ -1303,10 +1301,10 @@ function renderRealTimelineLegend(events) {
|
|
| 1303 |
}
|
| 1304 |
|
| 1305 |
const TYPE_COLORS = {
|
| 1306 |
-
system:
|
| 1307 |
-
detection:
|
| 1308 |
-
tracking:
|
| 1309 |
-
alert:
|
| 1310 |
};
|
| 1311 |
|
| 1312 |
legend.innerHTML = Object.entries(typeCounts).map(([type, count]) =>
|
|
|
|
| 772 |
'</div>';
|
| 773 |
}
|
| 774 |
|
| 775 |
+
const mc = ISR.getMissionColor(t);
|
| 776 |
card.innerHTML = `
|
| 777 |
+
<div class="track-dot" style="background: ${mc.solid}; box-shadow: 0 0 4px ${mc.solid};"></div>
|
| 778 |
<div class="track-info">
|
| 779 |
<div class="track-label" style="display:flex;align-items:center;gap:6px;">
|
| 780 |
<span>${t.label}</span>
|
|
|
|
| 914 |
const nw = nx2 - nx1;
|
| 915 |
const nh = ny2 - ny1;
|
| 916 |
|
| 917 |
+
// Determine color by mission status β uses unified MISSION_COLORS
|
| 918 |
+
const _mc = ISR.getMissionColor(t);
|
| 919 |
+
const strokeColor = _mc.stroke;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 920 |
|
| 921 |
const isSelected = ISR.STATE.selectedTrackId === t.track_id;
|
| 922 |
const isHighlighted = ISR.STATE.highlightTrackId === t.track_id;
|
|
|
|
| 1083 |
|
| 1084 |
// Color gradient based on density value
|
| 1085 |
const hue = 220 - val * 180; // blue(220) β amber range
|
| 1086 |
+
// Waveform density: high activity = match green, medium = unassessed gray, low = dim
|
| 1087 |
+
ctx.fillStyle = val > 0.6 ? '#34d39988' : val > 0.3 ? '#64748b88' : '#64748b44';
|
| 1088 |
ctx.fillRect(x, y, Math.max(barW - 1, 1), barH);
|
| 1089 |
}
|
| 1090 |
}
|
|
|
|
| 1209 |
container.innerHTML = '';
|
| 1210 |
|
| 1211 |
const PRIORITY_COLORS = {
|
| 1212 |
+
critical: ISR.MISSION_COLORS.match.solid, // mission match events
|
| 1213 |
+
high: '#f59e0b', // speed alerts
|
| 1214 |
+
normal: ISR.MISSION_COLORS.unassessed.solid, // detection/tracking events
|
| 1215 |
+
low: ISR.MISSION_COLORS.nomatch.solid, // no match / dismissed
|
| 1216 |
};
|
| 1217 |
|
| 1218 |
for (const evt of events) {
|
|
|
|
| 1259 |
if (!log) return;
|
| 1260 |
|
| 1261 |
const PRIORITY_STYLES = {
|
| 1262 |
+
critical: { bg: ISR.MISSION_COLORS.match.bg, color: ISR.MISSION_COLORS.match.solid },
|
| 1263 |
high: { bg: 'rgba(245,158,11,0.12)', color: '#f59e0b' },
|
| 1264 |
+
normal: { bg: ISR.MISSION_COLORS.unassessed.bg, color: ISR.MISSION_COLORS.unassessed.solid },
|
| 1265 |
+
low: { bg: ISR.MISSION_COLORS.nomatch.bg, color: ISR.MISSION_COLORS.nomatch.solid },
|
| 1266 |
};
|
| 1267 |
|
| 1268 |
log.innerHTML = events.map(evt => {
|
|
|
|
| 1301 |
}
|
| 1302 |
|
| 1303 |
const TYPE_COLORS = {
|
| 1304 |
+
system: ISR.MISSION_COLORS.unassessed.solid,
|
| 1305 |
+
detection: ISR.MISSION_COLORS.unassessed.solid,
|
| 1306 |
+
tracking: ISR.MISSION_COLORS.unassessed.solid,
|
| 1307 |
+
alert: ISR.MISSION_COLORS.match.solid,
|
| 1308 |
};
|
| 1309 |
|
| 1310 |
legend.innerHTML = Object.entries(typeCounts).map(([type, count]) =>
|
|
@@ -350,8 +350,8 @@
|
|
| 350 |
font-size: 8px; padding: 2px 6px; border-radius: 3px; letter-spacing: 0.5px;
|
| 351 |
font-weight: 600; text-transform: uppercase;
|
| 352 |
}
|
| 353 |
-
.status-badge.match { background:
|
| 354 |
-
.status-badge.no-match { background:
|
| 355 |
-
.status-badge.relevant { background:
|
| 356 |
-
.status-badge.not-relevant { background:
|
| 357 |
-
.status-badge.pending { background:
|
|
|
|
| 350 |
font-size: 8px; padding: 2px 6px; border-radius: 3px; letter-spacing: 0.5px;
|
| 351 |
font-weight: 600; text-transform: uppercase;
|
| 352 |
}
|
| 353 |
+
.status-badge.match { background: var(--mission-match-bg); color: var(--mission-match); }
|
| 354 |
+
.status-badge.no-match { background: var(--mission-nomatch-bg); color: var(--mission-nomatch); }
|
| 355 |
+
.status-badge.relevant { background: var(--mission-match-bg); color: var(--mission-match); }
|
| 356 |
+
.status-badge.not-relevant { background: var(--mission-nomatch-bg); color: var(--mission-nomatch); opacity: 0.6; }
|
| 357 |
+
.status-badge.pending { background: var(--mission-unassessed-bg); color: var(--mission-unassessed); }
|
|
@@ -12,6 +12,17 @@
|
|
| 12 |
--text-tertiary: rgba(255, 255, 255, 0.35);
|
| 13 |
--panel-bg: rgba(255, 255, 255, 0.02);
|
| 14 |
--panel-border: rgba(255, 255, 255, 0.06);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
}
|
| 16 |
|
| 17 |
/* ββ Reset ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
|
|
| 12 |
--text-tertiary: rgba(255, 255, 255, 0.35);
|
| 13 |
--panel-bg: rgba(255, 255, 255, 0.02);
|
| 14 |
--panel-border: rgba(255, 255, 255, 0.06);
|
| 15 |
+
|
| 16 |
+
/* Mission status colors β single source of truth */
|
| 17 |
+
--mission-match: #34d399;
|
| 18 |
+
--mission-match-bg: rgba(52, 211, 153, 0.15);
|
| 19 |
+
--mission-match-stroke: rgba(52, 211, 153, 0.8);
|
| 20 |
+
--mission-nomatch: #f87171;
|
| 21 |
+
--mission-nomatch-bg: rgba(248, 113, 113, 0.12);
|
| 22 |
+
--mission-nomatch-stroke: rgba(248, 113, 113, 0.8);
|
| 23 |
+
--mission-unassessed: #64748b;
|
| 24 |
+
--mission-unassessed-bg: rgba(100, 116, 139, 0.12);
|
| 25 |
+
--mission-unassessed-stroke: rgba(100, 116, 139, 0.5);
|
| 26 |
}
|
| 27 |
|
| 28 |
/* ββ Reset ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|