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 { plugins {
kotlin("multiplatform") version "1.5.31" kotlin("multiplatform") version "2.1.10"
`maven-publish` id("com.vanniktech.maven.publish") version "0.31.0"
signing signing
id("org.jetbrains.dokka") version "2.0.0"
} }
group = "nl.astraeus" group = "nl.astraeus"
version = "1.0.0" version = "1.1.0"
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
} }
kotlin { kotlin {
jvm() jvm()
js(BOTH) { js(IR) {
browser { browser {
testTask { /* testTask {
useKarma { // work around, browser test is broken atm
useFirefox() enabled = false
//useChrome() }*/
} }
} }
wasmJs {
//moduleName = project.name
browser()
mavenPublication {
groupId = group as String
pom { name = "${project.name}-wasm-js" }
} }
} }
sourceSets { sourceSets {
val commonMain by getting {} val commonMain by getting
val commonTest by getting { val commonTest by getting {
dependencies { dependencies {
implementation(kotlin("test-common")) implementation(kotlin("test"))
implementation(kotlin("test-annotations-common"))
} }
} }
val jvmTest by getting { val jvmTest by getting {
@@ -39,100 +50,69 @@ kotlin {
implementation(kotlin("test-junit")) implementation(kotlin("test-junit"))
} }
} }
val jsTest by getting { val jsMain by getting
dependencies { val wasmJsMain by getting
implementation(kotlin("test-js"))
}
}
} }
} }
extra["PUBLISH_GROUP_ID"] = "nl.astraeus" val javadocJar by tasks.registering(Jar::class) {
extra["PUBLISH_VERSION"] = "1.0.0" archiveClassifier.set("javadoc")
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
publishing { publishing {
repositories { repositories {
mavenLocal()
maven { maven {
name = "releases" name = "gitea"
// change to point to your repo, e.g. http://my.org/repo setUrl("https://gitea.astraeus.nl/api/packages/rnentjes/maven")
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/releases")
credentials {
val nexusUsername: String by project
val nexusPassword: String by project
username = nexusUsername credentials() {
password = nexusPassword val giteaUsername: kotlin.String? by project
} val giteaPassword: kotlin.String? by project
}
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
username = nexusUsername username = giteaUsername
password = nexusPassword password = giteaPassword
}
}
maven {
name = "sonatype"
setUrl("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = ossrhUsername
password = ossrhPassword
} }
} }
} }
// 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 { signing {
sign(publishing.publications) 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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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. 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. 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: Examples:
## Nesting / colors / variables ## Nesting / colors / variables

View File

@@ -1,13 +1,20 @@
pluginManagement { pluginManagement {
repositories { repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") } google()
mavenCentral() mavenCentral()
gradlePluginPortal()
maven { setUrl("https://plugins.gradle.org/m2/") }
} }
} }
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 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 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 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 blackAlpha(alpha: Double) = Color.black.withAlpha(alpha)
fun whiteAlpha(alpha: Double) = Color.white.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 css(): String = value
override fun toString(): String = value
} }
fun text(value: String) = TextProperty(value) fun text(value: String) = TextProperty(value)

View File

