diff options
Diffstat (limited to 'dokka-subprojects/plugin-versioning/src')
12 files changed, 739 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt new file mode 100644 index 00000000..7e03f59c --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.renderers.PostAction +import org.jetbrains.dokka.templates.TemplateProcessingStrategy +import org.jetbrains.dokka.templates.TemplatingPlugin +import java.io.File + +public class DefaultPreviousDocumentationCopyPostAction( + private val context: DokkaContext +) : PostAction { + private val versioningStorage by lazy { context.plugin<VersioningPlugin>().querySingle { versioningStorage } } + private val processingStrategies: List<TemplateProcessingStrategy> = + context.plugin<TemplatingPlugin>().query { templateProcessingStrategy } + + override fun invoke() { + versioningStorage.createVersionFile() + versioningStorage.previousVersions.forEach { (_, dirs) -> copyVersion(dirs.src, dirs.dst) } + } + + private fun copyVersion(versionRoot: File, targetParent: File) { + targetParent.apply { mkdirs() } + val ignoreDir = versionRoot.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR) + runBlocking(Dispatchers.Default) { + coroutineScope { + versionRoot.listFiles().orEmpty() + .filter { it.absolutePath != ignoreDir.absolutePath } + .forEach { versionRootContent -> + launch { + processRecursively(versionRootContent, targetParent) + } + } + } + } + } + + private fun processRecursively(versionRootContent: File, targetParent: File) { + if (versionRootContent.isDirectory) { + val target = targetParent.resolve(versionRootContent.name).also { it.mkdir() } + versionRootContent.listFiles()?.forEach { + processRecursively(it, target) + } + } else if (versionRootContent.extension == "html") processingStrategies.first { + it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null) + } else { + versionRootContent.copyTo(targetParent.resolve(versionRootContent.name), overwrite = true) + } + } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt new file mode 100644 index 00000000..b31afb9a --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import kotlinx.html.unsafe +import kotlinx.html.visit +import kotlinx.html.visitAndFinalize +import org.jetbrains.dokka.base.renderers.html.TemplateBlock +import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolutionTagConsumer +import org.jetbrains.dokka.base.renderers.html.templateCommandFor +import org.jetbrains.dokka.base.templating.Command +import org.jetbrains.dokka.base.templating.ImmediateHtmlCommandConsumer +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle + +public class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlCommandConsumer { + + private val versionsNavigationCreator = + context.plugin<VersioningPlugin>().querySingle { versionsNavigationCreator } + private val versioningStorage = + context.plugin<VersioningPlugin>().querySingle { versioningStorage } + + override fun canProcess(command: Command): Boolean = command is ReplaceVersionsCommand + + override fun <R> processCommand( + command: Command, + block: TemplateBlock, + tagConsumer: ImmediateResolutionTagConsumer<R> + ) { + command as ReplaceVersionsCommand + templateCommandFor(command, tagConsumer).visit { + unsafe { + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) + } + } + } + + override fun <R> processCommandAndFinalize( + command: Command, + block: TemplateBlock, + tagConsumer: ImmediateResolutionTagConsumer<R> + ): R { + command as ReplaceVersionsCommand + return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { + unsafe { + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) + } + } + } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt new file mode 100644 index 00000000..c9bc57b2 --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + + +import org.jetbrains.dokka.base.templating.Command +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.templates.CommandHandler +import org.jsoup.nodes.Element +import java.io.File + +public class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler { + + public val versionsNavigationCreator: VersionsNavigationCreator by lazy { + context.plugin<VersioningPlugin>().querySingle { versionsNavigationCreator } + } + + override fun canHandle(command: Command): Boolean = command is ReplaceVersionsCommand + + override fun handleCommandAsTag(command: Command, body: Element, input: File, output: File) { + body.empty() + body.append(versionsNavigationCreator(output)) + } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt new file mode 100644 index 00000000..91b1117d --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import org.jetbrains.dokka.plugability.ConfigurableBlock +import org.jetbrains.dokka.plugability.DokkaContext +import java.io.File + +public data class VersioningConfiguration( + var olderVersionsDir: File? = defaultOlderVersionsDir, + var olderVersions: List<File>? = defaultOlderVersions, + var versionsOrdering: List<String>? = defaultVersionsOrdering, + var version: String? = defaultVersion, + var renderVersionsNavigationOnAllPages: Boolean? = defaultRenderVersionsNavigationOnAllPages +) : ConfigurableBlock { + internal fun versionFromConfigurationOrModule(dokkaContext: DokkaContext): String = + version ?: dokkaContext.configuration.moduleVersion ?: "1.0" + + internal fun allOlderVersions(): List<File> { + if (olderVersionsDir != null) + assert(olderVersionsDir!!.isDirectory) { "Supplied previous version $olderVersionsDir is not a directory!" } + + return olderVersionsDir?.listFiles()?.toList().orEmpty() + olderVersions.orEmpty() + } + + public companion object { + public val defaultOlderVersionsDir: File? = null + public val defaultOlderVersions: List<File>? = null + public val defaultVersionsOrdering: List<String>? = null + public val defaultVersion: String? = null + public val defaultRenderVersionsNavigationOnAllPages: Boolean = true + + public const val OLDER_VERSIONS_DIR: String = "older" + public const val VERSIONS_FILE: String = "version.json" + } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt new file mode 100644 index 00000000..2e1fde8d --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import org.jetbrains.dokka.CoreExtensions.postActions +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.templating.ImmediateHtmlCommandConsumer +import org.jetbrains.dokka.plugability.* +import org.jetbrains.dokka.renderers.PostAction +import org.jetbrains.dokka.templates.CommandHandler +import org.jetbrains.dokka.templates.TemplatingPlugin +import org.jetbrains.dokka.transformers.pages.PageTransformer + +public class VersioningPlugin : DokkaPlugin() { + + public val versioningStorage: ExtensionPoint<VersioningStorage> by extensionPoint() + public val versionsNavigationCreator: ExtensionPoint<VersionsNavigationCreator> by extensionPoint() + public val versionsOrdering: ExtensionPoint<VersionsOrdering> by extensionPoint() + + private val dokkaBase by lazy { plugin<DokkaBase>() } + private val templatingPlugin by lazy { plugin<TemplatingPlugin>() } + + public val defaultVersioningStorage: Extension<VersioningStorage, *, *> by extending { + versioningStorage providing ::DefaultVersioningStorage + } + + public val defaultVersioningNavigationCreator: Extension<VersionsNavigationCreator, *, *> by extending { + versionsNavigationCreator providing ::HtmlVersionsNavigationCreator + } + + public val replaceVersionCommandHandler: Extension<CommandHandler, *, *> by extending { + templatingPlugin.directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler override templatingPlugin.replaceVersionCommandHandler + } + + public val resolveLinkConsumer: Extension<ImmediateHtmlCommandConsumer, *, *> by extending { + dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer override dokkaBase.replaceVersionConsumer + } + + public val cssStyleInstaller: Extension<PageTransformer, *, *> by extending { + dokkaBase.htmlPreprocessors providing ::MultiModuleStylesInstaller order { + after(dokkaBase.assetsInstaller) + before(dokkaBase.customResourceInstaller) + } + } + + public val notFoundPageInstaller: Extension<PageTransformer, *, *> by extending { + dokkaBase.htmlPreprocessors providing ::NotFoundPageInstaller order { + after(dokkaBase.assetsInstaller) + before(dokkaBase.customResourceInstaller) + } applyIf { !delayTemplateSubstitution } + } + + public val versionsDefaultOrdering: Extension<VersionsOrdering, *, *> by extending { + versionsOrdering providing { ctx -> + configuration<VersioningPlugin, VersioningConfiguration>(ctx)?.versionsOrdering?.let { + ByConfigurationVersionOrdering(ctx) + } ?: SemVerVersionOrdering() + } + } + + public val previousDocumentationCopyPostAction: Extension<PostAction, *, *> by extending { + postActions providing ::DefaultPreviousDocumentationCopyPostAction applyIf { !delayTemplateSubstitution } + } + + @OptIn(DokkaPluginApiPreview::class) + override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = + PluginApiPreviewAcknowledgement +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt new file mode 100644 index 00000000..7c9d1da0 --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration +import java.io.File + +public data class VersionDirs(val src: File, val dst: File) +public data class CurrentVersion(val name: String, val dir: File) + +public interface VersioningStorage { + public val previousVersions: Map<VersionId, VersionDirs> + public val currentVersion: CurrentVersion + + public fun createVersionFile() +} + +public typealias VersionId = String + +public class DefaultVersioningStorage( + public val context: DokkaContext +) : VersioningStorage { + + private val mapper = ObjectMapper() + private val configuration = configuration<VersioningPlugin, VersioningConfiguration>(context) + + override val previousVersions: Map<VersionId, VersionDirs> by lazy { + configuration?.let { versionsConfiguration -> + getPreviousVersions(versionsConfiguration.allOlderVersions(), context.configuration.outputDir) + } ?: emptyMap() + } + + override val currentVersion: CurrentVersion by lazy { + configuration?.let { versionsConfiguration -> + CurrentVersion(versionsConfiguration.versionFromConfigurationOrModule(context), + context.configuration.outputDir) + }?: CurrentVersion(context.configuration.moduleVersion.orEmpty(), context.configuration.outputDir) + } + + override fun createVersionFile() { + mapper.writeValue( + currentVersion.dir.resolve(VersioningConfiguration.VERSIONS_FILE), + Version(currentVersion.name) + ) + } + + private fun getPreviousVersions(olderVersions: List<File>, output: File): Map<String, VersionDirs> = + versionsFrom(olderVersions).associate { (key, srcDir) -> + key to VersionDirs(srcDir, output.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR).resolve(key)) + } + + private fun versionsFrom(olderVersions: List<File>) = + olderVersions.mapNotNull { versionDir -> + versionDir.listFiles { _, name -> name == VersioningConfiguration.VERSIONS_FILE }?.firstOrNull() + ?.let { file -> + val versionsContent = mapper.readValue<Version>(file) + Pair(versionsContent.version, versionDir) + }.also { + if (it == null) context.logger.warn("Failed to find versions file named ${VersioningConfiguration.VERSIONS_FILE} in $versionDir") + } + } + + private data class Version( + @JsonProperty("version") val version: String, + ) +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt new file mode 100644 index 00000000..59ce93e2 --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import kotlinx.html.a +import kotlinx.html.div +import kotlinx.html.stream.appendHTML +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.utilities.urlEncoded +import java.io.File + +public fun interface VersionsNavigationCreator { + public operator fun invoke(output: File): String +} + +public class HtmlVersionsNavigationCreator( + private val context: DokkaContext +) : VersionsNavigationCreator { + + private val versioningStorage by lazy { context.plugin<VersioningPlugin>().querySingle { versioningStorage } } + + private val versionsOrdering by lazy { context.plugin<VersioningPlugin>().querySingle { versionsOrdering } } + + private val isOnlyOnRootPage = + configuration<VersioningPlugin, VersioningConfiguration>(context)?.renderVersionsNavigationOnAllPages == false + + private val versions: Map<VersionId, File> by lazy { + versioningStorage.previousVersions.map { (k, v) -> k to v.dst }.toMap() + + (versioningStorage.currentVersion.name to versioningStorage.currentVersion.dir) + } + + override fun invoke(output: File): String { + if (versions.size == 1) { + return versioningStorage.currentVersion.name + } + val position = output.takeIf { it.isDirectory } ?: output.parentFile + if (isOnlyOnRootPage) { + getActiveVersion(position)?.takeIf { + it.value == versioningStorage.currentVersion.dir + && it.value != position + }?.also { return@invoke it.key } + } + return versions + .let { versions -> versionsOrdering.order(versions.keys.toList()).map { it to versions[it] } } + .takeIf { it.isNotEmpty() } + ?.let { orderedVersions -> + StringBuilder().appendHTML().div(classes = "versions-dropdown") { + val activeVersion = getActiveVersion(position) + val relativePosition: String = activeVersion?.value?.let { output.toRelativeString(it) } ?: "index.html" + div(classes = "versions-dropdown-button") { + activeVersion?.key?.let { text(it) } + } + div(classes = "versions-dropdown-data") { + orderedVersions.forEach { (version, path) -> + if (version == activeVersion?.key) { + a(href = output.name) { text(version) } + } else { + val isExistsFile = + if (version == versioningStorage.currentVersion.name) + path?.resolve(relativePosition)?.exists() == true + else + versioningStorage.previousVersions[version]?.src?.resolve(relativePosition) + ?.exists() == true + + val absolutePath = + if (isExistsFile) + path?.resolve(relativePosition) + else + versioningStorage.currentVersion.dir.resolve("not-found-version.html") + + a(href = absolutePath?.toRelativeString(position) + + if (!isExistsFile) "?v=" + version.urlEncoded() else "") { + text(version) + } + } + } + } + }.toString() + }.orEmpty() + } + + private fun getActiveVersion(position: File) = + versions.minByOrNull { (_, versionLocation) -> + versionLocation.let { position.toRelativeString(it).length } + } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt new file mode 100644 index 00000000..3d1fbe3d --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import org.apache.maven.artifact.versioning.ComparableVersion +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration + +public fun interface VersionsOrdering { + public fun order(records: List<VersionId>): List<VersionId> +} + +public class ByConfigurationVersionOrdering( + public val dokkaContext: DokkaContext +) : VersionsOrdering { + override fun order(records: List<VersionId>): List<VersionId> = + configuration<VersioningPlugin, VersioningConfiguration>(dokkaContext)?.versionsOrdering + ?: throw IllegalStateException("Attempted to use a configuration ordering without providing configuration") +} + +public class SemVerVersionOrdering : VersionsOrdering { + override fun order(records: List<VersionId>): List<VersionId> = + records.map { it to ComparableVersion(it) }.sortedByDescending { it.second }.map { it.first } +} diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt new file mode 100644 index 00000000..9bdaf7d5 --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.versioning + +import org.jetbrains.dokka.pages.RendererSpecificResourcePage +import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.pages.PageTransformer + +public class MultiModuleStylesInstaller( + private val dokkaContext: DokkaContext +) : PageTransformer { + private val stylesPages = listOf( + "styles/multimodule.css", + ) + + override fun invoke(input: RootPageNode): RootPageNode = + input.let { root -> + if (dokkaContext.configuration.delayTemplateSubstitution) root + else root.modified(children = input.children + stylesPages.toRenderSpecificResourcePage()) + }.transformContentPagesTree { + it.modified( + embeddedResources = it.embeddedResources + stylesPages + ) + } +} + +public class NotFoundPageInstaller( + private val dokkaContext: DokkaContext +) : PageTransformer { + private val notFoundPage = listOf( + "not-found-version.html", + ) + + override fun invoke(input: RootPageNode): RootPageNode = + input.let { root -> + if (dokkaContext.configuration.delayTemplateSubstitution) root + else root.modified(children = input.children + notFoundPage.toRenderSpecificResourcePage()) + } +} + +private fun List<String>.toRenderSpecificResourcePage(): List<RendererSpecificResourcePage> = + map { RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) } diff --git a/dokka-subprojects/plugin-versioning/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/dokka-subprojects/plugin-versioning/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..2afa663b --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1,5 @@ +# +# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. +# + +org.jetbrains.dokka.versioning.VersioningPlugin diff --git a/dokka-subprojects/plugin-versioning/src/main/resources/dokka/not-found-version.html b/dokka-subprojects/plugin-versioning/src/main/resources/dokka/not-found-version.html new file mode 100644 index 00000000..36cf343d --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/resources/dokka/not-found-version.html @@ -0,0 +1,193 @@ +<!-- + ~ Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + --> + +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>Unavailable page</title> + <style> +.article-content h1._big { + text-transform: uppercase; + color: #161616; + font-size: 54px; + font-weight: 800; + line-height: 45px; +} +.sub-title { + margin-bottom: 40px; + font-size: 20px; + font-weight: 400; + line-height: 30px; +} +.margin-top-vertical-unit-half { + margin-top: 25px; +} +.wt-row_size_m { + --wt-horizontal-layout-gutter: 16px; +} +.article-content { + color: #343434; + font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Droid Sans, Helvetica Neue, Arial, sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 25px; +} +.wt-container { + width: 100%; + margin-left: auto; + margin-right: auto; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding-left: 22px; + padding-right: 22px; + max-width: 1276px; +} +.wt-col-5 { + --wt-col-count: 5; +} +.wt-col-3 { + --wt-col-count: 3; +} +.page-404__logo { + position: relative; + display: flex; +} +.wt-row, .wt-row_wide { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +[class*="wt-col"] { + -ms-flex-preferred-size: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + flex-basis: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + max-width: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.wt-row_size_m { + --wt-horizontal-layout-gutter: 16px; +} +[class*="wt-col"], [class*="wt-col"].wt-row { + margin-right: var(--wt-horizontal-layout-gutter); + margin-left: var(--wt-horizontal-layout-gutter); +} +.wt-row_justify_center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.page-404__logo .sprite-img._404 { + position: absolute; + width: 100%; + height: 100%; +} +.page-404__logo::before { + float: left; + padding-bottom: 100%; + content: ""; +} +.page-404__beam { + position: absolute; + left: -50%; + top: -50%; + width: 587px; + height: 636px; + z-index: -1; +} +.heavy { + font-size: 14px; + font-weight: bold; +} + </style> +</head> +<body> +<script type="text/javascript"> +function getUrlParams(url) { + + var queryString = url ? url.split('?')[1] : window.location.search.slice(1); + var obj = {}; + + if (queryString) { + queryString = queryString.split('#')[0]; + + var arr = queryString.split('&'); + + for (var i = 0; i < arr.length; i++) { + var a = arr[i].split('='); + + var paramName = a[0]; + var paramValue = typeof (a[1]) === 'undefined' ? true : a[1]; + + paramName = paramName.toLowerCase(); + if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase(); + + if (!obj[paramName]) { + obj[paramName] = paramValue; + } + } + } + return obj; +} +window.onload = function() { + document.getElementById("version").textContent = getUrlParams()['v'] +} +</script> + +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + style="position: absolute; width: 0; height: 0" id="__SVG_SPRITE_NODE__"> + <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64" id="404"> + <g> + <rect y="0" width="64" height="64"></rect> + <rect x="5.9" y="52" fill="#fff" width="24" height="4"></rect> + <text x="5" y="20" fill="#fff" class="heavy">NOT</text> + <text x="5" y="35" fill="#fff" class="heavy">FOUND</text> + </g> + </symbol> + <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="183 -134 978 1061" + id="page-404-beam"> + <g style="opacity:0.49;"> + <path style="fill-opacity:0;stroke:#D9D9D9;stroke-dasharray:10,3;" + d="M1117.5,424.5l-535-476l87,449L1117.5,424.5z"></path> + <path style="fill-opacity:0;stroke:#E1E1E1;stroke-dasharray:10,3;" + d="M1118.3,465.9c-23.3,0-42.2-18.9-42.2-42.2 s18.9-42.2,42.2-42.2c23.3,0,42.2,18.9,42.2,42.2S1141.6,465.9,1118.3,465.9z M583.6,34.4c-46.3,0-83.9-37.6-83.9-83.9 s37.6-83.9,83.9-83.9s83.9,37.6,83.9,83.9S630,34.4,583.6,34.4z M536.2,841.7c0,46.8-37.9,84.8-84.7,84.8s-84.7-37.9-84.7-84.8 s37.9-84.8,84.7-84.8S536.2,794.9,536.2,841.7z M273.9,263.1c-49.9,0-90.4-40.5-90.4-90.4s40.5-90.4,90.4-90.4s90.4,40.5,90.4,90.4 S323.8,263.1,273.9,263.1z"></path> + <path style="fill:#FFFFFF;fill-opacity:0;stroke:#CCCCCC;stroke-linejoin:round;" + d="M1138.3,460.8L494,916l-0.4-0.7 c-12.4,7.1-26.8,11.2-42.2,11.2c-46.8,0-84.8-37.9-84.8-84.8c0-34.5,20.6-64.1,50.2-77.4l638.2-348l-470.3-382L417,173.1 l222.9,172.2c13.4,5.4,22.8,18.5,22.8,33.8c0,20.2-16.3,36.5-36.5,36.5c-9.8,0-18.6-3.8-25.2-10.1L242.9,257.6 c-2.2-0.8-4.3-1.7-6.3-2.6l-2-0.8l0-0.1c-30.2-14.6-51.1-45.6-51.1-81.4c0-28.6,13.3-54.1,34.1-70.7l0-0.3l321.1-222.2l0.2,0 c13-8.2,28.3-13,44.8-13c25.1,0,47.7,11.1,63,28.6l497.7,495.4c9.8,7.7,16.2,19.7,16.2,33.2 C1160.5,439.7,1151.5,453.7,1138.3,460.8z"></path> + <path style="fill-opacity:0;stroke:#D9D9D9;stroke-dasharray:10,3;" + d="M451.5,849.5l219-452l-398-223L451.5,849.5z"></path> + <g> + <path style="fill:#CDCDCD;" + d="M608.5,58.4l-5.7-5.1l-3.1,6.9l-0.7-0.6l3.1-6.9l-0.1-0.1l0.4-0.8l6.5,5.8L608.5,58.4z"></path> + <path style="fill:#CDCDCD;" + d="M353.8,220.4l3.1,6.9l-0.9,0.1l-3.1-6.9l-0.2,0l-0.4-0.8l8.6-1l0.4,0.8L353.8,220.4z"></path> + <path style="fill:#CDCDCD;" + d="M1041.4,418.5l-7.2,4.9l-0.7-0.5l6.3-4.3l-6-4.7l0.8-0.5l6,4.7l0.1-0.1L1041.4,418.5z"></path> + <path style="fill:#CDCDCD;" + d="M528.6,699.3l-6.9,3.1l0,0.2l-0.8,0.4l-1-8.6l0.8-0.4l0.8,7.6l6.9-3.1L528.6,699.3z"></path> + </g> + </g> + </symbol> +</svg> +<div class="wt-container article-content"> + <div class="wt-row wt-row_size_m wt-row_justify_center"> + <div class="wt-col-3"> + <div class="page-404__logo"> + <svg class="sprite-img _404"> + <use xlink:href="#404"></use> + </svg> + <svg class="page-404__beam"> + <use xlink:href="#page-404-beam"></use> + </svg> + </div> + </div> + <div class="wt-col-5"> + <h1 class="_big">uh-oh!</h1> + <div class="sub-title margin-top-vertical-unit-half">You are requesting a page that not + available in documentation version <span id="version"></span> + </div> + </div> + </div> +</div> +</body> +</html> diff --git a/dokka-subprojects/plugin-versioning/src/main/resources/dokka/styles/multimodule.css b/dokka-subprojects/plugin-versioning/src/main/resources/dokka/styles/multimodule.css new file mode 100644 index 00000000..91798c1d --- /dev/null +++ b/dokka-subprojects/plugin-versioning/src/main/resources/dokka/styles/multimodule.css @@ -0,0 +1,55 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +.versions-dropdown { + position: relative; +} + +.versions-dropdown-button { + display: flex; + border: none; + cursor: pointer; + padding: 5px; +} + +.versions-dropdown-button::after { + content: ''; + -webkit-mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask-size: auto; + -webkit-mask-size: cover; + mask-size: cover; + background-color: #fff; + display: inline-block; + transform: rotate(90deg); + width: 24px; + height: 16px; +} + +.versions-dropdown-data { + display: none; + position: absolute; + background-color: #27282c; + border: 1px solid hsla(0, 0%, 100%, .6); + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); + z-index: 1; + overflow-y: auto; + max-height: 200px; + min-width: 50px; +} + +.versions-dropdown-data > a { + display: block; + padding: 5px; + color: #fff; + text-decoration: none; +} + +.versions-dropdown-data > a:hover { + background-color: hsla(0,0%,100%,.1) +} + +.versions-dropdown:hover .versions-dropdown-data { + display: block; +} |