diff --git a/build.mill b/build.mill index 442cb2d..a221ffe 100644 --- a/build.mill +++ b/build.mill @@ -49,10 +49,32 @@ object example extends ScalaCommon: PathRef(Task.dest) } + def tailwindConfig = Task.Source(moduleDir / "tailwind.css") + + def generateCss = Task { + sources() + os.proc( + "tailwindcss", + "--minify", + "--input", + tailwindConfig().path + ).call().out.text() + } + + def cssResources = Task { + os.write( + target = Task.dest / "public" / "app.css", + data = generateCss(), + createFolders = true + ) + PathRef(Task.dest) + } + def resources = Task { - super.resources() ++ Seq(scaliveBundle()) + super.resources() :+ scaliveBundle() :+ cssResources() } object js extends TypeScriptModule: def mainFileName = "app.js" def npmDeps = Seq("phoenix@1.7.21", "phoenix_live_view@1.1.8", "topbar@3.0.0") +end example diff --git a/example/src/ExampleLiveView.scala b/example/src/ExampleLiveView.scala index 4f2a3e6..0caec78 100644 --- a/example/src/ExampleLiveView.scala +++ b/example/src/ExampleLiveView.scala @@ -31,38 +31,66 @@ class ExampleLiveView(someParam: String) extends LiveView[Msg, Model]: def view(model: Dyn[Model]) = div( - h1(someParam), - h2(model(_.cls)), + h1( + cls := "text-2xl font-semibold tracking-tight text-gray-900", + someParam + ), + cls := "max-w-2xl mx-auto bg-white shadow rounded-2xl p-6 space-y-6", idAttr := "42", - cls := model(_.cls), ul( + cls := "divide-y divide-gray-200", model(_.elems).splitByIndex((_, elem) => li( - "Nom: ", - elem(_.name), - " Age: ", - elem(_.age.toString) + cls := "py-3 flex flex-wrap items-center justify-between gap-2", + span( + cls := "text-gray-700", + "Nom: ", + span(cls := "font-medium", elem(_.name)) + ), + span( + cls := "text-sm text-gray-500", + "Age: ", + span(cls := "font-semibold text-gray-700", elem(_.age.toString)) + ) ) ) ), - button( - phx.click := Msg.IncAge(1), - "Inc age" - ), - br(), - br(), - br(), - button( - phx.click := Msg.ToggleCounter, - model(_.isVisible match - case true => "Hide counter" - case false => "Show counter") + div( + cls := "flex flex-wrap items-center gap-3", + button( + cls := "inline-flex items-center rounded-lg px-3 py-2 text-sm font-medium bg-gray-900 text-white shadow hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-900/30", + phx.click := Msg.IncAge(1), + "Inc age" + ), + span(cls := "grow"), + button( + cls := "inline-flex items-center rounded-lg px-3 py-2 text-sm font-medium ring-1 ring-inset ring-gray-300 text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-gray-400/30", + phx.click := Msg.ToggleCounter, + model(_.isVisible match + case true => "Hide counter" + case false => "Show counter") + ) ), model.when(_.isVisible)( div( - button(phx.click := Msg.DecCounter, "-"), - div(model(_.counter.toString)), - button(phx.click := Msg.IncCounter, "+") + cls := "rounded-xl border border-gray-200 p-4 bg-gray-50", + div( + cls := "flex items-center justify-center gap-4", + button( + cls := "inline-flex items-center justify-center h-9 w-9 rounded-lg ring-1 ring-inset ring-gray-300 text-gray-700 hover:bg-white focus:outline-none focus:ring-2 focus:ring-gray-400/30", + phx.click := Msg.DecCounter, + "-" + ), + div( + cls := "min-w-[4rem] text-center text-lg font-semibold text-gray-900", + model(_.counter.toString) + ), + button( + cls := "inline-flex items-center justify-center h-9 w-9 rounded-lg bg-gray-900 text-white shadow hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-900/30", + phx.click := Msg.IncCounter, + "+" + ) + ) ) ) ) @@ -83,6 +111,5 @@ object ExampleLiveView: final case class Model( isVisible: Boolean, counter: Int, - elems: List[NestedModel], - cls: String = "text-xs") + elems: List[NestedModel]) final case class NestedModel(name: String, age: Int) diff --git a/example/src/RootLayout.scala b/example/src/RootLayout.scala index 3f26530..9d8eb66 100644 --- a/example/src/RootLayout.scala +++ b/example/src/RootLayout.scala @@ -8,6 +8,7 @@ object RootLayout: metaTag(charset := "utf-8"), metaTag(nameAttr := "viewport", contentAttr := "width=device-width, initial-scale=1"), scriptTag(defer := true, typ := "text/javascript", src := "/static/app.js"), + linkTag(rel := "stylesheet", href := "/static/app.css"), titleTag("Scalive Example") ), bodyTag( diff --git a/example/tailwind.css b/example/tailwind.css new file mode 100644 index 0000000..058b8d2 --- /dev/null +++ b/example/tailwind.css @@ -0,0 +1,7 @@ +@import 'tailwindcss'; + +@plugin '@tailwindcss/forms'; +@plugin '@tailwindcss/typography'; +@plugin '@tailwindcss/aspect-ratio'; + +@source './src/**/*.scala'; diff --git a/flake.nix b/flake.nix index 753ed4f..fb0b6a1 100644 --- a/flake.nix +++ b/flake.nix @@ -11,10 +11,10 @@ let pkgs = nixpkgs.legacyPackages.${system}; mill = pkgs.mill.overrideAttrs (old: rec { - version = "1.0.3"; + version = "1.0.4"; src = pkgs.fetchurl { url = "https://repo1.maven.org/maven2/com/lihaoyi/mill-dist-native-linux-amd64/${version}/mill-dist-native-linux-amd64-${version}.exe"; - hash = "sha256-Q7Yc9MXnMmggyMeNq0nEoL1iNTGEbJpdwH2j8/JkJyI="; + hash = "sha256-rgAqlTCZc8nedUU2D+Klo3KY0z9sI0KJczdaugM3//8="; }; buildInputs = [ pkgs.zlib ]; nativeBuildInputs = [ @@ -41,6 +41,7 @@ buildInputs = [ mill pkgs.scalafmt + pkgs.tailwindcss_4 ]; shellHook = "mill --bsp-install"; };