Skip to content

Commit

Permalink
Make logo replaceable #1339 (#1488)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcinAman authored Oct 7, 2020
1 parent de60193 commit e9f5da4
Show file tree
Hide file tree
Showing 45 changed files with 373 additions and 145 deletions.
17 changes: 13 additions & 4 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
implementation(kotlin("reflect"))
implementation("org.jsoup:jsoup:1.12.1")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.1")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.1")

val coroutines_version: String by project
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
Expand Down
15 changes: 14 additions & 1 deletion core/src/main/kotlin/configuration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

package org.jetbrains.dokka

import org.jetbrains.dokka.plugability.ConfigurableBlock
import org.jetbrains.dokka.utilities.parseJson
import org.jetbrains.dokka.utilities.toJsonString
import java.io.File
Expand Down Expand Up @@ -29,6 +30,7 @@ object DokkaDefaults {
const val sourceSetDisplayName = "JVM"
const val sourceSetName = "main"
val moduleVersion: String? = null
val pluginsConfiguration = mutableListOf<PluginConfigurationImpl>()
}

enum class Platform(val key: String) {
Expand Down Expand Up @@ -81,6 +83,7 @@ data class DokkaSourceSetID(
fun DokkaConfigurationImpl(json: String): DokkaConfigurationImpl = parseJson(json)

fun DokkaConfiguration.toJsonString(): String = toJsonString(this)
fun <T : ConfigurableBlock> T.toJsonString(): String = toJsonString(this)

interface DokkaConfiguration : Serializable {
val moduleName: String
Expand All @@ -92,7 +95,17 @@ interface DokkaConfiguration : Serializable {
val sourceSets: List<DokkaSourceSet>
val modules: List<DokkaModuleDescription>
val pluginsClasspath: List<File>
val pluginsConfiguration: Map<String, String>
val pluginsConfiguration: List<PluginConfiguration>

enum class SerializationFormat : Serializable {
JSON, XML
}

interface PluginConfiguration : Serializable {
val fqPluginName: String
val serializationFormat: SerializationFormat
val values: String
}

interface DokkaSourceSet : Serializable {
val sourceSetID: DokkaSourceSetID
Expand Down
8 changes: 7 additions & 1 deletion core/src/main/kotlin/defaultConfiguration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ data class DokkaConfigurationImpl(
override val offlineMode: Boolean = DokkaDefaults.offlineMode,
override val sourceSets: List<DokkaSourceSetImpl> = emptyList(),
override val pluginsClasspath: List<File> = emptyList(),
override val pluginsConfiguration: Map<String, String> = emptyMap(),
override val pluginsConfiguration: List<PluginConfigurationImpl> = DokkaDefaults.pluginsConfiguration,
override val modules: List<DokkaModuleDescriptionImpl> = emptyList(),
override val failOnWarning: Boolean = DokkaDefaults.failOnWarning
) : DokkaConfiguration

data class PluginConfigurationImpl(
override val fqPluginName: String,
override val serializationFormat: DokkaConfiguration.SerializationFormat,
override val values: String
) : DokkaConfiguration.PluginConfiguration


data class DokkaSourceSetImpl(
override val displayName: String = DokkaDefaults.sourceSetDisplayName,
Expand Down
42 changes: 18 additions & 24 deletions core/src/main/kotlin/plugability/DokkaPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.jetbrains.dokka.plugability

import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.module.kotlin.readValue
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.utilities.parseJson
import org.jetbrains.dokka.utilities.toJsonString
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
import kotlin.reflect.full.createInstance

abstract class DokkaPlugin {
private val extensionDelegates = mutableListOf<KProperty<*>>()
Expand Down Expand Up @@ -40,32 +41,21 @@ abstract class DokkaPlugin {
internal fun internalInstall(ctx: DokkaContextConfiguration, configuration: DokkaConfiguration) {
val extensionsToInstall = extensionDelegates.asSequence()
.filterIsInstance<KProperty1<DokkaPlugin, Extension<*, *, *>>>() // should be always true
.map { it.get(this) } + unsafePlugins.map{ it.value }
.map { it.get(this) } + unsafePlugins.map { it.value }
extensionsToInstall.forEach { if (configuration.(it.condition)()) ctx.installExtension(it) }
}

protected fun <T: Any> unsafeInstall(ext: Lazy<Extension<T, *, *>>){
unsafePlugins.add(ext)
protected fun <T : Any> unsafeInstall(ext: Lazy<Extension<T, *, *>>) {
unsafePlugins.add(ext)
}
}

interface WithUnsafeExtensionSuppression {
val extensionsSuppressed: List<Extension<*, *, *>>
}

interface Configurable {
val pluginsConfiguration: Map<String, String>
}

interface ConfigurableBlock

inline fun <reified P : DokkaPlugin, reified T : ConfigurableBlock> Configurable.pluginConfiguration(block: T.() -> Unit) {
val instance = T::class.createInstance().apply(block)

val mutablePluginsConfiguration = pluginsConfiguration as MutableMap<String, String>
mutablePluginsConfiguration[P::class.qualifiedName!!] = toJsonString(instance)
}

inline fun <reified P : DokkaPlugin, reified E : Any> P.query(extension: P.() -> ExtensionPoint<E>): List<E> =
context?.let { it[extension()] } ?: throwIllegalQuery()

Expand All @@ -75,11 +65,15 @@ inline fun <reified P : DokkaPlugin, reified E : Any> P.querySingle(extension: P
fun throwIllegalQuery(): Nothing =
throw IllegalStateException("Querying about plugins is only possible with dokka context initialised")

inline fun <reified T : DokkaPlugin, reified R : ConfigurableBlock> configuration(context: DokkaContext): ReadOnlyProperty<Any?, R> {
return ReadOnlyProperty { _, _ ->
val configuration = context.configuration.pluginsConfiguration[
T::class.qualifiedName ?: throw AssertionError("Plugin must be named class")
]
parseJson(checkNotNull(configuration))
}
}
inline fun <reified T : DokkaPlugin, reified R : ConfigurableBlock> configuration(context: DokkaContext): R? =
context.configuration.pluginsConfiguration.firstOrNull { it.fqPluginName == T::class.qualifiedName }
?.let { configuration ->
when (configuration.serializationFormat) {
DokkaConfiguration.SerializationFormat.JSON -> parseJson(configuration.values)
DokkaConfiguration.SerializationFormat.XML -> XmlMapper(JacksonXmlModule().apply {
setDefaultUseWrapper(
true
)
}).readValue<R>(configuration.values)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TestDokkaConfigurationBuilder {
var offlineMode: Boolean = false
var cacheRoot: String? = null
var pluginsClasspath: List<File> = emptyList()
var pluginsConfigurations: Map<String, String> = emptyMap()
var pluginsConfigurations: MutableList<PluginConfigurationImpl> = mutableListOf()
var failOnWarning: Boolean = false
private val lazySourceSets = mutableListOf<Lazy<DokkaSourceSetImpl>>()

Expand Down
29 changes: 29 additions & 0 deletions docs/src/doc/docs/user_guide/base-specific/frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Configuration specific to HTML format

## Modifying assets

It is possible to change static assets that are used to generate dokka's HTML.
Currently, user can modify:
* customAssets
* customStyleSheets

Every file provided in those values will be applied to **every** page.

Dokka uses 3 stylesheets:
* `style.css` - main css file responsible for styling the page
* `jetbrains-mono.css` - fonts used across dokka
* `logo-styles.css` - logo styling

User can choose to add or override those files.
Resources will be overridden when in `pluginConfiguration` block there is a resource with the same name.

### Examples
In order to override a logo and style it accordingly a simple css file named `logo-styles.css` is needed:
```css
#logo {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');
/* other styles required to make your page pretty */
}
```

For build system specific instructions please visit dedicated pages: [gradle](../gradle/usage.md#Applying plugins), [maven](../maven/usage.md#Applying plugins) and [cli](../cli/usage.md#Configuration options)
1 change: 1 addition & 0 deletions docs/src/doc/docs/user_guide/cli/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Dokka supports the following command line arguments:
* `-moduleName` - (required) - module name used as a part of source set ID when declaring dependent source sets
* `-cacheRoot` - cache directory to enable package-list caching
* `-pluginsClasspath` - artifacts with Dokka plugins, separated by `;`. At least `dokka-base` and all its dependencies must be added there
* `-pluginsConfiguration` - configuration for plugins in format fqPluginName=json^^fqPluginName=json...
* `-offlineMode` - do not resolve package-lists online
* `-failOnWarning` - throw an exception instead of a warning
* `-globalPackageOptions` - per package options added to all source sets
Expand Down
19 changes: 19 additions & 0 deletions docs/src/doc/docs/user_guide/gradle/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ dokkaHtml {
suppress.set(true)
}
}
// Configures a plugin separately from the global configuration
pluginConfiguration<PluginClass, ConfigurationClass>{
// values
}
}
}
```
Expand Down Expand Up @@ -249,6 +253,21 @@ To generate the documentation, use the appropriate `dokka${format}` Gradle task:
./gradlew dokkaHtml
```

Some plugins can be configured separately using a plugin class and configuration class. For example:

```kotlin
pluginConfiguration<DokkaBase, DokkaBaseConfiguration> {
customAssets = listOf(file("<path to asset>"))
customStyleSheets = listOf(file("<path to custom stylesheet>"))
}
```

Keep in mind, that this only works when using a buildscript (with the configured plugin on classpath) since it is not possible to import plugin's class without it.

If you don't want to use a buildscript or use Kotlin version lower than 1.3.50 you can achieve the same behaviour manually:
```kotlin
pluginsMapConfiguration.set(mapOf("<fully qualified plugin's name>" to """<json configuration>"""))
```
## Android

!!! important
Expand Down
23 changes: 23 additions & 0 deletions docs/src/doc/docs/user_guide/maven/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ The available configuration options are shown below:
<version>${dokka.version}</version>
</plugin>
</dokkaPlugins>

<!-- Configures a plugin separately -->
<pluginsConfiguration>
<fullyQualifiedPluginName>
<!-- Configuration -->
</fullyQualifiedPluginName>
</pluginsConfiguration>

</configuration>
</plugin>
```
Expand Down Expand Up @@ -192,6 +200,21 @@ You can add plugins inside the `dokkaPlugins` block:
</plugin>
```

Some plugins can be configured separately using plugin's fully qualified name. For example:

```xml
<pluginsConfiguration>
<org.jetbrains.dokka.base.DokkaBase>
<customStyleSheets>
<customStyleSheet><!-- path to custom stylesheet --></customStyleSheet>
</customStyleSheets>
<customAssets>
<customAsset><!-- path to custom asset --></customAsset>
</customAssets>
</org.jetbrains.dokka.base.DokkaBase>
</pluginsConfiguration>
```

## Example project

Please see the [Dokka Maven example project](https://github.com/JetBrains/kotlin-examples/tree/master/maven/dokka-maven-example) for an example.
2 changes: 2 additions & 0 deletions integration-tests/gradle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ dependencies {
}

tasks.integrationTest {
val dokka_version: String by project
environment("DOKKA_VERSION", dokka_version)
inputs.dir(file("projects"))
dependsOnMavenLocalPublication()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ dependencies {

dokkaHtml {
outputDirectory = new File(buildDir, "/dokka/customHtml")
pluginsConfiguration.put("pluginA", "configA")
failOnWarning = false
dokkaSourceSets {
customSourceSet {
Expand Down
9 changes: 9 additions & 0 deletions integration-tests/gradle/projects/it-basic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.dokka.gradle.kotlinSourceSet
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.DokkaBaseConfiguration
import java.net.URL

plugins {
kotlin("jvm")
id("org.jetbrains.dokka")
}

buildscript {
dependencies {
classpath("org.jetbrains.dokka:dokka-base:${System.getenv("DOKKA_VERSION")}")
}
}

version = "1.5-SNAPSHOT"

apply(from = "../template.root.gradle.kts")
Expand Down Expand Up @@ -40,4 +48,5 @@ tasks.withType<DokkaTask> {
kotlinSourceSet(kotlin.sourceSets["test"])
}
}
pluginsMapConfiguration.set(mapOf(DokkaBase::class.qualifiedName to """{ "customStyleSheets": ["${file("customResources/logo-styles.css")}", "${file("customResources/custom-style-to-add.css")}"], "customAssets" : ["${file("customResources/custom-resource.svg")}"] }"""))
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* custom stylesheet */
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#logo {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac
.forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }

File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
val customResourcesDir = File(templateProjectDir, "customResources")
if(customResourcesDir.exists() && customResourcesDir.isDirectory) customResourcesDir.copyRecursively(File(projectDir, "customResources"))
}

@Test
Expand Down Expand Up @@ -116,6 +118,17 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac
},
"Anchors should not have hashes inside"
)

assertEquals(
"""#logo{background-image:url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');}""",
stylesDir.resolve("logo-styles.css").readText().replace("\\s".toRegex(), ""),
)
assertTrue(stylesDir.resolve("custom-style-to-add.css").isFile)
assertEquals("""/* custom stylesheet */""", stylesDir.resolve("custom-style-to-add.css").readText())
allHtmlFiles().forEach { file ->
if(file.name != "navigation.html") assertTrue("custom-style-to-add.css" in file.readText(), "custom styles not added to html file ${file.name}")
}
assertTrue(imagesDir.resolve("custom-resource.svg").isFile)
}

private fun File.assertJavadocOutputDir() {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* custom stylesheet */
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#logo {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');
}
Loading

0 comments on commit e9f5da4

Please sign in to comment.