@@ -58,14 +58,14 @@ class TemplateRowColumn(
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
val none = GridValue("none") val none = TemplateRowColumn("none")
val auto = GridValue("auto") val auto = TemplateRowColumn("auto")
val maxContent = GridValue("max-content") val maxContent = TemplateRowColumn("max-content")
val minContent = GridValue("min-content") val minContent = TemplateRowColumn("min-content")
val initial = GridValue("initial") val initial = TemplateRowColumn("initial")
val inherit = GridValue("inherit") 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, PC,
PRC, PRC,
CM, CM,
FR FR,
VH,
VW
} }
open class Measurement( open class Measurement(
value: String, value: String,
val uom: MeasurementUoM = MeasurementUoM.NONE val uom: MeasurementUoM = MeasurementUoM.NONE
) : CssProperty(value) { ) : CssProperty(value), CalcExpression {
override fun toString(): String = super.value override fun toString(): String = super.value
@@ -25,37 +27,14 @@ open class Measurement(
val inherit = Measurement("inherit") val inherit = Measurement("inherit")
val normal = Measurement("normal") val normal = Measurement("normal")
fun fromString(value:String): Measurement = when { fun fromString(value: String): Measurement = when {
value == "0" -> Measurement("0", MeasurementUoM.PX) value == "0" -> Measurement("0", MeasurementUoM.PX)
value.endsWith("px") -> Measurement(value.slice(0..(value.length-2)), 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) value.endsWith("rel") -> Measurement(value.slice(0..(value.length - 3)), MeasurementUoM.REL)
else -> { else -> {
TODO("Unable to parse $value") 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) get() = Measurement("${this}cm", MeasurementUoM.CM)
val Int.fr: Measurement val Int.fr: Measurement
get() = Measurement("${this}fr", MeasurementUoM.FR) get() = Measurement("${this}fr", MeasurementUoM.FR)
val Int.vw: Measurement
fun Int.px(): Measurement = Measurement.px(this) get() = Measurement("${this}vw", MeasurementUoM.VW)
val Int.vh: Measurement
get() = Measurement("${this}vh", MeasurementUoM.VH)
val Double.px: Measurement val Double.px: Measurement
get() = Measurement("${this}px", MeasurementUoM.PX) get() = Measurement("${this}px", MeasurementUoM.PX)
@@ -115,8 +96,12 @@ val Double.pc: Measurement
get() = Measurement("${this}pc", MeasurementUoM.PC) get() = Measurement("${this}pc", MeasurementUoM.PC)
val Double.cm: Measurement val Double.cm: Measurement
get() = Measurement("${this}cm", MeasurementUoM.CM) get() = Measurement("${this}cm", MeasurementUoM.CM)
val Double.fr: Measurement
fun Double.px(): Measurement = Measurement.px(this) 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) { open class LineHeight(value: String) : CssProperty(value) {
companion object { 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>? 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() val builder = StringBuilder()
getValidator(name)?.forEach { getValidator(name)?.forEach {
@@ -52,18 +57,23 @@ abstract class CssGenerator {
} }
val paddedName = StringBuilder() val paddedName = StringBuilder()
paddedName.append(indent) if (!minified) {
paddedName.append(indent)
}
paddedName.append(name) paddedName.append(name)
paddedName.append(":") paddedName.append(":")
while (paddedName.length < 32) { if (!minified) {
paddedName.append(' ') while (paddedName.length < 32) {
paddedName.append(' ')
}
} }
return "$paddedName$builder;\n" return "$paddedName$builder;"
} }
fun generatePropertyCss( fun generatePropertyCss(
indent: String, indent: String,
sortProperties: Boolean sortProperties: Boolean,
minified: Boolean
): String { ): String {
val builder = StringBuilder() val builder = StringBuilder()
@@ -71,11 +81,17 @@ abstract class CssGenerator {
for (name in props.keys.sorted()) { for (name in props.keys.sorted()) {
val prop = props[name] ?: error("$name not found in properties after sorting!") 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 { } else {
for ((name, prop) in props) { 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) { if (selectors.isNotEmpty() && block != null) {
append(indent) append(indent)
append(selectors.joinToString(",\n")) append(selectors.joinToString(if (minified) { "," } else { ",\n" }))
append(" {\n") if (!minified) {
append(" ")
}
append("{")
if (!minified) {
append("\n")
}
append(block.content) append(block.content)
append(indent) append(indent)
append("}\n\n") append("}")
if (!minified) {
append("\n\n")
}
} }
} }
@@ -165,18 +190,7 @@ abstract class CssGenerator {
} }
} }
return if (minified) { return builder.toString()
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()
}
} }
open fun generateCssBlocks( open fun generateCssBlocks(
@@ -203,12 +217,12 @@ abstract class CssGenerator {
prop(finalStyle) prop(finalStyle)
} }
css.append(finalStyle.generatePropertyCss(" $indent", sortProperties)) css.append(finalStyle.generatePropertyCss(" $indent", sortProperties, minified))
if (css.isNotBlank()) { if (css.isNotBlank()) {
val builder = StringBuilder() val builder = StringBuilder()
check (allowCommaInSelector || !name.contains(',')) { check (allowCommaInSelector || (name.indexOf(',') == -1)) {
"Comma is not allowed in selector (option is set in generateCss call)" "Comma is not allowed in selector (option is set in generateCss call)"
} }
@@ -218,40 +232,79 @@ abstract class CssGenerator {
//builder.append(" {\n") //builder.append(" {\n")
finalStyle.fontFace?.let { ff -> finalStyle.fontFace?.let { ff ->
builder.append(" $indent") if (!minified) {
builder.append("@font-face {\n") builder.append(" $indent")
builder.append(ff.generatePropertyCss(" $indent", sortProperties)) }
builder.append(" $indent") builder.append("@font-face")
builder.append("}\n") 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 -> finalStyle.keyFrames.let { kf ->
kf.keys.sorted().forEach { frameName -> kf.keys.sorted().forEach { frameName ->
val css = kf[frameName] val css = kf[frameName]
builder.append(" $indent") if (!minified) {
builder.append(" $indent")
}
builder.append("@keyframes ") builder.append("@keyframes ")
builder.append(frameName) builder.append(frameName)
builder.append(" {\n") if (!minified) {
builder.append(" ")
}
builder.append("{")
if (!minified) {
builder.append("\n")
}
css?.let { css -> css?.let { css ->
for ((nr, style) in css.frames) { for ((nr, style) in css.frames) {
builder.append(" $indent") if (!minified) {
builder.append(" $indent")
}
builder.append("${nr}% ") builder.append("${nr}% ")
builder.append(" $indent") if (!minified) {
builder.append("{\n") builder.append(" $indent")
}
builder.append("{")
if (!minified) {
builder.append("\n")
}
val finalStyle = Style() val finalStyle = Style()
style(finalStyle) style(finalStyle)
builder.append(finalStyle.generatePropertyCss(" $indent", sortProperties)) builder.append(finalStyle.generatePropertyCss(" $indent", sortProperties, minified))
builder.append(" $indent") if (!minified) {
builder.append("}\n") builder.append(" $indent")
}
builder.append("}")
if (!minified) {
builder.append("\n")
}
} }
builder.append(" $indent") if (!minified) {
builder.append("}\n") 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]") ValueDescriptionProvider("[${name.description()}^=$value]")
@CssTagMarker @CssTagMarker
open class Style : CssGenerator() { open class InlineStyle : CssGenerator() {
var fontFace: FontFace? = null
var keyFrames: MutableMap<String, KeyFrames> = mutableMapOf()
private val validators = mapOf<String, List<Validator>>( private val validators = mapOf<String, List<Validator>>(
"background-position" to listOf(InitialInheritSingleValue()), "background-position" to listOf(InitialInheritSingleValue()),
@@ -393,82 +444,6 @@ open class Style : CssGenerator() {
definitions[selector]?.add(style) 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) { fun active(style: Css) {
addStyle(":active", style) addStyle(":active", style)
} }
@@ -485,30 +460,10 @@ open class Style : CssGenerator() {
addStyle(":hover", style) 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) { fun visited(style: Css) {
addStyle(":visited", style) addStyle(":visited", style)
} }
fun not(selector: DescriptionProvider, style: Css) {
addStyle(":not(${selector.description()})", style)
}
fun plain(name: String, value: String) { fun plain(name: String, value: String) {
props[name] = prp(value) props[name] = prp(value)
} }
@@ -907,6 +862,10 @@ open class Style : CssGenerator() {
props["content"] = prp(content) props["content"] = prp(content)
} }
fun content(content: String) {
props["content"] = prp(content)
}
fun counterIncrement(increment: String) { fun counterIncrement(increment: String) {
props["counter-increment"] = prp(increment) props["counter-increment"] = prp(increment)
} }
@@ -971,12 +930,6 @@ open class Style : CssGenerator() {
props["font"] = prp(font) props["font"] = prp(font)
} }
fun fontFace(face: FontFace.() -> Unit) {
fontFace = FontFace()
face.invoke(fontFace!!)
}
fun fontFamily(font: String) { fun fontFamily(font: String) {
props["font-family"] = prp(font) props["font-family"] = prp(font)
} }
@@ -1066,8 +1019,8 @@ open class Style : CssGenerator() {
} }
fun gridGap( fun gridGap(
rowGap: Measurement = Measurement.px(0), rowGap: Measurement = 0.px,
columnGap: Measurement = Measurement.px(0) columnGap: Measurement = 0.px
) { ) {
props["grid-gap"] = prp(rowGap, columnGap) props["grid-gap"] = prp(rowGap, columnGap)
} }
@@ -1132,10 +1085,6 @@ open class Style : CssGenerator() {
props["hyphens"] = prp(hyphens) props["hyphens"] = prp(hyphens)
} }
fun import(style: Css) {
style(this)
}
fun isolation(isolation: Isolation) { fun isolation(isolation: Isolation) {
props["isolation"] = prp(isolation) props["isolation"] = prp(isolation)
} }
@@ -1144,14 +1093,6 @@ open class Style : CssGenerator() {
props["justify-content"] = prp(content) 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) { fun left(left: Measurement) {
props["left"] = prp(left) 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 @CssTagMarker
open class ConditionalStyle : Style() { open class ConditionalStyle : Style() {
var media: MutableMap<String, ConditionalCss> = mutableMapOf() 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.BorderStyle
import nl.astraeus.css.properties.Color 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.Measurement
import nl.astraeus.css.properties.em import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.hsla import nl.astraeus.css.properties.hsla
@@ -128,4 +130,28 @@ class Examples {
combineEqualBlocks = true 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()) println(css2.generateCss())
} }
@Test @Test
fun testOr() { fun testOr() {
val css = style { val css = style {