lila/app/views/puzzle/dashboard.scala

185 lines
5.8 KiB
Scala

package views
package html.puzzle
import controllers.routes
import play.api.i18n.Lang
import play.api.libs.json.Json
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.common.String.html.safeJsonValue
import lila.puzzle.PuzzleDashboard
import lila.puzzle.PuzzleTheme
import lila.user.User
object dashboard {
private val baseClass = "puzzle-dashboard"
private val metricClass = s"${baseClass}__metric"
private val themeClass = s"${baseClass}__theme"
private val dataWinPercent = attr("data-win-percent")
def home(user: User, dashOpt: Option[PuzzleDashboard], days: Int)(implicit ctx: Context) =
dashboardLayout(
user = user,
days = days,
path = "dashboard",
title =
if (ctx is user) "Puzzle dashboard"
else s"${user.username} puzzle dashboard",
subtitle = "Train, analyse, improve",
dashOpt = dashOpt,
moreJs = dashOpt ?? { dash =>
val mostPlayed = dash.mostPlayed.sortBy { case (key, _) =>
PuzzleTheme(key).name.txt()
}
frag(
jsModule("puzzle.dashboard"),
embedJsUnsafeLoadThen(s"""LichessPuzzleDashboard.renderRadar(${safeJsonValue(
Json
.obj(
"radar" -> Json.obj(
"labels" -> mostPlayed.map { case (key, _) =>
PuzzleTheme(key).name.txt()
},
"datasets" -> Json.arr(
Json.obj(
"label" -> "Performance",
"data" -> mostPlayed.map { case (_, results) =>
results.performance
}
)
)
)
)
)})""")
)
}
) { dash =>
dash.mostPlayed.size > 2 option
div(cls := s"${baseClass}__global")(
metricsOf(days, PuzzleTheme.mix.key, dash.global),
canvas(cls := s"${baseClass}__radar")
)
}
def improvementAreas(user: User, dashOpt: Option[PuzzleDashboard], days: Int)(implicit ctx: Context) =
dashboardLayout(
user = user,
days = days,
"improvementAreas",
title =
if (ctx is user) trans.puzzle.improvementAreas.txt()
else s"${user.username} improvement areas",
subtitle = "Train these to optimize your progress!",
dashOpt = dashOpt
) { dash =>
dash.weakThemes.nonEmpty option themeSelection(days, dash.weakThemes)
}
def strengths(user: User, dashOpt: Option[PuzzleDashboard], days: Int)(implicit ctx: Context) =
dashboardLayout(
user = user,
days = days,
"strengths",
title =
if (ctx is user) trans.puzzle.strengths.txt()
else s"${user.username} puzzle strengths",
subtitle = "You perform the best in these themes",
dashOpt = dashOpt
) { dash =>
dash.strongThemes.nonEmpty option themeSelection(days, dash.strongThemes)
}
private def dashboardLayout(
user: User,
days: Int,
path: String,
title: String,
subtitle: String,
dashOpt: Option[PuzzleDashboard],
moreJs: Frag = emptyFrag
)(
body: PuzzleDashboard => Option[Frag]
)(implicit ctx: Context) =
views.html.base.layout(
title = title,
moreCss = cssTag("puzzle.dashboard"),
moreJs = moreJs
)(
main(cls := "page-menu")(
bits.pageMenu(path),
div(cls := s"page-menu__content box box-pad $baseClass")(
div(cls := "box__top")(
// iconTag(''),
h1(
title,
strong(subtitle)
),
views.html.base.bits.mselect(
s"${baseClass}__day-select box__top__actions",
span(trans.nbDays.pluralSame(days)),
PuzzleDashboard.dayChoices map { d =>
a(
cls := (d == days).option("current"),
href := s"${routes.Puzzle.dashboard(d, path)}${!(ctx is user) ?? s"?u=${user.username}"}"
)(trans.nbDays.pluralSame(d))
}
)
),
dashOpt.flatMap(body) |
div(cls := s"${baseClass}__empty")(
a(href := routes.Puzzle.home)("Nothing to show, go play some puzzles first!")
)
)
)
)
private def themeSelection(days: Int, themes: List[(PuzzleTheme.Key, PuzzleDashboard.Results)])(implicit
lang: Lang
) =
themes.map { case (key, results) =>
div(cls := themeClass)(
div(cls := s"${themeClass}__meta")(
h3(cls := s"${themeClass}__name")(
a(href := routes.Puzzle.show(key.value))(PuzzleTheme(key).name())
),
p(cls := s"${themeClass}__description")(PuzzleTheme(key).description())
),
metricsOf(days, key, results)
)
}
private def metricsOf(days: Int, theme: PuzzleTheme.Key, results: PuzzleDashboard.Results)(implicit
lang: Lang
) =
div(cls := s"${baseClass}__metrics")(
div(cls := s"$metricClass $metricClass--played")(
strong(results.nb.localize),
span("played")
),
div(cls := s"$metricClass $metricClass--perf")(
strong(results.performance, results.unclear ?? "?"),
span("performance")
),
div(
cls := s"$metricClass $metricClass--win",
style := s"--first:${results.firstWinPercent}%;--win:${results.winPercent}%"
)(
strong(s"${results.winPercent}%"),
span("solved")
),
a(
cls := s"$metricClass $metricClass--fix",
href := results.canReplay.option(routes.Puzzle.replay(days, theme.value).url)
)(
results.canReplay option span(cls := s"$metricClass--fix__text")(
strong(results.unfixed),
span("to replay")
),
iconTag(if (results.canReplay) '' else '')
)
)
}