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

There is a newer version: 2.0.0
Show 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.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

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): 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(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