diff --git a/build.sc b/build.sc index fbbc3b8..7f729cc 100644 --- a/build.sc +++ b/build.sc @@ -8,24 +8,25 @@ trait CommonModule extends ScalaModule { def scalaVersion = "3.1.1" - def scalacOptions = Seq( - "-encoding", - "utf8", - "-deprecation", - "-explain-types", - "-explain", - "-feature", - "-language:experimental.macros", - "-language:higherKinds", - "-language:implicitConversions", - "-unchecked", - "-Xfatal-warnings", - "-Ykind-projector" - ) + def scalacOptions = T { + super.scalacOptions() ++ Seq( + "-encoding", + "utf8", + "-deprecation", + "-explain-types", + "-feature", + "-language:experimental.macros", + "-language:higherKinds", + "-language:implicitConversions", + "-unchecked", + "-Xfatal-warnings", + "-Ykind-projector" + ) + } } trait CommonJSModule extends CommonModule with ScalaJSModule { - def scalaJSVersion = "1.8.0" + def scalaJSVersion = "1.9.0" } trait CrossPlatformModule extends Module { outer => diff --git a/build.sc b/build.sc index fbbc3b8..7f729cc 100644 --- a/build.sc +++ b/build.sc @@ -8,24 +8,25 @@ trait CommonModule extends ScalaModule { def scalaVersion = "3.1.1" - def scalacOptions = Seq( - "-encoding", - "utf8", - "-deprecation", - "-explain-types", - "-explain", - "-feature", - "-language:experimental.macros", - "-language:higherKinds", - "-language:implicitConversions", - "-unchecked", - "-Xfatal-warnings", - "-Ykind-projector" - ) + def scalacOptions = T { + super.scalacOptions() ++ Seq( + "-encoding", + "utf8", + "-deprecation", + "-explain-types", + "-feature", + "-language:experimental.macros", + "-language:higherKinds", + "-language:implicitConversions", + "-unchecked", + "-Xfatal-warnings", + "-Ykind-projector" + ) + } } trait CommonJSModule extends CommonModule with ScalaJSModule { - def scalaJSVersion = "1.8.0" + def scalaJSVersion = "1.9.0" } trait CrossPlatformModule extends Module { outer => diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala index 0fc8796..b8da1f9 100644 --- a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala @@ -3,19 +3,22 @@ import CustomAttrs.ariaHidden import com.raquo.laminar.api.L.{*, given} import com.raquo.domtypes.generic.codecs.BooleanAsTrueFalseStringCodec +import works.iterative.ui.components.tailwind.Macros // TODO: render icon or picture based on img signal class Avatar($avatarImg: Signal[Option[String]]): inline def avatarPlaceholder(size: Int): HtmlElement = div( - cls := s"rounded-full text-indigo-200 bg-indigo-500 h-${size} w-${size} flex items-center justify-center", + cls := s"rounded-full text-indigo-200 bg-indigo-500 flex items-center justify-center", + cls := Macros.size(size), Icons.outline.user(size - 2) ) inline def avatarImage(size: Int): Signal[HtmlElement] = $avatarImg.split(_ => ())((_, _, $url) => img( - cls := s"w-$size h-$size rounded-full", + cls := s"rounded-full", + cls := Macros.size(size), src <-- $url, alt := "" ) diff --git a/build.sc b/build.sc index fbbc3b8..7f729cc 100644 --- a/build.sc +++ b/build.sc @@ -8,24 +8,25 @@ trait CommonModule extends ScalaModule { def scalaVersion = "3.1.1" - def scalacOptions = Seq( - "-encoding", - "utf8", - "-deprecation", - "-explain-types", - "-explain", - "-feature", - "-language:experimental.macros", - "-language:higherKinds", - "-language:implicitConversions", - "-unchecked", - "-Xfatal-warnings", - "-Ykind-projector" - ) + def scalacOptions = T { + super.scalacOptions() ++ Seq( + "-encoding", + "utf8", + "-deprecation", + "-explain-types", + "-feature", + "-language:experimental.macros", + "-language:higherKinds", + "-language:implicitConversions", + "-unchecked", + "-Xfatal-warnings", + "-Ykind-projector" + ) + } } trait CommonJSModule extends CommonModule with ScalaJSModule { - def scalaJSVersion = "1.8.0" + def scalaJSVersion = "1.9.0" } trait CrossPlatformModule extends Module { outer => diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala index 0fc8796..b8da1f9 100644 --- a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala @@ -3,19 +3,22 @@ import CustomAttrs.ariaHidden import com.raquo.laminar.api.L.{*, given} import com.raquo.domtypes.generic.codecs.BooleanAsTrueFalseStringCodec +import works.iterative.ui.components.tailwind.Macros // TODO: render icon or picture based on img signal class Avatar($avatarImg: Signal[Option[String]]): inline def avatarPlaceholder(size: Int): HtmlElement = div( - cls := s"rounded-full text-indigo-200 bg-indigo-500 h-${size} w-${size} flex items-center justify-center", + cls := s"rounded-full text-indigo-200 bg-indigo-500 flex items-center justify-center", + cls := Macros.size(size), Icons.outline.user(size - 2) ) inline def avatarImage(size: Int): Signal[HtmlElement] = $avatarImg.split(_ => ())((_, _, $url) => img( - cls := s"w-$size h-$size rounded-full", + cls := s"rounded-full", + cls := Macros.size(size), src <-- $url, alt := "" ) diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala index 4a8b065..b49255d 100644 --- a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala @@ -5,6 +5,7 @@ import com.raquo.laminar.api.L.svg.{*, given} import com.raquo.laminar.builders.SvgBuilders import com.raquo.laminar.keys.ReactiveSvgAttr +import works.iterative.ui.components.tailwind.Macros // TODO: fix sizes, colors, hover and stuff, normalize and amend on call site object Icons: @@ -16,7 +17,7 @@ inline def bell(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -32,7 +33,7 @@ inline def `check-circle`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -47,7 +48,7 @@ inline def `document-add`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -62,7 +63,7 @@ inline def `external-link`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -77,7 +78,7 @@ inline def menu(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -93,7 +94,7 @@ inline def `status-offline`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -109,7 +110,7 @@ inline def user(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -125,7 +126,7 @@ inline def x(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -146,7 +147,7 @@ inline def users(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -158,7 +159,7 @@ inline def `location-marker`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -172,7 +173,7 @@ inline def calendar(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -186,7 +187,7 @@ inline def `chevron-right`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -200,7 +201,7 @@ inline def search(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -214,7 +215,7 @@ inline def filter(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -228,7 +229,7 @@ inline def `arrow-narrow-left`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -242,7 +243,7 @@ inline def home(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -254,7 +255,7 @@ inline def paperclip(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size} text-gray-400", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", diff --git a/build.sc b/build.sc index fbbc3b8..7f729cc 100644 --- a/build.sc +++ b/build.sc @@ -8,24 +8,25 @@ trait CommonModule extends ScalaModule { def scalaVersion = "3.1.1" - def scalacOptions = Seq( - "-encoding", - "utf8", - "-deprecation", - "-explain-types", - "-explain", - "-feature", - "-language:experimental.macros", - "-language:higherKinds", - "-language:implicitConversions", - "-unchecked", - "-Xfatal-warnings", - "-Ykind-projector" - ) + def scalacOptions = T { + super.scalacOptions() ++ Seq( + "-encoding", + "utf8", + "-deprecation", + "-explain-types", + "-feature", + "-language:experimental.macros", + "-language:higherKinds", + "-language:implicitConversions", + "-unchecked", + "-Xfatal-warnings", + "-Ykind-projector" + ) + } } trait CommonJSModule extends CommonModule with ScalaJSModule { - def scalaJSVersion = "1.8.0" + def scalaJSVersion = "1.9.0" } trait CrossPlatformModule extends Module { outer => diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala index 0fc8796..b8da1f9 100644 --- a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Avatar.scala @@ -3,19 +3,22 @@ import CustomAttrs.ariaHidden import com.raquo.laminar.api.L.{*, given} import com.raquo.domtypes.generic.codecs.BooleanAsTrueFalseStringCodec +import works.iterative.ui.components.tailwind.Macros // TODO: render icon or picture based on img signal class Avatar($avatarImg: Signal[Option[String]]): inline def avatarPlaceholder(size: Int): HtmlElement = div( - cls := s"rounded-full text-indigo-200 bg-indigo-500 h-${size} w-${size} flex items-center justify-center", + cls := s"rounded-full text-indigo-200 bg-indigo-500 flex items-center justify-center", + cls := Macros.size(size), Icons.outline.user(size - 2) ) inline def avatarImage(size: Int): Signal[HtmlElement] = $avatarImg.split(_ => ())((_, _, $url) => img( - cls := s"w-$size h-$size rounded-full", + cls := s"rounded-full", + cls := Macros.size(size), src <-- $url, alt := "" ) diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala index 4a8b065..b49255d 100644 --- a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Icons.scala @@ -5,6 +5,7 @@ import com.raquo.laminar.api.L.svg.{*, given} import com.raquo.laminar.builders.SvgBuilders import com.raquo.laminar.keys.ReactiveSvgAttr +import works.iterative.ui.components.tailwind.Macros // TODO: fix sizes, colors, hover and stuff, normalize and amend on call site object Icons: @@ -16,7 +17,7 @@ inline def bell(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -32,7 +33,7 @@ inline def `check-circle`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -47,7 +48,7 @@ inline def `document-add`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -62,7 +63,7 @@ inline def `external-link`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -77,7 +78,7 @@ inline def menu(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -93,7 +94,7 @@ inline def `status-offline`(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -109,7 +110,7 @@ inline def user(size: Int = defaultSize) = svg( - cls := s"w-${size} h-${size}", + cls := Macros.size(size), fill := "none", stroke := "currentColor", viewBox := "0 0 24 24", @@ -125,7 +126,7 @@ inline def x(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", fill := "none", viewBox := "0 0 24 24", @@ -146,7 +147,7 @@ inline def users(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -158,7 +159,7 @@ inline def `location-marker`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -172,7 +173,7 @@ inline def calendar(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -186,7 +187,7 @@ inline def `chevron-right`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -200,7 +201,7 @@ inline def search(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -214,7 +215,7 @@ inline def filter(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -228,7 +229,7 @@ inline def `arrow-narrow-left`(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -242,7 +243,7 @@ inline def home(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size}", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", @@ -254,7 +255,7 @@ inline def paperclip(size: Int = defaultSize) = svg( - cls := s"h-${size} w-${size} text-gray-400", + cls := Macros.size(size), xmlns := "http://www.w3.org/2000/svg", viewBox := "0 0 20 20", fill := "currentColor", diff --git a/ui/src/main/scala/fiftyforms/ui/components/tailwind/Macros.scala b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Macros.scala new file mode 100644 index 0000000..f36d7ed --- /dev/null +++ b/ui/src/main/scala/fiftyforms/ui/components/tailwind/Macros.scala @@ -0,0 +1,16 @@ +package works.iterative.ui.components.tailwind + +import scala.quoted.* + +/** Tailwind uses JIT compiler that needs to find relevant classes in the code + * in a form that is recognizable - eg. "w-10", not ("w-" + "10") + * + * Macros compute the strings during compile time. + */ +object Macros: + + inline def size(edgeSize: Int): String = ${ sizeImpl('edgeSize) } + + private def sizeImpl(edgeSize: Expr[Int])(using Quotes): Expr[String] = '{ + "h-" + $edgeSize + " w-" + $edgeSize + }