Avoid an unstyled rendering moment with the tables of contents

Tables of contents are now statically rendered in their appropriately
open/closed states, rather than updated via JavaScript, so they render
correctly on the first page load. In order to make the "page sections"
table still usable without JS, this adds a stylesheet in a <noscript>
tag that forces the sections into an open state.
This commit is contained in:
Natalie Weizenbaum 2019-04-12 00:01:56 -07:00
parent ce9244b504
commit e7ffef4fc9
7 changed files with 62 additions and 37 deletions

View File

@ -58,12 +58,11 @@ before_render do |body, page, _, template_class|
if current_page.data.table_of_contents && if current_page.data.table_of_contents &&
template_class == Middleman::Renderers::RedcarpetTemplate template_class == Middleman::Renderers::RedcarpetTemplate
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML_TOC.new) markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML_TOC.new)
toc = markdown.render(body).sub(/<ul( |>)/, '<ul class="table-of-contents"\1') fragment = Nokogiri::HTML::DocumentFragment.parse(markdown.render(body))
# The JS API's header names are uniquely large and difficult to break up # The JS API's header names are uniquely large and difficult to break up
# effectively. We do some post-processing to clean them up. # effectively. We do some post-processing to clean them up.
if page.start_with?("js-api.") if page.start_with?("js-api.")
fragment = Nokogiri::HTML::DocumentFragment.parse(toc)
fragment.css("a code").each do |code| fragment.css("a code").each do |code|
code.content = code.content. code.content = code.content.
gsub(/^types\.[A-Za-z]+\./, ''). gsub(/^types\.[A-Za-z]+\./, '').
@ -71,10 +70,18 @@ before_render do |body, page, _, template_class|
gsub(/^new types\./, 'new '). gsub(/^new types\./, 'new ').
gsub(/\(.+\)$/, '()') gsub(/\(.+\)$/, '()')
end end
toc = fragment.to_html
end end
current_page.add_metadata(table_of_contents: toc) # Modify the default Markdown table of contents to have overview links and
# section classes.
fragment.css("li > ul").each do |ul|
a = ul.parent.elements.first
a.add_class("section")
ul.elements.before('<li class="overview"><a>Overview</a></li>')
ul.elements.first.elements.first['href'] = a['href']
end
current_page.add_metadata(table_of_contents: fragment.to_html)
body body
end end
end end

View File

@ -52,21 +52,34 @@ module SassHelpers
end end
def documentation_toc def documentation_toc
_toc_level(data.documentation.toc) _toc_level(nil, data.documentation.toc)
end end
def _toc_level(links) def _toc_level(parent_href, links)
content_tag(:ul, links.map do |link| if parent_href
children = link[:children] overview = content_tag(:li,
text = link.keys.reject {|k| k == :children}.first content_tag(:a, "Overview", href: parent_href,
href = link[text] class: ("selected" if current_page.url == parent_href + ".html")),
class: "overview")
end
content_tag(:li, [ content_tag(:ul, [
content_tag(:a, text, href: href, overview,
class: ("open selected" if current_page.url.start_with?(href))), *links.map do |link|
(_toc_level(children) if children) children = link[:children]
].compact) text = link.keys.reject {|k| k == :children}.first
end) href = link[text]
content_tag(:li, [
content_tag(:a, text, href: href,
class: [
("section" if children),
("open selected" if current_page.url.start_with?(href))
].compact.join(" ")),
(_toc_level(href, children) if children)
].compact)
end
].compact)
end end
# Renders a code example. # Renders a code example.

View File

@ -51,14 +51,15 @@
width: 100%; width: 100%;
&:hover { background-color: $sl-color--dawn-pink; } &:hover { background-color: $sl-color--dawn-pink; }
&.overview { }
font-size: $sl-font-size--small;
&:not(.selected) { color: transparentize($sl-color--midnight-blue, 0.5); } li.overview a {
} font-size: $sl-font-size--small;
&:not(.selected) { color: transparentize($sl-color--midnight-blue, 0.5); }
} }
li a { li a {
&:not([href]) { &.section {
&::after { &::after {
content: ""; content: "";
float: right; float: right;
@ -77,7 +78,7 @@
&.selected { &.selected {
font-weight: bold; font-weight: bold;
&[href] { background-color: $sl-color--dawn-pink; } &:not(.section) { background-color: $sl-color--dawn-pink; }
} }
} }
} }

View File

@ -0,0 +1,10 @@
// Styles that are included only when JavaScript is disabled. These override the
// default styles to make them work better without JS.
// Make the in-page table of contents fully open by default, since we can't
// dynamically expand it.
.page-sections li a.section {
&::after { transform: rotate(90deg); }
+ ul {display: block; }
}

View File

@ -115,18 +115,11 @@ $(function() {
$(function() { $(function() {
$(".sl-c-list-navigation-wrapper--collapsible li > ul") $(".sl-c-list-navigation-wrapper--collapsible li > ul")
.parent().children("a").each(function() { .parent()
var overview = $('<li><a class="overview">Overview</a></li>\n'); .children("a")
var link = overview.children().first().attr("href", $(this).attr("href")); .removeAttr("href")
.click(function() {
if ($(this).hasClass("selected") && $(this).toggleClass("open");
link[0].pathname == window.location.pathname) { return false;
link.addClass("selected"); });
}
$(this).parent().children("ul").prepend(overview);
$(this).removeAttr("href");
}).click(function() {
$(this).toggleClass("open");
});
}); });

View File

@ -11,6 +11,7 @@
= stylesheet_link_tag 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css' = stylesheet_link_tag 'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css'
= stylesheet_link_tag 'sass' = stylesheet_link_tag 'sass'
= yield_content :css = yield_content :css
%noscript= stylesheet_link_tag 'noscript'
-# Old version of analytics (https://developers.google.com/analytics/devguides/collection/gajs/). -# Old version of analytics (https://developers.google.com/analytics/devguides/collection/gajs/).
:javascript :javascript

View File

@ -8,5 +8,5 @@
- content_for :complementary do - content_for :complementary do
%h3 Page Sections %h3 Page Sections
%nav.sl-c-list-navigation-wrapper.sl-c-list-navigation-wrapper--collapsible %nav.page-sections.sl-c-list-navigation-wrapper.sl-c-list-navigation-wrapper--collapsible
= current_page.metadata[:table_of_contents] = current_page.metadata[:table_of_contents]