Skip to content

Commit 7aa04d8

Browse files
authored
Merge pull request #10776 from romanowski/scala3doc/snappier-navigation
Make navigation much snappier
2 parents 1ec8041 + f19dfca commit 7aa04d8

File tree

7 files changed

+119
-123
lines changed

7 files changed

+119
-123
lines changed

scala3doc/resources/dotty_res/scripts/fast-navigation-loader.js

Lines changed: 0 additions & 55 deletions
This file was deleted.

scala3doc/resources/dotty_res/scripts/ux.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ window.addEventListener("DOMContentLoaded", () => {
1515
}
1616
}
1717

18+
$("#sideMenu2 span").on('click', function(){
19+
$(this).parent().toggleClass("expanded")
20+
});
21+
1822

1923
if (location.hash) {
2024
var selected = document.getElementById(location.hash.substring(1));

scala3doc/resources/dotty_res/styles/scalastyle.css

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,6 @@ th {
123123
}
124124

125125
/* Left bar */
126-
#sideMenu {
127-
overflow-y: auto;
128-
scrollbar-width: thin;
129-
height: 100%;
130-
font-size: var(--leftbar-font-size);
131-
}
132126
#paneSearch {
133127
display: none;
134128
}
@@ -159,63 +153,88 @@ th {
159153
width: 116px;
160154
}
161155

