Skip to content

Add table of content to static sites #14607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions docs/_layouts/doc-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,5 @@ <h1>{{ page.title }}</h1>
{% endif %}
</header>
{{ content }}
<div class="content-contributors hidden">
<h5>Contributors to this page:</h5>
<div id="documentation-contributors" class="contributors-container"></div>
</div>
</main>

10 changes: 8 additions & 2 deletions docs/_layouts/static-site-main.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,20 @@
{{ content }}
<nav class="arrows-wrapper" aria-label="Page navigation">
{% if page.previous %}
<a rel="prev" href="{{ page.previous }}" class="arrows previous" aria-keyshortcuts="Left">
<a rel="prev" href="{{ page.previous.url }}" class="arrows previous" aria-keyshortcuts="Left">
<span>{{ page.previous.title }}</span>
<i class="fa fa-angle-left"></i>
</a>
{% endif %}
{% if page.next %}
<a rel="next" href="{{ page.next }}" class="arrows next" aria-keyshortcuts="Right">
<a rel="next" href="{{ page.next.url }}" class="arrows next" aria-keyshortcuts="Right">
<span>{{ page.next.title }}</span>
<i class="fa fa-angle-right"></i>
</a>
{% endif %}
</nav>
<div class="content-contributors hidden">
<span><b>Contributors to this page</b></span>
<div id="documentation-contributors" class="contributors-container"></div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@
{{ content }}
<nav class="arrows-wrapper" aria-label="Page navigation">
{% if page.previous %}
<a rel="prev" href="{{ page.previous }}" class="arrows previous" aria-keyshortcuts="Left">
<a rel="prev" href="{{ page.previous.url }}" class="arrows previous" aria-keyshortcuts="Left">
<span>{{ page.previous.title }}</span>
<i class="fa fa-angle-left"></i>
</a>
{% endif %}
{% if page.next %}
<a rel="next" href="{{ page.next }}" class="arrows next" aria-keyshortcuts="Right">
<a rel="next" href="{{ page.next.url }}" class="arrows next" aria-keyshortcuts="Right">
<span>{{ page.next.title }}</span>
<i class="fa fa-angle-right"></i>
</a>
{% endif %}
</nav>
<div class="content-contributors hidden">
<span><b>Contributors to this page</b></span>
<div id="documentation-contributors" class="contributors-container"></div>
</div>
</div>
3 changes: 3 additions & 0 deletions scaladoc-testcases/docs/_docs/docs/f5.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
10 changes: 8 additions & 2 deletions scaladoc-testcases/docs/_layouts/static-site-main.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@
{{ content }}
<nav class="arrows-wrapper" aria-label="Page navigation">
{% if page.previous %}
<a rel="prev" href="{{ page.previous }}" class="arrows previous" aria-keyshortcuts="Left">
<a rel="prev" href="{{ page.previous.url }}" class="arrows previous" aria-keyshortcuts="Left">
<span>{{ page.previous.title }}</span>
<i class="fa fa-angle-left"></i>
</a>
{% endif %}
{% if page.next %}
<a rel="next" href="{{ page.next }}" class="arrows next" aria-keyshortcuts="Right">
<a rel="next" href="{{ page.next.url }}" class="arrows next" aria-keyshortcuts="Right">
<span>{{ page.next.title }}</span>
<i class="fa fa-angle-right"></i>
</a>
{% endif %}
</nav>
<div class="content-contributors hidden">
<span><b>Contributors to this page</b></span>
<div id="documentation-contributors" class="contributors-container"></div>
</div>
</div>
1 change: 1 addition & 0 deletions scaladoc-testcases/docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ subsection:
- page: docs/f2.md
- page: docs/f3.md
- page: docs/f4.md
- page: docs/f5.html
16 changes: 16 additions & 0 deletions scaladoc/resources/dotty_res/scripts/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ window.addEventListener("DOMContentLoaded", () => {
$(this).parent().toggleClass("expanded")
});

const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const id = entry.target.getAttribute('id');
if (entry.intersectionRatio > 0) {
document.querySelector(`#toc li a[href="#${id}"]`).parentElement.classList.add('active');
} else {
document.querySelector(`#toc li a[href="#${id}"]`).parentElement.classList.remove('active');
}
});
});


document.querySelectorAll('#content section[id]').forEach((section) => {
observer.observe(section);
});

document.querySelectorAll("#sideMenu2 a").forEach(elem => elem.addEventListener('click', e => e.stopPropagation()))

$('.names .tab').on('click', function() {
Expand Down
88 changes: 72 additions & 16 deletions scaladoc/resources/dotty_res/styles/scalastyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

/* Layout Settings (changes on small screens) */
--side-width: 300px;
--toc-width: 300px;
--content-padding: 24px 42px;
--footer-height: 42px;
}
Expand Down Expand Up @@ -43,6 +44,7 @@ body, button, input {
#main-content {
min-height: calc(100vh - var(--footer-height) - 24px);
margin-left: var(--side-width);
margin-right: var(--toc-width);
padding: var(--content-padding);
padding-bottom: calc(24px + var(--footer-height));

Expand Down Expand Up @@ -905,6 +907,46 @@ footer .socials {
height: 8px;
}

#toc {
position: fixed;
right: 0px;
top: 0px;
width: var(--toc-width);
height: 100%;

padding-top: 15vh;
padding-right: 10px;

display: flex;
flex-direction: column;
}

#toc .toc-title {
font-weight: bold;
padding-left: 16px;
}

#toc ul {
list-style-type: none;
padding-left: 16px;
}

#toc a {
display: block;
padding-top: 0.5em;
padding-bottom: 0.5em;
color: var(--leftbar-fg);
transition-duration: 0.2s;
}

