17 Commits
master ... main

Author SHA1 Message Date
0e1c1cd99f Version 1.1.0, add oklch color option
- Update publish plugin
2025-05-03 10:49:00 +02:00
996a8f385e version 1.0.11-SNAPSHOT 2024-10-23 14:00:59 +02:00
d2349c9308 version 1.0.10 2024-10-23 13:50:36 +02:00
e0a4ff54de v. 1.0.8 update Kotlin to 1.9.22, gradle to 8.5 and test-logger to 4.0.0 2024-01-27 12:04:24 +01:00
3f5f1c6543 Example
Took 15 minutes
2023-07-24 10:34:20 +02:00
ac491761d9 v. 1.0.7, kotlin v. 1.7.20, gradle 7.5.1
Took 24 minutes
2022-10-15 11:11:11 +02:00
0d8157cabf Update to snapshot version 2022-03-24 09:29:47 +01:00
1e37ac07ba v. 1.0.6
- Fix not

Took 9 minutes
2022-03-24 09:24:10 +01:00
780dd0782a Update to snapshot version
Took 6 minutes
2021-11-09 13:45:34 +01:00
70a52a3bb5 v. 1.0.4, add vh,vw measurements
Took 47 seconds
2021-11-09 13:38:36 +01:00
68ce4ffa16 Merge remote-tracking branch 'github/main' into main 2021-10-23 11:56:35 +02:00
9f3be7cadd v. 1.0.3, add inline style, fix TemplateRowColumn value types
Took 27 minutes
2021-10-23 11:56:18 +02:00
9217476ae7 Update readme.md 2021-10-15 15:08:08 +02:00
7e86441d84 v. 1.0.2, fix minified option
Took 8 minutes
2021-10-15 15:04:22 +02:00
6375a0d78d v. 1.0.1, update readme.md
Took 1 hour 56 minutes
2021-10-09 20:13:38 +02:00
b2c112f711 Merge branch 'master' into main 2021-10-03 13:26:11 +02:00
95c190defd Initial commit 2021-10-03 13:19:37 +02:00
16 changed files with 477 additions and 315 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Rien
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,37 +1,48 @@
@file:OptIn(ExperimentalWasmDsl::class)
import com.vanniktech.maven.publish.SonatypeHost
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
kotlin("multiplatform") version "1.5.31"
`maven-publish`
kotlin("multiplatform") version "2.1.10"
id("com.vanniktech.maven.publish") version "0.31.0"
signing
id("org.jetbrains.dokka") version "2.0.0"
}
group = "nl.astraeus"
version = "1.0.0"
version = "1.1.0"
repositories {
mavenLocal()
mavenCentral()
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
}
kotlin {
jvm()
js(BOTH) {
js(IR) {
browser {
testTask {
useKarma {
useFirefox()
//useChrome()
}
}
/* testTask {
// work around, browser test is broken atm
enabled = false
}*/
}
}
wasmJs {
//moduleName = project.name
browser()
mavenPublication {
groupId = group as String
pom { name = "${project.name}-wasm-js" }
}
}
sourceSets {
val commonMain by getting {}
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
implementation(kotlin("test"))
}
}
val jvmTest by getting {
@@ -39,100 +50,69 @@ kotlin {
implementation(kotlin("test-junit"))
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
val jsMain by getting
val wasmJsMain by getting
}
}
extra["PUBLISH_GROUP_ID"] = "nl.astraeus"
extra["PUBLISH_VERSION"] = "1.0.0"
extra["PUBLISH_ARTIFACT_ID"] = "kotlin-css-generator"
// Stub secrets to let the project sync and build without the publication values set up
val signingKeyId: String by project
val signingPassword: String by project
val signingSecretKeyRingFile: String by project
val ossrhUsername: String by project
val ossrhPassword: String by project
extra["signing.keyId"] = signingKeyId
extra["signing.password"] = signingPassword
extra["signing.secretKeyRingFile"] = signingSecretKeyRingFile
extra["ossrhUsername"] = ossrhUsername
extra["ossrhPassword"] = ossrhPassword
val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}
publishing {
repositories {
mavenLocal()
maven {
name = "releases"
// change to point to your repo, e.g. http://my.org/repo
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/releases")
credentials {
val nexusUsername: String by project
val nexusPassword: String by project
name = "gitea"
setUrl("https://gitea.astraeus.nl/api/packages/rnentjes/maven")
username = nexusUsername
password = nexusPassword
}
}
maven {
name = "snapshots"
// change to point to your repo, e.g. http://my.org/repo
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/snapshots")
credentials {
val nexusUsername: String by project
val nexusPassword: String by project
credentials() {
val giteaUsername: kotlin.String? by project
val giteaPassword: kotlin.String? by project
username = nexusUsername
password = nexusPassword
}
}
maven {
name = "sonatype"
setUrl("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = ossrhUsername
password = ossrhPassword
username = giteaUsername
password = giteaPassword
}
}
}
// Configure all publications
publications.withType<MavenPublication> {
// Stub javadoc.jar artifact
//artifact(javadocJar.get())
// Provide artifacts information requited by Maven Central
pom {
name.set("kotlin-css-generator")
description.set("Kotlin css generator")
url.set("https://github.com/rnentjes/kotlin-css-generator")
licenses {
license {
name.set("MIT")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("rnentjes")
name.set("Rien Nentjes")
email.set("info@nentjes.com")
}
}
scm {
url.set("https://github.com/rnentjes/kotlin-css-generator")
}
}
}
}
signing {
sign(publishing.publications)
}
tasks.withType<AbstractPublishToMaven> {
dependsOn(tasks.withType<Sign>())
}
mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
signAllPublications()
coordinates(group.toString(), name, version.toString())
pom {
name = "kotlin-css-generator"
description = "Kotlin css generator"
inceptionYear = "2020"
url = "https://github.com/rnentjes/kotlin-css-generator"
licenses {
license {
name = "MIT"
url = "https://opensource.org/licenses/MIT"
}
}
developers {
developer {
id = "rnentjes"
name = "Rien Nentjes"
email = "info@nentjes.com"
}
}
scm {
url = "https://github.com/rnentjes/kotlin-css-generator"
}
}
}

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -6,6 +6,22 @@ It can be used as an alternative to less/sass or as a runtime library to generat
Tools like less and sass are often used as a build step and take some time.
This library is meant to be fast enough to generate the css on the fly either from the server or directly in the browser.
## Usage
Include in build.gradle.kts:
```kotlin
repositories {
mavenCentral()
}
val commonMain by getting {
dependencies {
api("nl.astraeus:kotlin-css-generator:1.0.9")
}
}
```
Examples:
## Nesting / colors / variables

