radai-api / extension /sidepanel.html
RageCoder2006's picture
Clean deployment for Hugging Face
879d39c
Raw
History Blame Contribute Delete
15.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RADAI / Analysis</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet" />
<style>
/* ─────────────────────────────────────────────────────────────
DESIGN SYSTEM — forensic tool aesthetic
Palette: near-white bg, near-black text, grey structure,
muted red (#b91c1c) for danger, amber for warnings.
No gradients. No box-shadows beyond hairlines. No rounding > 6px.
───────────────────────────────────────────────────────────── */
:root {
--bg: #f4f4f4;
--surface: #ffffff;
--border: #d4d4d4;
--border-lg: #e5e5e5;
--text: #111111;
--text2: #525252;
--text3: #737373;
--danger: #b91c1c;
--danger-dim: rgba(185, 28, 28, 0.07);
--warn: #92400e;
--warn-dim: rgba(146, 64, 14, 0.07);
--ok: #14532d;
--ok-dim: rgba(20, 83, 45, 0.07);
--mono: 'IBM Plex Mono', monospace;
--sans: 'Inter', system-ui, sans-serif;
}
[data-theme="dark"] {
--bg: #0f0f0f;
--surface: #1a1a1a;
--border: #303030;
--border-lg: #242424;
--text: #e5e5e5;
--text2: #a3a3a3;
--text3: #737373;
--danger: #ef4444;
--danger-dim: rgba(239, 68, 68, 0.08);
--warn: #f59e0b;
--warn-dim: rgba(245, 158, 11, 0.08);
--ok: #22c55e;
--ok-dim: rgba(34, 197, 94, 0.08);
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
font-family: var(--sans);
background: var(--bg);
color: var(--text);
font-size: 13px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
overflow: hidden;
}
/* ── Panel ── */
.panel {
height: 100vh;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.panel::-webkit-scrollbar {
width: 4px;
}
.panel::-webkit-scrollbar-thumb {
background: var(--border);
}
/* ── Top bar ── */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
position: sticky;
top: 0;
z-index: 100;
}
.brand {
display: flex;
align-items: center;
gap: 8px;
}
.brand-mark {
width: 20px;
height: 20px;
display: grid;
place-items: center;
color: var(--text);
}
.brand-mark svg {
width: 18px;
height: 18px;
}
.brand-name {
font-size: 12px;
font-weight: 700;
letter-spacing: 0.5px;
text-transform: uppercase;
color: var(--text);
}
.brand-sep {
width: 1px;
height: 12px;
background: var(--border);
}
.brand-sub {
font-size: 10px;
color: var(--text3);
font-family: var(--mono);
letter-spacing: 0.5px;
}
.topbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.topbar-chip {
font-size: 10px;
font-family: var(--mono);
font-weight: 500;
color: var(--text3);
border: 1px solid var(--border);
padding: 2px 8px;
border-radius: 2px;
white-space: nowrap;
}
.theme-toggle {
font-size: 10px;
font-family: var(--mono);
font-weight: 500;
color: var(--text2);
background: none;
border: 1px solid var(--border);
padding: 2px 8px;
border-radius: 2px;
cursor: pointer;
transition: color 0.1s, border-color 0.1s;
}
.theme-toggle:hover {
color: var(--text);
border-color: var(--text2);
}
/* ── Content area ── */
.content {
flex: 1;
padding: 14px;
display: flex;
flex-direction: column;
gap: 12px;
}
/* ── Empty state ── */
.empty {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
text-align: center;
padding: 40px 24px;
}
.empty-icon {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text3);
margin-bottom: 6px;
}
.empty-icon svg {
width: 22px;
height: 22px;
}
.empty-title {
font-size: 14px;
font-weight: 600;
color: var(--text);
}
.empty-desc {
font-size: 12px;
color: var(--text3);
line-height: 1.55;
max-width: 220px;
}
/* ── Section label ── */
.section-label {
font-size: 10px;
font-family: var(--mono);
font-weight: 500;
letter-spacing: 0.8px;
text-transform: uppercase;
color: var(--text3);
margin-bottom: 6px;
}
/* ── Verdict card ── */
.verdict-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 4px;
padding: 14px;
}
.verdict-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.verdict-label {
font-size: 28px;
font-weight: 700;
letter-spacing: -1px;
line-height: 1;
color: var(--text);
}
.verdict-meta {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
flex-shrink: 0;
}
.confidence-value {
font-size: 28px;
font-weight: 700;
letter-spacing: -1px;
line-height: 1;
font-family: var(--mono);
color: var(--text);
}
.confidence-label {
font-size: 10px;
font-family: var(--mono);
color: var(--text3);
letter-spacing: 0.5px;
}
.verdict-desc {
font-size: 12px;
color: var(--text2);
margin-top: 8px;
line-height: 1.5;
}
/* ── Status bar ── */
.status-bar {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--border-lg);
display: flex;
align-items: center;
gap: 6px;
}
.status-dot {
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
}
.status-text {
font-size: 11px;
font-family: var(--mono);
color: var(--text2);
}
/* ── Risk bar ── */
.risk-bar-wrap {
margin-top: 12px;
}
.risk-bar-header {
display: flex;
justify-content: space-between;
font-size: 10px;
font-family: var(--mono);
color: var(--text3);
margin-bottom: 5px;
}
.risk-bar-track {
height: 3px;
background: var(--border);
border-radius: 2px;
overflow: hidden;
}
.risk-bar-fill {
height: 100%;
width: 0%;
border-radius: 2px;
transition: width 0.6s ease;
}
/* ── How it works ── */
.how-it-works-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 4px;
overflow: hidden;
}
.hiw-header {
padding: 10px 14px;
border-bottom: 1px solid var(--border-lg);
}
.hiw-body {
padding: 12px 14px;
}
.hiw-text {
font-size: 12px;
color: var(--text2);
line-height: 1.6;
margin-bottom: 8px;
}
.hiw-list {
list-style-type: disc;
padding-left: 20px;
margin-bottom: 0px;
}
.hiw-list li {
font-size: 12px;
color: var(--text2);
line-height: 1.6;
margin-bottom: 4px;
}
/* ── Footer ── */
.panel-footer {
padding: 8px 14px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
background: var(--surface);
}
.footer-left {
font-size: 10px;
font-family: var(--mono);
color: var(--text3);
}
.footer-right {
font-size: 10px;
font-family: var(--mono);
color: var(--text3);
}
/* ── Loading state ── */
.loading-bar {
height: 2px;
background: var(--border);
position: relative;
overflow: hidden;
}
.loading-bar::after {
content: '';
position: absolute;
left: -40%;
top: 0;
width: 40%;
height: 100%;
background: var(--text3);
animation: loading-slide 1.2s ease-in-out infinite;
}
@keyframes loading-slide {
0% {
left: -40%;
}
100% {
left: 110%;
}
}
/* ── Data container toggle ── */
#dataContainer {
display: none;
}
#dataContainer.visible {
display: contents;
}
#emptyState {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
}
#emptyState.hidden {
display: none;
}
/* ── Stopped state ── */
.stopped-banner {
background: var(--warn-dim);
border: 1px solid currentColor;
color: var(--warn);
border-radius: 3px;
padding: 9px 12px;
font-size: 11px;
font-family: var(--mono);
margin-bottom: 12px;
}
/* ── Action buttons ── */
.btn-row {
display: grid;
grid-template-columns: 1fr auto;
gap: 6px;
margin-bottom: 2px;
flex-shrink: 0;
}
.btn {
border: 1px solid var(--border);
border-radius: 3px;
padding: 8px 12px;
background: var(--surface);
color: var(--text);
font-family: var(--mono);
font-size: 11px;
font-weight: 500;
cursor: pointer;
letter-spacing: 0.3px;
transition: background 0.1s, border-color 0.1s;
}
.btn:hover:not(:disabled) {
background: var(--border-lg);
}
.btn:disabled {
opacity: 0.35;
cursor: default;
}
.btn-danger {
color: var(--danger);
border-color: var(--danger);
}
.btn-danger:hover:not(:disabled) {
background: var(--danger-dim);
}
</style>
</head>
<body data-theme="light">
<div class="panel" id="panel">
<!-- Sticky topbar -->
<div class="topbar">
<div class="brand">
<div class="brand-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
</svg>
</div>
<span class="brand-name">RADAI</span>
<div class="brand-sep"></div>
<span class="brand-sub">FORENSIC ANALYSIS</span>
</div>
<div class="topbar-right">
<div class="topbar-chip" id="statusChip">IDLE</div>
<button class="theme-toggle" id="themeBtn">DARK</button>
</div>
</div>
<!-- Loading bar (hidden by default, shown during initial load) -->
<div class="loading-bar" id="loadingBar" style="display:none"></div>
<!-- Main content -->
<div class="content">
<!-- Action buttons -->
<div class="btn-row">
<button class="btn" id="scanBtn">SCAN IMAGES</button>
<button class="btn btn-danger" id="stopBtn" disabled>STOP</button>
</div>
<!-- Empty state -->
<div id="emptyState">
<div class="empty">
<div class="empty-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
</div>
<div class="empty-title">No scan data</div>
<div class="empty-desc">Click "SCAN IMAGES" to analyze the current webpage for AI-generated content.</div>
</div>
</div>
<!-- Data sections -->
<div id="dataContainer">
<!-- Stopped banner (shown only when scan was stopped) -->
<div class="stopped-banner" id="stoppedBanner" style="display:none">
SCAN INTERRUPTED — incomplete data. Run a full scan for complete results.
</div>
<!-- Verdict -->
<div class="verdict-card">
<div class="verdict-top">
<div>
<div class="verdict-label" id="verdictLabel"></div>
<div class="verdict-desc" id="verdictDesc" style="white-space: pre-line;"></div>
</div>
</div>
<div class="risk-bar-wrap">
<div class="risk-bar-header">
<span>Risk score</span>
<span id="riskBarLabel"></span>
</div>
<div class="risk-bar-track">
<div class="risk-bar-fill" id="riskBarFill"></div>
</div>
</div>
<div class="status-bar">
<div class="status-dot" id="statusDot"></div>
<div class="status-text" id="statusText"></div>
</div>
</div>
<!-- How it works -->
<div class="how-it-works-card" id="howItWorks">
<div class="hiw-header">
<div class="section-label">How detection works</div>
</div>
<div class="hiw-body">
<div class="hiw-text">
Our system utilizes a dual-model ensemble to assess images for forensic anomalies:
</div>
<ul class="hiw-list">
<li><strong>Vision-Language Model</strong> (OpenCLIP) for broad semantic and texture analysis</li>
<li><strong>Secondary CNN Model</strong> (ConvNeXt) for deep feature pattern matching</li>
</ul>
<div class="hiw-text" style="margin-top: 10px;">
The algorithms flag synthetic origins by detecting subtle, generated inconsistencies in: <strong>texture
frequencies, lighting coherence, and spatial composition.</strong>
</div>
</div>
</div>
</div><!-- /dataContainer -->
</div><!-- /content -->
<!-- Footer -->
<div class="panel-footer">
<div class="footer-left" id="footerLeft">RADAI v2.0</div>
<div class="footer-right" id="footerRight"></div>
</div>
</div><!-- /panel -->
<script src="sidepanel.js"></script>
</body>
</html>