Initial commit

This commit is contained in:
2020-02-10 19:31:44 +01:00
commit 1b83f88c8f
14 changed files with 685 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
package nl.astraeus.css
fun rgb(red: Int, green: Int, blue: Int): Color = RGBColor(red, green, blue)
fun rgba(red: Int, green: Int, blue: Int, alpha: Double): Color = RGBAColor(red, green, blue, alpha)
fun hsl(hue: Int, saturation: Int, lightness: Int): Color = HSLColor(hue, saturation, lightness)
fun hsla(hue: Int, saturation: Int, lightness: Int, alpha: Double): Color = HSLAColor(hue, saturation, lightness, alpha)
open class Color : CssProperty() {
override fun css(): String = "#xxxxxx"
}
class RGBColor(
val red: Int,
val green: Int,
val blue: Int
) : Color() {
override fun css(): String = "rgb($red, $green, $blue)"
}
class RGBAColor(
val red: Int,
val green: Int,
val blue: Int,
val alpha: Double
) : Color() {
override fun css(): String = "rgba($red, $green, $blue, $alpha)"
}
class HSLColor(
val hue: Int,
val saturation: Int,
val lightness: Int
) : Color() {
override fun css(): String = "hsl($hue, $saturation, $lightness)"
}
class HSLAColor(
val hue: Int,
val saturation: Int,
val lightness: Int,
val alpha: Double
) : Color() {
override fun css(): String = "hsla($hue, $saturation, $lightness, $alpha)"
}

View File

@@ -0,0 +1,108 @@
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()})"
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css
abstract class CssProperty {
abstract fun css(): String
}
fun plain(value: String) = PlainProperty(value)
class PlainProperty(
val value: String
): CssProperty() {
override fun css(): String = value
}

View File

@@ -0,0 +1,54 @@
package nl.astraeus.css
fun px(nr: Int): Measurement = Measurement(MeasurementType.PX, nr)
fun em(nr: Int): Measurement = Measurement(MeasurementType.EM, nr)
fun perc(nr: Int): Measurement = Measurement(MeasurementType.PERCENTAGE, nr)
enum class MeasurementType {
PX,
EM,
PERCENTAGE,
OTHER
}
open class Measurement(
val type: MeasurementType,
val intValue: Int = 0,
val stringValue: String = ""
) : CssProperty() {
override fun css(): String = when(type) {
MeasurementType.PX -> {
"${intValue}px"
}
MeasurementType.EM -> {
"${intValue}em"
}
MeasurementType.PERCENTAGE -> {
"${stringValue}%"
}
else -> {
error("Unhandled type $type")
}
}
}
enum class FontSizeType {
PX,
EM,
PERCENTAGE,
}
class FontSize(
val fontType: FontSizeType,
intValue: Int = 0,
stringValue: String = ""
) : Measurement(
MeasurementType.PX,
intValue,
stringValue
) {
override fun css(): String = "12px"
}

View File

@@ -0,0 +1,27 @@
package nl.astraeus.css
import kotlin.test.Test
object TestCssBuilder {
@Test
fun testBuilder() {
val css = CssBuilder()
css.style {
css(".test") {
top = px(10)
left = em(5)
backgroundColor = rgba(255, 255, 255, 0.75)
sel("> a") {
color = hsl(200, 50, 50)
}
}
}
println(css)
}
}

View File

@@ -0,0 +1,72 @@
package nl.astraeus.css
class StyleBase(
val mainColor: Color = hsl(128, 50, 50),
val mainBackgroundColor: Color = hsl(64, 50, 50),
val mainFont: PlainProperty = plain("Arial")
)
private fun StyleDefinition.sizePX(
left: Int,
top: Int,
width: Int,
height: Int
) {
this@sizePX.top = px(top)
this@sizePX.left = px(left)
this@sizePX.width = px(width)
this@sizePX.height = px(height)
}
private fun generateCss(
base: StyleBase
): String {
val css = CssBuilder()
css.style {
css("body") {
fontFamily = base.mainFont
color = base.mainColor
backgroundColor = base.mainBackgroundColor
}
css(".test") {
top = px(10)
left = em(5)
backgroundColor = rgba(255, 255, 255, 0.75)
css("> a") {
color = hsl(200, 50, 50)
}
}
css("nav") {
css("ul") {
color = hsl(0, 100, 25)
backgroundColor = base.mainBackgroundColor
}
css("li") {
sizePX(25, 25, 200, 200)
css("a") {
width = px(725)
backgroundColor = base.mainBackgroundColor
}
}
}
}
return css.getCss()
}
fun main() {
val css1 = generateCss(StyleBase())
val css2 = generateCss(StyleBase(
hsl(32, 40, 50),
hsl(64, 60, 35),
plain("Courier")
))
println(css1)
println(css2)
}