View File

@@ -1,13 +1,20 @@
pluginManagement {
repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
google()
mavenCentral()
maven { setUrl("https://plugins.gradle.org/m2/") }
gradlePluginPortal()
}
}
rootProject.name = "kotlin-css-generator"
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
//enableFeaturePreview("GRADLE_METADATA")
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
rootProject.name = "kotlin-css-generator"

View File

@@ -0,0 +1,31 @@
package nl.astraeus.css.properties
fun calc(expression: CalcExpression) = Calc(expression)
infix operator fun CalcExpression.plus(other: CalcExpression) = CompoundCalcExpression(
this,
"+",
other
)
infix operator fun CalcExpression.minus(other: CalcExpression) = CompoundCalcExpression(
this,
"-",
other
)
interface CalcExpression
class CompoundCalcExpression(
val left: CalcExpression,
val operator: String,
val right: CalcExpression
): CalcExpression {
override fun toString(): String {
return "$left $operator $right"
}
}
class Calc(
expression: CalcExpression
) : CssProperty(expression.toString())

View File

@@ -585,6 +585,8 @@ fun rgb(red: Int, green: Int, blue: Int) = Color("rgb($red, $green, $blue)")
fun rgba(red: Int, green: Int, blue: Int, alpha: Double) = Color("rgba($red, $green, $blue, ${formatAlpha(alpha)})")
fun hsl(hue: Int, saturation: Int, lightness: Int) = Color("hsl($hue, $saturation%, $lightness%)")
fun hsla(hue: Int, saturation: Int, lightness: Int, alpha: Double) = Color("hsla($hue, $saturation%, $lightness%, ${formatAlpha(alpha)})")
fun oklch(lightness: Int, chroma: Double, hue: Double) = Color("oklch($lightness% $chroma $hue)")
fun oklch(lightness: Int, chroma: Double, hue: Double, alpha: Double) = Color("oklch($lightness% $chroma $hue / ${formatAlpha(alpha)})")
fun blackAlpha(alpha: Double) = Color.black.withAlpha(alpha)
fun whiteAlpha(alpha: Double) = Color.white.withAlpha(alpha)