#toc li:hover > a {
color: var(--link-hover-fg);
}

#toc li.active > a {
color: var(--link-hover-fg);
}

/* Signature coloring */

:root {
Expand Down Expand Up @@ -941,6 +983,12 @@ footer .socials {
}
}
/* Landscape phones, portait tablets */
@media(max-width: 1200px) {
:root {
--toc-width: 0px;
}
}

@media(max-width: 768px) {
:root {
--content-padding: 12px 12px;
Expand Down Expand Up @@ -1070,43 +1118,51 @@ footer .socials {

/* Nav Icons */

.arrows-wrapper {
display: flex;
justify-content: space-between;
padding-top: 16px;
padding-bottom: 16px;
}

.arrows {
font-size: 3em;
color: var(--link-fg);
font-size: 1em;
text-align: center;

position: fixed;
top: 0;
bottom: 0;
margin: 0;
max-width: 150px;
min-width: 90px;

display: flex;
justify-content: center;
flex-direction: column;
align-items: center;

transition: color 0.5s, background-color 0.5s;
}

.arrows span {
max-width: 10vw;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.arrows i {
margin: 8px;
}

.arrows.previous, .arrows.next {
color: var(--grey400);
}

.arrows:hover {
text-decoration: none;
color: var(--grey300);
background-color: var(--grey900);
color: var(--link-hover-fg);
transition: background-color 0.15s, color 0.15s;
}

.previous {
left: var(--side-width);
float: left;
flex-direction: row-reverse;
}

.next {
right: 0;
float: right;
flex-direction: row;
}

@media screen and (max-width: 1000px) {
Expand Down
16 changes: 16 additions & 0 deletions scaladoc/src/dotty/tools/scaladoc/api.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dotty.tools.scaladoc

import dotty.tools.scaladoc.tasty.comments.Comment
import util.HTML.AppliedTag

enum Visibility(val name: String):
case Unrestricted extends Visibility("")
Expand Down Expand Up @@ -258,3 +259,18 @@ case class SnippetCompilerData(
imports: List[String],
position: SnippetCompilerData.Position
)

case class PageContent(content: AppliedTag, toc: Seq[TocEntry])

case class TocEntry(level: Int, content: String, anchor: String)

object TocEntry:
val tagLevels: Map[String, Int] = Map(
("h1" -> 1),
("h2" -> 2),
("h3" -> 3),
("h4" -> 4),
("h5" -> 5),
("h6" -> 6)
)
def apply(tag: String, content: String, anchor: String): TocEntry = TocEntry(tagLevels(tag), content, anchor)
30 changes: 26 additions & 4 deletions scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
html(
mkHead(page),
body(
if !page.hasFrame then renderContent(page)
if !page.hasFrame then renderContent(page).content
else mkFrame(page.link, parents, renderContent(page))
)
)
Expand Down Expand Up @@ -148,7 +148,23 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
)
}

private def mkFrame(link: Link, parents: Vector[Link], content: => AppliedTag): AppliedTag =
private def renderTableOfContents(toc: Seq[TocEntry]): Option[AppliedTag] =
def renderTocRec(level: Int, rest: Seq[TocEntry]): Seq[AppliedTag] =
rest match {
case Nil => Nil
case head :: tail if head.level == level =>
val (nested, rest) = tail.span(_.level > level)
val nestedList = if nested.nonEmpty then Seq(ul(renderTocRec(level + 1, nested))) else Nil
li(a(href := head.anchor)(head.content), nestedList) +: renderTocRec(level, rest)
case rest @ (head :: tail) if head.level > level =>
val (prefix, suffix) = rest.span(_.level > level)
li(ul(renderTocRec(level + 1, prefix))) +: renderTocRec(level, suffix)
}

renderTocRec(1, toc).headOption.map(toc => nav(cls := "toc-nav")(ul(cls := "toc-list")(toc)))


private def mkFrame(link: Link, parents: Vector[Link], content: => PageContent): AppliedTag =
val projectLogo =
args.projectLogo.map { path =>
val fileName = Paths.get(path).getFileName()
Expand Down Expand Up @@ -202,7 +218,7 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
div(id := "scaladoc-searchBar"),
main(id := "main-content")(
parentsHtml,
div(id := "content")(content),
div(id := "content")(content.content),
),
footer(
div(id := "generated-by")(
Expand Down Expand Up @@ -239,5 +255,11 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
)
)
)
)
),
renderTableOfContents(content.toc).fold(Nil) { toc =>
div(id := "toc")(
span(cls := "toc-title")("In this article"),
toc
)
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class MarkdownRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx
super.render()

override def pageContent(page: Page, parents: Vector[Link]): AppliedTag =
renderContent(page)
renderContent(page).content

private def renderResources(): Seq[String] =
allResources(Nil).flatMap(renderResource)
18 changes: 10 additions & 8 deletions scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
div(cls := "filterLowerContainer")()
)

def fullMember(m: Member): AppliedTag =
def fullMember(m: Member): PageContent =
val intro = m.kind match
case Kind.RootPackage =>Seq(h1(summon[DocContext].args.name))
case _ =>
Expand All @@ -401,11 +401,13 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
memberSignature(m)
)
)

div(
intro,
memberInfo(m, withBrief = false),
classLikeParts(m),
buildDocumentableFilter, // TODO Need to make it work in JS :(
buildMembers(m)
PageContent(
div(
intro,
memberInfo(m, withBrief = false),
classLikeParts(m),
buildDocumentableFilter, // TODO Need to make it work in JS :(
buildMembers(m)
),
Seq.empty // For now, we don't support table of contents in members
)
Loading