/* global React */
// Long-name handling inside a fixed-width sidebar (deep hierarchy).
// Same two-zone layout (ancestry spine + children); four truncation strategies
// applied to REAL long archival titles so the tradeoffs are visible.

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", warn: "#8a4a1f",
  serif: '"Newsreader", Georgia, serif',
  sans: '"Geist", ui-sans-serif, system-ui, sans-serif',
  mono: '"Geist Mono", ui-monospace, Menlo, monospace',
};

const ART_W = 1180;
const ART_H = 820;
const SIDEBAR = 304;

// 10-level lineage with REALISTIC long archival names
const LINEAGE = [
  { level: "Fonds",      name: "Mira K. Adesanya Coastal Adaptation Photographic Archive" },
  { level: "Series",     name: "Field Studies and On-Site Documentation" },
  { level: "Subseries",  name: "Europe — Low Countries" },
  { level: "Group",      name: "Netherlands" },
  { level: "Subgroup",   name: "Rotterdam Metropolitan Region" },
  { level: "File",       name: "Maeslantkering Storm Surge Barrier" },
  { level: "Subfile",    name: "1998 Commissioning and Acceptance Testing" },
  { level: "Item group", name: "Roll 14 — Second Full-Closure Stress Test" },
  { level: "Item",       name: "Frame 22 — Northern Gate Sealing Sequence" },
  { level: "Component",  name: "Verso — Engineer's Annotation in Pencil" },
];

const CHILDREN = [
  "Recto — Silver gelatin print, full frame",
  "Verso — Engineer's annotation concerning hydraulic pressure readings during the closure sequence",
  "Conservation note — surface abrasion, lower-left quadrant",
  "Rights and reproduction statement (Adesanya Estate)",
];

/* ── atoms ── */
const SmallCaps = ({ children, style }) => (
  <span style={{ fontFamily: T.sans, fontSize: 9.5, letterSpacing: "0.14em",
    textTransform: "uppercase", fontWeight: 600, color: T.muted, ...style }}>{children}</span>
);
const Folder = ({ size = 12 }) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M3 7h6l2 2h10v10H3z" /></svg>
);
const Doc = ({ size = 12 }) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M6 3h9l4 4v14H6z" /><path d="M14 3v5h5" /></svg>
);
const Chev = ({ size = 11, dir = "r" }) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2"
    style={{ transform: dir === "d" ? "rotate(90deg)" : dir === "l" ? "rotate(180deg)" : "none" }}>
    <path d="M9 6l6 6-6 6" /></svg>
);

function Frame({ children }) {
  return <div style={{ width: ART_W, height: ART_H, background: T.paper2,
    position: "relative", overflow: "hidden", fontFamily: T.sans }}>{children}</div>;
}
function Bar() {
  return (
    <div style={{ height: 48, background: T.paper, borderBottom: `1px solid ${T.hairline}`,
      display: "flex", alignItems: "center", padding: "0 24px", gap: 10 }}>
      <span style={{ width: 24, height: 24, background: T.ink, color: T.paper,
        display: "grid", placeItems: "center", fontFamily: T.serif, fontWeight: 600, fontSize: 12 }}>E</span>
      <span style={{ fontFamily: T.serif, fontWeight: 600, fontSize: 14 }}>Eastbrook Libraries</span>
    </div>
  );
}
function Annot({ verdict, strategy, tone = "good" }) {
  const bg = tone === "good" ? T.good : tone === "warn" ? T.warn : T.ink;
  return (
    <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, background: bg, color: T.surface,
      padding: "9px 24px", display: "flex", gap: 14, alignItems: "center", fontFamily: T.sans, fontSize: 11.5 }}>
      <span style={{ fontFamily: T.mono, fontSize: 9.5, letterSpacing: "0.08em", textTransform: "uppercase", opacity: 0.7 }}>Long names</span>
      <strong style={{ fontWeight: 600 }}>{verdict}</strong>
      <span style={{ opacity: 0.5 }}>·</span>
      <span style={{ opacity: 0.85 }}>{strategy}</span>
    </div>
  );
}
function Stage({ sidebar }) {
  return (
    <div style={{ position: "absolute", top: 48, left: 0, right: 0, bottom: 34,
      display: "grid", gridTemplateColumns: `${SIDEBAR}px 1fr`, background: T.paper }}>
      <aside style={{ borderRight: `1px solid ${T.hairline}`, background: T.surface,
        display: "flex", flexDirection: "column", overflow: "hidden" }}>{sidebar}</aside>
      <main style={{ background: T.paper2, display: "flex", flexDirection: "column",
        alignItems: "center", justifyContent: "center", gap: 10 }}>
        <div style={{ width: 170, height: 128, background: "linear-gradient(135deg,#1f3a2e,#406b51)" }} />
        <div style={{ fontFamily: T.serif, fontSize: 15, fontWeight: 500, maxWidth: 280, textAlign: "center" }}>
          Frame 22 — Northern Gate Sealing Sequence
        </div>
      </main>
    </div>
  );
}

