189 lines
7.4 KiB
Kotlin
189 lines
7.4 KiB
Kotlin
plugins {
|
|
alias(libs.plugins.kotlin.multiplatform)
|
|
id("kobweb-compose")
|
|
id("com.varabyte.kobweb.internal.publish")
|
|
}
|
|
|
|
group = "com.varabyte.kobwebx"
|
|
version = libs.versions.kobweb.get()
|
|
|
|
private val GENERATED_SRC_ROOT = "build/generated/icons/src/jsMain/kotlin"
|
|
|
|
enum class IconStyle {
|
|
FILLED,
|
|
OUTLINED,
|
|
ROUNDED,
|
|
SHARP,
|
|
TWO_TONED;
|
|
}
|
|
|
|
val generateIconsTask = tasks.register("generateIcons") {
|
|
val srcFile = layout.projectDirectory.file("md-icon-list.txt")
|
|
val dstFile =
|
|
layout.projectDirectory.file("$GENERATED_SRC_ROOT/com/varabyte/kobweb/silk/components/icons/mdi/MdIcons.kt")
|
|
|
|
inputs.files(srcFile)
|
|
outputs.dir(GENERATED_SRC_ROOT)
|
|
|
|
doLast {
|
|
val iconRawNames = srcFile.asFile
|
|
.readLines()
|
|
.asSequence()
|
|
.filter { line -> !line.startsWith("#") }
|
|
.associate { line ->
|
|
// Convert icon name to function name, e.g.
|
|
// align-left -> MdiAlignLeft
|
|
line.split("=", limit = 2).let { parts ->
|
|
val style = when (parts[0]) {
|
|
"mdi" -> IconStyle.FILLED
|
|
"mdio" -> IconStyle.OUTLINED
|
|
"mdir" -> IconStyle.ROUNDED
|
|
"mdis" -> IconStyle.SHARP
|
|
"mdit" -> IconStyle.TWO_TONED
|
|
else -> throw GradleException("Unexpected style grouping: ${parts[0]}")
|
|
}
|
|
val names = parts[1]
|
|
|
|
style to names.split(",")
|
|
}
|
|
}
|
|
|
|
// For each icon name, figure out what categories they are in. This will affect the function signature we generate.
|
|
val iconStyleGroups = mutableMapOf<String, MutableSet<IconStyle>>()
|
|
iconRawNames.forEach { entry ->
|
|
val category = entry.key
|
|
entry.value.forEach { rawName ->
|
|
iconStyleGroups.computeIfAbsent(rawName) { mutableSetOf() }.add(category)
|
|
}
|
|
}
|
|
|
|
val iconMethodEntries = iconStyleGroups
|
|
.map { entry ->
|
|
// TODO(194): Figure out how ligature fallbacks to work, if people report us breaking on legacy browsers.
|
|
// See also: https://developers.google.com/fonts/docs/material_icons#using_the_icons_in_html
|
|
val rawName = entry.key
|
|
|
|
@Suppress("DEPRECATION") // capitalize is way more readable than a direct replacement
|
|
val methodName = "Mdi" + rawName.split("_").joinToString("") { it.capitalize() }
|
|
val styles = entry.value
|
|
|
|
when {
|
|
// A rare solo-style icon? No need to allow a user to pass in a style parameter in that case
|
|
styles.size == 1 -> {
|
|
"@Composable fun $methodName(modifier: Modifier = Modifier) = MdIcon(\"$rawName\", modifier, ${styles.first().name})"
|
|
}
|
|
|
|
styles.isEmpty() -> {
|
|
// This shouldn't be possible, but just in case...
|
|
throw GradleException("Unexpected icon entry with no styles: $entry")
|
|
}
|
|
|
|
styles.size == IconStyle.values().size -> {
|
|
// This icon supports all styles. No need to assert input parameters.
|
|
"@Composable fun $methodName(modifier: Modifier = Modifier, style: IconStyle = FILLED) = MdIcon(\"$rawName\", modifier, style)"
|
|
}
|
|
|
|
else -> {
|
|
// Not all styles are valid. For now, we throw an exception to inform the user about this, but we
|
|
// can always decide to relax this later.
|
|
"@Composable fun $methodName(modifier: Modifier = Modifier, style: IconStyle = ${styles.first().name}) = MdIcon(\"$rawName\", modifier, style.also { it.assertValidStyle(\"$methodName\", ${styles.joinToString { it.name }}) })"
|
|
}
|
|
}
|
|
}
|
|
|
|
val iconsCode =
|
|
"""
|
|
|//@formatter:off
|
|
|@file:Suppress("unused", "SpellCheckingInspection")
|
|
|
|
|
|// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|// THIS FILE IS AUTOGENERATED.
|
|
|//
|
|
|// Do not edit this file by hand. Instead, update `md-icon-list.txt` in the module root and run the Gradle
|
|
|// task "generateIcons"
|
|
|// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
|
|package com.varabyte.kobweb.silk.components.icons.mdi
|
|
|
|
|
|import androidx.compose.runtime.*
|
|
|import com.varabyte.kobweb.compose.ui.Modifier
|
|
|import com.varabyte.kobweb.compose.ui.toAttrs
|
|
|import com.varabyte.kobweb.silk.components.icons.mdi.IconStyle.FILLED
|
|
|import com.varabyte.kobweb.silk.components.icons.mdi.IconStyle.OUTLINED
|
|
|import com.varabyte.kobweb.silk.components.icons.mdi.IconStyle.ROUNDED
|
|
|import com.varabyte.kobweb.silk.components.icons.mdi.IconStyle.SHARP
|
|
|import com.varabyte.kobweb.silk.components.icons.mdi.IconStyle.TWO_TONED
|
|
|import org.jetbrains.compose.web.dom.Span
|
|
|import org.jetbrains.compose.web.dom.Text
|
|
|
|
|
|enum class IconStyle {
|
|
| FILLED,
|
|
| OUTLINED,
|
|
| ROUNDED,
|
|
| SHARP,
|
|
| TWO_TONED;
|
|
|}
|
|
|
|
|
|private fun IconStyle.toClassNameSuffix(): String {
|
|
| return when (this) {
|
|
| FILLED -> ""
|
|
| OUTLINED -> "-outlined"
|
|
| ROUNDED -> "-round"
|
|
| SHARP -> "-sharp"
|
|
| TWO_TONED -> "-two-tone"
|
|
| }
|
|
|}
|
|
|
|
|
|private fun IconStyle.assertValidStyle(methodName: String, vararg validStyles: IconStyle) {
|
|
| if (this !in validStyles) {
|
|
| error("Attempted to render \"${'$'}methodName\" with style ${'$'}this. Must be one of: ${'$'}{validStyles.joinToString()}")
|
|
| }
|
|
|}
|
|
|
|
|
|@Composable
|
|
|fun MdIcon(
|
|
| name: String,
|
|
| modifier: Modifier,
|
|
| style: IconStyle = FILLED,
|
|
|) {
|
|
| Span(
|
|
| attrs = modifier.toAttrs { classes("material-icons${'$'}{style.toClassNameSuffix()}") }
|
|
| ) {
|
|
| Text(name)
|
|
| }
|
|
|}
|
|
|
|
|
|${iconMethodEntries.joinToString("\n")}
|
|
""".trimMargin()
|
|
|
|
dstFile.asFile.apply {
|
|
parentFile.mkdirs()
|
|
writeText(iconsCode)
|
|
}
|
|
}
|
|
}
|
|
|
|
kotlin {
|
|
js {
|
|
browser()
|
|
}
|
|
|
|
sourceSets {
|
|
jsMain {
|
|
kotlin.srcDir(generateIconsTask)
|
|
dependencies {
|
|
implementation(libs.compose.runtime)
|
|
implementation(libs.compose.html.core)
|
|
|
|
api(projects.frontend.kobwebCompose)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
kobwebPublication {
|
|
artifactName.set("Kobweb Silk Icons (Material Design Icons)")
|
|
artifactId.set("silk-icons-mdi")
|
|
description.set("A collection of composables that directly wrap Material Design Icons.")
|
|
}
|