View File

@@ -10,6 +10,7 @@ open class CssProperty(
override fun css(): String = value
override fun toString(): String = value
}
fun text(value: String) = TextProperty(value)

View File

@@ -58,14 +58,14 @@ class TemplateRowColumn(
) : CssProperty(value) {
companion object {
val none = GridValue("none")
val auto = GridValue("auto")
val maxContent = GridValue("max-content")
val minContent = GridValue("min-content")
val initial = GridValue("initial")
val inherit = GridValue("inherit")
val none = TemplateRowColumn("none")
val auto = TemplateRowColumn("auto")
val maxContent = TemplateRowColumn("max-content")
val minContent = TemplateRowColumn("min-content")
val initial = TemplateRowColumn("initial")
val inherit = TemplateRowColumn("inherit")
fun length(length: Measurement) = GridValue(length.value)
fun length(length: Measurement) = TemplateRowColumn(length.value)
}
}

View File

@@ -9,13 +9,15 @@ enum class MeasurementUoM {
PC,
PRC,
CM,
FR
FR,
VH,
VW
}
open class Measurement(
value: String,
val uom: MeasurementUoM = MeasurementUoM.NONE
) : CssProperty(value) {
) : CssProperty(value), CalcExpression {
override fun toString(): String = super.value
@@ -25,37 +27,14 @@ open class Measurement(
val inherit = Measurement("inherit")
val normal = Measurement("normal")
fun fromString(value:String): Measurement = when {
value == "0" -> Measurement("0", MeasurementUoM.PX)
value.endsWith("px") -> Measurement(value.slice(0..(value.length-2)), MeasurementUoM.PX)
value.endsWith("rel") -> Measurement(value.slice(0..(value.length-3)), MeasurementUoM.REL)
else -> {
TODO("Unable to parse $value")
}
fun fromString(value: String): Measurement = when {
value == "0" -> Measurement("0", MeasurementUoM.PX)
value.endsWith("px") -> Measurement(value.slice(0..(value.length - 2)), MeasurementUoM.PX)
value.endsWith("rel") -> Measurement(value.slice(0..(value.length - 3)), MeasurementUoM.REL)
else -> {
TODO("Unable to parse $value")
}
fun px(nr: Int) = if (nr == 0) {
Measurement(
"0",
MeasurementUoM.PX
)
} else {
Measurement(
"${nr}px",
MeasurementUoM.PX
)
}
fun px(nr: Double) = nr.px
fun em(nr: Int) = nr.em
fun em(nr: Double) = nr.em
fun prc(nr: Int) = nr.prc
fun prc(nr: Double) = nr.prc
fun pc(nr: Int) = nr.pc
fun pc(nr: Double) = nr.pc
fun cm(nr: Int) = nr.cm
fun cm(nr: Double) = nr.cm
fun fr(nr: Int) = nr.fr
}
}
@@ -100,8 +79,10 @@ val Int.cm: Measurement
get() = Measurement("${this}cm", MeasurementUoM.CM)
val Int.fr: Measurement
get() = Measurement("${this}fr", MeasurementUoM.FR)
fun Int.px(): Measurement = Measurement.px(this)
val Int.vw: Measurement
get() = Measurement("${this}vw", MeasurementUoM.VW)
val Int.vh: Measurement
get() = Measurement("${this}vh", MeasurementUoM.VH)
val Double.px: Measurement
get() = Measurement("${this}px", MeasurementUoM.PX)
@@ -115,8 +96,12 @@ val Double.pc: Measurement
get() = Measurement("${this}pc", MeasurementUoM.PC)
val Double.cm: Measurement
get() = Measurement("${this}cm", MeasurementUoM.CM)
fun Double.px(): Measurement = Measurement.px(this)
val Double.fr: Measurement
get() = Measurement("${this}fr", MeasurementUoM.FR)
val Double.vw: Measurement
get() = Measurement("${this}vw", MeasurementUoM.VW)
val Double.vh: Measurement
get() = Measurement("${this}vh", MeasurementUoM.VH)
open class LineHeight(value: String) : CssProperty(value) {
companion object {

View File

@@ -1,11 +0,0 @@
package nl.astraeus.css.style
import nl.astraeus.css.properties.Color
object CssFunctions {
fun darken(color: Color, percentage: Int): Color {
return color
}
}

View File

@@ -35,7 +35,12 @@ abstract class CssGenerator {
abstract fun getValidator(name: String): List<Validator>?
private fun propertyCss(indent: String, name: String, props: List<CssProperty>): String {
private fun propertyCss(
indent: String,
name: String,
minified: Boolean,
props: List<CssProperty>
): String {
val builder = StringBuilder()
getValidator(name)?.forEach {
@@ -52,18 +57,23 @@ abstract class CssGenerator {
}
val paddedName = StringBuilder()
paddedName.append(indent)
if (!minified) {
paddedName.append(indent)
}
paddedName.append(name)
paddedName.append(":")
while (paddedName.length < 32) {
paddedName.append(' ')
if (!minified) {
while (paddedName.length < 32) {
paddedName.append(' ')
}
}
return "$paddedName$builder;\n"
return "$paddedName$builder;"
}
fun generatePropertyCss(
indent: String,
sortProperties: Boolean
sortProperties: Boolean,
minified: Boolean
): String {
val builder = StringBuilder()
@@ -71,11 +81,17 @@ abstract class CssGenerator {
for (name in props.keys.sorted()) {
val prop = props[name] ?: error("$name not found in properties after sorting!")
builder.append(propertyCss(indent, name, prop))
builder.append(propertyCss(indent, name, minified, prop))
if (!minified) {
builder.append("\n")
}
}
} else {
for ((name, prop) in props) {
builder.append(propertyCss(indent, name, prop))
builder.append(propertyCss(indent, name, minified, prop))
if (!minified) {
builder.append("\n")
}
}
}
@@ -107,11 +123,20 @@ abstract class CssGenerator {
) {
if (selectors.isNotEmpty() && block != null) {
append(indent)
append(selectors.joinToString(",\n"))
append(" {\n")
append(selectors.joinToString(if (minified) { "," } else { ",\n" }))
if (!minified) {
append(" ")
}
append("{")
if (!minified) {
append("\n")
}
append(block.content)
append(indent)
append("}\n\n")
append("}")
if (!minified) {
append("\n\n")
}
}
}
@@ -165,18 +190,7 @@ abstract class CssGenerator {
}
}
return if (minified) {
val stripped = StringBuilder()
val skip = arrayOf(' ', '\t', '\n', '\r')
for (char in builder) {
if (!skip.contains(char)) {
stripped.append(char)
}
}
stripped.toString()
} else {
builder.toString()
}
return builder.toString()
}
open fun generateCssBlocks(
@@ -203,12 +217,12 @@ abstract class CssGenerator {
prop(finalStyle)
}
css.append(finalStyle.generatePropertyCss(" $indent", sortProperties))
css.append(finalStyle.generatePropertyCss(" $indent", sortProperties, minified))
if (css.isNotBlank()) {
val builder = StringBuilder()
check (allowCommaInSelector || !name.contains(',')) {
check (allowCommaInSelector || (name.indexOf(',') == -1)) {
"Comma is not allowed in selector (option is set in generateCss call)"
}
@@ -218,40 +232,79 @@ abstract class CssGenerator {
//builder.append(" {\n")
finalStyle.fontFace?.let { ff ->
builder.append(" $indent")
builder.append("@font-face {\n")
builder.append(ff.generatePropertyCss(" $indent", sortProperties))
builder.append(" $indent")
builder.append("}\n")
if (!minified) {
builder.append(" $indent")
}
builder.append("@font-face")
if (!minified) {
builder.append(" ")
}
builder.append("{")
if (!minified) {
builder.append("\n")
}
builder.append(ff.generatePropertyCss(" $indent", sortProperties, minified))
if (!minified) {
builder.append(" $indent")
}
builder.append("}")
if (!minified) {
builder.append("\n")
}
}
finalStyle.keyFrames.let { kf ->
kf.keys.sorted().forEach { frameName ->
val css = kf[frameName]
builder.append(" $indent")
if (!minified) {
builder.append(" $indent")
}
builder.append("@keyframes ")
builder.append(frameName)
builder.append(" {\n")
if (!minified) {
builder.append(" ")
}
builder.append("{")
if (!minified) {
builder.append("\n")
}
css?.let { css ->
for ((nr, style) in css.frames) {
builder.append(" $indent")
if (!minified) {
builder.append(" $indent")
}
builder.append("${nr}% ")
builder.append(" $indent")
builder.append("{\n")
if (!minified) {
builder.append(" $indent")
}
builder.append("{")
if (!minified) {
builder.append("\n")
}
val finalStyle = Style()
style(finalStyle)
builder.append(finalStyle.generatePropertyCss(" $indent", sortProperties))
builder.append(finalStyle.generatePropertyCss(" $indent", sortProperties, minified))
builder.append(" $indent")
builder.append("}\n")
if (!minified) {
builder.append(" $indent")
}
builder.append("}")
if (!minified) {
builder.append("\n")
}
}
builder.append(" $indent")
builder.append("}\n")
if (!minified) {
builder.append(" $indent")
}
builder.append("}")
if (!minified) {
builder.append("\n")
}
}
}
}
@@ -366,9 +419,7 @@ fun attrStartsWith(name: DescriptionProvider, value: String): DescriptionProvide
ValueDescriptionProvider("[${name.description()}^=$value]")
@CssTagMarker
open class Style : CssGenerator() {
var fontFace: FontFace? = null
var keyFrames: MutableMap<String, KeyFrames> = mutableMapOf()
open class InlineStyle : CssGenerator() {
private val validators = mapOf<String, List<Validator>>(
"background-position" to listOf(InitialInheritSingleValue()),
@@ -393,82 +444,6 @@ open class Style : CssGenerator() {
definitions[selector]?.add(style)
}
/**
* like the scss &
* @param selector blabla
*/
fun and(vararg selectors: DescriptionProvider, style: Css) {
for (selector in selectors) {
addStyle(selector.description(), style)
}
}
fun and(vararg selectors: String, style: Css) {
for (selector in selectors) {
addStyle(selector, style)
}
}
fun select(vararg selectors: DescriptionProvider, style: Css) {
for (selector in selectors) {
addStyle(" ${selector.description()}", style)
}
}
fun select(vararg selectors: String, style: Css) {
for (selector in selectors) {
addStyle(" $selector", style)
}
}
fun descendant(vararg descNames: DescriptionProvider, style: Css) {
for (descName in descNames) {
addStyle(" ${descName.description()}", style)
}
}
fun descendant(vararg descNames: String, style: Css) {
for (descName in descNames) {
addStyle(" $descName", style)
}
}
fun child(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" > ${childName.description()}", style)
}
}
fun child(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" > $childName", style)
}
}
fun sibling(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" ~ ${childName.description()}", style)
}
}
fun sibling(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" ~ $childName", style)
}
}
fun adjSibling(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" + ${childName.description()}", style)
}
}
fun adjSibling(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" + $childName", style)
}
}
fun active(style: Css) {
addStyle(":active", style)
}
@@ -485,30 +460,10 @@ open class Style : CssGenerator() {
addStyle(":hover", style)
}
fun firstChild(style: Css) {
addStyle(":first-child", style)
}
fun lastChild(style: Css) {
addStyle(":last-child", style)
}
fun pseudoElement(selector: DescriptionProvider, style: Css) {
addStyle(":${selector.description()}", style)
}
fun pseudoChild(selector: DescriptionProvider, style: Css) {
addStyle("::${selector.description()}", style)
}
fun visited(style: Css) {
addStyle(":visited", style)
}
fun not(selector: DescriptionProvider, style: Css) {
addStyle(":not(${selector.description()})", style)
}
fun plain(name: String, value: String) {
props[name] = prp(value)
}
@@ -907,6 +862,10 @@ open class Style : CssGenerator() {
props["content"] = prp(content)
}
fun content(content: String) {
props["content"] = prp(content)
}
fun counterIncrement(increment: String) {
props["counter-increment"] = prp(increment)
}
@@ -971,12 +930,6 @@ open class Style : CssGenerator() {
props["font"] = prp(font)
}
fun fontFace(face: FontFace.() -> Unit) {
fontFace = FontFace()
face.invoke(fontFace!!)
}
fun fontFamily(font: String) {
props["font-family"] = prp(font)
}
@@ -1066,8 +1019,8 @@ open class Style : CssGenerator() {
}
fun gridGap(
rowGap: Measurement = Measurement.px(0),
columnGap: Measurement = Measurement.px(0)
rowGap: Measurement = 0.px,
columnGap: Measurement = 0.px
) {
props["grid-gap"] = prp(rowGap, columnGap)
}
@@ -1132,10 +1085,6 @@ open class Style : CssGenerator() {
props["hyphens"] = prp(hyphens)
}
fun import(style: Css) {
style(this)
}
fun isolation(isolation: Isolation) {
props["isolation"] = prp(isolation)
}
@@ -1144,14 +1093,6 @@ open class Style : CssGenerator() {
props["justify-content"] = prp(content)
}
fun keyFrames(animationName: String, frames: KeyFrames.() -> Unit) {
val frameCss = KeyFrames()
frames.invoke(frameCss)
keyFrames[animationName] = frameCss
}
fun left(left: Measurement) {
props["left"] = prp(left)
}
@@ -1572,6 +1513,132 @@ open class Style : CssGenerator() {
}
}
@CssTagMarker
open class Style : InlineStyle() {
var fontFace: FontFace? = null
var keyFrames: MutableMap<String, KeyFrames> = mutableMapOf()
private fun addStyle(selector: String, style: Css) {
definitions[selector] = definitions[selector] ?: mutableListOf()
definitions[selector]?.add(style)
}
/**
* like the scss &
*/
fun and(vararg selectors: DescriptionProvider, style: Css) {
for (selector in selectors) {
addStyle(selector.description(), style)
}
}
fun and(vararg selectors: String, style: Css) {
for (selector in selectors) {
addStyle(selector, style)
}
}
fun select(vararg selectors: DescriptionProvider, style: Css) {
for (selector in selectors) {
addStyle(" ${selector.description()}", style)
}
}
fun select(vararg selectors: String, style: Css) {
for (selector in selectors) {
addStyle(" $selector", style)
}
}
fun descendant(vararg descNames: DescriptionProvider, style: Css) {
for (descName in descNames) {
addStyle(" ${descName.description()}", style)
}
}
fun descendant(vararg descNames: String, style: Css) {
for (descName in descNames) {
addStyle(" $descName", style)
}
}
fun child(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" > ${childName.description()}", style)
}
}
fun child(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" > $childName", style)
}
}
fun sibling(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" ~ ${childName.description()}", style)
}
}
fun sibling(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" ~ $childName", style)
}
}
fun adjSibling(vararg childNames: DescriptionProvider, style: Css) {
for (childName in childNames) {
addStyle(" + ${childName.description()}", style)
}
}
fun adjSibling(vararg childNames: String, style: Css) {
for (childName in childNames) {
addStyle(" + $childName", style)
}
}
fun firstChild(style: Css) {
addStyle(":first-child", style)
}
fun lastChild(style: Css) {
addStyle(":last-child", style)
}
fun pseudoElement(selector: DescriptionProvider, style: Css) {
addStyle(":${selector.description()}", style)
}
fun pseudoChild(selector: DescriptionProvider, style: Css) {
addStyle("::${selector.description()}", style)
}
fun not(name: DescriptionProvider): DescriptionProvider = ValueDescriptionProvider(":not(${name.description()})")
@Deprecated("Use select(not(...)) instead.")
fun not(selector: DescriptionProvider, style: Css) {
addStyle(":not(${selector.description()})", style)
}
fun fontFace(face: FontFace.() -> Unit) {
fontFace = FontFace()
face.invoke(fontFace!!)
}
fun import(style: Css) {
style(this)
}
fun keyFrames(animationName: String, frames: KeyFrames.() -> Unit) {
val frameCss = KeyFrames()
frames.invoke(frameCss)
keyFrames[animationName] = frameCss
}
}
@CssTagMarker
open class ConditionalStyle : Style() {
var media: MutableMap<String, ConditionalCss> = mutableMapOf()

View File

@@ -0,0 +1,20 @@
package nl.astraeus.css
import nl.astraeus.css.properties.oklch
import kotlin.test.Test
class ColorTest {
@Test
fun testColor() {
val css = style {
select("body") {
color(oklch(100, 0.5, 0.5))
backgroundColor(oklch(100, 0.5, 0.5, 0.25))
}
}
println(css.generateCss())
}
}

View File

@@ -2,6 +2,8 @@ package nl.astraeus.css
import nl.astraeus.css.properties.BorderStyle
import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.FontStyle
import nl.astraeus.css.properties.FontWeight
import nl.astraeus.css.properties.Measurement
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.hsla
@@ -128,4 +130,28 @@ class Examples {
combineEqualBlocks = true
))
}
@Test
fun testFontFace() {
val css = style {
select("*") {
fontFace {
fontFamily("UbuntuCondensed")
fontStyle(FontStyle.normal)
fontWeight(FontWeight.normal)
//fontDisplay("auto")
src("fonts/ubuntu.condensed.ttf")
}
}
}
val cssTxt = css.generateCss(
minified = false,
sortProperties = true,
combineEqualBlocks = true
)
println(cssTxt)
}
}

View File

@@ -0,0 +1,18 @@
package nl.astraeus.css
import nl.astraeus.css.properties.calc
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.minus
import nl.astraeus.css.properties.plus
import nl.astraeus.css.properties.px
import kotlin.test.Test
class TestCalcExpression {
@Test
fun testCalcExpression() {
val a = calc(10.px + 20.px - 5.em)
println(a)
}
}

View File

@@ -187,7 +187,6 @@ class TestCssBuilder {
println(css2.generateCss())
}
@Test
fun testOr() {
val css = style {