diff --git a/build.gradle.kts b/build.gradle.kts index 960d8808e..3f7c1afb8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,69 +1,5 @@ -import org.jetbrains.dokka.gradle.DokkaTask -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile -import java.io.ByteArrayOutputStream - plugins { - kotlin("multiplatform").version(libs.versions.kotlin).apply(false) - alias(libs.plugins.dokka).apply(false) - alias(libs.plugins.publish).apply(false) - alias(libs.plugins.kotlinApiDump) -} - -val VERSION_NAME: String by project - - -fun getPublishVersion(): String { - // Call gradle with -PinferVersion to set the dynamic version name. - // Otherwise, we skip it to save time. - if (!project.hasProperty("inferVersion")) return VERSION_NAME - - val stdout = ByteArrayOutputStream() - project.exec { - commandLine = listOf("git", "tag", "--points-at", "master") - standardOutput = stdout - } - val tag = String(stdout.toByteArray()).trim() - if (tag.isNotEmpty()) return tag - - val buildNumber = System.getenv("GITHUB_RUN_NUMBER") ?: "0" - return "$VERSION_NAME.$buildNumber-SNAPSHOT" -} - - - -subprojects { - project.setProperty("VERSION_NAME", getPublishVersion()) - - if (name != "graalvm") { - tasks.withType().configureEach { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) - } - } - tasks.withType().configureEach { - options.release.set(8) - } - } - - pluginManager.withPlugin("com.vanniktech.maven.publish") { - apply(plugin = "org.jetbrains.dokka") - - tasks.named("dokkaHtml") { - outputDirectory.set(rootProject.rootDir.resolve("docs/api")) - pluginsMapConfiguration.set( - mapOf( - "org.jetbrains.dokka.base.DokkaBase" to """{ - "footerMessage": "Copyright © 2017 AJ Alt" - }""" - ) - ) - dokkaSourceSets.configureEach { - reportUndocumented.set(false) - skipDeprecated.set(true) - } - } - } + alias(libs.plugins.kotlinBinaryCompatibilityValidator) } apiValidation { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..e481ef4a1 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() + gradlePluginPortal() +} + +dependencies { + implementation(libs.kotlin.gradle.plugin) + implementation(libs.publish) + implementation(libs.dokka) +} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 000000000..62991c1ef --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,9 @@ +rootProject.name = "buildSrc" + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/buildSrc/src/main/kotlin/mordant-js-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-js-conventions.gradle.kts new file mode 100644 index 000000000..a2b661bce --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-js-conventions.gradle.kts @@ -0,0 +1,11 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + js { + // We have different code paths on browsers and node, so we run tests on both + nodejs() + browser() + } +} diff --git a/buildSrc/src/main/kotlin/mordant-jvm-sample-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-jvm-sample-conventions.gradle.kts new file mode 100644 index 000000000..4543d5949 --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-jvm-sample-conventions.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id("mordant-kotlin-conventions") + application +} + +kotlin { + // For some reason MainKt isn't present in the jar unless we add withJava + jvm { withJava() } + + sourceSets { + val jvmMain by getting { + dependencies { + implementation(project(":mordant")) + } + } + } +} + +application { + mainClass.set("com.github.ajalt.mordant.samples.MainKt") + applicationDefaultJvmArgs = listOf("-Dfile.encoding=utf-8") +} diff --git a/buildSrc/src/main/kotlin/mordant-kotlin-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-kotlin-conventions.gradle.kts new file mode 100644 index 000000000..3c581effc --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-kotlin-conventions.gradle.kts @@ -0,0 +1,17 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile + +plugins { + kotlin("multiplatform") +} + +tasks.withType().configureEach { + kotlinOptions { + freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" + } + compilerOptions.jvmTarget.set(JvmTarget.JVM_1_8) +} + +tasks.withType().configureEach { + options.release.set(8) +} diff --git a/buildSrc/src/main/kotlin/mordant-mpp-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-mpp-conventions.gradle.kts new file mode 100644 index 000000000..b1e206bc7 --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-mpp-conventions.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("mordant-kotlin-conventions") + id("mordant-js-conventions") + id("mordant-native-conventions") +} + +kotlin { + jvm() +} diff --git a/buildSrc/src/main/kotlin/mordant-mpp-sample-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-mpp-sample-conventions.gradle.kts new file mode 100644 index 000000000..8f3c914d1 --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-mpp-sample-conventions.gradle.kts @@ -0,0 +1,4 @@ +plugins { + id("mordant-jvm-sample-conventions") + id("mordant-native-sample-conventions") +} diff --git a/buildSrc/src/main/kotlin/mordant-native-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-native-conventions.gradle.kts new file mode 100644 index 000000000..787e6ae7a --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-native-conventions.gradle.kts @@ -0,0 +1,18 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + macosX64() + macosArm64() + linuxX64() + mingwX64() + + applyDefaultHierarchyTemplate() + + sourceSets { + val posixMain by creating { dependsOn(nativeMain.get()) } + linuxMain.get().dependsOn(posixMain) + macosMain.get().dependsOn(posixMain) + } +} diff --git a/buildSrc/src/main/kotlin/mordant-native-sample-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-native-sample-conventions.gradle.kts new file mode 100644 index 000000000..2ba3697f3 --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-native-sample-conventions.gradle.kts @@ -0,0 +1,11 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + +plugins { + id("mordant-native-conventions") +} + +kotlin.targets.filterIsInstance().forEach { target -> + target.binaries.executable { + entryPoint = "com.github.ajalt.mordant.samples.main" + } +} diff --git a/buildSrc/src/main/kotlin/mordant-publishing-conventions.gradle.kts b/buildSrc/src/main/kotlin/mordant-publishing-conventions.gradle.kts new file mode 100644 index 000000000..63f90caec --- /dev/null +++ b/buildSrc/src/main/kotlin/mordant-publishing-conventions.gradle.kts @@ -0,0 +1,46 @@ +@file:Suppress("PropertyName") + +import org.jetbrains.dokka.gradle.DokkaTask +import org.gradle.kotlin.dsl.provideDelegate +import java.io.ByteArrayOutputStream + +plugins { + id("com.vanniktech.maven.publish") + id("org.jetbrains.dokka") +} + +val VERSION_NAME: String by project + +fun getPublishVersion(): String { + // Call gradle with -PinferVersion to set the dynamic version name. + // Otherwise, we skip it to save time. + if (!project.hasProperty("inferVersion")) return VERSION_NAME + + val stdout = ByteArrayOutputStream() + project.exec { + commandLine = listOf("git", "tag", "--points-at", "master") + standardOutput = stdout + } + val tag = String(stdout.toByteArray()).trim() + if (tag.isNotEmpty()) return tag + + val buildNumber = System.getenv("GITHUB_RUN_NUMBER") ?: "0" + return "$VERSION_NAME.$buildNumber-SNAPSHOT" +} + +project.setProperty("VERSION_NAME", getPublishVersion()) + +tasks.named("dokkaHtml") { + outputDirectory.set(rootProject.rootDir.resolve("docs/api")) + pluginsMapConfiguration.set( + mapOf( + "org.jetbrains.dokka.base.DokkaBase" to """{ + "footerMessage": "Copyright © 2017 AJ Alt" + }""" + ) + ) + dokkaSourceSets.configureEach { + reportUndocumented.set(false) + skipDeprecated.set(true) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 976b1ae40..729eb70e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,12 +10,15 @@ jna-core = "net.java.dev.jna:jna:5.13.0" graalvm-svm = "org.graalvm.nativeimage:svm:23.1.0" # used in tests -kotest = "io.kotest:kotest-assertions-core:5.7.2" +kotest = "io.kotest:kotest-assertions-core:5.7.2" systemrules = "com.github.stefanbirkner:system-rules:1.19.0" r8 = "com.android.tools:r8:8.1.56" +# build logic +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version="1.9.10"} +publish = { module = "com.vanniktech:gradle-maven-publish-plugin", version="0.25.3"} + [plugins] -dokka = "org.jetbrains.dokka:1.9.10" -publish = "com.vanniktech.maven.publish:0.25.3" graalvm-nativeimage = "org.graalvm.buildtools.native:0.9.27" -kotlinApiDump = "org.jetbrains.kotlinx.binary-compatibility-validator:0.13.2" +kotlinBinaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:0.13.2" diff --git a/mordant/build.gradle.kts b/mordant/build.gradle.kts index c6fad1f1c..42002dccf 100644 --- a/mordant/build.gradle.kts +++ b/mordant/build.gradle.kts @@ -1,22 +1,9 @@ plugins { - kotlin("multiplatform") - alias(libs.plugins.publish) + id("mordant-mpp-conventions") + id("mordant-publishing-conventions") } kotlin { - jvm() - js(IR) { - nodejs() - browser() - } - - macosX64() - macosArm64() - linuxX64() - mingwX64() - - applyDefaultHierarchyTemplate() - sourceSets { val commonMain by getting { dependencies { @@ -43,9 +30,5 @@ kotlin { api(libs.systemrules) } } - - val posixMain by creating { dependsOn(nativeMain.get()) } - linuxMain.get().dependsOn(posixMain) - macosMain.get().dependsOn(posixMain) } } diff --git a/samples/build.gradle.kts b/samples/build.gradle.kts deleted file mode 100644 index 630ce6d01..000000000 --- a/samples/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -subprojects { - tasks.withType().configureEach { - kotlinOptions { - freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" - } - } -} diff --git a/samples/detection/build.gradle.kts b/samples/detection/build.gradle.kts index 7249f2457..b4788949b 100644 --- a/samples/detection/build.gradle.kts +++ b/samples/detection/build.gradle.kts @@ -1,35 +1,3 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - plugins { - kotlin("multiplatform") - application -} - -kotlin { - jvm { - withJava() - } - - macosX64() - linuxX64() - mingwX64() - - targets.filterIsInstance().forEach { target -> - target.binaries.executable { - entryPoint = "com.github.ajalt.mordant.samples.main" - } - } - - sourceSets { - val commonMain by getting { - dependencies { - implementation(project(":mordant")) - } - } - } -} - -application { - mainClass.set("com.github.ajalt.mordant.samples.MainKt") - applicationDefaultJvmArgs = listOf("-Dfile.encoding=utf-8") + id("mordant-mpp-sample-conventions") } diff --git a/samples/markdown/build.gradle.kts b/samples/markdown/build.gradle.kts index 3f423d4b4..b4788949b 100644 --- a/samples/markdown/build.gradle.kts +++ b/samples/markdown/build.gradle.kts @@ -1,14 +1,3 @@ plugins { - application - kotlin("jvm") -} - -application { - mainClass.set("com.github.ajalt.mordant.samples.MainKt") - applicationDefaultJvmArgs = listOf("-Dfile.encoding=utf-8") -} - -dependencies { - api(kotlin("stdlib")) - api(project(":mordant")) + id("mordant-mpp-sample-conventions") } diff --git a/samples/markdown/src/main/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/markdown/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt similarity index 100% rename from samples/markdown/src/main/kotlin/com/github/ajalt/mordant/samples/main.kt rename to samples/markdown/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt diff --git a/samples/progress/build.gradle.kts b/samples/progress/build.gradle.kts index 23411f1d5..8e682dfef 100644 --- a/samples/progress/build.gradle.kts +++ b/samples/progress/build.gradle.kts @@ -1,15 +1,3 @@ plugins { - application - kotlin("jvm") + id("mordant-jvm-sample-conventions") } - -application { - mainClass.set("com.github.ajalt.mordant.samples.MainKt") - applicationDefaultJvmArgs = listOf("-Dfile.encoding=utf-8") -} - -dependencies { - api(kotlin("stdlib")) - api(project(":mordant")) -} - diff --git a/samples/progress/src/main/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/progress/src/jvmMain/kotlin/com/github/ajalt/mordant/samples/main.kt similarity index 100% rename from samples/progress/src/main/kotlin/com/github/ajalt/mordant/samples/main.kt rename to samples/progress/src/jvmMain/kotlin/com/github/ajalt/mordant/samples/main.kt diff --git a/samples/table/build.gradle.kts b/samples/table/build.gradle.kts index 7249f2457..b4788949b 100644 --- a/samples/table/build.gradle.kts +++ b/samples/table/build.gradle.kts @@ -1,35 +1,3 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - plugins { - kotlin("multiplatform") - application -} - -kotlin { - jvm { - withJava() - } - - macosX64() - linuxX64() - mingwX64() - - targets.filterIsInstance().forEach { target -> - target.binaries.executable { - entryPoint = "com.github.ajalt.mordant.samples.main" - } - } - - sourceSets { - val commonMain by getting { - dependencies { - implementation(project(":mordant")) - } - } - } -} - -application { - mainClass.set("com.github.ajalt.mordant.samples.MainKt") - applicationDefaultJvmArgs = listOf("-Dfile.encoding=utf-8") + id("mordant-mpp-sample-conventions") } diff --git a/samples/tour/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/tour/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt new file mode 100644 index 000000000..b8c154864 --- /dev/null +++ b/samples/tour/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt @@ -0,0 +1,199 @@ +package com.github.ajalt.mordant.samples + +import com.github.ajalt.colormath.model.Oklab +import com.github.ajalt.colormath.model.RGB +import com.github.ajalt.colormath.model.SRGB +import com.github.ajalt.colormath.transform.interpolator +import com.github.ajalt.colormath.transform.sequence +import com.github.ajalt.mordant.markdown.Markdown +import com.github.ajalt.mordant.rendering.* +import com.github.ajalt.mordant.rendering.TextColors.Companion.rgb +import com.github.ajalt.mordant.rendering.TextColors.brightRed +import com.github.ajalt.mordant.rendering.TextStyles.* +import com.github.ajalt.mordant.rendering.TextStyles.Companion.hyperlink +import com.github.ajalt.mordant.table.Borders +import com.github.ajalt.mordant.table.ColumnWidth +import com.github.ajalt.mordant.table.horizontalLayout +import com.github.ajalt.mordant.table.table +import com.github.ajalt.mordant.terminal.Terminal +import com.github.ajalt.mordant.widgets.* + +private val shadowColor = rgb("#24218c") + +private val green = rgb("#2fb479") +private val blue = rgb("#2f61b4") +private val magenta = rgb("#b02fb4") +private val orange = rgb("#b4832f") + +fun main() { + val terminal = Terminal(theme = Theme { + styles["hr.rule"] = shadowColor + styles["panel.border"] = shadowColor + }) + + val layout = table { + borderType = BorderType.BLANK + column(0) { width = ColumnWidth.Fixed(55) } + body { + row { + cell(titleExample()) { + columnSpan = 2 + align = TextAlign.CENTER + } + } + row { + cell( + Panel( + featuresExample().withPadding { horizontal = 2; vertical = 1 }, + Text(brightRed("Colorful styling for command-line applications")), + expand = true + ) + ) { columnSpan = 2 } + } + row { + cell( + Panel( + tableExample().withPadding { vertical = 1; horizontal = 2 }, + Text(brightRed("Tables")), + expand = true + ) + ) { rowSpan = 2 } + cell( + Panel( + cjkExample(), + brightRed("Asian Languages and Emoji"), + expand = true + ), + ) + } + row { + cell( + Panel( + progressExample().withPadding(1), + Text(brightRed("Animations and Progress Bars")), + expand = true + ), + ) + } + row { + cell( + Panel( + markdownExample().withPadding { vertical = 1; left = 4 }, + Text(brightRed("Render Markdown directly in your terminal")), + expand = true + ) + ) { columnSpan = 2 } + } + } + } + + terminal.println("\n\n") + terminal.println(layout) + +} + +private fun featuresExample() = UnorderedList( + orange("Color text with themed ANSI colors or full RGB values"), + magenta( + "Add styles like ${italic("italic")}, " + + "${(blue + hyperlink("www.example.com"))("hyperlinks")}, " + + "and ${strikethrough("strikethrough")} " + ), + green( + "Colors are automatically downsampled to what your terminal supports" + ) +) + +private fun cjkExample(): String { + return """ + | + | πŸš€δ½ ε₯½δΈ–η•Œ + | πŸ™Œγ“γ‚“γ«γ‘γ―δΈ–η•Œ + | πŸ‘μ•ˆλ…•ν•˜μ„Έμš” 세계 + | + """.trimMargin() +} + +private fun progressExample() = progressLayout { + padding = 1 + text("file.iso") + progressBar() + speed("B/s") + timeRemaining() +}.build(25000000000, 30000000000, 351.0) + + +private const val rightArrow = """ + β”‚β•² + β•­β”€β”€β”€β”˜ β•² + ╰───┐ β•± + β”‚β•± +""" + +private val markdown = """ +# Markdown + +- Supports all of GFM markdown +- Including lists and `inline` *styles* + +| Tables | Work | Too | +|--------|:----:|----:| +| 1 | 2 | 3 | +""".trim() + +private fun markdownExample() = horizontalLayout { + column(0) { width = ColumnWidth.Auto } + column(1) { width = ColumnWidth.Auto } + column(2) { width = ColumnWidth.Fixed(50) } + cell(Panel(Text(dim(markdown)).withPadding(2))) + cell(brightRed(rightArrow)) { verticalAlign = VerticalAlign.MIDDLE } + cell(Panel(Markdown(markdown).withPadding { + vertical = 1; horizontal = 2 + })) +} + + +private fun tableExample() = table { + borderType = BorderType.SQUARE_DOUBLE_SECTION_SEPARATOR + tableBorders = Borders.NONE + borderStyle = rgb("#4b25b9") + column(0) { style = green } + column(1) { style = blue } + column(2) { style = magenta } + column(3) { style = orange } + + header { + style = italic + bold + row("Airport", "Location", "Code", "Passengers") + } + body { + rowStyles(TextStyle(), dim.style) + row("Hartsfield–Jackson", "Georgia", "ATL", "93,699,630") + row("Dallas/Fort Worth", "Texas", "DFW", "73,362,946") + row("Denver", "Colorado", "DEN", "69,286,461") + row("O'Hare", "Illinois", "ORD", "68,340,619") + } +} + +private fun titleExample(): String { + val title = """ +β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— +β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β• +β–ˆβ–ˆβ•”β–ˆβ–ˆβ–ˆβ–ˆβ•”β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ +β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ +β–ˆβ–ˆβ•‘ β•šβ•β• β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ +β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β• β•šβ•β• +""".trim('\n') + return buildString { + for (line in title.lineSequence()) { + val lerp = Oklab.interpolator { + stop(SRGB("#e74856")) + stop(SRGB("#9648e7")) + }.sequence(line.length) + line.asSequence().zip(lerp).forEach { (c, color) -> + append(TextColors.color(color)(c.toString())) + } + append("\n") + } + }.replace(Regex("""[β•”β•β•—β•‘β•šβ•]""")) { shadowColor(it.value) } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index a222c87c9..8b070d7d8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,12 +1,15 @@ -include("mordant") -include("samples:detection") -include("samples:markdown") -include("samples:progress") -include("samples:table") -include("samples:tour") -include("test:graalvm") -include("test:proguard") +rootProject.name = "mordant" +include( + "mordant", + "samples:detection", + "samples:markdown", + "samples:progress", + "samples:table", + "samples:tour", + "test:graalvm", + "test:proguard", +) @Suppress("UnstableApiUsage") dependencyResolutionManagement {