/* global React */
// Five VISUAL solutions to the deep-tree / long-label trilemma.
// Same 10-level archive with long names shown in each, so the approaches
// can be compared head-to-head.

const { useState } = React;

const T = {
  paper: "#f3eee2", paper2: "#e6dfc9", surface: "#fbf8ef",
  ink: "#1c1814", ink2: "#3a342c", muted: "#6c655a",
  hairline: "#d8cfba", hairline2: "#c5b99c",
  accent: "#6a1f23", accentInk: "#fbf8ef", accentSoft: "#f0d8d4",
  good: "#2f5a3a",
  // depth color ramp (for color-coded variants)
  ramp: ["#1f3a2e", "#2c5544", "#406b51", "#5a7d3a", "#8a7a1f", "#8a4a1f", "#8a2f1f", "#6a1f23", "#5a1f3a", "#3a2b56"],
  serif: '"Newsreader", Georgia, serif',
  sans: '"Geist", ui-sans-serif, system-ui, sans-serif',
  mono: '"Geist Mono", ui-monospace, Menlo, monospace',
};

const ART_W = 460;
const ART_H = 660;

// 10-level lineage with realistic long names
const PATH = [
  { lv: "Fonds", name: "Mira K. Adesanya Coastal Adaptation Photographic Archive" },
  { lv: "Series", name: "Field Studies and On-Site Documentation" },
  { lv: "Subseries", name: "Europe — Low Countries" },
  { lv: "Group", name: "Netherlands" },
  { lv: "Subgroup", name: "Rotterdam Metropolitan Region" },
  { lv: "File", name: "Maeslantkering Storm Surge Barrier" },
  { lv: "Subfile", name: "1998 Commissioning and Acceptance Testing" },
  { lv: "Item group", name: "Roll 14 — Second Full-Closure Stress Test" },
  { lv: "Item", name: "Frame 22 — Northern Gate Sealing Sequence" },
  { lv: "Component", name: "Verso — Engineer's annotation in pencil" },
];
const SIBS = {
  9: ["Recto — Silver gelatin print, full frame", "Verso — Engineer's annotation in pencil", "Conservation note — surface abrasion", "Rights & reproduction statement"],
};

/* atoms */
const Tri = ({ open }) => (
  <svg viewBox="0 0 12 12" width="9" height="9" style={{ transform: open ? "rotate(90deg)" : "none" }}>
    <path d="M4 2l5 4-5 4z" fill="currentColor" /></svg>
);
const Folder = ({ s = 13 }) => (
  <svg viewBox="0 0 24 24" width={s} height={s} fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M3 7h6l2 2h10v10H3z" /></svg>
);
const FolderOpen = ({ s = 13 }) => (
  <svg viewBox="0 0 24 24" width={s} height={s} fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M3 7h6l2 2h10v3H3z" /><path d="M3 12h17l-2 7H3z" /></svg>
);
const Doc = ({ s = 13 }) => (
  <svg viewBox="0 0 24 24" width={s} height={s} fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M6 3h9l4 4v14H6z" /><path d="M14 3v5h5" /></svg>
);
const SC = ({ children, style }) => (
  <span style={{ fontFamily: T.sans, fontSize: 9, letterSpacing: "0.13em", textTransform: "uppercase",
    fontWeight: 600, color: T.muted, ...style }}>{children}</span>
);

function Shell({ children, caption, solves }) {
  return (
    <div style={{ width: ART_W, height: ART_H, background: T.surface, border: `1px solid ${T.hairline}`,
      display: "flex", flexDirection: "column", overflow: "hidden", fontFamily: T.sans }}>
      <div style={{ height: 42, background: T.paper, borderBottom: `1px solid ${T.hairline}`,
        display: "flex", alignItems: "center", padding: "0 14px", gap: 8, flexShrink: 0 }}>
        <span style={{ width: 20, height: 20, background: T.ink, color: T.paper, display: "grid",
          placeItems: "center", fontFamily: T.serif, fontWeight: 600, fontSize: 11 }}>E</span>
        <span style={{ fontFamily: T.serif, fontWeight: 600, fontSize: 13 }}>Finding aid</span>
        <span style={{ marginLeft: "auto", fontFamily: T.mono, fontSize: 9.5, color: T.muted }}>360px panel</span>
      </div>
      <div style={{ flex: 1, minHeight: 0, overflow: "hidden", position: "relative" }}>{children}</div>
      <div style={{ background: T.ink, color: T.surface, padding: "9px 14px", flexShrink: 0 }}>
        <div style={{ fontFamily: T.serif, fontSize: 13, fontWeight: 600 }}>{caption}</div>
        <div style={{ fontSize: 11, color: "rgba(243,238,226,0.72)", marginTop: 2, lineHeight: 1.4 }}>
          <span style={{ color: T.accentSoft }}>Solves it by: </span>{solves}</div>
      </div>
    </div>
  );
}

function middleTrunc(s, max) {
  if (s.length <= max) return s;
  const half = Math.floor((max - 1) / 2);
  return s.slice(0, half) + "…" + s.slice(s.length - half);
}

