Download src/components/TopBar.jsx from NKessler/Horizon: direct link, hf CLI and curl.
- Browser
- Download file 3.04 kB
-
https://huggingface.co/NKessler/Horizon/resolve/main/src/components/TopBar.jsx
- Command line
-
hf download hf://NKessler/Horizon/src/components/TopBar.jsx
-
curl -L -o TopBar.jsx https://huggingface.co/NKessler/Horizon/resolve/main/src/components/TopBar.jsx
3.04 kB
| import { Menu, PanelLeftClose, Pencil } from "lucide-react"; | |
| import "./TopBar.css"; | |
| import { getNewsTimeframeLabel } from "../constants/timeframes.js"; | |
| function fmt(n) { | |
| if (n == null) return "—"; | |
| if (n >= 1000) return new Intl.NumberFormat("en-US").format(n); | |
| return String(n); | |
| } | |
| function fmtTime(iso) { | |
| if (!iso) return "—"; | |
| const d = new Date(iso); | |
| return d.toLocaleString("en-GB", { | |
| year: "numeric", | |
| month: "short", | |
| day: "2-digit", | |
| hour: "2-digit", | |
| minute: "2-digit", | |
| }); | |
| } | |
| function divLabel(d) { | |
| if (d == null) return { text: "—", tone: "" }; | |
| if (d > 0.7) return { text: "high", tone: "danger" }; | |
| if (d > 0.45) return { text: "moderate", tone: "warn" }; | |
| return { text: "low", tone: "neutral" }; | |
| } | |
| export default function TopBar({ | |
| query, | |
| meta, | |
| metaLoading, | |
| menuOpen, | |
| onToggleMenu, | |
| onEditTopic, | |
| }) { | |
| const div = divLabel(meta?.divergenceIndex); | |
| return ( | |
| <div className="topbar"> | |
| <button | |
| className="topbar__menu-btn" | |
| onClick={onToggleMenu} | |
| aria-label="Toggle visualization menu" | |
| title="Toggle visualization menu" | |
| > | |
| {menuOpen ? <PanelLeftClose size={15} /> : <Menu size={15} />} | |
| <span>views</span> | |
| </button> | |
| <div className="topbar__topic"> | |
| <div className="label">Topic</div> | |
| <button | |
| className="topbar__topic-button" | |
| onClick={onEditTopic} | |
| title="Change topic" | |
| > | |
| <span className="topbar__topic-block"> | |
| <span className="topbar__topic-text"> | |
| {query.topic || "Untitled"} | |
| </span> | |
| <span className="topbar__topic-meta"> | |
| {getNewsTimeframeLabel(query.newsTimeframe)} | |
| </span> | |
| </span> | |
| <Pencil size={14} strokeWidth={1.5} className="topbar__topic-icon" /> | |
| </button> | |
| </div> | |
| <div className="topbar__metrics" aria-busy={metaLoading || undefined}> | |
| <Metric label="Articles" value={fmt(meta?.totalArticles)} /> | |
| <Metric label="Sources" value={fmt(meta?.totalSources)} /> | |
| <Metric label="Countries" value={fmt(meta?.countriesCovered)} /> | |
| <Metric label="Languages" value={fmt(meta?.languagesCovered)} /> | |
| <Metric | |
| label="Divergence" | |
| value={ | |
| meta?.divergenceIndex != null | |
| ? meta.divergenceIndex.toFixed(2) | |
| : "—" | |
| } | |
| accent={div.tone} | |
| suffix={div.text} | |
| /> | |
| <Metric | |
| label="Updated" | |
| value={fmtTime(meta?.lastUpdated)} | |
| tight | |
| /> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function Metric({ label, value, accent = "", suffix, tight = false }) { | |
| return ( | |
| <div className={`metric ${tight ? "metric--tight" : ""}`}> | |
| <div className="label metric__label">{label}</div> | |
| <div className={`metric__value metric__value--${accent}`}> | |
| {value} | |
| {suffix && <span className="metric__suffix">{suffix}</span>} | |
| </div> | |
| </div> | |
| ); | |
| } | |