Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cssdsl.bootstrap3

import munit.FunSuite
import zio.http.template2._

class ZioHttpTemplate2DslSpec extends FunSuite {
test("chain CSS classes onto a ZIO HTTP template2 element") {
import Dsl._

val result =
div(className := C.panelSuccess).panel.hiddenXs(
h3.panelTitle("Panel title")
)

assertEquals(
result.render,
"""<div class="panel-success panel hidden-xs"><h3 class="panel-title">Panel title</h3></div>"""
)
}

test("compose C values in a template2 className attribute") {
import Dsl._

val result = div(className := (C.panel, C.hiddenXs))

assertEquals(result.render, """<div class="panel hidden-xs"></div>""")
}

test("compose C collections in a template2 className attribute") {
import Dsl._

val result = div(className := List(C.panel, C.hiddenXs))

assertEquals(result.render, """<div class="panel hidden-xs"></div>""")
}

test("do not convert C values into template2 text children") {
val errors = compileErrors("""
import cssdsl.bootstrap3.Dsl._
import zio.http.template2._
div(C.panel)
""")

assert(errors.nonEmpty)
}

test("preserve an existing single-value class attribute") {
import Dsl._

val result = div(Dom.attr("class", "custom")).panel

assertEquals(result.render, """<div class="custom panel"></div>""")
}

test("normalize an existing class attribute to space separation") {
import Dsl._

val result = div(Dom.multiAttr("class", AttributeSeparator.Comma, "custom")).panel

assertEquals(result.render, """<div class="custom panel"></div>""")
}
}
25 changes: 25 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ def scalatagsSettings(config: CssDslConfig) = Seq(
cssDslConfig := config
)

def zioHttpTemplate2Settings(config: CssDslConfig) = Seq(
libraryDependencies += "dev.zio" %% "zio-http" % "3.11.3",
cssVariant := TargetImpl.ZioHttpTemplate2,
cssDslConfig := config
)

val bootstrap3Config =
CssDslConfig(
"Bootstrap 3",
Expand Down Expand Up @@ -116,38 +122,57 @@ lazy val bootstrap3_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(bootstrap3Config))
lazy val bootstrap3_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(bootstrap3Config))
lazy val bootstrap3_ziohttp =
project
.enablePlugins(GeneratorPlugin)
.settings(zioHttpTemplate2Settings(bootstrap3Config))
.settings(libraryDependencies += "org.scalameta" %% "munit" % "1.2.4" % Test)

lazy val bootstrap4_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(bootstrap4Config))
lazy val bootstrap4_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(bootstrap4Config))
lazy val bootstrap4_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(bootstrap4Config))

lazy val bootstrap5_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(bootstrap5Config))
lazy val bootstrap5_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(bootstrap5Config))
lazy val bootstrap5_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(bootstrap5Config))

lazy val bulma_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(bulmaConfig))
lazy val bulma_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(bulmaConfig))
lazy val bulma_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(bulmaConfig))

lazy val tabler_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(tablerConfig))
lazy val tabler_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(tablerConfig))
lazy val tabler_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(tablerConfig))

lazy val semanticui_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(semanticUiConfig))
lazy val semanticui_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(semanticUiConfig))
lazy val semanticui_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(semanticUiConfig))

lazy val fomanticui_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(fomanticUiConfig))
lazy val fomanticui_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(fomanticUiConfig))
lazy val fomanticui_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(fomanticUiConfig))

lazy val fontawesome_scalajsreact =
project.enablePlugins(ScalaJSPlugin, GeneratorPlugin).settings(scalaJsReactSettings(fontawesomeUiConfig))
lazy val fontawesome_scalatags =
project.enablePlugins(GeneratorPlugin).settings(scalatagsSettings(fontawesomeUiConfig))
lazy val fontawesome_ziohttp =
project.enablePlugins(GeneratorPlugin).settings(zioHttpTemplate2Settings(fontawesomeUiConfig))
1 change: 1 addition & 0 deletions generateInstructions.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ LocalRootProject / generateInstallInstructions := {
val (op, library) = moduleNameSuffix match {
case "scalatags" => "%%" -> "`scalatags.Text` (JVM)"
case "scalajsreact" => "%%%" -> "scalajs-react (scala.js)"
case "ziohttp" => "%%" -> "ZIO HTTP `template2`"
}
List(
config.name,
Expand Down
14 changes: 13 additions & 1 deletion project/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ class Generator(packageName: String,

def defs: List[Stat] =
classes.toList.map { cls =>
Defn.Val(List(Mod.Lazy()), List(Pat.Var(Term.Name(ident(cls)))), None, q"this.op($cls)")
val name = Term.Name(ident(cls))
q"def $name: A = this.op($cls)"
}

def cachedDefs: List[Stat] =
classes.toList.map { cls =>
val name = Pat.Var(Term.Name(ident(cls)))
q"override lazy val $name: A = this.op($cls)"
}

def allDefs = defs :+ q"protected def op(clz: String): A"
Expand All @@ -51,6 +58,11 @@ class Generator(packageName: String,
..$allDefs
}

trait CachedClasses[A] extends Classes[A] {
..$cachedDefs
}

..${variant.support}
${variant.C}

${variant.implicitClass}
Expand Down
42 changes: 40 additions & 2 deletions project/TargetImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import scala.meta._

sealed trait TargetImpl {
def imports: List[Import]
def support: List[Stat] = Nil
def C: Defn.Object
def implicitClass: Defn.Class
}
Expand All @@ -15,7 +16,7 @@ object TargetImpl {

override def C =
q"""
object C extends Classes[TagMod] {
object C extends CachedClasses[TagMod] {
protected override def op(clz: String) = ^.cls := clz
}
"""
Expand All @@ -29,14 +30,51 @@ object TargetImpl {
"""
}

object ZioHttpTemplate2 extends TargetImpl {
override def imports = List(
q"import zio.http.template2.Dom"
)

override def support = List(
q"final case class ClassName(value: String) extends AnyVal",
q"implicit def classNameToString(className: ClassName): String = className.value",
q"implicit def classNamesToStrings(classNames: Iterable[ClassName]): Iterable[String] = classNames.map(_.value)"
)
Comment thread
nafg marked this conversation as resolved.

override def C =
q"""
object C extends CachedClasses[ClassName] {
protected override def op(clz: String): ClassName = ClassName(clz)
}
"""

override def implicitClass = {
// Keep the literal synthetic: parsed string literals require a tokenizer when Scalameta 4.16 renders the tree.
val classAttribute = Lit.String("class")
q"""
implicit class DomElementExtensionMethods(self: Dom.Element)
extends Classes[Dom.Element] {
protected override def op(clz: String): Dom.Element = {
val classes = self.attributes.get($classAttribute) match {
case Some(Dom.AttributeValue.MultiValue(values, _)) => values
case Some(value) => Vector(value.toString)
case None => Vector.empty
}
self(Dom.multiAttr($classAttribute, classes :+ clz))
}
}
"""
}
}

object Scalatags extends TargetImpl {
override def imports = List(
q"import scalatags.Text.all._"
)

override def C =
q"""
object C extends Classes[Modifier] {
object C extends CachedClasses[Modifier] {
protected override def op(clz: String) = cls := clz
}
"""
Expand Down
Loading