more template rewrite
parent
55e6cdd896
commit
0e228891e8
|
@ -18,6 +18,9 @@ trait I18nHelper {
|
|||
def i18nJsObject(keys: I18nKey*)(implicit lang: Lang): JsObject =
|
||||
JsDump.keysToObject(keys, I18nDb.Site, lang)
|
||||
|
||||
def i18nJsObject(keys: List[I18nKey])(implicit lang: Lang): JsObject =
|
||||
JsDump.keysToObject(keys, I18nDb.Site, lang)
|
||||
|
||||
def i18nOptionJsObject(keys: Option[I18nKey]*)(implicit lang: Lang): JsObject =
|
||||
JsDump.keysToObject(keys.flatten, I18nDb.Site, lang)
|
||||
|
||||
|
|
|
@ -245,20 +245,19 @@ trait UserHelper { self: I18nHelper with StringHelper with HtmlHelper with Numbe
|
|||
private def userHref(username: String, params: String = "") =
|
||||
s"""href="${routes.User.show(username)}$params""""
|
||||
|
||||
private def addClass(cls: Option[String]) = cls.fold("")(" " + _)
|
||||
|
||||
protected def userClass(
|
||||
userId: String,
|
||||
cssClass: Option[String],
|
||||
withOnline: Boolean,
|
||||
withPowerTip: Boolean = true
|
||||
) = {
|
||||
"user_link" :: List(
|
||||
cssClass,
|
||||
withPowerTip option "ulpt",
|
||||
withOnline option {
|
||||
if (isOnline(userId)) "online" else "offline"
|
||||
}
|
||||
).flatten
|
||||
}.mkString("class=\"", " ", "\"")
|
||||
): String = {
|
||||
val online = if (withOnline) {
|
||||
if (isOnline(userId)) " online" else " offline"
|
||||
} else ""
|
||||
s"""class="user_link${addClass(cssClass)}${addClass(withPowerTip option "ulpt")}$online""""
|
||||
}
|
||||
|
||||
def userGameFilterTitle(u: User, nbs: UserInfo.NbGames, filter: GameFilter)(implicit ctx: UserContext) =
|
||||
splitNumber(userGameFilterTitleNoTag(u, nbs, filter))
|
||||
|
|
|
@ -21,6 +21,7 @@ trait Scalatags {
|
|||
implicit val playCallAttr = genericAttr[play.api.mvc.Call]
|
||||
|
||||
lazy val dataIcon = attr("data-icon")
|
||||
lazy val dataHint = attr("data-hint")
|
||||
|
||||
implicit val charAttr = genericAttr[Char]
|
||||
|
||||
|
@ -32,9 +33,9 @@ trait Scalatags {
|
|||
}
|
||||
}
|
||||
|
||||
/* for class maps such as Map("foo" -> true, "active" -> isActive) */
|
||||
implicit val stringMapAttr = new AttrValue[Map[String, Boolean]] {
|
||||
def apply(t: scalatags.text.Builder, a: Attr, m: Map[String, Boolean]): Unit = {
|
||||
/* for class maps such as List("foo" -> true, "active" -> isActive) */
|
||||
implicit val classesAttr = new AttrValue[List[(String, Boolean)]] {
|
||||
def apply(t: scalatags.text.Builder, a: Attr, m: List[(String, Boolean)]): Unit = {
|
||||
val cls = m collect { case (s, true) => s } mkString " "
|
||||
if (cls.nonEmpty) t.setAttr(a.name, scalatags.text.Builder.GenericAttrValueSource(cls))
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ tablebaseEndpoint: "@tablebaseEndpoint"
|
|||
|
||||
@analyse.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, initialFen, none, simul = simul, userTv = userTv, bookmarked = bookmarked).some,
|
||||
side = Some(views.html.game.side(pov, initialFen, none, simul = simul, userTv = userTv, bookmarked = bookmarked)),
|
||||
chat = chat.html.some,
|
||||
underchat = underchat.some,
|
||||
moreCss = moreCss,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@analyse.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, initialFen, none, simul = simul, bookmarked = false).some,
|
||||
side = Some(views.html.game.side(pov, initialFen, none, simul = simul, bookmarked = false)),
|
||||
chat = none,
|
||||
underchat = views.html.game.bits.watchers.some,
|
||||
moreCss = cssTag("analyse.css"),
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package views.html
|
||||
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.i18n.{ I18nKeys => trans }
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object bookmark {
|
||||
|
||||
def toggle(g: lila.game.Game, bookmarked: Boolean)(implicit ctx: Context) = ctx.me map { m =>
|
||||
a(cls := List(
|
||||
"bookmark" -> true,
|
||||
"bookmarked" -> bookmarked,
|
||||
"hint--top" -> true
|
||||
), href := routes.Bookmark.toggle(g.id), dataHint := trans.bookmarkThisGame.txt())(
|
||||
span(dataIcon := "t", cls := "on is3")(g.showBookmarks),
|
||||
span(dataIcon := "s", cls := "off is3")(g.showBookmarks)
|
||||
)
|
||||
} orElse {
|
||||
g.hasBookmarks option span(cls := "bookmark")(
|
||||
span(dataIcon := "s", cls := "is3")(g.showBookmarks)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
@(g: Game, bookmarked: Boolean)(implicit ctx: Context)
|
||||
|
||||
@ctx.me.map { m =>
|
||||
<a class="bookmark@if(bookmarked){ bookmarked} hint--top" href="@routes.Bookmark.toggle(g.id)" data-hint="@trans.bookmarkThisGame()">
|
||||
<span data-icon="t" class="on is3">@g.showBookmarks</span>
|
||||
<span data-icon="s" class="off is3">@g.showBookmarks</span>
|
||||
</a>
|
||||
}.getOrElse {
|
||||
@if(g.hasBookmarks) {
|
||||
<span class="bookmark">
|
||||
<span data-icon="s" class="is3">@g.showBookmarks</span>
|
||||
</span>
|
||||
}
|
||||
}
|
|
@ -25,4 +25,13 @@ object bits {
|
|||
def watchers(implicit ctx: Context) = Html {
|
||||
s"""<div class="watchers hidden"><span class="number"> </span> ${trans.spectators.txt().replace(":", "")} <span class="list inline_userlist"></span></div>"""
|
||||
}
|
||||
|
||||
def gameIcon(game: lila.game.Game): Char = game.perfType match {
|
||||
case _ if game.fromPosition => '*'
|
||||
case _ if game.imported => '/'
|
||||
case Some(p) if game.variant.exotic => p.iconChar
|
||||
case _ if game.hasAi => 'n'
|
||||
case Some(p) => p.iconChar
|
||||
case _ => '8'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
@(game: Game)(implicit ctx: Context)
|
||||
@game.perfType match {
|
||||
case _ if game.fromPosition => {*}
|
||||
case _ if game.imported => {/}
|
||||
case Some(p) if game.variant.exotic => {@p.iconChar}
|
||||
case _ if game.hasAi => {n}
|
||||
case Some(p) => {@p.iconChar}
|
||||
case _ => {8}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package views.html
|
||||
package game
|
||||
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.i18n.{ I18nKeys => trans }
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object side {
|
||||
|
||||
private val separator = " • "
|
||||
|
||||
def apply(
|
||||
pov: lila.game.Pov,
|
||||
initialFen: Option[chess.format.FEN],
|
||||
tour: Option[lila.tournament.Tournament],
|
||||
simul: Option[lila.simul.Simul],
|
||||
userTv: Option[lila.user.User] = None,
|
||||
bookmarked: Boolean
|
||||
)(implicit ctx: Context) = {
|
||||
import pov._
|
||||
div(cls := "side")(
|
||||
div(cls := "side_box padded")(
|
||||
div(cls := "game_infos", dataIcon := bits.gameIcon(game))(
|
||||
div(cls := "header")(
|
||||
span(cls := "setup")(
|
||||
views.html.bookmark.toggle(game, bookmarked),
|
||||
if (game.imported) frag(
|
||||
a(cls := "hint--top", href := routes.Importer.importGame, dataHint := trans.importGame.txt())("IMPORT"),
|
||||
separator,
|
||||
if (game.variant.exotic)
|
||||
variantLink(game.variant, (if (game.variant == chess.variant.KingOfTheHill) game.variant.shortName else game.variant.name).toUpperCase, cssClass = "hint--top", initialFen = initialFen)
|
||||
else
|
||||
game.variant.name.toUpperCase
|
||||
)
|
||||
else frag(
|
||||
game.clock.map { clock =>
|
||||
frag(clock.config.show)
|
||||
} getOrElse {
|
||||
game.daysPerTurn.map { days =>
|
||||
span(cls := "hint--top", dataHint := trans.correspondence.txt())(
|
||||
if (days == 1) trans.oneDay() else trans.nbDays.pluralSame(days)
|
||||
)
|
||||
}.getOrElse {
|
||||
span(cls := "hint--top", dataHint := trans.unlimited.txt())("∞")
|
||||
}
|
||||
},
|
||||
separator,
|
||||
if (game.rated) trans.rated.txt() else trans.casual.txt(),
|
||||
separator,
|
||||
if (game.variant.exotic)
|
||||
variantLink(game.variant, (if (game.variant == chess.variant.KingOfTheHill) game.variant.shortName else game.variant.name).toUpperCase, cssClass = "hint--top", initialFen = initialFen)
|
||||
else
|
||||
game.perfType.map { pt =>
|
||||
span(cls := "hint--top", dataHint := pt.title)(pt.shortName)
|
||||
}
|
||||
)
|
||||
),
|
||||
game.pgnImport.flatMap(_.date).map(frag(_)) getOrElse {
|
||||
frag(if (game.isBeingPlayed) trans.playingRightNow() else momentFromNow(game.createdAt))
|
||||
}
|
||||
),
|
||||
game.pgnImport.flatMap(_.date).map { date =>
|
||||
frag(
|
||||
"Imported",
|
||||
game.pgnImport.flatMap(_.user).map { user =>
|
||||
frag(
|
||||
"by ",
|
||||
userIdLink(user.some, None, false),
|
||||
br
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
div(cls := "players")(
|
||||
game.players.map { p =>
|
||||
div(cls := s"player color-icon is ${p.color.name} text")(
|
||||
playerLink(p, withOnline = false, withDiff = true, withBerserk = true)
|
||||
)
|
||||
}
|
||||
),
|
||||
game.finishedOrAborted option {
|
||||
div(cls := "status")(
|
||||
gameEndStatus(game),
|
||||
game.winner.map { winner =>
|
||||
frag(
|
||||
separator,
|
||||
winner.color.fold(trans.whiteIsVictorious(), trans.blackIsVictorious())
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
initialFen.ifTrue(game.variant.chess960).map(_.value).flatMap {
|
||||
chess.variant.Chess960.positionNumber
|
||||
}.map { number =>
|
||||
frag(
|
||||
"Chess960 start position: ",
|
||||
strong(number)
|
||||
)
|
||||
}
|
||||
),
|
||||
|
||||
game.userIds.filter(isStreaming).map { id =>
|
||||
a(cls := "context-streamer text side_box", dataIcon := "", href := routes.Streamer.show(id))(
|
||||
usernameOrId(id),
|
||||
" is streaming"
|
||||
)
|
||||
},
|
||||
|
||||
userTv.map { u =>
|
||||
div(cls := "side_box")(
|
||||
h2(cls := "top user_tv text", attr("data-user-tv") := u.id, dataIcon := "1")(u.titleUsername)
|
||||
)
|
||||
} orElse {
|
||||
lila.common.HTTPRequest.isMobile(ctx.req) option
|
||||
a(cls := "side_box text deep_link", dataIcon := "", href := "lichess://analyse/@pov.gameId")(
|
||||
"Open with ",
|
||||
strong("Mobile app")
|
||||
)
|
||||
},
|
||||
|
||||
tour.map { t =>
|
||||
div(cls := "game_tournament side_box no_padding scroll-shadow-soft")(
|
||||
p(cls := "top text", dataIcon := "g")(a(href := routes.Tournament.show(t.id))(t.fullName)),
|
||||
div(cls := "clock", attr("data-time") := t.secondsToFinish)(
|
||||
div(cls := "time")(t.clockStatus)
|
||||
)
|
||||
)
|
||||
} orElse {
|
||||
game.tournamentId map { tourId =>
|
||||
div(cls := "game_tournament side_box no_padding")(
|
||||
p(cls := "top text", dataIcon := "g")(a(href := routes.Tournament.show(tourId))(tournamentIdToName(tourId)))
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
simul.map { sim =>
|
||||
div(cls := "game_simul side_box no_padding")(
|
||||
p(cls := "top text", dataIcon := "|")(a(href := routes.Simul.show(sim.id))(sim.fullName))
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
@(pov: Pov, initialFen: Option[chess.format.FEN], tour: Option[lila.tournament.Tournament], simul: Option[lila.simul.Simul], userTv: Option[User] = None, bookmarked: Boolean)(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
||||
<div class="side">
|
||||
<div class="side_box padded">
|
||||
<div class="game_infos" data-icon="@gameIcon(game)">
|
||||
<div class="header">
|
||||
<span class="setup">
|
||||
@bookmark.toggle(game, bookmarked)
|
||||
@if(game.imported) {
|
||||
<a class="hint--top" href="@routes.Importer.importGame" data-hint="@trans.importGame()">IMPORT</a>
|
||||
•
|
||||
@if(game.variant.exotic) {
|
||||
@variantLink(game.variant, (if (game.variant == chess.variant.KingOfTheHill) game.variant.shortName else game.variant.name).toUpperCase, cssClass = "hint--top", initialFen = initialFen)
|
||||
} else {
|
||||
@game.variant.name.toUpperCase
|
||||
}
|
||||
} else {
|
||||
@game.clock.map(_.config.show).getOrElse {
|
||||
@game.daysPerTurn.map { days =>
|
||||
<span data-hint="@trans.correspondence()" class="hint--top">@if(days == 1){@trans.oneDay()}else{@trans.nbDays.pluralSame(days)}</span>
|
||||
}.getOrElse {
|
||||
<span data-hint="@trans.unlimited()" class="hint--top">∞</span>
|
||||
}
|
||||
} • @if(game.rated){@trans.rated.txt()}else{@trans.casual.txt()} •
|
||||
@if(game.variant.exotic) {
|
||||
@variantLink(game.variant, (if (game.variant == chess.variant.KingOfTheHill) game.variant.shortName else game.variant.name).toUpperCase, cssClass = "hint--top", initialFen = initialFen)
|
||||
} else {
|
||||
@game.perfType.map { pt => <span class="hint--top" data-hint="@pt.title">@pt.shortName</span> }
|
||||
}
|
||||
}
|
||||
</span>
|
||||
@game.pgnImport.flatMap(_.date).getOrElse(
|
||||
if (game.isBeingPlayed) trans.playingRightNow() else momentFromNow(game.createdAt)
|
||||
)
|
||||
</div>
|
||||
@game.pgnImport.flatMap(_.date).map { date =>
|
||||
Imported
|
||||
@game.pgnImport.flatMap(_.user).map { user =>
|
||||
by @userIdLink(user.some, None, false)
|
||||
<br />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="players">
|
||||
@List(game.whitePlayer, game.blackPlayer).map { p =>
|
||||
<div class="player color-icon is @{p.color.name} text">
|
||||
@playerLink(p, withOnline = false, withDiff = true, withBerserk = true)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if(game.finishedOrAborted) {
|
||||
<div class="status">
|
||||
@gameEndStatus(game)
|
||||
@game.winner.map { winner =>
|
||||
• @winner.color.fold(trans.whiteIsVictorious(), trans.blackIsVictorious())
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if(game.variant.chess960) {
|
||||
@initialFen.map { fen =>
|
||||
@chess.variant.Chess960.positionNumber(fen.value).map { number =>
|
||||
Chess960 start position: <strong>@number</strong>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@game.userIds.filter(isStreaming).map { id =>
|
||||
<a href="@routes.Streamer.show(id)" class="context-streamer text side_box" data-icon="">@usernameOrId(id) is streaming</a>
|
||||
}
|
||||
|
||||
@userTv.map { u =>
|
||||
<div class="side_box">
|
||||
<h2 class="top user_tv text" data-user-tv="@u.id" data-icon="1">@u.titleUsername</h2>
|
||||
</div>
|
||||
}.getOrElse {
|
||||
@if(lila.common.HTTPRequest.isMobile(ctx.req)) {
|
||||
<a class="side_box text deep_link" data-icon="" href="lichess://analyse/@pov.gameId">Open with <strong>Mobile app</strong></a>
|
||||
}
|
||||
}
|
||||
|
||||
@tour.map { t =>
|
||||
<div class="game_tournament side_box no_padding scroll-shadow-soft">
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(t.id)">@t.fullName</a></p>
|
||||
<div class="clock" data-time="@t.secondsToFinish">
|
||||
<div class="time">@t.clockStatus</div>
|
||||
</div>
|
||||
</div>
|
||||
}.getOrElse {
|
||||
@game.tournamentId.map { tourId =>
|
||||
<div class="game_tournament side_box no_padding">
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(tourId)">@tournamentIdToName(tourId)</a></p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@simul.map { sim =>
|
||||
<div class="game_simul side_box no_padding">
|
||||
<p class="top text" data-icon="|"><a href="@routes.Simul.show(sim.id)">@sim.fullName</a></p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
|
@ -31,7 +31,7 @@
|
|||
@defining(fromPlayer | g.firstPlayer ) { firstPlayer =>
|
||||
@gameFen(Pov(g, firstPlayer), ownerLink, withTitle = false)
|
||||
<a class="game_link_overlay" href="@gameLink(g, firstPlayer.color, ownerLink)"></a>
|
||||
<div class="infos" data-icon="@gameIcon(g)">
|
||||
<div class="infos" data-icon="@bits.gameIcon(g)">
|
||||
<div class="header">
|
||||
<strong>
|
||||
@if(g.imported) {
|
||||
|
|
|
@ -20,7 +20,9 @@ object bits {
|
|||
attr("data-lastmove") := lastMove
|
||||
)(miniBoardContent)
|
||||
|
||||
def jsI18n(implicit context: Context) = toJson(i18nJsObject(
|
||||
def jsI18n(implicit context: Context) = toJson(i18nJsObject(translations))
|
||||
|
||||
private val translations = List(
|
||||
trans.training,
|
||||
trans.yourPuzzleRatingX,
|
||||
trans.goodMove,
|
||||
|
@ -66,5 +68,5 @@ object bits {
|
|||
trans.gameOver,
|
||||
trans.inLocalBrowser,
|
||||
trans.toggleLocalEvaluation
|
||||
))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ object message {
|
|||
views.html.base.layout(title = title, moreCss = ~moreCss) {
|
||||
div(cls := "content_box small_box")(
|
||||
div(cls := "head")(
|
||||
h1(cls := Map("text" -> icon.isDefined), dataIcon := icon)(title)
|
||||
h1(cls := List("text" -> icon.isDefined), dataIcon := icon)(title)
|
||||
),
|
||||
br, br,
|
||||
p(message),
|
||||
|
|
|
@ -50,7 +50,7 @@ object variant {
|
|||
menu = Some(frag(
|
||||
lila.rating.PerfType.variants map { pt =>
|
||||
a(
|
||||
cls := Map("text" -> true, "active" -> active.has(pt)),
|
||||
cls := List("text" -> true, "active" -> active.has(pt)),
|
||||
href := routes.Page.variant(pt.key),
|
||||
dataIcon := pt.iconChar
|
||||
)(pt.name)
|
||||
|
|
|
@ -57,14 +57,14 @@ object side {
|
|||
}
|
||||
)
|
||||
},
|
||||
verdicts.relevant option div(dataIcon := "7", cls := Map(
|
||||
verdicts.relevant option div(dataIcon := "7", cls := List(
|
||||
"game_infos conditions" -> true,
|
||||
"accepted" -> (ctx.isAuth && verdicts.accepted),
|
||||
"refused" -> (ctx.isAuth && !verdicts.accepted)
|
||||
))(
|
||||
(verdicts.list.size < 2) option p(trans.conditionOfEntry()),
|
||||
verdicts.list map { v =>
|
||||
p(cls := Map(
|
||||
p(cls := List(
|
||||
"condition text" -> true,
|
||||
"accepted" -> v.verdict.accepted,
|
||||
"refused" -> !v.verdict.accepted
|
||||
|
|
|
@ -67,19 +67,18 @@ case class ContentSecurityPolicy(
|
|||
|
||||
def withPrismic(editor: Boolean): ContentSecurityPolicy = withPrismicEditor(editor).withTwitter
|
||||
|
||||
override def toString: String =
|
||||
List(
|
||||
"default-src " -> defaultSrc,
|
||||
"connect-src " -> connectSrc,
|
||||
"style-src " -> styleSrc,
|
||||
"font-src " -> fontSrc,
|
||||
"frame-src " -> frameSrc,
|
||||
"worker-src " -> workerSrc,
|
||||
"img-src " -> imgSrc,
|
||||
"script-src " -> scriptSrc,
|
||||
"base-uri " -> baseUri
|
||||
) collect {
|
||||
case (directive, sources) if sources.nonEmpty =>
|
||||
sources.mkString(directive, " ", ";")
|
||||
} mkString (" ")
|
||||
override def toString: String = List(
|
||||
"default-src " -> defaultSrc,
|
||||
"connect-src " -> connectSrc,
|
||||
"style-src " -> styleSrc,
|
||||
"font-src " -> fontSrc,
|
||||
"frame-src " -> frameSrc,
|
||||
"worker-src " -> workerSrc,
|
||||
"img-src " -> imgSrc,
|
||||
"script-src " -> scriptSrc,
|
||||
"base-uri " -> baseUri
|
||||
) collect {
|
||||
case (directive, sources) if sources.nonEmpty =>
|
||||
sources.mkString(directive, " ", ";")
|
||||
} mkString " "
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue