All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.dokka.base.renderers.html.NavigationPage.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package org.jetbrains.dokka.base.renderers.html

import kotlinx.html.*
import kotlinx.html.stream.createHTML
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

public class NavigationPage(
    public val root: NavigationNode,
    public val moduleName: String,
    public val context: DokkaContext
) : RendererSpecificPage {

    override val name: String = "navigation"

    override val children: List = emptyList()

    override fun modified(name: String, children: List): NavigationPage = this

    override val strategy: RenderingStrategy = 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,
        level: Int = 0
    ): R =
        with(renderer) {
            div("toc--part") {
                id = navId
                attributes["pageId"] = "${moduleName}::${node.pageId}"
                attributes["data-nesting-level"] = level.toString()
                div("toc--row") {
                    if (node.children.isNotEmpty()) {
                        button(classes = "toc--button") {
                            onClick = """document.getElementById("$navId").classList.toggle("toc--part_hidden");"""
                        }
                    }
                    buildLink(node.dri, node.sourceSets.toList()) {
                        [email protected]["class"] = "toc--link"
                        val withIcon = node.icon != null
                        if (withIcon) {
                            // in case a 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("toc--link-grid") {
                                span(node.icon?.style())
                                span {
                                    nodeText(node)
                                }
                            }
                        } else {
                            nodeText(node)
                        }
                    }
                }
                node.children.withIndex().forEach { (n, p) -> visit(p, "$navId-$n", renderer, level + 1) }
            }
        }

    private fun FlowContent.nodeText(node: NavigationNode) {
        if (node.styles.contains(TextStyle.Strikethrough)) {
            strike(classes = "strikethrough") {
                buildBreakableText(node.name)
            }
        } else {
            buildBreakableText(node.name)
        }
    }
}

public data class NavigationNode(
    val name: String,
    val dri: DRI,
    val sourceSets: Set,
    val icon: NavigationNodeIcon?,
    val styles: Set