da335975e0d5712f47ee0d19b0eb5003d1a1b7f0 lrnassar Mon Apr 27 14:16:44 2026 -0700 Add sticky sidebar table of contents to /docs/ pages, ReadTheDocs-style. refs #36894 staticPage.lua: wrap doc body in a Bootstrap row with a col-md-2 sidebar holding a .docs-toc nav list and a col-md-10 content column. Collect both lev==1 and lev==2 headings into the TOC and emit id attributes on <h2> elements (replacing the prior inline <a name=> anchors). staticPage.html: add a small vanilla-JS scroll-spy that toggles .active on the TOC <li> matching the section currently scrolled past the top. No-ops on pages without #docs-toc. gbStatic.css: add styles for .docs-toc / .docs-toc-row (position: sticky, flex row for equal-height columns, link styling with active-state border). All rules are scoped to the .docs-toc class so non-docs pages sharing gbStatic.css are unaffected. diff --git docs/staticPage.lua docs/staticPage.lua index c14e6f33c1b..e0057e7df9c 100644 --- docs/staticPage.lua +++ docs/staticPage.lua @@ -124,37 +124,47 @@ add(" INSTRUCTIONS TO COMMIT THIS PAGE INTO git.") add(" Please read the file kent/src/product/Note-To-QA.txt for details.") add(" -->") add("<!--#set var=\"TITLE\" value=\"" .. metadata["title"] .. "\" -->") add("<!--#set var=\"ROOT\" value=\"" .. (variables["ROOT"] or metadata["ROOT"] or "..") .. "\" -->") add("") add("<!-- Relative paths to support mirror sites with non-standard GB docs install -->") add("<!--#include virtual=\"$ROOT/inc/gbPageStart.html\" -->") add("<link rel=\"stylesheet\" href=\"<!--#echo var=\"ROOT\" -->/style/bootstrap-3-3-7.min.css\">") add("") add("<h1>" .. metadata["title"] .. "</h1>") else add("<h1>No title defined in document, first line must be % mytitle </h1>") end + -- Sidebar TOC + body in Bootstrap grid + add('<div class="row docs-toc-row">') + add('<div class="col-md-2 hidden-sm hidden-xs">') + add('<nav class="docs-toc" id="docs-toc">') + add('<ul>') for i, h in ipairs(headers) do - idStr = simplifyId(h) - add("<h6><a href='#" .. idStr .. "'>" .. h .. "</a></h6>") + add("<li><a href='#" .. h.id .. "'>" .. h.text .. "</a></li>") end + add('</ul>') + add('</nav>') + add('</div>') + add('<div class="col-md-10">') -- ucsc change end add(body) + add('</div>') -- close col-md-9 + add('</div>') -- close row if #notes > 0 then add('<ol class="footnotes">') for _,note in pairs(notes) do add(note) end add('</ol>') end return table.concat(buffer,'\n') .. '\n' end -- The functions that follow render corresponding pandoc elements. -- s is always a string, attr is always a table of attributes, and -- items is always an array of strings (the items in a list). -- Comments indicate the types of other variables. @@ -281,36 +291,41 @@ return s end function Para(s) return "<p>\n" .. s .. "\n</p>" end -- lev is an integer, the header level. function Header(lev, s, attr) local lines = { } if lev == 1 then idStr = simplifyId(s) - table.insert(headers, s) + table.insert(headers, {text = s, id = idStr}) - table.insert(lines, "<a name='" .. idStr .. "'></a>") - table.insert(lines, "<h2>" .. s .. "</h2>") + table.insert(lines, "<h2 id='" .. idStr .. "'>" .. s .. "</h2>") headerOpen = true + elseif lev == 2 then + -- Collect lev==2 headers for TOC (markdown ## headings) + local idStr = attr.id or simplifyId(s) + table.insert(headers, {text = s, id = idStr}) + table.insert(lines, "<h" .. lev .. " id='" .. idStr .. "'" .. ">" .. s .. "</h" .. lev .. ">") + else table.insert(lines, "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">") end return table.concat(lines, "\n") end function BlockQuote(s) return "<blockquote>\n" .. s .. "\n</blockquote>" end function HorizontalRule() return "<hr/>" end