Download frontend/index.html from aasthav18/PulseAI: direct link, hf CLI and curl.
- Browser
- Download file 94.9 kB
-
https://huggingface.co/spaces/aasthav18/PulseAI/resolve/main/frontend/index.html
- Command line
-
hf download hf://spaces/aasthav18/PulseAI/frontend/index.html
-
curl -L -o index.html https://huggingface.co/spaces/aasthav18/PulseAI/resolve/main/frontend/index.html
94.9 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PulseAI β Social Intelligence Platform</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&family=DM+Mono:ital,wght@0,300;0,400;0,500;1,400&family=Instrument+Sans:ital,wght@0,400;0,500;0,600;1,400&display=swap" rel="stylesheet"> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.2/dist/chart.umd.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script> | |
| <style> | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| DESIGN TOKENS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| :root { | |
| --bg-void: #080b12; | |
| --bg-base: #0d1117; | |
| --bg-surface: #111827; | |
| --bg-elevated: #161f2e; | |
| --bg-overlay: #1a2535; | |
| --border-subtle: rgba(255,255,255,0.05); | |
| --border-default: rgba(255,255,255,0.09); | |
| --border-strong: rgba(255,255,255,0.15); | |
| --text-primary: #f0f4ff; | |
| --text-secondary: #8b9ab4; | |
| --text-tertiary: #4a5568; | |
| --text-accent: #5b9cf6; | |
| --blue-500: #5b9cf6; | |
| --blue-400: #7db3f8; | |
| --blue-300: #a5c8fb; | |
| --blue-glow: rgba(91,156,246,0.15); | |
| --amber-500: #f59e0b; | |
| --amber-400: #fbbf24; | |
| --amber-glow: rgba(245,158,11,0.15); | |
| --green-500: #10b981; | |
| --green-400: #34d399; | |
| --green-glow: rgba(16,185,129,0.12); | |
| --red-500: #ef4444; | |
| --red-400: #f87171; | |
| --red-glow: rgba(239,68,68,0.12); | |
| --purple-500: #8b5cf6; | |
| --purple-400: #a78bfa; | |
| --cyan-500: #06b6d4; | |
| --cyan-400: #22d3ee; | |
| --font-display: 'Syne', sans-serif; | |
| --font-body: 'Instrument Sans', sans-serif; | |
| --font-mono: 'DM Mono', monospace; | |
| --radius-sm: 6px; | |
| --radius-md: 10px; | |
| --radius-lg: 14px; | |
| --radius-xl: 20px; | |
| --sidebar-w: 240px; | |
| --header-h: 60px; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| RESET & BASE | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| html { height: 100%; } | |
| body { | |
| font-family: var(--font-body); | |
| background: var(--bg-void); | |
| color: var(--text-primary); | |
| height: 100%; | |
| overflow: hidden; | |
| font-size: 14px; | |
| line-height: 1.5; | |
| } | |
| a { color: inherit; text-decoration: none; } | |
| button { cursor: pointer; border: none; background: none; font-family: inherit; } | |
| input, textarea { font-family: inherit; } | |
| /* Noise overlay for depth */ | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| inset: 0; | |
| background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.035'/%3E%3C/svg%3E"); | |
| pointer-events: none; | |
| z-index: 9999; | |
| opacity: 0.5; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| LAYOUT | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .app-shell { | |
| display: grid; | |
| grid-template-columns: var(--sidebar-w) 1fr; | |
| grid-template-rows: var(--header-h) 1fr; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| /* βββ Header ββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .header { | |
| grid-column: 1 / -1; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 24px; | |
| border-bottom: 1px solid var(--border-subtle); | |
| background: var(--bg-base); | |
| backdrop-filter: blur(20px); | |
| position: relative; | |
| z-index: 100; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .logo-mark { | |
| width: 32px; height: 32px; | |
| background: linear-gradient(135deg, var(--blue-500) 0%, var(--purple-500) 100%); | |
| border-radius: 8px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 16px; | |
| box-shadow: 0 0 20px var(--blue-glow); | |
| } | |
| .logo-text { | |
| font-family: var(--font-display); | |
| font-size: 18px; | |
| font-weight: 800; | |
| letter-spacing: -0.02em; | |
| background: linear-gradient(135deg, var(--text-primary) 0%, var(--text-secondary) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .logo-tag { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--blue-500); | |
| background: var(--blue-glow); | |
| border: 1px solid rgba(91,156,246,0.2); | |
| padding: 2px 7px; | |
| border-radius: 4px; | |
| letter-spacing: 0.05em; | |
| text-transform: uppercase; | |
| } | |
| .header-center { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| background: var(--bg-surface); | |
| border: 1px solid var(--border-default); | |
| border-radius: var(--radius-md); | |
| padding: 6px 12px; | |
| width: 320px; | |
| } | |
| .search-icon { color: var(--text-tertiary); flex-shrink: 0; } | |
| .header-search { | |
| background: none; | |
| border: none; | |
| color: var(--text-primary); | |
| width: 100%; | |
| font-size: 13px; | |
| outline: none; | |
| } | |
| .header-search::placeholder { color: var(--text-tertiary); } | |
| .header-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .status-pill { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-family: var(--font-mono); | |
| font-size: 11px; | |
| color: var(--green-400); | |
| background: var(--green-glow); | |
| border: 1px solid rgba(16,185,129,0.2); | |
| padding: 4px 10px; | |
| border-radius: 20px; | |
| } | |
| .status-dot { | |
| width: 6px; height: 6px; | |
| border-radius: 50%; | |
| background: var(--green-400); | |
| animation: pulse-dot 2s infinite; | |
| } | |
| @keyframes pulse-dot { | |
| 0%, 100% { opacity: 1; transform: scale(1); } | |
| 50% { opacity: 0.5; transform: scale(0.8); } | |
| } | |
| .avatar { | |
| width: 32px; height: 32px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--blue-500), var(--purple-500)); | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: var(--font-display); | |
| font-size: 12px; | |
| font-weight: 700; | |
| } | |
| /* βββ Sidebar βββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .sidebar { | |
| background: var(--bg-base); | |
| border-right: 1px solid var(--border-subtle); | |
| display: flex; | |
| flex-direction: column; | |
| padding: 16px 0; | |
| overflow: hidden; | |
| } | |
| .nav-section-label { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.1em; | |
| color: var(--text-tertiary); | |
| padding: 8px 20px 4px; | |
| margin-top: 8px; | |
| } | |
| .nav-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 9px 20px; | |
| margin: 1px 8px; | |
| border-radius: var(--radius-sm); | |
| cursor: pointer; | |
| transition: all 0.15s ease; | |
| font-size: 13px; | |
| font-weight: 500; | |
| color: var(--text-secondary); | |
| position: relative; | |
| } | |
| .nav-item:hover { background: var(--bg-elevated); color: var(--text-primary); } | |
| .nav-item.active { | |
| background: var(--blue-glow); | |
| color: var(--blue-400); | |
| border: 1px solid rgba(91,156,246,0.15); | |
| } | |
| .nav-item.active::before { | |
| content: ''; | |
| position: absolute; | |
| left: 0; top: 50%; | |
| transform: translateY(-50%); | |
| width: 2px; height: 60%; | |
| background: var(--blue-500); | |
| border-radius: 0 2px 2px 0; | |
| } | |
| .nav-icon { font-size: 15px; width: 18px; text-align: center; flex-shrink: 0; } | |
| .nav-badge { | |
| margin-left: auto; | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| padding: 2px 6px; | |
| border-radius: 10px; | |
| background: var(--red-glow); | |
| color: var(--red-400); | |
| border: 1px solid rgba(239,68,68,0.2); | |
| } | |
| .nav-badge.blue { | |
| background: var(--blue-glow); | |
| color: var(--blue-400); | |
| border-color: rgba(91,156,246,0.2); | |
| } | |
| .sidebar-bottom { | |
| margin-top: auto; | |
| padding: 16px; | |
| border-top: 1px solid var(--border-subtle); | |
| } | |
| .sidebar-brand-select { | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-default); | |
| border-radius: var(--radius-md); | |
| padding: 10px 12px; | |
| } | |
| .brand-label { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--text-tertiary); | |
| text-transform: uppercase; | |
| letter-spacing: 0.08em; | |
| margin-bottom: 4px; | |
| } | |
| .brand-name { | |
| font-family: var(--font-display); | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-primary); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| /* βββ Main Content ββββββββββββββββββββββββββββββββββββββββββ */ | |
| .main { | |
| overflow-y: auto; | |
| background: var(--bg-void); | |
| scrollbar-width: thin; | |
| scrollbar-color: var(--border-default) transparent; | |
| } | |
| .main::-webkit-scrollbar { width: 4px; } | |
| .main::-webkit-scrollbar-track { background: transparent; } | |
| .main::-webkit-scrollbar-thumb { background: var(--border-default); border-radius: 2px; } | |
| .view { display: none; padding: 24px; } | |
| .view.active { display: block; } | |
| /* βββ Page Header βββββββββββββββββββββββββββββββββββββββββββ */ | |
| .page-header { | |
| display: flex; | |
| align-items: flex-start; | |
| justify-content: space-between; | |
| margin-bottom: 24px; | |
| } | |
| .page-title { | |
| font-family: var(--font-display); | |
| font-size: 22px; | |
| font-weight: 700; | |
| letter-spacing: -0.02em; | |
| } | |
| .page-subtitle { | |
| font-size: 13px; | |
| color: var(--text-secondary); | |
| margin-top: 2px; | |
| } | |
| .header-actions-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .btn { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 8px 14px; | |
| border-radius: var(--radius-sm); | |
| font-size: 12px; | |
| font-weight: 600; | |
| letter-spacing: 0.01em; | |
| transition: all 0.15s ease; | |
| border: 1px solid transparent; | |
| } | |
| .btn-ghost { | |
| color: var(--text-secondary); | |
| border-color: var(--border-default); | |
| background: transparent; | |
| } | |
| .btn-ghost:hover { background: var(--bg-surface); color: var(--text-primary); } | |
| .btn-primary { | |
| background: var(--blue-500); | |
| color: white; | |
| border-color: var(--blue-500); | |
| box-shadow: 0 0 20px var(--blue-glow); | |
| } | |
| .btn-primary:hover { background: var(--blue-400); box-shadow: 0 0 30px var(--blue-glow); } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| GRID & CARDS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 20px; } | |
| .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 20px; } | |
| .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; } | |
| .grid-3-1 { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; margin-bottom: 20px; } | |
| .grid-1-2 { display: grid; grid-template-columns: 1fr 2fr; gap: 16px; margin-bottom: 20px; } | |
| .card { | |
| background: var(--bg-surface); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: var(--radius-lg); | |
| padding: 20px; | |
| position: relative; | |
| overflow: hidden; | |
| transition: border-color 0.2s ease; | |
| } | |
| .card:hover { border-color: var(--border-default); } | |
| .card::after { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(135deg, rgba(255,255,255,0.015) 0%, transparent 60%); | |
| pointer-events: none; | |
| border-radius: inherit; | |
| } | |
| /* βββ KPI Cards βββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .kpi-card { | |
| padding: 18px 20px; | |
| } | |
| .kpi-label { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.1em; | |
| color: var(--text-tertiary); | |
| margin-bottom: 8px; | |
| } | |
| .kpi-value { | |
| font-family: var(--font-display); | |
| font-size: 28px; | |
| font-weight: 800; | |
| letter-spacing: -0.03em; | |
| line-height: 1; | |
| } | |
| .kpi-sub { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| margin-top: 8px; | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| } | |
| .delta { | |
| display: flex; | |
| align-items: center; | |
| gap: 3px; | |
| font-family: var(--font-mono); | |
| font-size: 11px; | |
| font-weight: 500; | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| } | |
| .delta.pos { color: var(--green-400); background: var(--green-glow); } | |
| .delta.neg { color: var(--red-400); background: var(--red-glow); } | |
| .delta.neu { color: var(--amber-400); background: var(--amber-glow); } | |
| .kpi-accent { | |
| position: absolute; | |
| top: 0; right: 0; | |
| width: 60px; height: 60px; | |
| border-radius: 0 14px 0 60px; | |
| opacity: 0.08; | |
| } | |
| /* βββ Card headers ββββββββββββββββββββββββββββββββββββββββββ */ | |
| .card-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 16px; | |
| } | |
| .card-title { | |
| font-family: var(--font-display); | |
| font-size: 13px; | |
| font-weight: 700; | |
| letter-spacing: -0.01em; | |
| } | |
| .card-tag { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| padding: 2px 8px; | |
| border-radius: 4px; | |
| background: var(--bg-overlay); | |
| color: var(--text-tertiary); | |
| border: 1px solid var(--border-default); | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| SENTIMENT GAUGE | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .sentiment-gauge-wrap { | |
| display: flex; | |
| align-items: center; | |
| gap: 20px; | |
| } | |
| .gauge-svg { flex-shrink: 0; } | |
| .gauge-legend { flex: 1; } | |
| .gauge-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 10px; | |
| } | |
| .gauge-dot { | |
| width: 8px; height: 8px; | |
| border-radius: 50%; | |
| flex-shrink: 0; | |
| } | |
| .gauge-item-label { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| flex: 1; | |
| } | |
| .gauge-item-val { | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| font-weight: 500; | |
| color: var(--text-primary); | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CHART CONTAINERS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .chart-wrap { | |
| position: relative; | |
| height: 220px; | |
| } | |
| .chart-wrap-sm { height: 160px; } | |
| .chart-wrap-lg { height: 280px; } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| TOPIC CLUSTERS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| #topic-bubble-svg { | |
| width: 100%; | |
| overflow: visible; | |
| } | |
| .topic-bubble { cursor: pointer; transition: opacity 0.2s; } | |
| .topic-bubble:hover { opacity: 0.85; } | |
| .topic-card-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 10px; | |
| } | |
| .topic-chip { | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: var(--radius-md); | |
| padding: 12px 14px; | |
| cursor: pointer; | |
| transition: all 0.15s ease; | |
| } | |
| .topic-chip:hover { border-color: var(--border-strong); background: var(--bg-overlay); } | |
| .topic-chip.selected { border-color: var(--blue-500); background: var(--blue-glow); } | |
| .topic-chip-name { | |
| font-size: 12px; | |
| font-weight: 600; | |
| margin-bottom: 4px; | |
| color: var(--text-primary); | |
| } | |
| .topic-chip-meta { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .topic-count { | |
| font-family: var(--font-mono); | |
| font-size: 11px; | |
| color: var(--text-tertiary); | |
| } | |
| .topic-sentiment-bar { | |
| height: 4px; | |
| border-radius: 2px; | |
| background: var(--bg-void); | |
| flex: 1; | |
| overflow: hidden; | |
| } | |
| .topic-sentiment-fill { | |
| height: 100%; | |
| border-radius: 2px; | |
| transition: width 0.8s ease; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CRISIS PANEL | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .crisis-alert { | |
| border-radius: var(--radius-md); | |
| padding: 14px 16px; | |
| margin-bottom: 12px; | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| border: 1px solid; | |
| transition: all 0.2s ease; | |
| } | |
| .crisis-alert.critical { background: rgba(239,68,68,0.06); border-color: rgba(239,68,68,0.2); } | |
| .crisis-alert.high { background: rgba(245,158,11,0.06); border-color: rgba(245,158,11,0.2); } | |
| .crisis-alert.medium { background: rgba(16,185,129,0.04); border-color: rgba(16,185,129,0.15); } | |
| .crisis-alert.low { background: var(--bg-elevated); border-color: var(--border-subtle); } | |
| .crisis-icon { font-size: 18px; flex-shrink: 0; margin-top: 1px; } | |
| .crisis-content { flex: 1; min-width: 0; } | |
| .crisis-title { | |
| font-weight: 600; | |
| font-size: 13px; | |
| margin-bottom: 3px; | |
| } | |
| .crisis-desc { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| line-height: 1.5; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .crisis-time { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--text-tertiary); | |
| margin-top: 4px; | |
| } | |
| .crisis-score { | |
| font-family: var(--font-mono); | |
| font-size: 16px; | |
| font-weight: 700; | |
| flex-shrink: 0; | |
| } | |
| .crisis-score.critical { color: var(--red-400); } | |
| .crisis-score.high { color: var(--amber-400); } | |
| .crisis-score.medium { color: var(--green-400); } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| COMPETITOR COMPARISON | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .competitor-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 12px 0; | |
| border-bottom: 1px solid var(--border-subtle); | |
| } | |
| .competitor-row:last-child { border-bottom: none; } | |
| .competitor-name { | |
| font-weight: 600; | |
| font-size: 13px; | |
| width: 90px; | |
| flex-shrink: 0; | |
| } | |
| .competitor-name.own { color: var(--blue-400); } | |
| .comp-bar-wrap { | |
| flex: 1; | |
| height: 8px; | |
| background: var(--bg-elevated); | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .comp-bar { | |
| height: 100%; | |
| border-radius: 4px; | |
| transition: width 1s ease; | |
| } | |
| .comp-score { | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| font-weight: 500; | |
| width: 36px; | |
| text-align: right; | |
| flex-shrink: 0; | |
| } | |
| .comp-trend { | |
| font-size: 11px; | |
| width: 20px; | |
| text-align: center; | |
| flex-shrink: 0; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| POST FEED | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .post-feed { max-height: 420px; overflow-y: auto; } | |
| .post-feed::-webkit-scrollbar { width: 3px; } | |
| .post-feed::-webkit-scrollbar-thumb { background: var(--border-default); border-radius: 2px; } | |
| .post-item { | |
| padding: 12px 0; | |
| border-bottom: 1px solid var(--border-subtle); | |
| cursor: default; | |
| transition: all 0.15s ease; | |
| } | |
| .post-item:hover { padding-left: 6px; } | |
| .post-item:last-child { border-bottom: none; } | |
| .post-meta { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 5px; | |
| } | |
| .post-source { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| padding: 2px 7px; | |
| border-radius: 4px; | |
| background: var(--bg-overlay); | |
| color: var(--text-tertiary); | |
| } | |
| .sentiment-pill { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| padding: 2px 7px; | |
| border-radius: 4px; | |
| font-weight: 500; | |
| } | |
| .sentiment-pill.positive { background: var(--green-glow); color: var(--green-400); } | |
| .sentiment-pill.negative { background: var(--red-glow); color: var(--red-400); } | |
| .sentiment-pill.neutral { background: var(--bg-overlay); color: var(--text-tertiary); } | |
| .sentiment-pill.crisis { background: rgba(239,68,68,0.15); color: var(--red-400); } | |
| .post-text { | |
| font-size: 13px; | |
| color: var(--text-secondary); | |
| line-height: 1.5; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| .post-time { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--text-tertiary); | |
| margin-top: 4px; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| LIVE ANALYZER | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .analyzer-textarea { | |
| width: 100%; | |
| min-height: 100px; | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-default); | |
| border-radius: var(--radius-md); | |
| padding: 14px; | |
| color: var(--text-primary); | |
| font-size: 14px; | |
| resize: vertical; | |
| outline: none; | |
| transition: border-color 0.2s; | |
| margin-bottom: 12px; | |
| } | |
| .analyzer-textarea:focus { border-color: var(--blue-500); } | |
| .analyzer-textarea::placeholder { color: var(--text-tertiary); } | |
| .analyzer-result { | |
| display: none; | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-default); | |
| border-radius: var(--radius-md); | |
| padding: 16px; | |
| margin-top: 12px; | |
| animation: slideUp 0.3s ease; | |
| } | |
| .analyzer-result.visible { display: block; } | |
| @keyframes slideUp { | |
| from { opacity: 0; transform: translateY(8px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .result-label { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| margin-bottom: 12px; | |
| } | |
| .result-sentiment-badge { | |
| font-family: var(--font-display); | |
| font-size: 16px; | |
| font-weight: 700; | |
| padding: 6px 14px; | |
| border-radius: var(--radius-sm); | |
| } | |
| .result-confidence { | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| } | |
| .aspect-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 8px; | |
| margin-top: 12px; | |
| } | |
| .aspect-item { | |
| background: var(--bg-surface); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: var(--radius-sm); | |
| padding: 8px 10px; | |
| } | |
| .aspect-name { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--text-tertiary); | |
| text-transform: uppercase; | |
| letter-spacing: 0.08em; | |
| margin-bottom: 3px; | |
| } | |
| .aspect-sentiment { | |
| font-size: 12px; | |
| font-weight: 600; | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| LOADING STATE | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .loading-overlay { | |
| position: fixed; | |
| inset: 0; | |
| background: var(--bg-void); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 1000; | |
| gap: 20px; | |
| transition: opacity 0.5s ease; | |
| } | |
| .loading-overlay.hidden { opacity: 0; pointer-events: none; } | |
| .loading-logo { | |
| font-family: var(--font-display); | |
| font-size: 32px; | |
| font-weight: 800; | |
| letter-spacing: -0.03em; | |
| background: linear-gradient(135deg, var(--blue-400) 0%, var(--purple-400) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .loading-bar-wrap { | |
| width: 200px; | |
| height: 2px; | |
| background: var(--bg-surface); | |
| border-radius: 1px; | |
| overflow: hidden; | |
| } | |
| .loading-bar { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--blue-500), var(--purple-500)); | |
| border-radius: 1px; | |
| animation: loadBar 2s ease infinite; | |
| } | |
| @keyframes loadBar { | |
| 0% { width: 0%; margin-left: 0; } | |
| 50% { width: 60%; } | |
| 100% { width: 0%; margin-left: 100%; } | |
| } | |
| .loading-text { | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| color: var(--text-tertiary); | |
| } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ANIMATIONS & TRANSITIONS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .fade-in { | |
| animation: fadeIn 0.4s ease forwards; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .stagger > * { opacity: 0; animation: fadeIn 0.4s ease forwards; } | |
| .stagger > *:nth-child(1) { animation-delay: 0.05s; } | |
| .stagger > *:nth-child(2) { animation-delay: 0.10s; } | |
| .stagger > *:nth-child(3) { animation-delay: 0.15s; } | |
| .stagger > *:nth-child(4) { animation-delay: 0.20s; } | |
| .stagger > *:nth-child(5) { animation-delay: 0.25s; } | |
| .stagger > *:nth-child(6) { animation-delay: 0.30s; } | |
| .stagger > *:nth-child(7) { animation-delay: 0.35s; } | |
| .stagger > *:nth-child(8) { animation-delay: 0.40s; } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| SCROLLBAR | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| * { scrollbar-width: thin; scrollbar-color: var(--border-default) transparent; } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| OPPORTUNITY CARDS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .opportunity-card { | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: var(--radius-md); | |
| padding: 14px; | |
| margin-bottom: 10px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .opportunity-card::before { | |
| content: ''; | |
| position: absolute; | |
| left: 0; top: 0; bottom: 0; | |
| width: 3px; | |
| background: var(--amber-500); | |
| border-radius: 3px 0 0 3px; | |
| } | |
| .opportunity-card.high::before { background: var(--blue-500); } | |
| .opp-tag { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| color: var(--amber-400); | |
| text-transform: uppercase; | |
| letter-spacing: 0.08em; | |
| margin-bottom: 4px; | |
| } | |
| .opp-tag.high { color: var(--blue-400); } | |
| .opp-text { font-size: 12px; color: var(--text-secondary); line-height: 1.5; } | |
| .opp-action { font-size: 11px; color: var(--text-primary); margin-top: 6px; font-weight: 500; } | |
| /* Source badges */ | |
| .source-badge-row { display: flex; gap: 6px; flex-wrap: wrap; } | |
| .source-badge { | |
| font-family: var(--font-mono); | |
| font-size: 10px; | |
| padding: 3px 8px; | |
| border-radius: 4px; | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-default); | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| transition: all 0.15s ease; | |
| } | |
| .source-badge:hover, .source-badge.active { background: var(--blue-glow); border-color: var(--blue-500); color: var(--blue-400); } | |
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MINI SPARKLINES | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .mini-spark { display: block; overflow: visible; } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Loading overlay --> | |
| <div class="loading-overlay" id="loadingOverlay"> | |
| <div class="loading-logo">PulseAI</div> | |
| <div class="loading-bar-wrap"> | |
| <div class="loading-bar"></div> | |
| </div> | |
| <div class="loading-text" id="loadingText">Connecting to intelligence engine...</div> | |
| </div> | |
| <div class="app-shell"> | |
| <!-- ββ Header βββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <header class="header"> | |
| <div class="logo"> | |
| <div class="logo-mark">β‘</div> | |
| <span class="logo-text">PulseAI</span> | |
| <span class="logo-tag">BETA</span> | |
| </div> | |
| <div class="header-center"> | |
| <svg class="search-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg> | |
| <input class="header-search" type="text" placeholder="Search posts, topics, keywordsβ¦" /> | |
| </div> | |
| <div class="header-actions"> | |
| <div class="status-pill"><div class="status-dot"></div><span id="modelMode">Loadingβ¦</span></div> | |
| <div class="avatar">AK</div> | |
| </div> | |
| </header> | |
| <!-- ββ Sidebar βββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <nav class="sidebar"> | |
| <div class="nav-section-label">Overview</div> | |
| <div class="nav-item active" onclick="showView('dashboard', this)"> | |
| <span class="nav-icon">β</span> Dashboard | |
| </div> | |
| <div class="nav-item" onclick="showView('trends', this)"> | |
| <span class="nav-icon">β·</span> Trends | |
| </div> | |
| <div class="nav-section-label">Intelligence</div> | |
| <div class="nav-item" onclick="showView('topics', this)"> | |
| <span class="nav-icon">⬑</span> Topic Clusters | |
| <span class="nav-badge blue" id="topicCount">β</span> | |
| </div> | |
| <div class="nav-item" onclick="showView('crisis', this)"> | |
| <span class="nav-icon">β</span> Crisis Radar | |
| <span class="nav-badge" id="crisisBadge">β</span> | |
| </div> | |
| <div class="nav-item" onclick="showView('competitors', this)"> | |
| <span class="nav-icon">β</span> Competitors | |
| </div> | |
| <div class="nav-section-label">Tools</div> | |
| <div class="nav-item" onclick="showView('analyzer', this)"> | |
| <span class="nav-icon">β¬</span> Live Analyzer | |
| </div> | |
| <div class="nav-item" onclick="showView('feed', this)"> | |
| <span class="nav-icon">β‘</span> Post Feed | |
| </div> | |
| <div class="sidebar-bottom"> | |
| <div class="sidebar-brand-select"> | |
| <div class="brand-label">Monitoring</div> | |
| <div class="brand-name"> | |
| TechFlow | |
| <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" opacity="0.4"><polyline points="6 9 12 15 18 9"/></svg> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MAIN CONTENT | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <main class="main"> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: DASHBOARD | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-dashboard" class="view active"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Brand Intelligence Dashboard</div> | |
| <div class="page-subtitle">Real-time sentiment, trends, and competitive signals for TechFlow</div> | |
| </div> | |
| <div class="header-actions-row"> | |
| <button class="btn btn-ghost">β Export</button> | |
| <button class="btn btn-primary">+ Add Source</button> | |
| </div> | |
| </div> | |
| <!-- KPI Row --> | |
| <div class="grid-4 stagger" id="kpiRow"> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Brand Sentiment</div> | |
| <div class="kpi-value" id="kpi-sentiment" style="color:var(--green-400)">β</div> | |
| <div class="kpi-sub"> | |
| <span class="delta pos" id="kpi-sentiment-delta">β</span> | |
| <span>vs 30-day avg</span> | |
| </div> | |
| <div class="kpi-accent" style="background:var(--green-500)"></div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Post Volume</div> | |
| <div class="kpi-value" id="kpi-volume" style="color:var(--blue-400)">β</div> | |
| <div class="kpi-sub"> | |
| <span class="delta neu" id="kpi-vol-trend">β</span> | |
| <span>volume trend</span> | |
| </div> | |
| <div class="kpi-accent" style="background:var(--blue-500)"></div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Net Promoter (est.)</div> | |
| <div class="kpi-value" id="kpi-nps" style="color:var(--amber-400)">β</div> | |
| <div class="kpi-sub"> | |
| <span class="delta pos" id="kpi-nps-sub">β</span> | |
| <span>positive posts</span> | |
| </div> | |
| <div class="kpi-accent" style="background:var(--amber-500)"></div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Crisis Alert</div> | |
| <div class="kpi-value" id="kpi-crisis" style="color:var(--red-400); font-size:20px;">β</div> | |
| <div class="kpi-sub"> | |
| <span class="delta neg" id="kpi-crisis-count">β</span> | |
| <span>active signals</span> | |
| </div> | |
| <div class="kpi-accent" style="background:var(--red-500)"></div> | |
| </div> | |
| </div> | |
| <!-- Trend + Sentiment Donut --> | |
| <div class="grid-3-1"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Sentiment Trend β 90 Days</span> | |
| <span class="card-tag" id="trendTag">β</span> | |
| </div> | |
| <div class="chart-wrap-lg"> | |
| <canvas id="trendChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Sentiment Mix</span> | |
| <span class="card-tag">Last 30d</span> | |
| </div> | |
| <div class="sentiment-gauge-wrap" style="margin-top: 10px;"> | |
| <canvas id="sentimentDonut" width="130" height="130" class="gauge-svg"></canvas> | |
| <div class="gauge-legend" id="sentimentLegend"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Sources + Top Crisis Posts --> | |
| <div class="grid-2"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Volume by Source</span> | |
| <span class="card-tag">All time</span> | |
| </div> | |
| <div class="chart-wrap"> | |
| <canvas id="sourceChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">π΄ Top Crisis Signals</span> | |
| <span class="card-tag" id="crisisAlertLevel">β</span> | |
| </div> | |
| <div id="topCrisisList"></div> | |
| </div> | |
| </div> | |
| <!-- Recent Posts --> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Recent Posts</span> | |
| <div class="source-badge-row" id="filterBadges"> | |
| <span class="source-badge active" onclick="filterPosts(null, this)">All</span> | |
| <span class="source-badge" onclick="filterPosts('positive', this)">Positive</span> | |
| <span class="source-badge" onclick="filterPosts('negative', this)">Negative</span> | |
| <span class="source-badge" onclick="filterPosts('crisis', this)">Crisis</span> | |
| </div> | |
| </div> | |
| <div class="post-feed" id="postFeed"></div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: TRENDS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-trends" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Trend Analysis & Forecasting</div> | |
| <div class="page-subtitle">Sentiment momentum, anomaly detection, and 14-day forecast</div> | |
| </div> | |
| </div> | |
| <div class="grid-4 stagger" id="trendKpis"> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">7-Day Avg Sentiment</div> | |
| <div class="kpi-value" id="t-kpi-7d" style="color:var(--blue-400)">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">30-Day Avg Sentiment</div> | |
| <div class="kpi-value" id="t-kpi-30d" style="color:var(--text-secondary)">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Trend Direction</div> | |
| <div class="kpi-value" id="t-kpi-dir" style="font-size:14px; padding-top:8px;">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Anomalies Detected</div> | |
| <div class="kpi-value" id="t-kpi-anomalies" style="color:var(--amber-400)">β</div> | |
| </div> | |
| </div> | |
| <div class="card" style="margin-bottom:20px;"> | |
| <div class="card-header"> | |
| <span class="card-title">Sentiment Timeline + Forecast (14-Day)</span> | |
| <div style="display:flex;gap:12px;align-items:center;"> | |
| <span style="display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-secondary)"><span style="width:16px;height:2px;background:var(--blue-500);display:inline-block;border-radius:2px;"></span>Actual</span> | |
| <span style="display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-secondary)"><span style="width:16px;height:2px;background:var(--purple-500);display:inline-block;border-radius:2px;border-top:2px dashed var(--purple-500);"></span>Forecast</span> | |
| </div> | |
| </div> | |
| <div class="chart-wrap-lg"> | |
| <canvas id="forecastChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="grid-2"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Volume Trend</span> | |
| <span class="card-tag">Daily posts</span> | |
| </div> | |
| <div class="chart-wrap"> | |
| <canvas id="volumeChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Anomalies Detected</span> | |
| <span class="card-tag">Statistical outliers</span> | |
| </div> | |
| <div id="anomalyList" style="max-height:220px;overflow-y:auto;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: TOPIC CLUSTERS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-topics" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Topic Intelligence</div> | |
| <div class="page-subtitle">NMF-powered topic discovery across all customer conversations</div> | |
| </div> | |
| <div class="header-actions-row"> | |
| <span style="font-family:var(--font-mono);font-size:11px;color:var(--text-tertiary)">Model: NMF + TF-IDF</span> | |
| </div> | |
| </div> | |
| <div class="grid-1-2" style="align-items:start;"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Topic Clusters</span> | |
| <span class="card-tag" id="topicTotalPosts">β</span> | |
| </div> | |
| <div class="topic-card-grid" id="topicChips"></div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Cluster Distribution</span> | |
| <span class="card-tag">Bubble = post volume</span> | |
| </div> | |
| <svg id="topic-bubble-svg" height="340"></svg> | |
| </div> | |
| </div> | |
| <div class="card" id="topicDetailCard" style="display:none;"> | |
| <div class="card-header"> | |
| <span class="card-title" id="topicDetailName">β</span> | |
| <span class="card-tag" id="topicDetailCount">β</span> | |
| </div> | |
| <div class="grid-2" style="margin-bottom:0;"> | |
| <div> | |
| <div style="font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-tertiary);margin-bottom:10px;">Top Keywords</div> | |
| <div id="topicKeywords" style="display:flex;flex-wrap:wrap;gap:6px;"></div> | |
| </div> | |
| <div> | |
| <div style="font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-tertiary);margin-bottom:10px;">Sample Posts</div> | |
| <div id="topicExamples"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: CRISIS RADAR | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-crisis" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Crisis Radar</div> | |
| <div class="page-subtitle">Multi-signal brand crisis detection and escalation intelligence</div> | |
| </div> | |
| </div> | |
| <div class="grid-4 stagger"> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Overall Alert Level</div> | |
| <div class="kpi-value" id="c-overall" style="font-size:18px;padding-top:4px;">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Crisis Posts</div> | |
| <div class="kpi-value" id="c-total" style="color:var(--red-400)">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Active High-Severity</div> | |
| <div class="kpi-value" id="c-active" style="color:var(--amber-400)">β</div> | |
| </div> | |
| <div class="card kpi-card"> | |
| <div class="kpi-label">Top Signal</div> | |
| <div class="kpi-value" id="c-top-signal" style="font-size:14px;padding-top:8px;">β</div> | |
| </div> | |
| </div> | |
| <div class="grid-2"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Active Crisis Posts</span> | |
| <span class="card-tag">By severity</span> | |
| </div> | |
| <div id="crisisList" style="max-height:360px;overflow-y:auto;"></div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Signal Frequency</span> | |
| <span class="card-tag">Crisis categories</span> | |
| </div> | |
| <div class="chart-wrap"> | |
| <canvas id="signalChart"></canvas> | |
| </div> | |
| <div style="margin-top:16px;"> | |
| <div class="card-header" style="margin-bottom:8px;"> | |
| <span class="card-title">Recommended Actions</span> | |
| </div> | |
| <div id="crisisActions"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: COMPETITORS | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-competitors" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Competitive Intelligence</div> | |
| <div class="page-subtitle">Competitor sentiment, share of voice, and opportunity signals</div> | |
| </div> | |
| </div> | |
| <div class="grid-2" style="align-items:start;"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Sentiment Comparison</span> | |
| <span class="card-tag">Score = % positive mentions</span> | |
| </div> | |
| <div id="competitorRows" style="margin-top:8px;"></div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Share of Voice</span> | |
| <span class="card-tag">% of corpus mentions</span> | |
| </div> | |
| <div class="chart-wrap"> | |
| <canvas id="sovChart"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">π‘ Opportunity Intelligence</span> | |
| <span class="card-tag">AI-identified gaps</span> | |
| </div> | |
| <div id="opportunityList" style="display:grid;grid-template-columns:repeat(2,1fr);gap:10px;"></div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: LIVE ANALYZER | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-analyzer" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Live Text Analyzer</div> | |
| <div class="page-subtitle">Real-time BERT-powered sentiment, aspect, and crisis scoring</div> | |
| </div> | |
| </div> | |
| <div class="grid-2" style="align-items:start;"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Analyze Text</span> | |
| <span class="card-tag" id="analyzerModelBadge">β</span> | |
| </div> | |
| <textarea class="analyzer-textarea" id="analyzerInput" placeholder="Paste a customer review, tweet, or support ticket here⦠| |
| Example: The dashboard is beautiful but loading times are painfully slow. Considering switching to a competitor if this isn't fixed soon."></textarea> | |
| <button class="btn btn-primary" onclick="runAnalysis()" style="width:100%;justify-content:center;" id="analyzeBtn"> | |
| β‘ Analyze | |
| </button> | |
| <div class="analyzer-result" id="analyzerResult"> | |
| <div class="result-label"> | |
| <span class="result-sentiment-badge" id="resultBadge">β</span> | |
| <span class="result-confidence" id="resultConf">β</span> | |
| </div> | |
| <div id="crisisResultBox"></div> | |
| <div> | |
| <div style="font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-tertiary);margin-bottom:8px;margin-top:12px;">Detected Aspects</div> | |
| <div class="aspect-grid" id="aspectGrid"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <span class="card-title">Quick Examples</span> | |
| </div> | |
| <div id="exampleList"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| VIEW: POST FEED | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div id="view-feed" class="view"> | |
| <div class="page-header"> | |
| <div> | |
| <div class="page-title">Post Feed</div> | |
| <div class="page-subtitle">All monitored posts with sentiment and topic labels</div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="source-badge-row"> | |
| <span class="source-badge active" onclick="filterFeedPosts(null, this)">All</span> | |
| <span class="source-badge" onclick="filterFeedPosts('positive', this)">β Positive</span> | |
| <span class="source-badge" onclick="filterFeedPosts('negative', this)">β Negative</span> | |
| <span class="source-badge" onclick="filterFeedPosts('neutral', this)">β Neutral</span> | |
| <span class="source-badge" onclick="filterFeedPosts('crisis', this)">β Crisis</span> | |
| </div> | |
| </div> | |
| <div class="post-feed" id="fullPostFeed" style="max-height:600px;"></div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <script> | |
| </script> | |
| </body> | |
| </html> | |