Import source: web/src/App

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:19:58 +03:30
parent b5ba217d25
commit f4f43b100b
+196
View File
@@ -0,0 +1,196 @@
import { useEffect, useMemo, useState } from "react";
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
import { useMonitor } from "./hooks/useMonitor";
import { springs, UIProvider, useUI } from "./lib/ui";
import type { CheckKind } from "./lib/types";
import { fmtNumber } from "./lib/format";
import { Header } from "./components/Header";
import { Boot } from "./components/Boot";
import { TargetCard } from "./components/TargetCard";
import { TargetDetail } from "./components/TargetDetail";
import { OrbitalOverview } from "./components/OrbitalOverview";
import { RadialDay } from "./components/RadialDay";
import { IncidentList } from "./components/IncidentList";
import { PublicView } from "./components/PublicView";
const MIN_BOOT_MS = 1700;
type Filter = "all" | CheckKind;
function FilterChips({
targets,
filter,
onChange,
}: {
targets: { type: CheckKind }[];
filter: Filter;
onChange: (f: Filter) => void;
}) {
const { t, lang, reduced } = useUI();
const kinds = useMemo(() => {
const present = new Set(targets.map((x) => x.type));
return (["http", "tls", "tcp", "icmp", "docker"] as CheckKind[]).filter((k) =>
present.has(k),
);
}, [targets]);
if (kinds.length < 2) return null;
const chip = (value: Filter, label: string, count: number) => {
const active = filter === value;
return (
<button
key={value}
onClick={() => onChange(value)}
aria-pressed={active}
className={`relative px-2.5 py-[3px] rounded-full font-mono text-[9.5px] tracking-[0.12em] uppercase cursor-pointer transition-colors ${
active ? "text-ink-950" : "text-paper-faint hover:text-paper-dim"
}`}
>
{active && (
<motion.span
layoutId="filter-chip"
className="absolute inset-0 rounded-full bg-brass"
transition={reduced ? { duration: 0 } : springs.snappy}
/>
)}
<span className="relative z-10">
{label} <span className="opacity-65 tabular">{fmtNumber(lang, count)}</span>
</span>
</button>
);
};
return (
<div className="flex items-center gap-1 flex-wrap">
{chip("all", t.all, targets.length)}
{kinds.map((k) =>
chip(k, k, targets.filter((x) => x.type === k).length),
)}
</div>
);
}
function Shell() {
const monitor = useMonitor();
const { t, mode, reduced } = useUI();
const [selected, setSelected] = useState<string | null>(
() => decodeURIComponent(location.hash.slice(1)) || null,
);
const [filter, setFilter] = useState<Filter>("all");
const [bootElapsed, setBootElapsed] = useState(reduced);
useEffect(() => {
const id = setTimeout(() => setBootElapsed(true), reduced ? 0 : MIN_BOOT_MS);
return () => clearTimeout(id);
}, [reduced]);
const booted = monitor.ready && bootElapsed;
const selectedTarget = monitor.targets.find((x) => x.id === selected) ?? null;
// The selected target lives in the URL — deep-linkable, back-button friendly.
const select = (id: string | null) => {
setSelected(id);
history.replaceState(null, "", id ? `#${encodeURIComponent(id)}` : location.pathname);
};
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") select(null);
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);
const visibleTargets =
filter === "all"
? monitor.targets
: monitor.targets.filter((x) => x.type === filter);
return (
<div className="relative z-[1] min-h-screen">
<AnimatePresence>{!booted && <Boot />}</AnimatePresence>
{booted && (
<>
<Header connected={monitor.connected} targets={monitor.targets} />
<div className="rule-fade mx-6 sm:mx-10" />
{mode === "public" ? (
<PublicView monitor={monitor} />
) : (
<LayoutGroup>
<main className="px-6 sm:px-10 pb-16">
{/* hero: orbit + day dial */}
<section className="grid gap-10 lg:grid-cols-[minmax(0,1.35fr)_minmax(0,1fr)] items-start pt-8">
<OrbitalOverview
targets={monitor.targets}
onSelect={select}
/>
<div className="flex flex-col gap-8">
<RadialDay
targets={monitor.targets}
dayBuckets={monitor.dayBuckets}
/>
<IncidentList
incidents={monitor.incidents.slice(0, 6)}
targets={monitor.targets}
onSelect={select}
compact
/>
</div>
</section>
{/* targets grid */}
<section className="mt-12">
<div className="flex items-baseline gap-4 mb-5 flex-wrap">
<h2 className="microlabel">{t.targets}</h2>
<div className="rule-fade flex-1 min-w-16" />
<FilterChips
targets={monitor.targets}
filter={filter}
onChange={setFilter}
/>
</div>
<div className="grid gap-4 [grid-template-columns:repeat(auto-fill,minmax(215px,1fr))]">
<AnimatePresence mode="popLayout" initial={false}>
{visibleTargets.map((target, i) => (
<TargetCard
key={target.id}
target={target}
index={i}
onSelect={select}
/>
))}
</AnimatePresence>
</div>
</section>
</main>
<AnimatePresence>
{selectedTarget && (
<TargetDetail
target={selectedTarget}
buckets={monitor.dayBuckets[selectedTarget.id] ?? []}
incidents={monitor.incidents.filter(
(i) => i.target_id === selectedTarget.id,
)}
onClose={() => select(null)}
/>
)}
</AnimatePresence>
</LayoutGroup>
)}
</>
)}
</div>
);
}
export default function App() {
return (
<UIProvider>
<Shell />
</UIProvider>
);
}