"use client"; import type { ADMETSwissADME } from "@/lib/api"; import { ResponsiveContainer, RadarChart, PolarGrid, PolarAngleAxis, Radar, ScatterChart, XAxis, YAxis, Scatter, CartesianGrid, Customized, BarChart, Bar, ReferenceLine, LabelList, } from "recharts"; const CYAN = "#4ADE80"; const GREEN = "#34D399"; const AMBER = "#FBBF24"; const ORANGE = "#FB923C"; const RED = "#F87171"; const SLATE = "#848CA4"; const INK = "#DDE0EE"; function Section({ title, children, className = "" }: { title: string; children: React.ReactNode; className?: string }) { return (

{title}

{children}
); } function Row({ label, value, unit, sub, color }: { label: string; value: React.ReactNode; unit?: string; sub?: string; color?: string }) { return (
{label}
{value} {unit && {unit}} {sub &&
{sub}
}
); } function Pill({ pass }: { pass: boolean }) { return pass ? Pass : Fail; } function FilterCard({ name, data }: { name: string; data: { pass: boolean; violations: string[]; violation_count: number } }) { return (
{name}
{data.violation_count} violation{data.violation_count === 1 ? "" : "s"} {data.violations.length > 0 && ( )}
); } /* ------------------------------------------------------------------ */ /* Bioavailability Radar (SwissADME-style, 6 axes) */ /* ------------------------------------------------------------------ */ function BioavailabilityRadar({ radar }: { radar: ADMETSwissADME["bioavailability_radar"] }) { const data = radar.axes.map((a) => { const max = a.max || 1; const min = a.min; const value = Math.max(0, Math.min(1, a.value / max)); const zoneStart = Math.max(0, Math.min(1, min / max)); const zoneEnd = Math.max(0, Math.min(1, max / max)); return { axis: a.axis, label: a.label, value, zoneStart, zoneEnd, raw: a.value, min, max, note: a.note }; }); return (

Optimal zone (green band), molecule (green line).

{data.map((d) => { const ok = d.raw >= d.min && d.raw <= d.max; return (
{d.axis} {d.label}
{d.raw} {ok ? "OK" : "out"}
); })}

{radar.all_optimal ? "All six axes within optimal ranges." : "Some axes fall outside the optimal (pink) zone."}

); } /* ------------------------------------------------------------------ */ /* BOILED-Egg (ScatterChart + ellipse polygons) */ /* ------------------------------------------------------------------ */ function BoiledEgg({ egg }: { egg: ADMETSwissADME["pharmacokinetics"]["boiled_egg"] }) { const point = [{ tpsa: egg.tpsa, wlogp: egg.wlogp, region: egg.region }]; const pointColor = egg.region === "yolk" ? AMBER : egg.region === "white" ? CYAN : RED; const Polygons = (props: any) => { const xScale = props?.xAxisMap?.["0"]?.scale; const yScale = props?.yAxisMap?.["0"]?.scale; if (!xScale || !yScale) return null; const toPoints = (arr: [number, number][]) => arr.map(([x, y]) => `${xScale(x)},${yScale(y)}`).join(" "); return ( ); }; const CompoundDot = (props: any) => { const { cx, cy, payload } = props; return ( compound ); }; return (
GI absorption — High BBB permeant — Yes This molecule Region: {egg.region} (TPSA {egg.tpsa}, WLOGP {egg.wlogp})
); } /* ------------------------------------------------------------------ */ /* Range bars (recharts) — ESOL / WLOGP / Log Kp on shared 0-100% axis */ /* ------------------------------------------------------------------ */ type RangeItem = { key: string; value: number; display: string; note: string; color: string; tick: string }; function RangeBars({ items }: { items: RangeItem[] }) { const data = items.map((it) => ({ key: it.key, value: it.value })); return (
{items.map((it) => ( `${Math.round(v * 100)}%`} fill={SLATE} fontSize={10} /> ))}
); } function norm(v: number, min: number, max: number) { return Math.max(0, Math.min(1, (v - min) / (max - min))); } /* ------------------------------------------------------------------ */ /* Main panel */ /* ------------------------------------------------------------------ */ export default function SwissADMEView({ data }: { data: ADMETSwissADME }) { const phys = data.physicochemical; const lipo = data.lipophilicity; const sol = data.water_solubility; const pk = data.pharmacokinetics; const dl = data.drug_likeness; const mc = data.medicinal_chemistry; const rangeItems: RangeItem[] = [ { key: "WLOGP", value: norm(lipo.wlogp, -2, 6), display: `${lipo.wlogp}`, note: "domain -2..6", color: CYAN, tick: `${lipo.wlogp}` }, { key: "ESOL log S", value: norm(sol.esol_log_s, -6, 0), display: `${sol.esol_log_s}`, note: "domain -6..0", color: GREEN, tick: `${sol.esol_log_s}` }, { key: "Log Kp (skin, cm/s)", value: norm(pk.log_kp_skin, -8, -1), display: `${pk.log_kp_skin}`, note: "domain -8..-1", color: ORANGE, tick: `${pk.log_kp_skin}` }, ]; return (

SwissADME-parity panel. Descriptors computed locally with RDKit (WLOGP = Wildman-Crippen). XLOGP3, MLOGP, SILICOS-IT and iLOGP are proprietary models and are marked unavailable; consensus Log P reflects WLOGP only. BOILED-Egg and ESOL use the published boundaries/models (Daina & Zoete 2016; Delaney 2004).

{lipo.note}

{sol.note}

{rangeItems.map((it) => (
{it.key}
{it.tick}
{it.note}
))}
Bioavailability Score {dl.bioavailability_score} Martin 2005
PAINS
{mc.pains_alerts.alert_count} alert(s) {mc.pains_alerts.alerts.length > 0 && (
    {mc.pains_alerts.alerts.map((a, i) =>
  • {a}
  • )}
)}
Brenk
{mc.brenk_alerts.alert_count} alert(s) {mc.brenk_alerts.alerts.length > 0 && (
    {mc.brenk_alerts.alerts.map((a, i) =>
  • {a}
  • )}
)}

SA score (1 = easy, 10 = hard), RDKit sascorer.

Reference: Daina A., Michielin O., Zoete V. Sci Rep 7, 42717 (2017) — SwissADME.

); }