mirror of
https://github.com/zvx-echo6/recon.git
synced 2026-05-20 14:44:54 +02:00
Two bugs in the Recently Completed table: 1. Title showed "Untitled" for all transcripts because the dashboard read documents.book_title (populated by PDF metadata voting) which is NULL for transcripts. Fixed by COALESCE(book_title, filename) in the SQL query -- falls back to catalogue.filename which holds the real video title. 2. Type showed "WEB" for all transcripts because the type CASE expression only had web and pdf branches, with web matching any http% path -- and transcript paths are PeerTube watch URLs. Fixed by adding a transcript branch keyed on catalogue.source = stream.echo6.co, evaluated before the web branch. Also adds badge-transcript CSS (purple) and JS rendering case. Applied consistently to both the Recently Completed and Sources table queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
317 lines
9.5 KiB
CSS
317 lines
9.5 KiB
CSS
/* RECON Design System
|
|
* Knowledge Extraction Pipeline — Dashboard CSS
|
|
*/
|
|
|
|
:root {
|
|
--bg-primary: #0a0a0a;
|
|
--bg-secondary: #111;
|
|
--bg-tertiary: #1a1a1a;
|
|
--border: #222;
|
|
--border-light: #333;
|
|
--text-primary: #c0c0c0;
|
|
--text-muted: #888;
|
|
--text-dim: #666;
|
|
--text-faint: #555;
|
|
--green: #00ff41;
|
|
--green-dim: #16a34a;
|
|
--red: #ff4444;
|
|
--red-dim: #dc2626;
|
|
--orange: #ffa500;
|
|
--blue: #00bfff;
|
|
--blue-sky: #0ea5e9;
|
|
--blue-dark: #0284c7;
|
|
--purple: #7c3aed;
|
|
--yellow: #fbbf24;
|
|
|
|
/* Pipeline colors */
|
|
--pipe-queued: #555;
|
|
--pipe-extracting: #b45309;
|
|
--pipe-extracted: #d97706;
|
|
--pipe-enriching: #0284c7;
|
|
--pipe-enriched: #0ea5e9;
|
|
--pipe-embedding: #7c3aed;
|
|
--pipe-complete: #16a34a;
|
|
--pipe-failed: #dc2626;
|
|
|
|
--font-mono: 'Courier New', monospace;
|
|
--radius: 3px;
|
|
--radius-md: 4px;
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: var(--font-mono); background: var(--bg-primary); color: var(--text-primary); }
|
|
|
|
/* ── Header ── */
|
|
.header {
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border-light);
|
|
padding: 10px 24px;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.header-left {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 12px;
|
|
}
|
|
.header-subtitle {
|
|
font-size: 11px;
|
|
color: var(--text-dim);
|
|
letter-spacing: 1px;
|
|
text-transform: uppercase;
|
|
}
|
|
.header h1 { color: var(--green); font-size: 18px; font-weight: 700; letter-spacing: 3px; }
|
|
.header .stats { font-size: 12px; color: var(--text-dim); }
|
|
.header .quick-stats { font-size: 11px; color: var(--text-muted); display: flex; gap: 16px; }
|
|
.header .quick-stats span { white-space: nowrap; }
|
|
|
|
/* Heartbeat indicator */
|
|
.heartbeat {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: var(--green);
|
|
margin-right: 6px;
|
|
vertical-align: middle;
|
|
animation: pulse 2s ease-in-out infinite;
|
|
}
|
|
.heartbeat.dead {
|
|
background: var(--red);
|
|
animation: none;
|
|
}
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.4; }
|
|
}
|
|
|
|
/* ── Navigation ── */
|
|
.nav-domain {
|
|
background: #0d0d0d;
|
|
border-bottom: 1px solid var(--border);
|
|
padding: 0 24px;
|
|
display: flex;
|
|
gap: 0;
|
|
flex-shrink: 0;
|
|
}
|
|
.nav-domain a {
|
|
color: var(--text-muted);
|
|
text-decoration: none;
|
|
font-size: 13px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
padding: 10px 16px;
|
|
border-bottom: 2px solid transparent;
|
|
transition: color 0.15s, border-color 0.15s;
|
|
}
|
|
.nav-domain a:hover { color: var(--text-primary); }
|
|
.nav-domain a.active {
|
|
color: var(--green);
|
|
border-bottom-color: var(--green);
|
|
}
|
|
|
|
.nav-sub {
|
|
background: var(--bg-primary);
|
|
border-bottom: 1px solid var(--border);
|
|
padding: 6px 24px;
|
|
}
|
|
.nav-sub a {
|
|
color: var(--text-dim);
|
|
text-decoration: none;
|
|
margin-right: 16px;
|
|
font-size: 12px;
|
|
transition: color 0.15s;
|
|
}
|
|
.nav-sub a:hover { color: var(--text-primary); }
|
|
.nav-sub a.active { color: var(--green); }
|
|
|
|
/* ── Content ── */
|
|
.content { padding: 24px; max-width: 1400px; margin: 0 auto; }
|
|
|
|
/* ── Panels ── */
|
|
.panel {
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border);
|
|
padding: 24px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
/* ── Forms ── */
|
|
.search-box {
|
|
width: 100%;
|
|
padding: 10px 16px;
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border-light);
|
|
color: var(--text-primary);
|
|
font-family: inherit;
|
|
font-size: 14px;
|
|
margin-bottom: 16px;
|
|
}
|
|
.search-box:focus { outline: none; border-color: var(--green); }
|
|
|
|
/* ── Tables ── */
|
|
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
th { background: var(--bg-secondary); color: var(--green); text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border-light); }
|
|
td { padding: 6px 12px; border-bottom: 1px solid var(--bg-tertiary); }
|
|
tr:hover { background: var(--bg-secondary); }
|
|
|
|
/* ── Status badges ── */
|
|
.status { padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
|
|
.status-complete { color: var(--green); }
|
|
.status-enriched { color: var(--blue); }
|
|
.status-extracted { color: var(--orange); }
|
|
.status-failed { color: var(--red); }
|
|
.status-queued { color: var(--text-muted); }
|
|
.status-duplicate { color: var(--text-muted); }
|
|
|
|
/* ── Stat cards ── */
|
|
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
|
.stat-card { background: var(--bg-secondary); border: 1px solid var(--border); padding: 16px; }
|
|
.stat-card .label { color: var(--text-dim); font-size: 11px; text-transform: uppercase; }
|
|
.stat-card .value { color: var(--green); font-size: 28px; margin-top: 4px; }
|
|
.stat-card .sublabel { color: var(--text-faint); font-size: 10px; margin-top: 2px; }
|
|
|
|
/* ── Search results ── */
|
|
.result { background: var(--bg-secondary); border: 1px solid var(--border); padding: 16px; margin-bottom: 12px; }
|
|
.result .title { color: var(--green); font-size: 14px; margin-bottom: 4px; }
|
|
.result .meta { color: var(--text-dim); font-size: 11px; margin-bottom: 8px; }
|
|
.result .content-text { color: #999; font-size: 12px; line-height: 1.5; }
|
|
.result .score { color: var(--orange); font-size: 12px; float: right; }
|
|
|
|
/* ── Buttons ── */
|
|
.btn {
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid var(--border-light);
|
|
color: var(--text-primary);
|
|
padding: 6px 14px;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: 12px;
|
|
}
|
|
.btn:hover { border-color: var(--green); color: var(--green); }
|
|
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
.btn.active { border-color: var(--green); color: var(--green); }
|
|
.btn-danger { color: var(--red); }
|
|
.btn-danger:hover { border-color: var(--red); }
|
|
.btn-warn { color: #ff8800; }
|
|
.btn-warn:hover { border-color: #ff8800; }
|
|
|
|
/* ── Tags ── */
|
|
.domain-tag {
|
|
display: inline-block;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid var(--border-light);
|
|
padding: 1px 6px;
|
|
margin: 1px;
|
|
font-size: 10px;
|
|
color: var(--text-muted);
|
|
}
|
|
.badge-web { background: #1e3a5f; color: #60a5fa; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
|
|
.badge-pdf { background: #2d5a2d; color: #4ade80; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
|
|
.badge-transcript { background: #3b1f5e; color: #c084fc; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; }
|
|
|
|
/* ── Trend indicators ── */
|
|
.trend { font-size: 11px; margin-left: 6px; }
|
|
.trend-up { color: var(--green); }
|
|
.trend-down { color: var(--red); }
|
|
.trend-flat { color: var(--text-faint); }
|
|
|
|
/* ── Pipeline bar ── */
|
|
.pipeline-bar {
|
|
height: 24px;
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
display: flex;
|
|
}
|
|
.pipeline-bar .segment { height: 100%; transition: width 0.3s ease; }
|
|
|
|
.pipeline-legend { display: flex; gap: 14px; margin-top: 6px; font-size: 10px; color: var(--text-muted); flex-wrap: wrap; }
|
|
.legend-dot {
|
|
display: inline-block;
|
|
width: 10px; height: 10px;
|
|
border-radius: 2px;
|
|
margin-right: 4px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* ── Service status dots ── */
|
|
.svc-dot {
|
|
display: inline-block;
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
margin-right: 6px;
|
|
vertical-align: middle;
|
|
}
|
|
.svc-dot.active { background: var(--green); }
|
|
.svc-dot.inactive { background: var(--red); }
|
|
.svc-dot.unknown { background: var(--text-faint); }
|
|
|
|
/* ── Service status row ── */
|
|
.svc-row {
|
|
display: flex;
|
|
gap: 24px;
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border);
|
|
padding: 12px 16px;
|
|
margin-bottom: 24px;
|
|
font-size: 12px;
|
|
}
|
|
.svc-row .svc-item { display: flex; align-items: center; }
|
|
|
|
/* ── Pagination ── */
|
|
.pagination {
|
|
display: flex;
|
|
gap: 4px;
|
|
margin-top: 16px;
|
|
justify-content: center;
|
|
}
|
|
.pagination a, .pagination span {
|
|
padding: 4px 10px;
|
|
border: 1px solid var(--border-light);
|
|
color: var(--text-muted);
|
|
text-decoration: none;
|
|
font-size: 12px;
|
|
}
|
|
.pagination a:hover { border-color: var(--green); color: var(--green); }
|
|
.pagination .current {
|
|
border-color: var(--green);
|
|
color: var(--green);
|
|
background: var(--bg-tertiary);
|
|
}
|
|
|
|
/* ── Misc helpers ── */
|
|
.section-title { color: var(--green); margin-bottom: 12px; }
|
|
.mt-24 { margin-top: 24px; }
|
|
.mb-16 { margin-bottom: 16px; }
|
|
.mb-24 { margin-bottom: 24px; }
|
|
.text-muted { color: var(--text-muted); }
|
|
.text-dim { color: var(--text-dim); }
|
|
.text-faint { color: var(--text-faint); }
|
|
.text-green { color: var(--green); }
|
|
.text-red { color: var(--red); }
|
|
.text-orange { color: var(--orange); }
|
|
.text-blue { color: var(--blue); }
|
|
.text-small { font-size: 12px; }
|
|
.text-xs { font-size: 11px; }
|
|
.text-xxs { font-size: 10px; }
|
|
.mono { font-family: monospace; }
|
|
|
|
.flex { display: flex; }
|
|
.flex-between { display: flex; justify-content: space-between; }
|
|
.flex-center { display: flex; align-items: center; }
|
|
.gap-8 { gap: 8px; }
|
|
.gap-16 { gap: 16px; }
|
|
|
|
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
|
|
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
|
|
|
|
/* ── Collapsible errors panel ── */
|
|
.errors-panel { display: none; }
|
|
.errors-panel.has-errors { display: block; }
|
|
.errors-panel summary { color: var(--red); cursor: pointer; font-size: 13px; margin-bottom: 8px; }
|
|
.errors-panel .error-line { color: var(--text-muted); font-size: 11px; padding: 2px 0; border-bottom: 1px solid var(--border); }
|