162-
.sideMenuPart {
163-
padding-left: 1em;
156+
/* Navigation */
157+
#sideMenu2 {
158+
overflow-y: auto;
159+
scrollbar-width: thin;
160+
height: 100%;
161+
font-size: var(--leftbar-font-size);
162+
}
163+
164+
/* divs in sidebar represent entry and its children */
165+
#sideMenu2 div {
166+
padding-left: 0.7em;
167+
position: relative;
168+
display: none;
169+
}
170+
171+
#sideMenu2 div.expanded {
172+
display: block;
173+
}
174+
175+
/* hide children of hidden entries even if are expanded */
176+
#sideMenu2 div>div.expanded {
177+
display: none;
178+
}
179+
180+
/* show direct children of currently exmanded node*/
181+
#sideMenu2 div.expanded>div {
182+
display: block;
183+
}
184+
185+
/* always show top level entry*/
186+
#sideMenu2>div{
187+
display: block;
164188
}
165-
.sideMenuPart a {
189+
190+
/* 'a's in side menu represent text of entry with link */
191+
#sideMenu2 a {
166192
align-items: center;
167193
flex: 1;
168194
overflow-x: hidden;
169195
overflow-wrap: anywhere;
170196
color: var(--leftbar-fg);
171197
margin-right: .5rem;
172-
padding: 7px 0;
173-
}
174-
.sideMenuPart > .overview {
175-
display: flex;
176-
align-items: center;
177-
position: relative;
178-
user-select: none;
179-
}
180-
.sideMenuPart > .overview::before {
181-
width: var(--side-width);
182-
box-sizing: border-box;
183-
content: '';
184-
top: 0;
185-
right: 0;
186-
bottom: 0;
187-
position: absolute;
188-
z-index: 1;
189-
}
190-
.sideMenuPart > .overview:hover::before {
191-
background: var(--leftbar-hover-bg);
198+
padding-top: 3px;
199+
padding-bottom: 3px;
200+
margin-top: 1px;
201+
margin-bottom: 1px;
202+
width: 100%;
203+
display: block;
204+
/* This trick adds selected bachground stratching to the lef side of screen */
205+
margin-left: calc(0px - var(--side-width));
206+
padding-left: var(--side-width);
207+
width: calc(2 * var(--side-width));
192208
}
193-
.sideMenuPart > .overview:hover > a {
194-
color: var(--leftbar-hover-fg);
209+
210+
#sideMenu2 a::before {
211+
margin-left: -12em;
212+
width: 12em;
213+
background: red;
195214
}
196-
.sideMenuPart[data-active] > .overview::before {
215+
216+
#sideMenu2 a.selected {
197217
background: var(--leftbar-current-bg);
198-
}
199-
.sideMenuPart[data-active] > .overview > a {
200218
font-weight: bold;
201-
color: var(--leftbar-current-fg);
202219
}
203-
.sideMenuPart.hidden > .sideMenuPart {
204-
height: 0;
205-
visibility: hidden;
206-
}
207-
.overview a, .overview .navButton {
208-
z-index: 3;
220+
221+
#sideMenu2 a:hover {
222+
color: var(--leftbar-hover-fg);
223+
background: var(--leftbar-hover-bg);
209224
}
210-
.sideMenuPart .navButton {
225+
226+
/* spans represent a expand button */
227+
#sideMenu2 span {
211228
align-items: center;
212-
display: flex;
213-
justify-content: flex-end;
214-
padding: 7px 10px;
215229
cursor: pointer;
230+
position: absolute;
231+
right: 1em;
232+
top: 0px;
233+
padding: 4px;
216234
}
217-
.sideMenuPart .navButtonContent::before {
218-
content: "\e905"; /* arrow up */
235+
236+
#sideMenu2 span::before {
237+
content: "\e903"; /* arrow down */
219238
font-family: "dotty-icons" !important;
220239
font-size: 20px;
221240
line-height: var(--leftbar-font-size);
@@ -225,10 +244,11 @@ th {
225244
align-items: center;
226245
justify-content: center;
227246
}
228-
.sideMenuPart.hidden .navButtonContent::before {
229-
content: "\e903"; /* arrow down */
247+
#sideMenu2 .expanded>span::before {
248+
content: "\e905"; /* arrow up */
230249
}
231-
.sideMenuPart .navButton:hover .navButtonContent::before {
250+
251+
#sideMenu2 .div:hover>span::before {
232252
color: var(--leftbar-current-bg);
233253
}
234254

@@ -295,7 +315,7 @@ th {
295315
padding-top: 0;
296316
}
297317

298-
span[data-unresolved-link].strikethrough, a.strikethrough, div.strikethrough {
318+
span[data-unresolved-link].deprecated, a.deprecated, div.deprecated {
299319
text-decoration: line-through;
300320
}
301321
.brief {

scala3doc/src/dotty/dokka/DocContext.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ extension (r: report.type)
6969
def warn(m: String, f: File)(using CompilerContext): Unit =
7070
r.warning(createMessage(m, f, null), sourcePostionFor(f))
7171

72+
case class NavigationNode(name: String, dri: DRI, nested: Seq[NavigationNode])
7273

7374
case class DocContext(args: Scala3doc.Args, compilerContext: CompilerContext)
7475
extends DokkaConfiguration:
@@ -86,6 +87,9 @@ case class DocContext(args: Scala3doc.Args, compilerContext: CompilerContext)
8687

8788
lazy val displaySourceSets = getSourceSets.toDisplaySourceSet
8889

90+
// Nasty hack but will get rid of it once we migrate away from dokka renderer
91+
var navigationNode: Option[NavigationNode] = None
92+
8993
val logger = new Scala3DocDokkaLogger(using compilerContext)
9094

9195
lazy val staticSiteContext = args.docsRoot.map(path => StaticSiteContext(

scala3doc/src/dotty/dokka/preprocessors/ScalaEmbeddedResourceApppender.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ class ScalaEmbeddedResourceAppender extends PageTransformer {
3737
"scripts/components/Input.js",
3838
"scripts/components/FilterGroup.js",
3939
"scripts/components/Filter.js",
40-
"scripts/data.js",
41-
"scripts/fast-navigation-loader.js"
40+
"scripts/data.js"
4241
)).asJava,
4342
page.getChildren
4443
)
Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dotty.dokka
22
package site
33

4-
import org.jetbrains.dokka.base.renderers.html.{NavigationNode, NavigationPage}
54
import org.jetbrains.dokka.model.DPackage
65
import org.jetbrains.dokka.model.DModule
76
import org.jetbrains.dokka.pages._
@@ -11,7 +10,7 @@ import scala.collection.JavaConverters._
1110

1211
class NavigationCreator(using ctx: DocContext) extends PageTransformer:
1312

14-
private def processApiPages(pages: List[PageNode]): JList[NavigationNode] =
13+
private def processApiPages(pages: List[PageNode]): List[NavigationNode] =
1514
def flatMapPackages(pn: PageNode): List[NavigationNode] =
1615
def processChildren = pn.getChildren.asScala.flatMap(flatMapPackages).toList
1716
pn match
@@ -22,24 +21,21 @@ class NavigationCreator(using ctx: DocContext) extends PageTransformer:
2221
case p: DPackage if p.getName == "<empty>" && p.getChildren.isEmpty =>
2322
Nil
2423
case p: DPackage =>
25-
val ss = p.getSourceSets.asScala.toSet.toDisplay
26-
List(new NavigationNode(p.getName, p.getDri, ss, JList())) ++ processChildren
24+
List(new NavigationNode(p.getName, p.getDri, Nil)) ++ processChildren
2725
case _: DModule =>
2826
processChildren
2927
case _ =>
3028
Nil
3129
case _ =>
3230
Nil
3331

34-
pages.flatMap(flatMapPackages).sortBy(_.getName).asJava
32+
pages.flatMap(flatMapPackages).sortBy(_.name)
3533

3634
private def processStaticPages(input: PageNode)(staticSiteContext: StaticSiteContext) =
3735
def toNavigationNode(page: StaticPageNode): NavigationNode = NavigationNode(
3836
page.title(),
3937
page.getDri.asScala.head,
40-
ctx.displaySourceSets,
41-
page.getChildren.asScala
42-
.collect { case p: StaticPageNode => toNavigationNode(p)}.asJava
38+
page.getChildren.asScala.collect { case p: StaticPageNode => toNavigationNode(p) }.toList
4339
)
4440

4541
def singleContentPage(p: PageNode) =
@@ -49,10 +45,9 @@ class NavigationCreator(using ctx: DocContext) extends PageTransformer:
4945
if !pageRoot.getDri.contains(topLevelDri) then pageRoot
5046
else singleContentPage(pageRoot)
5147
val apiPages = docsRoot.getChildren.asScala.filterNot(_.isInstanceOf[StaticPageNode])
52-
val staticPages = staticSiteContext.mainPages.map(toNavigationNode).toList.asJava
48+
val staticPages = staticSiteContext.mainPages.map(toNavigationNode).toList
5349
val apiNodes = processApiPages(apiPages.toList)
54-
staticPages ++
55-
JList(new NavigationNode("API", apiPageDRI, ctx.displaySourceSets, apiNodes))
50+
staticPages ++ List(NavigationNode("API", apiPageDRI, apiNodes))
5651

5752
private def emptyNavigationJson =
5853
val strategy = new RenderingStrategy.Write("[]")
@@ -62,11 +57,11 @@ class NavigationCreator(using ctx: DocContext) extends PageTransformer:
6257
def defaultApiPages = processApiPages(input.getChildren.asScala.toList)
6358
val nodes = ctx.staticSiteContext.fold(defaultApiPages)(processStaticPages(input))
6459

65-
val navigationPage = new NavigationPage(new NavigationNode(
60+
summon[DocContext].navigationNode = Some(NavigationNode(
6661
ctx.args.name,
6762
ctx.staticSiteContext.fold(topLevelDri)(_ => docsRootDRI),
68-
ctx.displaySourceSets,
6963
nodes
7064
))
71-
val newChildren = input.getChildren ++ JList(emptyNavigationJson, navigationPage)
65+
66+
val newChildren = input.getChildren ++ JList(emptyNavigationJson)
7267
input.modified(input.getName, newChildren)

scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import org.jsoup.Jsoup
2929
import java.nio.file.Paths
3030

3131
class SignatureRenderer(pageContext: ContentPage, sourceSetRestriciton: JSet[DisplaySourceSet], locationProvider: LocationProvider):
32+
val currentDri = pageContext.getDri.asScala.head
33+
3234
def link(dri: DRI): Option[String] = Option(locationProvider.resolve(dri, sourceSetRestriciton, pageContext))
3335

3436
def renderLink(name: String, dri: DRI, modifiers: AppliedAttr*) =
@@ -117,6 +119,29 @@ class ScalaHtmlRenderer(using ctx: DokkaContext) extends HtmlRenderer(ctx) {
117119
val renderer = SignatureRenderer(pageContext, sourceSets, getLocationProvider)
118120
(renderer, new MemberRenderer(renderer, buildWithKotlinx(_, pageContext, null)))
119121

122+
private def buildNavigation(r: SignatureRenderer)(rootNav: NavigationNode): AppliedTag =
123+
val currentPageDri = r.currentDri
124+
125+
def renderNested(nav: NavigationNode): (Boolean, AppliedTag) =
126+
val isSelected = nav.dri == currentPageDri
127+
def linkHtml(exapnded: Boolean = false) =
128+
val attrs = if (isSelected) Seq(cls := "selected expanded") else Nil
129+
a(href := r.link(nav.dri).getOrElse("#"), attrs)(nav.name)
130+
131+
nav.nested match
132+
case Nil => isSelected -> div(linkHtml())
133+
case children =>
134+
val nested = children.map(renderNested)
135+
val expanded = nested.exists(_._1) | nav == rootNav
136+
val attr = if expanded || isSelected then Seq(cls := "expanded") else Nil
137+
(isSelected || expanded) -> div(attr)(
138+
linkHtml(expanded),
139+
span(),
140+
nested.map(_._2)
141+
)
142+
143+
renderNested(rootNav)._2
144+
120145
private def buildDocumentableList(n: DocumentableList, pageContext: ContentPage, sourceSetRestriciton: JSet[DisplaySourceSet]) =
121146
def render(n: ContentNode) = raw(buildWithKotlinx(n, pageContext, null))
122147

@@ -297,6 +322,8 @@ class ScalaHtmlRenderer(using ctx: DokkaContext) extends HtmlRenderer(ctx) {
297322
span(img(src := resolveRoot(page, s"project-logo/$fileName")))
298323
}.toSeq
299324

325+
val renderer = SignatureRenderer(page.asInstanceOf[ContentPage], sourceSets, getLocationProvider)
326+
300327
html(
301328
head(
302329
meta(charset := "utf-8"),
@@ -320,7 +347,9 @@ class ScalaHtmlRenderer(using ctx: DokkaContext) extends HtmlRenderer(ctx) {
320347
)
321348
),
322349
div(id := "paneSearch"),
323-
nav(id := "sideMenu"),
350+
nav(id := "sideMenu2")(
351+
summon[DocContext ].navigationNode.fold("No Navigation")(buildNavigation(renderer))
352+
),
324353
),
325354
div(id := "main")(
326355
div (id := "leftToggler")(

0 commit comments

Comments
 (0)