function AncestryHeader({ children, note }) {
  return (
    <div style={{ padding: "10px 12px 8px", borderBottom: `1px solid ${T.hairline}` }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }}>
        <SmallCaps>Path · 10 levels</SmallCaps>
        {note && <span style={{ fontSize: 9.5, color: T.muted, fontStyle: "italic", fontFamily: T.serif }}>{note}</span>}
      </div>
      {children}
    </div>
  );
}

/* ═══════════ A · Single-line ellipsis (the problem) ═══════════ */
function EllipsisOnly() {
  return (
    <Frame>
      <Bar />
      <Stage sidebar={
        <>
          <AncestryHeader note="truncated">
            {LINEAGE.map((n, i) => {
              const last = i === LINEAGE.length - 1;
              return (
                <div key={i} style={{ display: "flex", alignItems: "center", gap: 6, padding: "2px 0", paddingLeft: i * 8,
                  color: last ? T.accent : T.ink2, fontWeight: last ? 600 : 400 }}>
                  <span style={{ width: 5, height: 5, borderRadius: 9, flexShrink: 0, background: last ? T.accent : T.hairline2 }} />
                  <span style={{ fontSize: 11.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{n.name}</span>
                </div>
              );
            })}
          </AncestryHeader>
          <div style={{ padding: "8px 12px 4px" }}><SmallCaps>Inside this item</SmallCaps></div>
          {CHILDREN.map((c) => {
            const cur = c.startsWith("Verso");
            return (
              <div key={c} style={{ display: "grid", gridTemplateColumns: "16px 1fr", gap: 8, alignItems: "center",
                padding: "7px 14px", fontSize: 12.5, background: cur ? T.accentSoft : "transparent",
                color: cur ? T.accent : T.ink, fontWeight: cur ? 600 : 400,
                borderLeft: cur ? `2px solid ${T.accent}` : "2px solid transparent" }}>
                <span style={{ color: cur ? T.accent : T.muted }}><Doc /></span>
                <span style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c}</span>
              </div>
            );
          })}
        </>
      } />
      <Annot tone="warn" verdict="Ellipsis hides the distinguishing words — often the END of the title"
        strategy="What I did before · fast but you can't tell rows apart · AVOID as the only tactic" />
    </Frame>
  );
}

/* ═══════════ B · Wrap ancestry, 2-line clamp children ═══════════ */
function WrapAndClamp() {
  return (
    <Frame>
      <Bar />
      <Stage sidebar={
        <>
          <AncestryHeader note="full wrap">
            {LINEAGE.map((n, i) => {
              const last = i === LINEAGE.length - 1;
              return (
                <div key={i} style={{ display: "flex", gap: 6, padding: "3px 0", paddingLeft: i * 7,
                  color: last ? T.accent : T.ink2, fontWeight: last ? 600 : 400 }}>
                  <span style={{ width: 5, height: 5, borderRadius: 9, flexShrink: 0, marginTop: 5,
                    background: last ? T.accent : T.hairline2 }} />
                  <span style={{ fontSize: 11, lineHeight: 1.3, textWrap: "pretty" }}>{n.name}</span>
                </div>
              );
            })}
          </AncestryHeader>
          <div style={{ padding: "8px 12px 4px" }}><SmallCaps>Inside this item</SmallCaps></div>
          <div style={{ overflow: "auto" }}>
            {CHILDREN.map((c) => {
              const cur = c.startsWith("Verso");
              return (
                <div key={c} style={{ display: "grid", gridTemplateColumns: "16px 1fr", gap: 8,
                  padding: "8px 14px", fontSize: 12.5, background: cur ? T.accentSoft : "transparent",
                  color: cur ? T.accent : T.ink, fontWeight: cur ? 600 : 400,
                  borderLeft: cur ? `2px solid ${T.accent}` : "2px solid transparent" }}>
                  <span style={{ color: cur ? T.accent : T.muted, marginTop: 2 }}><Doc /></span>
                  <span style={{ fontSize: 12, lineHeight: 1.35, display: "-webkit-box",
                    WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{c}</span>
                </div>
              );
            })}
          </div>
        </>
      } />
      <Annot verdict="Ancestry wraps fully (rows are cheap vertically); children clamp to 2 lines"
        strategy="No info lost in the path · children stay scannable · RECOMMENDED" />
    </Frame>
  );
}

/* ═══════════ C · Level label + truncated name (two-line rows) ═══════════ */
function LabelLed() {
  return (
    <Frame>
      <Bar />
      <Stage sidebar={
        <>
          <AncestryHeader note="label-led">
            {LINEAGE.map((n, i) => {
              const last = i === LINEAGE.length - 1;
              return (
                <div key={i} style={{ padding: "3px 0", paddingLeft: i * 6 }}>
                  <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
                    <span style={{ fontSize: 7.5, letterSpacing: "0.08em", textTransform: "uppercase",
                      color: T.muted, fontWeight: 600, flexShrink: 0, width: 52 }}>{n.level}</span>
                    <span style={{ fontSize: 11.5, color: last ? T.accent : T.ink2, fontWeight: last ? 600 : 400,
                      whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{n.name}</span>
                  </div>
                </div>
              );
            })}
          </AncestryHeader>
          <div style={{ padding: "8px 12px 4px" }}><SmallCaps>Inside this item</SmallCaps></div>
          {CHILDREN.map((c) => {
            const cur = c.startsWith("Verso");
            return (
              <div key={c} style={{ display: "grid", gridTemplateColumns: "16px 1fr", gap: 8,
                padding: "8px 14px", background: cur ? T.accentSoft : "transparent",
                color: cur ? T.accent : T.ink, borderLeft: cur ? `2px solid ${T.accent}` : "2px solid transparent" }}>
                <span style={{ color: cur ? T.accent : T.muted, marginTop: 2 }}><Doc /></span>
                <span style={{ fontSize: 12, lineHeight: 1.35, display: "-webkit-box",
                  WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden",
                  fontWeight: cur ? 600 : 400 }}>{c}</span>
              </div>
            );
          })}
        </>
      } />
      <Annot verdict="The level label carries meaning, so a truncated name still reads in context"
        strategy="“Subfile: 1998 Commissioning…” · label gives orientation even when name clips" />
    </Frame>
  );
}

/* ═══════════ D · Hover-peek (truncated, expands on hover) ═══════════ */
function HoverPeek() {
  const [hover, setHover] = useState(6);
  return (
    <Frame>
      <Bar />
      <Stage sidebar={
        <>
          <AncestryHeader note="hover to read">
            {LINEAGE.map((n, i) => {
              const last = i === LINEAGE.length - 1;
              const on = hover === i;
              return (
                <div key={i} onMouseEnter={() => setHover(i)} style={{ position: "relative",
                  display: "flex", alignItems: "center", gap: 6, padding: "2px 0", paddingLeft: i * 7,
                  color: last ? T.accent : T.ink2, fontWeight: last ? 600 : 400 }}>
                  <span style={{ width: 5, height: 5, borderRadius: 9, flexShrink: 0, background: last ? T.accent : T.hairline2 }} />
                  <span style={{ fontSize: 11.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{n.name}</span>
                  {on && (
                    <div style={{ position: "absolute", left: i * 7 + 12, top: -2, zIndex: 5,
                      background: T.ink, color: T.surface, padding: "5px 9px", fontSize: 11.5,
                      maxWidth: 360, boxShadow: "0 8px 20px -6px rgba(0,0,0,0.4)", lineHeight: 1.3 }}>
                      <span style={{ fontSize: 7.5, letterSpacing: "0.1em", textTransform: "uppercase",
                        opacity: 0.6, display: "block", marginBottom: 2 }}>{n.level}</span>
                      {n.name}
                    </div>
                  )}
                </div>
              );
            })}
          </AncestryHeader>
          <div style={{ padding: "8px 12px 4px" }}><SmallCaps>Inside this item</SmallCaps></div>
          {CHILDREN.map((c, j) => {
            const cur = c.startsWith("Verso");
            return (
              <div key={c} style={{ display: "grid", gridTemplateColumns: "16px 1fr", gap: 8, alignItems: "center",
                padding: "7px 14px", fontSize: 12.5, background: cur ? T.accentSoft : "transparent",
                color: cur ? T.accent : T.ink, fontWeight: cur ? 600 : 400,
                borderLeft: cur ? `2px solid ${T.accent}` : "2px solid transparent" }}>
                <span style={{ color: cur ? T.accent : T.muted }}><Doc /></span>
                <span style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c}</span>
              </div>
            );
          })}
        </>
      } />
      <Annot verdict="Stays one line; hovering any row reveals the full title in a tooltip"
        strategy="Compact list · full text on demand · weak on touch, pair with B as fallback" />
    </Frame>
  );
}

function App() {
  return (
    <DesignCanvas>
      <DCSection
        id="long-names"
        title="Long names in a fixed-width sidebar"
        subtitle="Real archival titles (full sentences). Same two-zone layout; four ways to handle overflow."
      >
        <DCArtboard id="a" label="A · Ellipsis only (the problem)" width={ART_W} height={ART_H}>
          <EllipsisOnly />
        </DCArtboard>
        <DCArtboard id="b" label="B · Wrap ancestry + clamp children" width={ART_W} height={ART_H}>
          <WrapAndClamp />
        </DCArtboard>
        <DCArtboard id="c" label="C · Level-label led" width={ART_W} height={ART_H}>
          <LabelLed />
        </DCArtboard>
        <DCArtboard id="d" label="D · Hover-peek tooltip" width={ART_W} height={ART_H}>
          <HoverPeek />
        </DCArtboard>
      </DCSection>
    </DesignCanvas>
  );
}

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