/* ── 1 · Ratcheting re-root ── */
function ReRoot() {
  return (
    <Shell caption="1 · Ratcheting re-root"
      solves="children reset to the left margin each level — depth lives in the breadcrumb, so every label gets the FULL column width.">
      <div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
        {/* breadcrumb stack */}
        <div style={{ background: T.paper2, borderBottom: `1px solid ${T.hairline}`, padding: "8px 12px" }}>
          <SC>Path</SC>
          <div style={{ marginTop: 4 }}>
            {PATH.slice(0, 5).map((n, i) => (
              <div key={i} style={{ display: "flex", alignItems: "center", gap: 6, padding: "1px 0", paddingLeft: i * 8,
                color: T.muted, fontSize: 11 }}>
                <span style={{ width: 4, height: 4, borderRadius: 9, background: T.hairline2 }} />
                <span style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{n.name}</span>
              </div>
            ))}
          </div>
        </div>
        {/* current level full width */}
        <div style={{ padding: "12px 14px 8px" }}>
          <SC style={{ color: T.accent }}>Subfile · L6 — open</SC>
          <div style={{ fontFamily: T.serif, fontSize: 16, fontWeight: 500, marginTop: 2, lineHeight: 1.25 }}>
            1998 Commissioning and Acceptance Testing</div>
        </div>
        <div style={{ padding: "0 0 8px" }}>
          <div style={{ padding: "2px 14px 6px" }}><SC>Contains</SC></div>
          {["Roll 14 — Second Full-Closure Stress Test", "Roll 15 — Public Observation Crowd", "Contact Sheet A — proof strips"].map((c, i) => (
            <div key={i} style={{ display: "flex", gap: 9, alignItems: "center", padding: "8px 14px",
              background: i === 0 ? T.accentSoft : "transparent", borderLeft: i === 0 ? `2px solid ${T.accent}` : "2px solid transparent",
              color: i === 0 ? T.accent : T.ink, fontWeight: i === 0 ? 600 : 400 }}>
              <span style={{ color: i === 0 ? T.accent : "#9a6b35" }}>{i === 0 ? <FolderOpen /> : <Folder />}</span>
              <span style={{ fontSize: 13 }}>{c}</span>
            </div>
          ))}
        </div>
      </div>
    </Shell>
  );
}

