Newer
Older
kotlin-css-generator / src / commonMain / kotlin / nl / astraeus / css / CssBuilder.kt
rnentjes on 10 Feb 2020 2 KB Initial commit
package nl.astraeus.css

@DslMarker
annotation class CssTagMarker

@CssTagMarker
open class Style(
    var color: Color? = null,
    var backgroundColor: Color? = null,
    var left: Measurement? = null,
    var top: Measurement? = null,
    var width: Measurement? = null,
    var height: Measurement? = null,
    var fontFamily: PlainProperty? = null,
    var fontSize: FontSize? = null
) {

    fun getMapping() = mapOf(
        "color" to color,
        "background-color" to backgroundColor,
        "left" to left,
        "top" to top,
        "width" to width,
        "height" to height,
        "font-family" to fontFamily,
        "font-size" to fontSize
    )

    fun propertyCss(indent: String, name: String, prop: CssProperty?): String = if (prop != null) {
        "$indent$name: ${prop.css()};\n"
    } else {
        ""
    }

    fun generatePropertyCss(indent: String): String {
        val builder = StringBuilder()

        for ((name, prop) in getMapping()) {
            builder.append(propertyCss(indent, name, prop))
        }

        return builder.toString()
    }

}

@CssTagMarker
open class StyleDefinition : Style() {
    val definitions: MutableMap<String, StyleDefinition> = mutableMapOf()
    val includes: MutableList<Style> = mutableListOf()

    fun css(selector: String, style: StyleDefinition.() -> Unit) {
        val styleValue = StyleDefinition()

        style(styleValue)

        definitions[selector] = styleValue
    }

    fun include(style: Style) {
        includes.add(style)
    }

    open fun generateCss(namespace: String = "", indent: String = "  "): String {
        val builder = StringBuilder()

        for ((name, prop) in definitions) {
            val css = StringBuilder()
            css.append(prop.generatePropertyCss(indent))
            for (style in prop.includes) {
                css.append(style.generatePropertyCss(indent))
            }
            if (css.isNotBlank()) {
                builder.append("$namespace $name".trim())
                builder.append(" {\n")
                builder.append(css)
                builder.append("}\n\n")
            }

            builder.append(prop.generateCss( "${namespace} $name".trim(), indent))
        }

        return builder.toString()
    }

}

fun css(definition: Style.() -> Unit): Style {
    val css = Style()

    definition(css)

    return css
}

class CssBuilder {
    var definition: StyleDefinition = StyleDefinition()

    fun style(definition: StyleDefinition.() -> Unit) {
        definition(this.definition)
    }

    fun getCss(): String = definition.generateCss()

    override fun toString(): String {
        return "CssBuilder(${definition.generateCss()})"
    }
}