Skip to content

Commit 5e8079e

Browse files
authored
Merge pull request #146 from iamgio/css-function
feat(stdlib): add `.css` and `.cssproperties`
2 parents 869135e + 2187194 commit 5e8079e

File tree

6 files changed

+159
-30
lines changed

6 files changed

+159
-30
lines changed

quarkdown-core/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ dependencies {
1212
implementation(kotlin("reflect"))
1313
implementation("com.github.h0tk3y.betterParse:better-parse:0.4.4")
1414
implementation("org.apache.logging.log4j:log4j-core:2.24.3")
15-
implementation("org.apache.commons:commons-text:1.13.0")
15+
implementation("org.apache.commons:commons-text:1.13.1")
1616
implementation("com.github.ajalt.colormath:colormath:3.6.1")
1717
implementation("com.github.fracpete:romannumerals4j:0.0.1")
1818
implementation("org.jbibtex:jbibtex:1.0.20")

quarkdown-html/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies {
1010
implementation(project(":quarkdown-core"))
1111
implementation(project(":quarkdown-interaction"))
1212
implementation(project(":quarkdown-server"))
13-
implementation("org.apache.commons:commons-text:1.13.0")
13+
implementation("org.apache.commons:commons-text:1.13.1")
1414
}
1515

1616
tasks.compileSass {

quarkdown-stdlib/src/main/kotlin/com/quarkdown/stdlib/Injection.kt

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import com.quarkdown.core.ast.base.block.Html
44
import com.quarkdown.core.function.library.loader.Module
55
import com.quarkdown.core.function.library.loader.moduleOf
66
import com.quarkdown.core.function.reflect.annotation.LikelyBody
7+
import com.quarkdown.core.function.reflect.annotation.Name
8+
import com.quarkdown.core.function.value.Value
79
import com.quarkdown.core.function.value.wrappedAsValue
810

911
/**
@@ -13,14 +15,76 @@ import com.quarkdown.core.function.value.wrappedAsValue
1315
val Injection: Module =
1416
moduleOf(
1517
::html,
18+
::css,
19+
::cssProperties,
1620
)
1721

1822
/**
19-
* Creates an HTML element, which is rendered as-is without any additional processing or escaping.
23+
* Creates an HTML element, which is rendered as-is without any additional processing or escaping,
24+
* as long as the rendering target supports HTML.
2025
* @param content raw HTML content to inject
2126
* @return a new [Html] node
2227
* @wiki HTML
2328
*/
2429
fun html(
2530
@LikelyBody content: String,
2631
) = Html(content).wrappedAsValue()
32+
33+
/**
34+
* Creates a `<style>` HTML element with the provided CSS content.
35+
* The content is wrapped in a `<style>` tag and rendered as-is,
36+
* without any additional processing or escaping, as long as the rendering target supports HTML.
37+
*
38+
* Example:
39+
* ```
40+
* .css
41+
* body {
42+
* background-color: green !important;
43+
* }
44+
* ```
45+
*
46+
* @param content raw CSS content to inject
47+
* @return a new [Html] node representing the style element
48+
* @see [cssProperties] for a more structured way to override CSS properties.
49+
* @wiki CSS
50+
*/
51+
fun css(
52+
@LikelyBody content: String,
53+
) = Html("<style data-hidden=\"\">$content</style>").wrappedAsValue()
54+
55+
private const val CSS_ROOT_SELECTOR = ":root"
56+
private const val CSS_PROPERTY_PREFIX = "--qd-"
57+
58+
/**
59+
* Overrides the value of Quarkdown CSS properties.
60+
* Each entry corresponds to a Quarkdown CSS property name and its value.
61+
* The names will be prefixed with `--qd-` to match the Quarkdown CSS variable naming convention.
62+
*
63+
* For example:
64+
* ```
65+
* .cssproperties
66+
* - background-color: green
67+
* - main-font-size: 20px
68+
* ```
69+
*
70+
* For a complete list of properties, see the [global theme](https://github.com/iamgio/quarkdown/blob/main/quarkdown-html/src/main/resources/render/theme/global.scss).
71+
* Unknown properties will be ignored.
72+
*
73+
* The content is wrapped in a `<style>` tag and rendered as-is,
74+
* without any additional processing or escaping, as long as the rendering target supports HTML.
75+
* @param properties a map of CSS property names and their values
76+
* @return a new [Html] node representing the style element
77+
* @wiki CSS
78+
*/
79+
@Name("cssproperties")
80+
fun cssProperties(properties: Map<String, Value<*>>) =
81+
css(
82+
buildString {
83+
append(CSS_ROOT_SELECTOR)
84+
append(" { ")
85+
properties.forEach { (name, value) ->
86+
append("$CSS_PROPERTY_PREFIX$name: ${value.unwrappedValue} !important; ")
87+
}
88+
append("}")
89+
},
90+
)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.quarkdown.test
2+
3+
import com.quarkdown.test.util.execute
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
7+
/**
8+
* Tests for language injection functions.
9+
*/
10+
class InjectionTest {
11+
@Test
12+
fun html() {
13+
execute(".html\n\tHello, <b>world</b>!") {
14+
assertEquals("Hello, <b>world</b>!", it)
15+
}
16+
}
17+
18+
@Test
19+
fun `block html`() {
20+
execute(
21+
"""
22+
Hello
23+
24+
.html
25+
<p><sup>World</sup></p>
26+
""".trimIndent(),
27+
) {
28+
assertEquals(
29+
"<p>Hello</p><p><sup>World</sup></p>",
30+
it,
31+
)
32+
}
33+
}
34+
35+
@Test
36+
fun `inline html`() {
37+
execute("Hello, .html {<sup>World</sup>}") {
38+
assertEquals(
39+
"<p>Hello, <sup>World</sup></p>",
40+
it,
41+
)
42+
}
43+
}
44+
45+
@Test
46+
fun css() {
47+
execute(
48+
"""
49+
.css
50+
.class {
51+
background: red;
52+
}
53+
""".trimIndent(),
54+
) {
55+
assertEquals(
56+
"<style data-hidden=\"\">.class {\n background: red;\n}</style>",
57+
it,
58+
)
59+
}
60+
}
61+
62+
@Test
63+
fun `css from file`() {
64+
execute(".css {.read {css/style.css}}") {
65+
assertEquals(
66+
"<style data-hidden=\"\">body {\n background-color: orange;\n}</style>",
67+
it,
68+
)
69+
}
70+
}
71+
72+
@Test
73+
fun `css properties`() {
74+
execute(
75+
"""
76+
.cssproperties
77+
- background-color: blue
78+
- main-font-size: 16px
79+
""".trimIndent(),
80+
) {
81+
assertEquals(
82+
"<style data-hidden=\"\">" +
83+
":root { --qd-background-color: blue !important; --qd-main-font-size: 16px !important; }" +
84+
"</style>",
85+
it,
86+
)
87+
}
88+
}
89+
}

quarkdown-test/src/test/kotlin/com/quarkdown/test/NodesTest.kt

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -310,31 +310,4 @@ class NodesTest {
310310
)
311311
}
312312
}
313-
314-
@Test
315-
fun `block html`() {
316-
execute(
317-
"""
318-
Hello
319-
320-
.html
321-
<p><sup>World</sup></p>
322-
""".trimIndent(),
323-
) {
324-
assertEquals(
325-
"<p>Hello</p><p><sup>World</sup></p>",
326-
it,
327-
)
328-
}
329-
}
330-
331-
@Test
332-
fun `inline html`() {
333-
execute("Hello, .html {<sup>World</sup>}") {
334-
assertEquals(
335-
"<p>Hello, <sup>World</sup></p>",
336-
it,
337-
)
338-
}
339-
}
340313
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
body {
2+
background-color: orange;
3+
}

0 commit comments

Comments
 (0)