parley-cli 0.1.0-rc4

Terminal-first review tool for AI-generated code changes
Documentation
(() => {
  const {
    depthTwoHeadings,
    documentUrl,
    escapeHtml,
    headingCount,
    installThemeToggle,
    loadDocs,
    readTimeMinutes,
  } = window.ParleyDocs;

  function currentSlug() {
    const prefix = "/docs/";
    if (!location.pathname.startsWith(prefix)) {
      return "overview";
    }

    const rest = location.pathname
      .slice(prefix.length)
      .replace(/\/+$/, "")
      .replace(/\.html$/i, "");
    if (!rest || rest === "index") {
      return "overview";
    }
    return rest;
  }

  function renderNav(docs, activeSlug) {
    const nav = document.getElementById("docs-nav");
    nav.innerHTML = docs
      .map(
        (doc) => `
          <li>
            <a href="${documentUrl(doc.slug)}" class="${doc.slug === activeSlug ? "active" : ""}">
              <strong>${escapeHtml(doc.title)}</strong>
              <span>${escapeHtml(doc.summary || "Open document")}</span>
            </a>
          </li>
        `
      )
      .join("");
  }

  function renderToc(doc) {
    const toc = document.getElementById("toc-list");
    const headings = depthTwoHeadings(doc);
    if (headings.length === 0) {
      toc.innerHTML = `<li class="empty-state">No section anchors in this doc.</li>`;
      return;
    }

    toc.innerHTML = headings
      .map(
        (heading) => `
          <li>
            <a href="#${escapeHtml(heading.id)}">${escapeHtml(heading.text)}</a>
          </li>
        `
      )
      .join("");
  }

  function renderDocNav(docs, currentIndex) {
    const nav = document.getElementById("doc-nav-links");
    const section = document.getElementById("doc-nav-section");
    const links = [];
    const prev = docs[currentIndex - 1];
    const next = docs[currentIndex + 1];

    if (prev) {
      links.push(`
        <li>
          <a href="${documentUrl(prev.slug)}">
            <strong>Previous</strong>
            <span>${escapeHtml(prev.title)}</span>
          </a>
        </li>
      `);
    }

    if (next) {
      links.push(`
        <li>
          <a href="${documentUrl(next.slug)}">
            <strong>Next</strong>
            <span>${escapeHtml(next.title)}</span>
          </a>
        </li>
      `);
    }

    nav.innerHTML = links.join("");
    section.hidden = links.length === 0;
  }

  function renderDoc(doc) {
    const parsed = new DOMParser().parseFromString(doc.html, "text/html");
    const topHeading = parsed.body.querySelector("h1");

    if (topHeading && topHeading.textContent.trim() === doc.title) {
      topHeading.remove();
    }

    document.title = `${doc.title} | Parley Docs`;
    document.getElementById("page-kicker").textContent = documentUrl(doc.slug);
    document.getElementById("page-title").textContent = doc.slug;
    document.getElementById("page-intro").textContent =
      doc.summary || "Workflow details and commands for this part of Parley.";
    document.getElementById("doc-meta-row").innerHTML = `
      <span class="meta-pill">${headingCount(doc)} sections</span>
      <span class="meta-pill">${readTimeMinutes(doc)} min read</span>
    `;
    document.getElementById("doc-article").innerHTML = parsed.body.innerHTML;
  }

  function installHeadingAnchors() {
    const article = document.getElementById("doc-article");
    for (const heading of article.querySelectorAll("h2[id], h3[id]")) {
      const { id } = heading;
      heading.innerHTML = `
        <a class="heading-anchor" href="#${escapeHtml(id)}" title="Link to this section">
          ${heading.innerHTML}
        </a>
      `;
    }
  }

  function installSearch(docs) {
    const input = document.getElementById("search-input");
    input.addEventListener("input", () => {
      const query = input.value.trim().toLowerCase();
      const filtered = docs.filter((doc) => {
        const haystack = `${doc.title} ${doc.summary} ${doc.headings.map((entry) => entry.text).join(" ")}`.toLowerCase();
        return haystack.includes(query);
      });
      renderNav(filtered, currentSlug());
    });
  }

  function installMobileToggle() {
    const panel = document.getElementById("side-panel");
    const button = document.getElementById("nav-toggle");
    if (!panel || !button) {
      return;
    }

    button.addEventListener("click", () => {
      const collapsed = panel.dataset.collapsed === "true";
      panel.dataset.collapsed = collapsed ? "false" : "true";
      button.textContent = collapsed ? "Hide contents" : "Show contents";
    });
  }

  async function main() {
    installThemeToggle();
    installMobileToggle();

    const article = document.getElementById("doc-article");

    try {
      const docs = await loadDocs();
      const slug = currentSlug();
      const index = docs.findIndex((doc) => doc.slug === slug);
      const doc = docs[index] ?? docs[0];

      renderNav(docs, doc.slug);
      renderDoc(doc);
      installHeadingAnchors();
      renderToc(doc);
      renderDocNav(docs, Math.max(0, docs.indexOf(doc)));
      installSearch(docs);

      if (window.hljs) {
        for (const block of article.querySelectorAll("pre code")) {
          window.hljs.highlightElement(block);
        }
      }
    } catch (error) {
      article.innerHTML = `<div class="empty-state">Failed to load docs: ${escapeHtml(error.message)}</div>`;
    }
  }

  main();
})();