her / ui /src /components /DisclaimerModal.jsx
geekwrestler's picture
Squash history (purge pre-scrub demo session blobs)
5f43c7d
import React from "react";
import { ShieldCheck, Lock, Sparkles, Trash2, X } from "lucide-react";
import { C, FD, FB, FM } from "../theme.js";
// Privacy disclosure for the hosted Space. Shown once on first run (localStorage) and
// re-openable any time via the "Privacy" button. The Space keeps NOTHING: uploads are
// isolated per-browser and deleted on exit / Clear / within 24h, and nothing derived
// from them ever leaves (enricher + sharing are off — HER_ENRICH=0 / HER_SHARE=0). The
// only outbound call is the one-time model download from Hugging Face.
const SEEN_KEY = "her.disclaimer.v1";
export function needsDisclaimer() {
try { return localStorage.getItem(SEEN_KEY) !== "1"; } catch { return true; }
}
export default function DisclaimerModal({ onDone }) {
function close() {
try { localStorage.setItem(SEEN_KEY, "1"); } catch { /* ignore */ }
onDone();
}
return (
<div onClick={close} style={{ position: "fixed", inset: 0, background: "rgba(15,14,13,.82)", zIndex: 100, display: "flex", alignItems: "center", justifyContent: "center", padding: 20, fontFamily: FB }}>
<div className="pop" onClick={(e) => e.stopPropagation()} style={{ width: "min(540px,94vw)", background: C.panel, border: `1px solid ${C.border}`, borderRadius: 14, boxShadow: "0 24px 70px rgba(0,0,0,.55)", overflow: "hidden" }}>
{/* header */}
<div style={{ padding: "20px 22px 14px", borderBottom: `1px solid ${C.borderSoft}`, display: "flex", alignItems: "center", gap: 11 }}>
<div style={{ width: 36, height: 36, borderRadius: 9, background: C.orange, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
<Lock size={18} color="#fff" />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontFamily: FD, fontWeight: 700, fontSize: 18, color: C.text }}>Your sessions are private</div>
<div style={{ fontFamily: FM, fontSize: 11, color: C.muted, marginTop: 2 }}>हेर · what you upload stays yours</div>
</div>
<X size={18} color={C.muted} style={{ cursor: "pointer" }} onClick={close} />
</div>
{/* body */}
<div style={{ padding: "16px 22px 8px", display: "flex", flexDirection: "column", gap: 13 }}>
<Row icon={Trash2} c={C.cyan} title="We never store your sessions"
body="Files you upload are isolated to your browser and deleted when you leave, when you click “clear my data”, or within 24 hours — whichever comes first." />
<Row icon={ShieldCheck} c={C.orange} title="Nothing leaves this Space"
body="No code, commands, file paths, secrets — or even tool names — are ever sent anywhere. We don’t train on your sessions and we don’t share them." />
<Row icon={Sparkles} c={C.amber} title="Analyzed here, then gone"
body="The forensics run on the Space and the plain-English write-up is generated by a model running here. The only thing ever downloaded is that model itself, once." />
</div>
{/* footer */}
<div style={{ padding: "12px 22px 18px", display: "flex", alignItems: "center", gap: 12, marginTop: 6 }}>
<span style={{ fontFamily: FM, fontSize: 10, color: C.muted, flex: 1, lineHeight: 1.45, display: "flex", alignItems: "center", gap: 6 }}>
<ShieldCheck size={12} color={C.cyan} /> Findings are computed here; your uploads are never retained.
</span>
<div onClick={close} className="lift"
style={{ cursor: "pointer", background: C.orange, color: "#fff", fontFamily: FD, fontWeight: 700, fontSize: 14, borderRadius: 9, padding: "10px 22px" }}>
Got it
</div>
</div>
</div>
</div>
);
}
function Row({ icon: Icon, c, title, body }) {
return (
<div style={{ display: "flex", gap: 11, alignItems: "flex-start" }}>
<Icon size={16} color={c} style={{ flexShrink: 0, marginTop: 2 }} />
<div>
<div style={{ fontSize: 13, fontWeight: 600, color: C.text }}>{title}</div>
<div style={{ fontSize: 12, color: C.text2, lineHeight: 1.5, marginTop: 1 }}>{body}</div>
</div>
</div>
);
}