/* ── 2 · Miller columns ── */
function Miller() {
  const cols = [
    { lv: "Subgroup", sel: "Rotterdam Metropolitan Region", items: ["Maeslantkering Storm Surge Barrier", "Boompjes Embankment", "Katendrecht Walkway"] },
    { lv: "File", sel: "Maeslantkering Storm Surge Barrier", items: ["1998 Commissioning and Acceptance Testing", "2014 Decadal Stress Test"] },
    { lv: "Subfile", sel: "1998 Commissioning and Acceptance Testing", items: ["Roll 14 — Second Full-Closure Stress Test", "Roll 15 — Public Observation Crowd"], wide: true },
  ];
  return (
    <Shell caption="2 · Miller columns"
      solves="each level is its own pane — full label width per level. Horizontal scroll handles arbitrary depth (Finder-style).">
      <div style={{ display: "flex", height: "100%" }}>
        <div style={{ width: 26, borderRight: `1px solid ${T.hairline}`, background: T.paper2,
          writingMode: "vertical-rl", transform: "rotate(180deg)", display: "flex", justifyContent: "center",
          paddingTop: 8, fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", color: T.muted }}>
          Fonds › … › Netherlands</div>
        {cols.map((c, k) => (
          <div key={k} style={{ width: c.wide ? "auto" : 130, flex: c.wide ? 1 : "none",
            borderRight: `1px solid ${T.hairline}`, background: c.wide ? T.surface : T.paper }}>
            <div style={{ padding: "7px 10px", borderBottom: `1px solid ${T.hairline}` }}>
              <SC style={{ fontSize: 8 }}>{c.lv}</SC></div>
            {c.items.map((it, i) => {
              const on = it === c.sel;
              return (
                <div key={i} style={{ display: "flex", gap: 6, alignItems: "flex-start", padding: "7px 10px",
                  background: on ? T.accent : "transparent", color: on ? T.accentInk : T.ink, fontSize: 12 }}>
                  <span style={{ marginTop: 1, color: on ? T.accentInk : "#9a6b35" }}>{k === 2 ? <Doc s={12} /> : <Folder s={12} />}</span>
                  <span style={{ lineHeight: 1.3, whiteSpace: c.wide ? "normal" : "nowrap",
                    overflow: "hidden", textOverflow: "ellipsis" }}>{it}</span>
                </div>
              );
            })}
          </div>
        ))}
      </div>
    </Shell>
  );
}

/* ── 3 · Capped indent + middle-truncation + depth badge ── */
function Capped() {
  const rows = PATH.map((n, i) => ({ ...n, d: Math.min(i, 3) })); // indent stops at 3
  return (
    <Shell caption="3 · Capped indent + middle-truncation"
      solves="indent stops after L3 (depth shown by an Ln badge); names truncate in the MIDDLE so the start AND end stay readable.">
      <div style={{ padding: "8px 0" }}>
        {rows.map((n, i) => {
          const active = i === 8;
          return (
            <div key={i} style={{ display: "grid", gridTemplateColumns: "auto 26px 14px 1fr", gap: 6, alignItems: "center",
              padding: "6px 12px", paddingLeft: 10 + n.d * 16,
              background: active ? T.accentSoft : "transparent", borderLeft: active ? `2px solid ${T.accent}` : "2px solid transparent",
              color: active ? T.accent : T.ink }}>
              <span style={{ color: T.muted, width: 9 }}>{i < 9 ? <Tri open={i < 9} /> : null}</span>
              <span style={{ fontFamily: T.mono, fontSize: 8.5, color: i > 3 ? T.accent : T.muted,
                border: `1px solid ${i > 3 ? T.accent : T.hairline2}`, padding: "0 3px", textAlign: "center" }}>L{i + 1}</span>
              <span style={{ color: i >= 8 ? "#6a1f23" : "#9a6b35" }}>{i >= 8 ? <Doc s={12} /> : <Folder s={12} />}</span>
              <span style={{ fontSize: 12.5, fontWeight: active ? 600 : 400, whiteSpace: "nowrap" }}>
                {middleTrunc(n.name, 34)}</span>
            </div>
          );
        })}
      </div>
    </Shell>
  );
}

/* ── 4 · Two-line wrap on the focused node ── */
function WrapActive() {
  return (
    <Shell caption="4 · Focused row wraps to 2 lines"
      solves="classic indented tree, but the SELECTED node wraps to show its full title; siblings stay single-line. Spends a little height, no width.">
      <div style={{ padding: "8px 0" }}>
        {PATH.map((n, i) => {
          const active = i === 8;
          const d = i;
          return (
            <div key={i} style={{ display: "flex", gap: 6, alignItems: "flex-start",
              padding: active ? "8px 12px" : "6px 12px", paddingLeft: 10 + d * 15,
              background: active ? T.accentSoft : "transparent", borderLeft: active ? `2px solid ${T.accent}` : "2px solid transparent",
              color: active ? T.accent : T.ink }}>
              <span style={{ color: T.muted, marginTop: 3, width: 9 }}>{i < 9 ? <Tri open /> : null}</span>
              <span style={{ marginTop: 2, color: i >= 8 ? "#6a1f23" : "#9a6b35" }}>{i >= 8 ? <Doc s={12} /> : <Folder s={12} />}</span>
              <span style={{ fontSize: 12.5, fontWeight: active ? 600 : 400, lineHeight: 1.3,
                whiteSpace: active ? "normal" : "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                {n.name}</span>
            </div>
          );
        })}
      </div>
    </Shell>
  );
}

/* ── 5 · Indent-free outline (depth spine + chips) ── */
function Outline() {
  return (
    <Shell caption="5 · Indent-free outline"
      solves="no indentation at all — every row uses full width. Depth is read from a colored spine + Ln chip on the left. Long names always fit.">
      <div style={{ padding: "8px 0" }}>
        {PATH.map((n, i) => {
          const active = i === 8;
          return (
            <div key={i} style={{ display: "grid", gridTemplateColumns: "6px 28px 1fr", gap: 8, alignItems: "center",
              padding: "8px 12px", background: active ? T.accentSoft : "transparent",
              borderBottom: `1px solid ${T.hairline}` }}>
              <span style={{ width: 6, height: 22, background: T.ramp[i], borderRadius: 2 }} />
              <span style={{ fontFamily: T.mono, fontSize: 9, color: T.muted, textAlign: "center" }}>
                L{i + 1}</span>
              <div style={{ minWidth: 0 }}>
                <SC style={{ fontSize: 8, color: active ? T.accent : T.muted, display: "block" }}>{n.lv}</SC>
                <span style={{ fontSize: 12.5, fontWeight: active ? 600 : 400, color: active ? T.accent : T.ink,
                  lineHeight: 1.25, display: "block" }}>{n.name}</span>
              </div>
            </div>
          );
        })}
      </div>
    </Shell>
  );
}

function App() {
  return (
    <DesignCanvas>
      <DCSection id="solutions" title="Deep tree × long labels — 5 visual solutions"
        subtitle="Same 10-level archive, same long names, in a 360px panel. Each card's footer says how it beats the trilemma.">
        <DCArtboard id="v1" label="1 · Ratcheting re-root" width={ART_W} height={ART_H}><ReRoot /></DCArtboard>
        <DCArtboard id="v2" label="2 · Miller columns" width={ART_W} height={ART_H}><Miller /></DCArtboard>
        <DCArtboard id="v3" label="3 · Capped indent + mid-truncate" width={ART_W} height={ART_H}><Capped /></DCArtboard>
        <DCArtboard id="v4" label="4 · Focused row wraps" width={ART_W} height={ART_H}><WrapActive /></DCArtboard>
        <DCArtboard id="v5" label="5 · Indent-free outline" width={ART_W} height={ART_H}><Outline /></DCArtboard>
      </DCSection>
    </DesignCanvas>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
