diff options
author | Jakob Odersky <jodersky@gmail.com> | 2015-03-24 10:51:42 +0100 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2015-03-27 09:33:01 +0100 |
commit | de730793fdb650e7e9a8dcc88ae84c3b153cd479 (patch) | |
tree | 22bdc2993769637212f066da45f841dc0701ed01 | |
parent | 2881fb6ba97cbd496eebb4d785b2ba6e59fa303c (diff) | |
download | mavigator-de730793fdb650e7e9a8dcc88ae84c3b153cd479.tar.gz mavigator-de730793fdb650e7e9a8dcc88ae84c3b153cd479.tar.bz2 mavigator-de730793fdb650e7e9a8dcc88ae84c3b153cd479.zip |
implement flexbox based layout
5 files changed, 225 insertions, 88 deletions
diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala index 4ec695e..0264e5f 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala @@ -1,12 +1,11 @@ package vfd.dashboard.ui import org.scalajs.dom.html - import scalatags.JsDom.all.ExtendedString import scalatags.JsDom.all.Int2CssNumber -import scalatags.JsDom.all.bindNode import scalatags.JsDom.all.`class` import scalatags.JsDom.all.div +import scalatags.JsDom.all.header import scalatags.JsDom.all.height import scalatags.JsDom.all.iframe import scalatags.JsDom.all.p @@ -16,12 +15,69 @@ import scalatags.JsDom.all.stringFrag import scalatags.JsDom.all.stringPixelStyle import scalatags.JsDom.all.style import scalatags.JsDom.all.width +import scalatags.JsDom.all.button +import scalatags.JsDom.all.id +import scalatags.JsDom.all._ +import scalatags.jsdom._ +import scalatags.jsdom.Frag import vfd.dashboard.Environment import vfd.dashboard.MavlinkSocket import vfd.dashboard.ui.panels.Communication import vfd.dashboard.ui.panels.Primary +import org.scalajs.dom.MouseEvent +import org.scalajs.dom + +class Layout(socket: MavlinkSocket)(implicit env: Environment) { + + private def panel(contents: Frag*) = div(`class` := "d-panel")(contents: _*) + + def layout = + div(`class` := "d-container d-column")( + div(`class` := "d-above")( + top), + div(`class` := "d-above d-container d-row")( + panel(modes), + panel(infos)), + div(`class` := "d-container d-row")( + div(`class` := "d-container d-details")( + panel("foo")), + div(`class` := "d-container d-left")( + left), + div(`class` := "d-container d-column d-middle")( + div(`class` := "d-container d-center")( + center), + div(`class` := "d-container d-below")( + below)), + div(`class` := "d-container d-right")( + right))) + + def top = header( + div("Flight Control Panel"), + div("00:00:00"), + div("System #")) -class Layout(socket: MavlinkSocket) { + def left = panel(map) + def center = panel(feed) + def below = panel(Primary(socket)) + def right = panel(Communication(socket)) + + def mode(name: String, kind: String, on: Boolean = false) = div(`class` := s"mode $kind ${if (!on) "off"}")(name) + + val modes = div( + mode("MANUAL", "warning", true), + mode("STABILIZED", "info", true), + mode("GUIDED", "success", true), + mode("AUTO", "success", true)) + + val infos = div( + mode("BAY", "info"), + mode("RECOVERY", "danger"), + mode("NOGPS", "warning", true), + mode("OVERLOAD", "danger", true), + mode("BATTERY", "danger", false), + mode("LINK", "danger", true), + mode("SOCKET", "danger", true), + div(style := "float: right")(mode("CRITICAL", "danger", true))) val map = iframe( width := 100.pct, @@ -35,24 +91,5 @@ class Layout(socket: MavlinkSocket) { val feed = div(style := "width: 100%; height: 460px; color: #ffffff; background-color: #c2c2c2; text-align: center;")( p(style := "padding-top: 220px")("video feed")) - def element(implicit env: Environment): html.Element = div(`class` := "container-fluid")( - div(`class` := "row")( - div(`class` := "col-xs-12")( - div(`class` := "panel panel-default")( - div(`class` := "panel-body")()))), - div(`class` := "row")( - div(`class` := "col-xs-4")( - div(`class` := "panel panel-default")( - div(`class` := "panel-body")( - map))), - div(`class` := "col-xs-5")( - div(`class` := "panel panel-default")( - div(`class` := "panel-body")( - feed)), - div(`class` := "panel panel-default")( - div(`class` := "panel-body")(Primary(socket)))), - div(`class` := "col-xs-3")( - div(`class` := "panel panel-default")( - div(`class` := "panel-body")(Communication(socket)))))).render - + def element: html.Element = layout.render }
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Communication.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Communication.scala index 220a7b8..c9a5c90 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Communication.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Communication.scala @@ -4,7 +4,6 @@ import org.mavlink.messages.Heartbeat import org.mavlink.messages.Motor import org.mavlink.messages.Power import org.scalajs.dom.html - import rx.core.Obs import scalatags.JsDom.all.bindNode import scalatags.JsDom.all.`class` @@ -26,10 +25,11 @@ import vfd.dashboard.ui.components.Balance import vfd.dashboard.ui.components.Bar import vfd.dashboard.ui.components.Generic import vfd.dashboard.ui.components.Led +import scalatags.jsdom.Frag object Communication { - def apply(socket: MavlinkSocket)(implicit app: Environment): html.Element = { + def apply(socket: MavlinkSocket)(implicit app: Environment): Frag = { val hb = i(`class` := "fa fa-heart heartbeat").render @@ -107,7 +107,7 @@ object Communication { tr( td(motor2.element), td(), - td(motor3.element))))).render + td(motor3.element))))) } }
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Primary.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Primary.scala index 6f66208..5308b40 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Primary.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/panels/Primary.scala @@ -2,7 +2,6 @@ package vfd.dashboard.ui.panels import org.mavlink.messages.Attitude import org.scalajs.dom.html - import rx.core.Obs import scalatags.JsDom.all.bindNode import scalatags.JsDom.all.`class` @@ -16,10 +15,11 @@ import vfd.dashboard.MavlinkSocket import vfd.dashboard.ui.components.Altimeter import vfd.dashboard.ui.components.Compass import vfd.dashboard.ui.components.Horizon +import scalatags.jsdom.Frag object Primary { - def apply(socket: MavlinkSocket)(implicit env: Environment): html.Element = { + def apply(socket: MavlinkSocket)(implicit env: Environment): Frag = { val compass = new Compass val horizon = new Horizon @@ -39,7 +39,7 @@ object Primary { tr( td(compass.element), td(horizon.element), - td(altimeter.element)))).render + td(altimeter.element)))) } diff --git a/vfd-main/app/views/dashboard.scala.html b/vfd-main/app/views/dashboard.scala.html index 02a79f7..b2cfdfd 100644 --- a/vfd-main/app/views/dashboard.scala.html +++ b/vfd-main/app/views/dashboard.scala.html @@ -2,33 +2,6 @@ @main("Main"){ - <header> - <nav class="navbar navbar-inverse navbar-static-top" role="navigation"> - <div class="container-fluid"> - <!-- Brand and toggle get grouped for better mobile display --> - <div class="navbar-header"> - <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-main-collapse"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a class="navbar-brand" href="@routes.Application.index"> - <!-- <img style="max-height: 100%;" src="@routes.Assets.at("images/logo-invert.svg")" alt="logo"> --> - Flight Control Panel - </a> - </div> - - <!-- Collect the nav links, forms, and other content for toggling --> - <div class="collapse navbar-collapse" id="navbar-main-collapse"> - <div class="nav navbar-nav navbar-right"> - <p class="navbar-text">Remote System @remoteSystemId</p> - </div> - </div><!-- /.navbar-collapse --> - </div><!-- /.container-fluid --> - </nav> - </header> - @app("vfd-dashboard")( "socketUrl" -> socket, "remoteSystemId" -> remoteSystemId.toString, diff --git a/vfd-main/public/stylesheets/main.css b/vfd-main/public/stylesheets/main.css index e92cd24..072f167 100644 --- a/vfd-main/public/stylesheets/main.css +++ b/vfd-main/public/stylesheets/main.css @@ -1,18 +1,9 @@ -@font-face { - font-family: ds-digi; - src: url('../fonts/ds-digi.ttf') -} - -html { - height: 100%; -} - -body { - height: 100%; +html, body { + height: 100%; } body { - background-color: #e6e6e6; + background-color: #e6e6e6; } .loader { @@ -21,6 +12,144 @@ body { text-align: center; } +#vfd-dashboard { + width: 100%; + height: 100%; +} + +#vfd-dashboard header { + color: #eeeeee; + background-color: #222222; + padding-left: 15px; + padding-right: 15px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 5px; + display: flex; +} + +#vfd-dashboard header > * { + margin: 5px; + flex: 1; +} + +#vfd-dashboard header > :nth-child(1) { + text-align: left; +} + +#vfd-dashboard header > :nth-child(2) { + text-align: center; +} + +#vfd-dashboard header > :nth-child(3) { + text-align: right; +} + +/* dashboard layout */ +.d-container { + display: flex; + align-content: flex-start; + align-items: stretch; +} + +.d-container > * { + flex: 1; +} + +.d-column { + flex-direction: column; + height: 100%; +} + +.d-row { + flex-direction: row; + width: 100%; +} + +.d-above { + flex: none; +} + +.d-left { + flex: 1 1 30%; +} + +.d-middle { + flex: 1 1 45%; +} + +.d-right { + flex: 1 1 25%; +} + +.d-center { + flex: none; +} + +.d-below { + flex: 1; +} + +.d-details { + display: none; +} + +.d-detailed .d-left, .d-detailed .d-right { + display: none; +} + +.d-detailed .d-middle { + flex: 1 1 25%; +} + +.d-detailed .d-details { + display: flex; + flex: 1 1 75%; + overerflow-y: scroll; +} + +.d-panel { + margin: 5px; + padding: 15px; + background-color: white; + border-radius: 3px; +} + + +/* Mode styles */ +.mode { + display: inline-block; + box-sizing: border-box; + text-decoration: normal; + margin-right: 5px; +} + +.mode.danger { + color: #d9534f; + text-shadow: 0 0 5px #d9534f; +} + +.mode.warning { + color: #f0ad4e; + text-shadow: 0 0 5px #f0ad4e; +} + +.mode.info { + color: #5bc0de; + text-shadow: 0 0 5px #5bc0de; +} + +.mode.success { + color: #5cb85c; + text-shadow: 0 0 5px #5cb85c; +} + +.mode.off { + color: #eeeeee; + text-shadow: none; +} + +/* TODO: Rules below are maybe obsolete and need to be reviewed */ .table-instrument { table-layout: fixed; width: 100%; @@ -31,25 +160,23 @@ body { } .heartbeat { - color: rgba(165, 25, 25, 1); - animation: heartbeat 2s linear infinite; + color: rgba(165, 25, 25, 1); + animation: heartbeat 2s linear infinite; } - @keyframes heartbeat { - 0% { - transform: scale(1); - } - 7% { - transform: scale(1.3); - } - 14% { - transform: scale(1); - } - 21% { - transform: scale(1.3); - } - 28% { - transform: scale(1); - } -} - + 0% { + transform: scale(1); + } + 7% { + transform: scale(1.3); + } + 14% { + transform: scale(1); + } + 21% { + transform: scale(1.3); + } + 28% { + transform: scale(1); + } +}
\ No newline at end of file |