---
// Recursive, collapsible docs sidebar tree. Renders arbitrarily deep: a node
// with children becomes a <details> toggle (native fold/unfold, no JS); a leaf
// becomes a page link. Each <details> is server-rendered `open` only when the
// current page lives at or below it, so on load exactly the branch leading to
// the active page is unfolded and everything else is folded. Users can toggle
// any node freely.
export interface TreeNode {
  label: string;
  /** Page slug (leaf). Mutually exclusive with `children`. */
  href?: string;
  /** Child nodes (directory / toggle). Absent or empty ⇒ this is a leaf. */
  children?: TreeNode[];
  /** The current page is this node or somewhere beneath it ⇒ render open. */
  hasCurrent?: boolean;
  /** This leaf is the current page. */
  isCurrent?: boolean;
  /** Cached sort key computed by DocsLayout's `finalize` pass (min order of a
   *  node's subtree). Internal — set during finalization, not by callers. */
  _order?: number;
}
interface Props {
  nodes: TreeNode[];
  base: string;
  level?: number;
}
const { nodes, base, level = 0 } = Astro.props;

// Indent each level; leaves sit a touch deeper so they line up past the parent
// summary's chevron.
const pad = (l: number) => `padding-left: ${(0.35 + l * 0.8).toFixed(3)}rem`;

const summaryBase =
  "tree-summary flex items-center gap-1.5 cursor-pointer rounded-md py-1 pr-2 select-none";
const summaryTone = (l: number) =>
  l === 0
    ? "text-caption font-caption uppercase tracking-wider text-subtext-color hover:text-default-font"
    : "text-body font-body text-default-font hover:bg-neutral-100";
const linkTone = (isCurrent?: boolean) =>
  isCurrent
    ? "bg-brand-100 text-brand-800"
    : "text-default-font hover:bg-neutral-100";
---

<ul class={level === 0 ? "flex flex-col gap-1.5" : "flex flex-col gap-0.5"}>
  {nodes.map((node) =>
    node.children && node.children.length > 0 ? (
      <li>
        {/* Level-0 (super-categories) stay open so the sidebar always shows at
            least two levels — the categories and their sections. Deeper nodes
            open only along the branch leading to the current page. */}
        <details open={level === 0 || node.hasCurrent}>
          <summary class={`${summaryBase} ${summaryTone(level)}`} style={pad(level)}>
            <svg
              class="tree-chevron flex-none"
              width="11"
              height="11"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="3"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
            >
              <path d="M9 6l6 6-6 6" />
            </svg>
            <span class="truncate">{node.label}</span>
          </summary>
          <Astro.self nodes={node.children} base={base} level={level + 1} />
        </details>
      </li>
    ) : (
      <li>
        <a
          href={`${base}/docs/${node.href}`}
          aria-current={node.isCurrent ? "page" : undefined}
          class={`block rounded-md py-1 pr-2 text-body font-body capitalize ${linkTone(node.isCurrent)}`}
          style={pad(level + 0.9)}
        >
          {node.label}
        </a>
      </li>
    ),
  )}
</ul>

<style>
  .tree-summary {
    list-style: none;
  }
  .tree-summary::-webkit-details-marker {
    display: none;
  }
  .tree-chevron {
    transition: transform 0.15s ease;
    color: var(--color-subtext-color);
  }
  details[open] > .tree-summary .tree-chevron {
    transform: rotate(90deg);
  }
</style>
