Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e1c1cd99f | |||
| 996a8f385e | |||
| d2349c9308 | |||
| e0a4ff54de | |||
| 3f5f1c6543 | |||
| ac491761d9 | |||
| 0d8157cabf | |||
| 1e37ac07ba | |||
| 780dd0782a | |||
| 70a52a3bb5 | |||
| 68ce4ffa16 | |||
| 9f3be7cadd | |||
| 9217476ae7 | |||
| 7e86441d84 | |||
| 6375a0d78d | |||
| b2c112f711 | |||
| 95c190defd |
21
LICENSE
Normal file
21
LICENSE
Normal 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.
|
||||
170
build.gradle.kts
170
build.gradle.kts
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
|
||||
|
||||
16
readme.md
16
readme.md
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
31
src/commonMain/kotlin/nl/astraeus/css/properties/Calc.kt
Normal file
31
src/commonMain/kotlin/nl/astraeus/css/properties/Calc.kt
Normal 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())
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ open class CssProperty(
|
||||
|
||||
override fun css(): String = value
|
||||
|
||||
override fun toString(): String = value
|
||||
}
|
||||
|
||||
fun text(value: String) = TextProperty(value)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
20
src/commonTest/kotlin/nl/astraeus/css/ColorTest.kt
Normal file
20
src/commonTest/kotlin/nl/astraeus/css/ColorTest.kt
Normal 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())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
18
src/commonTest/kotlin/nl/astraeus/css/TestCalcExpression.kt
Normal file
18
src/commonTest/kotlin/nl/astraeus/css/TestCalcExpression.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,6 @@ class TestCssBuilder {
|
||||
println(css2.generateCss())
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testOr() {
|
||||
val css = style {
|
||||
|
||||
Reference in New Issue
Block a user