Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.olegych.scastie.client

import com.olegych.scastie.api._
import japgolly.scalajs.react.extra.Reusability

object ApiReusability {

implicit val reusabilityUser: Reusability[User] =
Reusability.byRef || Reusability.caseClass

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ package client
import api._
import japgolly.scalajs.react._
import autowire._

import japgolly.scalajs.react.extra.StateSnapshot
import scalajs.concurrent.JSExecutionContext.Implicits.queue
import org.scalajs.dom._
import upickle.default.{read => uread}

import scala.util.{Failure, Success}
import scala.concurrent.Future

Expand Down Expand Up @@ -139,6 +138,8 @@ class AppBackend(scope: BackendScope[AppProps, AppState]) {
def setView(newView: View): Callback =
scope.modState(_.setView(newView))

val viewSnapshot = StateSnapshot.withReuse.prepare(setView)

def setTarget(target: ScalaTarget): Callback =
scope.modState(_.setTarget(target))

Expand Down
4 changes: 4 additions & 0 deletions client/src/main/scala/com.olegych.scastie.client/Views.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.olegych.scastie
package client

import japgolly.scalajs.react.extra.Reusability
import org.scalajs.dom

sealed trait View
Expand All @@ -9,6 +10,9 @@ object View {
case object BuildSettings extends View
case object CodeSnippets extends View

implicit val reusability: Reusability[View] =
Reusability.by_==

import upickle.default._

implicit val pkl: ReadWriter[View] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,57 @@ package client
package components

import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.all.{`class` => clazz, _}
import japgolly.scalajs.react.vdom.all._

object MainPanel {
private val component =
ScalaComponent
.builder[(AppState, AppBackend, AppProps)]("MainPanel")
.render_P {
case (state, backend, props) => {
def show(view: View) = {
if (view == state.view) TagMod(display.block)
else TagMod(display.none)
}
case (state, backend, props) =>

def show(view: View) =
if (view == state.view) display.block
else display.none

val embedded = props.embedded.isDefined

val embeddedMenu =
if (embedded) TagMod(EmbeddedMenu(state, backend))
else EmptyVdom
EmbeddedMenu(state, backend).when(embedded)

val consoleCssForEditor =
if (state.consoleState.consoleIsOpen)
TagMod(clazz := "console-open")
else EmptyVdom
(cls := "console-open").when(state.consoleState.consoleIsOpen)

val snippets =
if (state.user.isDefined) {
div(clazz := "snippets-container",
clazz := "inner-container",
show(View.CodeSnippets))(
CodeSnippets(props.router, state, backend)
)
} else EmptyVdom

div(clazz := "main-panel")(
// pre(clazz := "debug")(),
TopBar(state, backend),
div(cls := "snippets-container",
cls := "inner-container",
show(View.CodeSnippets))(
CodeSnippets(props.router, state, backend)
).when(state.user.isDefined)

div(cls := "main-panel",
// pre(cls := "debug")(),
TopBar(backend.viewSnapshot(state.view), state.user).render,
EditorTopBar(state, backend, props.snippetId),
div(clazz := "content")(
div(clazz := "editor-container",
clazz := "inner-container",
div(cls := "content",
div(cls := "editor-container",
cls := "inner-container",
show(View.Editor))(
div(clazz := "code", consoleCssForEditor)(
div(cls := "code", consoleCssForEditor)(
Editor(state, backend),
embeddedMenu
),
Console(state, backend)
),
div(clazz := "settings-container",
clazz := "inner-container",
div(cls := "settings-container",
cls := "inner-container",
show(View.BuildSettings))(
BuildSettings(state, backend)
),
snippets,
MobileBar(state, backend)
)
)
}
}
.build

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,106 +2,109 @@ package com.olegych.scastie
package client
package components

import com.olegych.scastie.api.User
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.all.{`class` => clazz, _}

import japgolly.scalajs.react.extra.{Reusability, StateSnapshot}
import japgolly.scalajs.react.vdom.all._
import org.scalajs.dom
import ApiReusability._

final case class TopBar(view: StateSnapshot[View], user: Option[User]) {
@inline def render: VdomElement = TopBar.component(this)
}

object TopBar {

def apply(state: AppState, backend: AppBackend) = component((state, backend))
implicit val reusability: Reusability[TopBar] =
Reusability.caseClass

private val component =
ScalaComponent
.builder[(AppState, AppBackend)]("TopBar")
.render_P {
case (state, backend) =>
import backend._
private def render(props: TopBar): VdomElement = {
def openInNewTab(link: String): Callback =
Callback {
dom.window.open(link, "_blank").focus()
}

def openInNewTab(link: String): Callback = {
Callback(
dom.window.open(link, "_blank").focus()
def feedback: Callback =
openInNewTab("https://gitter.im/scalacenter/scastie")

def issue: Callback =
openInNewTab("https://github.com/scalacenter/scastie/issues/new")

val logoutUrl = "/logout"

def logout: Callback =
props.view.setState(View.Editor) >>
Callback(dom.window.location.pathname = logoutUrl)

def login: Callback =
Callback(dom.window.location.pathname = "/login")

def selected(view: View) =
(cls := "selected").when(view == props.view.value)

val profileButton =
props.user match {
case Some(user) =>
li(cls := "btn dropdown",
img(src := user.avatar_url + "&s=30",
alt := "Your Github Avatar",
cls := "avatar"),
span(user.login),
i(cls := "fa fa-caret-down"),
ul(cls := "subactions",
li(onClick --> props.view.setState(View.CodeSnippets),
role := "link",
title := "Go to your code snippets",
cls := "btn",
selected(View.CodeSnippets)(
i(cls := "fa fa-code"),
"Snippets"
)),
li(role := "link", onClick --> logout, cls := "btn",
i(cls := "fa fa-sign-out"),
"Logout"
)
)
}

def feedback: Callback =
openInNewTab("https://gitter.im/scalacenter/scastie")

def issue: Callback =
openInNewTab("https://github.com/scalacenter/scastie/issues/new")

val logoutUrl = "/logout"

def logout: Callback =
backend.setView(View.Editor) >>
Callback(dom.window.location.pathname = logoutUrl)

def login: Callback =
Callback(dom.window.location.pathname = "/login")

def selected(view: View) =
if (view == state.view) TagMod(clazz := "selected")
else EmptyVdom

val profileButton =
state.user match {
case Some(user) =>
li(clazz := "btn dropdown")(
img(src := user.avatar_url + "&s=30",
alt := "Your Github Avatar",
clazz := "avatar"),
span(user.login),
i(clazz := "fa fa-caret-down"),
ul(clazz := "subactions")(
li(onClick --> setView(View.CodeSnippets),
role := "link",
title := "Go to your code snippets",
clazz := "btn",
selected(View.CodeSnippets)(
i(clazz := "fa fa-code"),
"Snippets"
)),
li(role := "link", onClick --> logout, clazz := "btn")(
i(clazz := "fa fa-sign-out"),
"Logout"
)
)
)
)

case None =>
li(role := "link", onClick --> login, clazz := "btn")(
i(clazz := "fa fa-sign-in"),
"Login"
)
}
case None =>
li(role := "link", onClick --> login, cls := "btn",
i(cls := "fa fa-sign-in"),
"Login"
)
}

nav(clazz := "topbar")(
ul(clazz := "actions")(
li(clazz := "btn dropdown")(
i(clazz := "fa fa-comments"),
span("Feedback"),
i(clazz := "fa fa-caret-down"),
ul(clazz := "subactions")(
li(onClick --> feedback,
role := "link",
title := "Open Gitter.im Chat to give us feedback",
clazz := "btn")(
i(clazz := "fa fa-gitter"),
span("Scastie's gitter")
),
li(onClick --> issue,
role := "link",
title := "Create new issue on GitHub",
clazz := "btn")(
i(clazz := "fa fa-github"),
span("Github issues")
)
)
),
profileButton
nav(cls := "topbar",
ul(cls := "actions",
li(cls := "btn dropdown",
i(cls := "fa fa-comments"),
span("Feedback"),
i(cls := "fa fa-caret-down"),
ul(cls := "subactions",
li(onClick --> feedback,
role := "link",
title := "Open Gitter.im Chat to give us feedback",
cls := "btn",
i(cls := "fa fa-gitter"),
span("Scastie's gitter")
),
li(onClick --> issue,
role := "link",
title := "Create new issue on GitHub",
cls := "btn",
i(cls := "fa fa-github"),
span("Github issues")
)
)

}
.build
),
profileButton
)
)
}

private val component = ScalaComponent
.builder[TopBar]("TopBar")
.render_P(render)
.configure(Reusability.shouldComponentUpdate)
.build
}