From f9533463cedcfee16177107932c64a444b269b85 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Wed, 9 May 2018 01:53:04 -0700 Subject: Add bootstrap and fancy UI --- common/shared/src/main/scala/Message.scala | 3 ++ common/shared/src/main/scala/Templates.scala | 50 +++++++++++++++++++++--- common/shared/src/main/scala/TextTemplates.scala | 22 ++++++++++- 3 files changed, 67 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/shared/src/main/scala/Message.scala b/common/shared/src/main/scala/Message.scala index 7ee36cb..84c733e 100644 --- a/common/shared/src/main/scala/Message.scala +++ b/common/shared/src/main/scala/Message.scala @@ -22,6 +22,9 @@ case class Message(content: String, Message.bytesToHex(digest.digest()) } + def hashTags: Seq[String] = + content.split("\\s").filter(_.startsWith("#")).map(_.drop(1)) + } object Message { diff --git a/common/shared/src/main/scala/Templates.scala b/common/shared/src/main/scala/Templates.scala index 82e1dda..10ee116 100644 --- a/common/shared/src/main/scala/Templates.scala +++ b/common/shared/src/main/scala/Templates.scala @@ -4,13 +4,51 @@ class Templates[Builder, Output <: FragT, FragT]( val bundle: scalatags.generic.Bundle[Builder, Output, FragT]) { import bundle.all._ - def message(msg: Message) = li( - div(`class` := "from")(msg.author), - div(`class` := "content")(msg.content) + val colorStyles = List( + "bg-primary", + "bg-secondary", + "bg-success", + "bg-danger", + "bg-warning", + "bg-info", + "bg-dark" ) + // pick a "random" style by computing a hash of arbitrary data + def dataStyle(data: String) = { + val dataHash = data.foldLeft(7) { + case (hash, char) => + (hash * 31 + char.toInt) + } + colorStyles( + ((dataHash % colorStyles.length) + colorStyles.length) % colorStyles.length) + } - def conversation(messages: Seq[Message]): Tag = ul(id := "conversation")( - for (msg <- messages.sortBy(_.timestamp)) yield message(msg) - ) + def message(msg: Message) = { + val tags = msg.hashTags.map( + hashTag => + span(`class` := "badge badge-light float-right ml-1")( + hashTag + )) + div(`class` := "col-xs-12 col-sm-6 col-md-3 col-lg-2")( + div(`class` := s"card text-white mb-3 ${dataStyle(msg.author)}")( + div(`class` := "card-header")( + msg.author, + tags + ), + 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(_.timestamp)) yield message(msg) + ) + ) } diff --git a/common/shared/src/main/scala/TextTemplates.scala b/common/shared/src/main/scala/TextTemplates.scala index 24a3b0e..e7e364a 100644 --- a/common/shared/src/main/scala/TextTemplates.scala +++ b/common/shared/src/main/scala/TextTemplates.scala @@ -6,6 +6,9 @@ object TextTemplates extends Templates(scalatags.Text) { def scripts(js: Boolean = true) = if (js) Seq( + div(id := "scalajs-error", style := "display: none;")( + "ScalaJS raised an exception. See the log for more information." + ), script(`type` := "text/javascript", src := "/assets/ui/js/ui-fastopt.js"), script(`type` := "text/javascript")( @@ -25,7 +28,7 @@ object TextTemplates extends Templates(scalatags.Text) { | triad.Main().main(root) | } catch(ex) { | // display warning message in case of exception - | //document.getElementById("scalajs-error").style.display = "block"; + | document.getElementById("scalajs-error").style.display = "block"; | throw ex; | } |}); @@ -36,7 +39,22 @@ object TextTemplates extends Templates(scalatags.Text) { else Seq.empty def page(messages: Seq[Message], js: Boolean = true) = html( - head(), + 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") + ), body( conversation(messages), scripts(js) -- cgit v1.2.3