diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala index de8760e..e7294be 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala @@ -5,7 +5,7 @@ import zio.prelude.Validation import works.iterative.ui.components.tailwind.ComponentContext -class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext) +class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext[_]) extends FormInput[V]: def render( property: Property[V], diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala index de8760e..e7294be 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala @@ -5,7 +5,7 @@ import zio.prelude.Validation import works.iterative.ui.components.tailwind.ComponentContext -class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext) +class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext[_]) extends FormInput[V]: def render( property: Property[V], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index 4c87800..bed1b68 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -6,11 +6,11 @@ object LaminarExtensions: inline given userMessageToModifier(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) inline given userMessageToString(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, String] with inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala index de8760e..e7294be 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala @@ -5,7 +5,7 @@ import zio.prelude.Validation import works.iterative.ui.components.tailwind.ComponentContext -class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext) +class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext[_]) extends FormInput[V]: def render( property: Property[V], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index 4c87800..bed1b68 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -6,11 +6,11 @@ object LaminarExtensions: inline given userMessageToModifier(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) inline given userMessageToString(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, String] with inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala index aac3596..a47b211 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala @@ -9,7 +9,7 @@ def apply[T](tabs: Seq[(MessageId, T)], selected: Signal[MessageId])( updates: Observer[T] )(using - ctx: ComponentContext + ctx: ComponentContext[_] ): HtmlElement = val m = tabs .map { case (t, v) => diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala index de8760e..e7294be 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala @@ -5,7 +5,7 @@ import zio.prelude.Validation import works.iterative.ui.components.tailwind.ComponentContext -class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext) +class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext[_]) extends FormInput[V]: def render( property: Property[V], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index 4c87800..bed1b68 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -6,11 +6,11 @@ object LaminarExtensions: inline given userMessageToModifier(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) inline given userMessageToString(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, String] with inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala index aac3596..a47b211 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala @@ -9,7 +9,7 @@ def apply[T](tabs: Seq[(MessageId, T)], selected: Signal[MessageId])( updates: Observer[T] )(using - ctx: ComponentContext + ctx: ComponentContext[_] ): HtmlElement = val m = tabs .map { case (t, v) => diff --git a/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala b/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala index 60de9f0..e4e14c4 100644 --- a/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala +++ b/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala @@ -25,30 +25,30 @@ def label: String - def element(using ComponentContext): HtmlElement + def element(using ComponentContext[_]): HtmlElement trait ScenarioExample: def title: String - def element(using ComponentContext): HtmlElement + def element(using ComponentContext[_]): HtmlElement object ScenarioExample: def apply( t: String, - elem: ComponentContext ?=> HtmlElement + elem: ComponentContext[_] ?=> HtmlElement ): ScenarioExample = new ScenarioExample: override val title: String = t - override def element(using ComponentContext): HtmlElement = elem + override def element(using ComponentContext[_]): HtmlElement = elem trait ScenarioExamples: self: Scenario => protected def examples(using ScenarioContext, - ComponentContext + ComponentContext[_] ): List[ScenarioExample] - override def element(using ComponentContext): HtmlElement = + override def element(using ComponentContext[_]): HtmlElement = val eventBus: EventBus[Any] = EventBus[Any]() given sc: ScenarioContext = new ScenarioContext: diff --git a/core/js/src/main/scala/works/iterative/core/Logging.scala b/core/js/src/main/scala/works/iterative/core/Logging.scala new file mode 100644 index 0000000..f836d7f --- /dev/null +++ b/core/js/src/main/scala/works/iterative/core/Logging.scala @@ -0,0 +1,18 @@ +package works.iterative.core + +/** Logging app service + * + * This typeclass will be implemented by a JS app to provide logging. + */ +trait Logging[A]: + def log(level: LogLevel, msg: String, t: Option[Throwable]): Unit + def logError(msg: String, t: Throwable): Unit = logError(msg, Some(t)) + def logError(msg: String, t: Option[Throwable]): Unit = + log(LogLevel.Error, msg, t) + def logWarning(msg: String): Unit = log(LogLevel.Warning, msg, None) + def logInfo(msg: String): Unit = log(LogLevel.Info, msg, None) + def logDebug(msg: String): Unit = log(LogLevel.Debug, msg, None) + def logTrace(msg: String): Unit = log(LogLevel.Trace, msg, None) + +enum LogLevel: + case Error, Warning, Info, Debug, Trace diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala index f6c583f..2b116cb 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/FormComponents.scala @@ -3,7 +3,8 @@ import com.raquo.laminar.api.L.{*, given} import works.iterative.ui.components.tailwind.ComponentContext -trait FormComponents(using ctx: ComponentContext) extends LocalDateSelectModule: +trait FormComponents(using ctx: ComponentContext[_]) + extends LocalDateSelectModule: def searchIcon: SvgElement def renderLocalDateSelect( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala index b93e6bd..2862dd5 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/tables/TableHeaderResolver.scala @@ -8,7 +8,7 @@ object TableHeaderResolver extends LowPriorityTableHeaderResolverImplicits: def apply(resolver: String => String): TableHeaderResolver = resolver - given (using ctx: ComponentContext): TableHeaderResolver = + given (using ctx: ComponentContext[_]): TableHeaderResolver = name => ctx.messages(name) given (using cat: MessageCatalogue): TableHeaderResolver = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala index 71dbd92..23bd049 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/ComponentContext.scala @@ -3,16 +3,17 @@ import works.iterative.core.MessageCatalogue -trait ComponentContext: +trait ComponentContext[App]: + def app: App def messages: MessageCatalogue def style: StyleGuide - def nested(prefixes: String*): ComponentContext = - ComponentContext.Nested(this, prefixes) + def nested(prefixes: String*): ComponentContext[App] = + ComponentContext.Nested[App](this, prefixes) object ComponentContext: - case class Nested(parent: ComponentContext, prefixes: Seq[String]) - extends ComponentContext: + case class Nested[App](parent: ComponentContext[App], prefixes: Seq[String]) + extends ComponentContext[App]: export parent.{messages => _, *} override lazy val messages: MessageCatalogue = diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala index b662394..0caff74 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/Layout.scala @@ -4,5 +4,7 @@ import com.raquo.laminar.api.L.{*, given} object Layout: - def card(content: Modifier[HtmlElement]*)(using cctx: ComponentContext): Div = + def card(content: Modifier[HtmlElement]*)(using + cctx: ComponentContext[_] + ): Div = div(cls(cctx.style.card), content) 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 61ae4aa..8caee39 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 @@ -26,13 +26,13 @@ object LabeledValue: given renderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, V), LabeledValue] with def apply(v: (String, V)) = LabeledValue(cctx.messages(v._1), Some(v._2.render)) given optionalRenderableToLabeledValue[V: HtmlRenderable](using - cctx: ComponentContext + cctx: ComponentContext[_] ): Conversion[(String, Option[V]), LabeledValue] with def apply(v: (String, Option[V])) = LabeledValue(cctx.messages(v._1), v._2.map(_.render)) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala index e02fe4d..28d1e6e 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/ActionButtons.scala @@ -29,7 +29,9 @@ action: A, style: ActionButtonStyle = ActionButtonStyle.default ): - def element(actions: Observer[A])(using ctx: ComponentContext): HtmlElement = + def element(actions: Observer[A])(using + ctx: ComponentContext[_] + ): HtmlElement = button( tpe("button"), cls("first:ml-0 ml-3"), @@ -47,7 +49,7 @@ case class ActionButtons[A](actions: List[ActionButton[A]]) object ActionButtons: - class Component[A](actions: Observer[A])(using ctx: ComponentContext) + class Component[A](actions: Observer[A])(using ctx: ComponentContext[_]) extends HtmlComponent[org.scalajs.dom.html.Div, ActionButtons[A]]: override def render(v: ActionButtons[A]) = div( diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala index 7d21f70..023f0b0 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/FormInput.scala @@ -25,5 +25,7 @@ TextArea() given optionLocalDateInput: FormInput[Option[LocalDate]] = Inputs.OptionDateInput() - given optionBooleanInput(using ComponentContext): FormInput[Option[Boolean]] = + given optionBooleanInput(using + ComponentContext[_] + ): FormInput[Option[Boolean]] = Switch() diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala index de8760e..e7294be 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/form/Switch.scala @@ -5,7 +5,7 @@ import zio.prelude.Validation import works.iterative.ui.components.tailwind.ComponentContext -class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext) +class Switch[V](using codec: FormCodec[V, Boolean], ctx: ComponentContext[_]) extends FormInput[V]: def render( property: Property[V], diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala index 4c87800..bed1b68 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/laminar/LaminarExtensions.scala @@ -6,11 +6,11 @@ object LaminarExtensions: inline given userMessageToModifier(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, Modifier[HtmlElement]] with inline def apply(msg: UserMessage) = ctx.messages(msg) inline given userMessageToString(using - ctx: ComponentContext + ctx: ComponentContext[_] ): Conversion[UserMessage, String] with inline def apply(msg: UserMessage) = ctx.messages(msg) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala index aac3596..a47b211 100644 --- a/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala +++ b/ui/js/src/main/scala/works/iterative/ui/components/tailwind/navigation/Tabs.scala @@ -9,7 +9,7 @@ def apply[T](tabs: Seq[(MessageId, T)], selected: Signal[MessageId])( updates: Observer[T] )(using - ctx: ComponentContext + ctx: ComponentContext[_] ): HtmlElement = val m = tabs .map { case (t, v) => diff --git a/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala b/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala index 60de9f0..e4e14c4 100644 --- a/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala +++ b/ui/js/src/main/scala/works/iterative/ui/scenarios/Scenario.scala @@ -25,30 +25,30 @@ def label: String - def element(using ComponentContext): HtmlElement + def element(using ComponentContext[_]): HtmlElement trait ScenarioExample: def title: String - def element(using ComponentContext): HtmlElement + def element(using ComponentContext[_]): HtmlElement object ScenarioExample: def apply( t: String, - elem: ComponentContext ?=> HtmlElement + elem: ComponentContext[_] ?=> HtmlElement ): ScenarioExample = new ScenarioExample: override val title: String = t - override def element(using ComponentContext): HtmlElement = elem + override def element(using ComponentContext[_]): HtmlElement = elem trait ScenarioExamples: self: Scenario => protected def examples(using ScenarioContext, - ComponentContext + ComponentContext[_] ): List[ScenarioExample] - override def element(using ComponentContext): HtmlElement = + override def element(using ComponentContext[_]): HtmlElement = val eventBus: EventBus[Any] = EventBus[Any]() given sc: ScenarioContext = new ScenarioContext: diff --git a/ui/js/src/main/scala/works/iterative/ui/scenarios/ScenarioMain.scala b/ui/js/src/main/scala/works/iterative/ui/scenarios/ScenarioMain.scala index ea8fe8a..5265c5a 100644 --- a/ui/js/src/main/scala/works/iterative/ui/scenarios/ScenarioMain.scala +++ b/ui/js/src/main/scala/works/iterative/ui/scenarios/ScenarioMain.scala @@ -49,7 +49,8 @@ def main(args: Array[String]): Unit = given MessageCatalogue = messageCatalogue - given ComponentContext with + given ComponentContext[Unit] with + val app: Unit = () val messages: MessageCatalogue = messageCatalogue val style: StyleGuide = StyleGuide.default