diff options
author | Jakob Odersky <jakob@inpher.io> | 2019-11-26 00:03:43 -0500 |
---|---|---|
committer | Jakob Odersky <jakob@inpher.io> | 2019-11-26 13:40:36 -0500 |
commit | f38dd59d93f56213a8400841c7ebb0a7202144a7 (patch) | |
tree | a697acc765cf6203eb0a499601185d1303da8939 /shared | |
parent | 2f298c65846b2f62b9b40cd23f11971b301829f3 (diff) | |
download | scala-tutorial-f38dd59d93f56213a8400841c7ebb0a7202144a7.tar.gz scala-tutorial-f38dd59d93f56213a8400841c7ebb0a7202144a7.tar.bz2 scala-tutorial-f38dd59d93f56213a8400841c7ebb0a7202144a7.zip |
Share model across fe and be and add websocket support
Diffstat (limited to 'shared')
-rw-r--r-- | shared/Message.scala | 26 | ||||
-rw-r--r-- | shared/Templates.scala | 70 |
2 files changed, 96 insertions, 0 deletions
diff --git a/shared/Message.scala b/shared/Message.scala new file mode 100644 index 0000000..55b4602 --- /dev/null +++ b/shared/Message.scala @@ -0,0 +1,26 @@ +import java.time.Instant + +case class Message( + author: String, + date: Long, // seconds since epoch + content: String +) + +object Message { + + // A ReadWriter is used to serialize a message to JSON. + // The call to macroRW will generate a readwriter through compiler-time + // introspection. By default, the mapping of a case class to JSON is pretty + // straightforward. A message: + // Message("John Smith", 0, "Hello, World!") + // will get rendered as + // { + // "author": "John Smith", + // "date": 0, + // "message": "Hello, World!" + // } + // + implicit def messageRW: upickle.default.ReadWriter[Message] = + upickle.default.macroRW[Message] + +} diff --git a/shared/Templates.scala b/shared/Templates.scala new file mode 100644 index 0000000..9c3c292 --- /dev/null +++ b/shared/Templates.scala @@ -0,0 +1,70 @@ +import scalatags.generic.Bundle + +class Templates[Builder, Output <: FragT, FragT](val backend: Bundle[Builder, Output, FragT]) { + import backend.all._ + + def message(msg: Message): Tag = { + div(cls := "col-xs-12 col-sm-6 col-md-3 col-lg-2")( + div(cls := s"card text-white mb-3 bg-primary")( + div(cls := "card-header")( + msg.author + ), + div(`class` := "card-body")( + div(`class` := "card-text")( + msg.content + ) + ) + ) + ) + } + + def conversation(messages: Seq[Message]): Tag = + div(`class` := "container-fluid")( + div(id := "conversation", `class` := "row")( + for (msg <- messages.sortBy(_.date)) yield message(msg) + ) + ) + + def page(messages: Seq[Message]): Tag = html( + head( + link( + rel := "stylesheet", + `type` := "text/css", + href := "/assets/lib/bootstrap-4.1.0/css/bootstrap-reboot.min.css" + ), + link( + rel := "stylesheet", + `type` := "text/css", + href := "/assets/lib/bootstrap-4.1.0/css/bootstrap-grid.min.css" + ), + link( + rel := "stylesheet", + `type` := "text/css", + href := "/assets/lib/bootstrap-4.1.0/css/bootstrap.min.css" + ), + link( + rel := "stylesheet", + `type` := "text/css", + href := "/assets/main.css" + ), + meta( + name := "viewport", + content := "width=device-width, initial-scale=1, shrink-to-fit=no" + ), + script(`type` := "text/javascript", src := "/assets/app.js") + ), + body( + conversation(messages), + script(`type` := "text/javascript")( + raw( + """|document.addEventListener("DOMContentLoaded", function(event) { + | console.info("Starting ScalaJS application...") + | Main.main() // run ScalaJS application + |}) + |""".stripMargin + ) + ) + ) + ) + +} |