diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala new file mode 100644 index 0000000..f2b20ae --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala @@ -0,0 +1,36 @@ +package works.iterative.ui.components.tailwind + +import com.raquo.laminar.api.L.{*, given} +import org.scalajs.dom +import java.time.LocalDate +import works.iterative.core.PlainMultiLine +import java.time.Instant +import java.time.format.DateTimeFormatter +import works.iterative.ui.components.tailwind.CustomAttrs.datetime + +trait HtmlRenderable[A]: + def toHtml(a: A): Modifier[HtmlElement] + extension (a: A) def render: Modifier[HtmlElement] = toHtml(a) + +object HtmlRenderable: + given elementValue: HtmlRenderable[HtmlElement] with + def toHtml(a: HtmlElement): Modifier[HtmlElement] = a + + given stringValue: HtmlRenderable[String] with + def toHtml(v: String): Modifier[HtmlElement] = + com.raquo.laminar.nodes.TextNode(v) + + given dateValue: HtmlRenderable[LocalDate] with + def toHtml(v: LocalDate): Modifier[HtmlElement] = + timeTag(datetime(TimeUtils.formatHtmlDate(v)), TimeUtils.formatDate(v)) + + given instantValue: HtmlRenderable[Instant] with + def toHtml(v: Instant): Modifier[HtmlElement] = + timeTag( + datetime(TimeUtils.formatHtmlDateTime(v)), + TimeUtils.formatDateTime(v) + ) + + given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with + def toHtml(v: PlainMultiLine): Modifier[HtmlElement] = + p(cls("whitespace-pre-wrap"), v.toString) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala new file mode 100644 index 0000000..f2b20ae --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala @@ -0,0 +1,36 @@ +package works.iterative.ui.components.tailwind + +import com.raquo.laminar.api.L.{*, given} +import org.scalajs.dom +import java.time.LocalDate +import works.iterative.core.PlainMultiLine +import java.time.Instant +import java.time.format.DateTimeFormatter +import works.iterative.ui.components.tailwind.CustomAttrs.datetime + +trait HtmlRenderable[A]: + def toHtml(a: A): Modifier[HtmlElement] + extension (a: A) def render: Modifier[HtmlElement] = toHtml(a) + +object HtmlRenderable: + given elementValue: HtmlRenderable[HtmlElement] with + def toHtml(a: HtmlElement): Modifier[HtmlElement] = a + + given stringValue: HtmlRenderable[String] with + def toHtml(v: String): Modifier[HtmlElement] = + com.raquo.laminar.nodes.TextNode(v) + + given dateValue: HtmlRenderable[LocalDate] with + def toHtml(v: LocalDate): Modifier[HtmlElement] = + timeTag(datetime(TimeUtils.formatHtmlDate(v)), TimeUtils.formatDate(v)) + + given instantValue: HtmlRenderable[Instant] with + def toHtml(v: Instant): Modifier[HtmlElement] = + timeTag( + datetime(TimeUtils.formatHtmlDateTime(v)), + TimeUtils.formatDateTime(v) + ) + + given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with + def toHtml(v: PlainMultiLine): Modifier[HtmlElement] = + p(cls("whitespace-pre-wrap"), v.toString) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala deleted file mode 100644 index 2764124..0000000 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala +++ /dev/null @@ -1,31 +0,0 @@ -package works.iterative.ui.components.tailwind - -import com.raquo.laminar.api.L.{*, given} -import org.scalajs.dom -import java.time.LocalDate -import works.iterative.core.PlainMultiLine -import java.time.Instant - -trait HtmlRenderable[A]: - def toHtml(a: A): Node - extension (a: A) def render: Node = toHtml(a) - -object HtmlRenderable: - given elementValue: HtmlRenderable[HtmlElement] with - def toHtml(a: HtmlElement): Node = a - given stringValue: HtmlRenderable[String] with - def toHtml(v: String): Node = - com.raquo.laminar.nodes.TextNode(v) - given dateValue: HtmlRenderable[LocalDate] with - def toHtml(v: LocalDate): Node = - TimeUtils.formatDate(v) - given instantValue: HtmlRenderable[Instant] with - def toHtml(v: Instant): Node = - TimeUtils.formatDateTime(v) - given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with - def toHtml(v: PlainMultiLine): Node = - p( - v.split("\n") - .map(t => Seq(com.raquo.laminar.nodes.TextNode(t), br())) - .flatten: _* - ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala new file mode 100644 index 0000000..f2b20ae --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala @@ -0,0 +1,36 @@ +package works.iterative.ui.components.tailwind + +import com.raquo.laminar.api.L.{*, given} +import org.scalajs.dom +import java.time.LocalDate +import works.iterative.core.PlainMultiLine +import java.time.Instant +import java.time.format.DateTimeFormatter +import works.iterative.ui.components.tailwind.CustomAttrs.datetime + +trait HtmlRenderable[A]: + def toHtml(a: A): Modifier[HtmlElement] + extension (a: A) def render: Modifier[HtmlElement] = toHtml(a) + +object HtmlRenderable: + given elementValue: HtmlRenderable[HtmlElement] with + def toHtml(a: HtmlElement): Modifier[HtmlElement] = a + + given stringValue: HtmlRenderable[String] with + def toHtml(v: String): Modifier[HtmlElement] = + com.raquo.laminar.nodes.TextNode(v) + + given dateValue: HtmlRenderable[LocalDate] with + def toHtml(v: LocalDate): Modifier[HtmlElement] = + timeTag(datetime(TimeUtils.formatHtmlDate(v)), TimeUtils.formatDate(v)) + + given instantValue: HtmlRenderable[Instant] with + def toHtml(v: Instant): Modifier[HtmlElement] = + timeTag( + datetime(TimeUtils.formatHtmlDateTime(v)), + TimeUtils.formatDateTime(v) + ) + + given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with + def toHtml(v: PlainMultiLine): Modifier[HtmlElement] = + p(cls("whitespace-pre-wrap"), v.toString) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala deleted file mode 100644 index 2764124..0000000 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala +++ /dev/null @@ -1,31 +0,0 @@ -package works.iterative.ui.components.tailwind - -import com.raquo.laminar.api.L.{*, given} -import org.scalajs.dom -import java.time.LocalDate -import works.iterative.core.PlainMultiLine -import java.time.Instant - -trait HtmlRenderable[A]: - def toHtml(a: A): Node - extension (a: A) def render: Node = toHtml(a) - -object HtmlRenderable: - given elementValue: HtmlRenderable[HtmlElement] with - def toHtml(a: HtmlElement): Node = a - given stringValue: HtmlRenderable[String] with - def toHtml(v: String): Node = - com.raquo.laminar.nodes.TextNode(v) - given dateValue: HtmlRenderable[LocalDate] with - def toHtml(v: LocalDate): Node = - TimeUtils.formatDate(v) - given instantValue: HtmlRenderable[Instant] with - def toHtml(v: Instant): Node = - TimeUtils.formatDateTime(v) - given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with - def toHtml(v: PlainMultiLine): Node = - p( - v.split("\n") - .map(t => Seq(com.raquo.laminar.nodes.TextNode(t), br())) - .flatten: _* - ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala index 3bb2d6e..d5a78ee 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala @@ -14,17 +14,33 @@ .ofLocalizedDateTime(FormatStyle.SHORT) // TODO: locale // .withLocale(Locale("cs", "CZ")) - .withZone(ZoneId.of("CET")) + .withZone(ZoneId.systemDefault()) val dateFormat = DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT) // TODO: locale // .withLocale(Locale("cs", "CZ")) - .withZone(ZoneId.of("CET")) + .withZone(ZoneId.systemDefault()) + + val htmlDateFormat = + DateTimeFormatter + .ofPattern("yyyy-MM-dd") + .withZone(ZoneId.systemDefault()) + + val htmlDateTimeFormat = + DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) def formatDateTime(i: TemporalAccessor): String = dateTimeFormat.format(i) def formatDate(i: TemporalAccessor): String = dateFormat.format(i) + + def formatHtmlDate(i: TemporalAccessor): String = + htmlDateFormat.format(i) + + def formatHtmlDateTime(i: TemporalAccessor): String = + htmlDateTimeFormat.format(i) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala new file mode 100644 index 0000000..f2b20ae --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/HtmlRenderable.scala @@ -0,0 +1,36 @@ +package works.iterative.ui.components.tailwind + +import com.raquo.laminar.api.L.{*, given} +import org.scalajs.dom +import java.time.LocalDate +import works.iterative.core.PlainMultiLine +import java.time.Instant +import java.time.format.DateTimeFormatter +import works.iterative.ui.components.tailwind.CustomAttrs.datetime + +trait HtmlRenderable[A]: + def toHtml(a: A): Modifier[HtmlElement] + extension (a: A) def render: Modifier[HtmlElement] = toHtml(a) + +object HtmlRenderable: + given elementValue: HtmlRenderable[HtmlElement] with + def toHtml(a: HtmlElement): Modifier[HtmlElement] = a + + given stringValue: HtmlRenderable[String] with + def toHtml(v: String): Modifier[HtmlElement] = + com.raquo.laminar.nodes.TextNode(v) + + given dateValue: HtmlRenderable[LocalDate] with + def toHtml(v: LocalDate): Modifier[HtmlElement] = + timeTag(datetime(TimeUtils.formatHtmlDate(v)), TimeUtils.formatDate(v)) + + given instantValue: HtmlRenderable[Instant] with + def toHtml(v: Instant): Modifier[HtmlElement] = + timeTag( + datetime(TimeUtils.formatHtmlDateTime(v)), + TimeUtils.formatDateTime(v) + ) + + given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with + def toHtml(v: PlainMultiLine): Modifier[HtmlElement] = + p(cls("whitespace-pre-wrap"), v.toString) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala deleted file mode 100644 index 2764124..0000000 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Renderable.scala +++ /dev/null @@ -1,31 +0,0 @@ -package works.iterative.ui.components.tailwind - -import com.raquo.laminar.api.L.{*, given} -import org.scalajs.dom -import java.time.LocalDate -import works.iterative.core.PlainMultiLine -import java.time.Instant - -trait HtmlRenderable[A]: - def toHtml(a: A): Node - extension (a: A) def render: Node = toHtml(a) - -object HtmlRenderable: - given elementValue: HtmlRenderable[HtmlElement] with - def toHtml(a: HtmlElement): Node = a - given stringValue: HtmlRenderable[String] with - def toHtml(v: String): Node = - com.raquo.laminar.nodes.TextNode(v) - given dateValue: HtmlRenderable[LocalDate] with - def toHtml(v: LocalDate): Node = - TimeUtils.formatDate(v) - given instantValue: HtmlRenderable[Instant] with - def toHtml(v: Instant): Node = - TimeUtils.formatDateTime(v) - given plainMultiLineValue: HtmlRenderable[PlainMultiLine] with - def toHtml(v: PlainMultiLine): Node = - p( - v.split("\n") - .map(t => Seq(com.raquo.laminar.nodes.TextNode(t), br())) - .flatten: _* - ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala index 3bb2d6e..d5a78ee 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/TimeUtils.scala @@ -14,17 +14,33 @@ .ofLocalizedDateTime(FormatStyle.SHORT) // TODO: locale // .withLocale(Locale("cs", "CZ")) - .withZone(ZoneId.of("CET")) + .withZone(ZoneId.systemDefault()) val dateFormat = DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT) // TODO: locale // .withLocale(Locale("cs", "CZ")) - .withZone(ZoneId.of("CET")) + .withZone(ZoneId.systemDefault()) + + val htmlDateFormat = + DateTimeFormatter + .ofPattern("yyyy-MM-dd") + .withZone(ZoneId.systemDefault()) + + val htmlDateTimeFormat = + DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) def formatDateTime(i: TemporalAccessor): String = dateTimeFormat.format(i) def formatDate(i: TemporalAccessor): String = dateFormat.format(i) + + def formatHtmlDate(i: TemporalAccessor): String = + htmlDateFormat.format(i) + + def formatHtmlDateTime(i: TemporalAccessor): String = + htmlDateTimeFormat.format(i) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/data_display/description_lists/LeftAlignedInCard.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/data_display/description_lists/LeftAlignedInCard.scala index 3b1128d..61ae4aa 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/data_display/description_lists/LeftAlignedInCard.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/data_display/description_lists/LeftAlignedInCard.scala @@ -11,17 +11,18 @@ import works.iterative.ui.components.tailwind.form.ActionButton import works.iterative.ui.components.tailwind.ComponentContext import works.iterative.ui.components.tailwind.Icons +import scala.reflect.ClassTag -type ValueContent = String | Node +type ValueContent = String | Modifier[HtmlElement] type OptionalValueContent = ValueContent | Option[ValueContent] case class LabeledValue(label: String, body: OptionalValueContent): - def content: Option[Node] = body match - case Some(s: String) => Some(s) - case Some(m: Node) => Some(m) - case s: String => Some(s) - case m: Node => Some(m) - case _ => None + def content: Option[Modifier[HtmlElement]] = body match + case Some(s: String) => Some(s) + case Some(m: Modifier[HtmlElement]) => Some(m) + case s: String => Some(s) + case m: Modifier[_] => Some(m.asInstanceOf[Modifier[HtmlElement]]) + case _ => None object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using