package org.jetbrains.dokka.base.renderers.html import kotlinx.html.* import kotlinx.html.stream.createHTML import org.jetbrains.dokka.base.renderers.html.NavigationNodeIcon.CLASS import org.jetbrains.dokka.base.renderers.html.NavigationNodeIcon.CLASS_KT import org.jetbrains.dokka.base.renderers.pageId import org.jetbrains.dokka.base.templating.AddToNavigationCommand import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.WithChildren import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext class NavigationPage( val root: NavigationNode, val moduleName: String, val context: DokkaContext ) : RendererSpecificPage { override val name = "navigation" override val children = emptyList() override fun modified(name: String, children: List) = this override val strategy = RenderingStrategy { createHTML().visit(root, this) } private fun TagConsumer.visit(node: NavigationNode, renderer: HtmlRenderer): R = with(renderer) { if (context.configuration.delayTemplateSubstitution) { templateCommand(AddToNavigationCommand(moduleName)) { visit(node, "${moduleName}-nav-submenu", renderer) } } else { visit(node, "${moduleName}-nav-submenu", renderer) } } private fun TagConsumer.visit(node: NavigationNode, navId: String, renderer: HtmlRenderer): R = with(renderer) { div("sideMenuPart") { id = navId attributes["pageId"] = "${moduleName}::${node.pageId}" div("overview") { if (node.children.isNotEmpty()) { span("navButton") { onClick = """document.getElementById("$navId").classList.toggle("hidden");""" span("navButtonContent") } } buildLink(node.dri, node.sourceSets.toList()) { val withIcon = node.icon != null if (withIcon) { // in case link text is so long that it needs to have word breaks, // and it stretches to two or more lines, make sure the icon // is always on the left in the grid and is not wrapped with text span("nav-link-grid") { span("nav-link-child ${node.icon?.style()}") span("nav-link-child") { nodeText(node) } } } else { nodeText(node) } } } node.children.withIndex().forEach { (n, p) -> visit(p, "$navId-$n", renderer) } } } private fun FlowContent.nodeText(node: NavigationNode) { if (node.styles.contains(TextStyle.Strikethrough)) { strike { buildBreakableText(node.name) } } else { buildBreakableText(node.name) } } } data class NavigationNode( val name: String, val dri: DRI, val sourceSets: Set, val icon: NavigationNodeIcon?, val styles: Set