rewrite homepage with scalatags
parent
5dd76fa631
commit
e1bf05c682
|
@ -121,4 +121,5 @@ trait AssetHelper { self: I18nHelper with SecurityHelper =>
|
|||
}
|
||||
|
||||
def embedJs(js: Html)(implicit ctx: Context): Html = embedJsUnsafe(js.body)
|
||||
def embedJs(js: String)(implicit ctx: Context): Html = embedJsUnsafe(js)
|
||||
}
|
||||
|
|
|
@ -61,8 +61,9 @@ object Environment
|
|||
def reportNbOpen: Int =
|
||||
lila.report.Env.current.api.nbOpen.awaitOrElse(10.millis, 0)
|
||||
|
||||
def NotForKids[Html](f: => Html)(implicit ctx: lila.api.Context) =
|
||||
if (ctx.kid) emptyHtml else f
|
||||
def NotForKids(f: => Html)(implicit ctx: lila.api.Context) = if (ctx.kid) emptyHtml else f
|
||||
|
||||
def NotForKids(f: => scalatags.Text.all.Frag)(implicit ctx: lila.api.Context) = if (ctx.kid) emptyFrag else f
|
||||
|
||||
def signalBars(v: Int) = Html {
|
||||
val bars = (1 to 4).map { b =>
|
||||
|
|
|
@ -94,4 +94,29 @@ object bits {
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
def currentGameInfo(current: lila.app.mashup.Preload.CurrentGame)(implicit ctx: Context) =
|
||||
div(id := "lobby_current_game")(
|
||||
h2("Hang on!"),
|
||||
p("You have a game in progress with ", strong(current.opponent), "."),
|
||||
br, br,
|
||||
a(cls := "big text button", dataIcon := "G", href := routes.Round.player(current.pov.fullId))("Join the game"),
|
||||
br, br,
|
||||
"or",
|
||||
br, br,
|
||||
form(action := routes.Round.resign(current.pov.fullId), method := "post")(
|
||||
button(cls := "big text button", dataIcon := "L")(
|
||||
if (current.pov.game.abortable) "Abort" else "Resign", " the game"
|
||||
)
|
||||
),
|
||||
br,
|
||||
p("You can't start a new game until this one is finished."),
|
||||
br, br,
|
||||
p(
|
||||
"If you want to play several games simultaneously,",
|
||||
br,
|
||||
a(href := routes.Simul.home)("create a simultaneous exhibition event"),
|
||||
"!"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
@(current: lila.app.mashup.Preload.CurrentGame)(implicit ctx: Context)
|
||||
|
||||
<div id="lobby_current_game">
|
||||
<h2>Hang on!</h2>
|
||||
<p>You have a game in progress with <strong>@current.opponent</strong>.</p>
|
||||
<br />
|
||||
<br />
|
||||
<a class="big text button" data-icon="G" href="@routes.Round.player(current.pov.fullId)">Join the game</a>
|
||||
<br />
|
||||
<br />
|
||||
or
|
||||
<br />
|
||||
<br />
|
||||
<form action="@routes.Round.resign(current.pov.fullId)" method="post">
|
||||
<button class="big text button" data-icon="L">
|
||||
@if(current.pov.game.abortable) { Abort } else { Resign} the game
|
||||
</button>
|
||||
</form>
|
||||
<br />
|
||||
<p>You can't start a new game until this one is finished.</p>
|
||||
<br />
|
||||
<br />
|
||||
<p>
|
||||
If you want to play several games simultaneously,<br />
|
||||
<a href="@routes.Simul.home">create a simultaneous exhibition event</a>!
|
||||
</p>
|
||||
</div>
|
|
@ -0,0 +1,192 @@
|
|||
package views.html.lobby
|
||||
|
||||
import play.api.libs.json.Json
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.common.HTTPRequest
|
||||
import lila.common.String.html.{ safeJson, safeJsonValue }
|
||||
import lila.game.Pov
|
||||
import lila.i18n.{ I18nKeys => trans }
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object home {
|
||||
|
||||
def apply(
|
||||
data: play.api.libs.json.JsObject,
|
||||
userTimeline: Vector[lila.timeline.Entry],
|
||||
forumRecent: List[lila.forum.MiniForumPost],
|
||||
tours: List[lila.tournament.Tournament],
|
||||
events: List[lila.event.Event],
|
||||
simuls: List[lila.simul.Simul],
|
||||
featured: Option[lila.game.Game],
|
||||
leaderboard: List[lila.user.User.LightPerf],
|
||||
tournamentWinners: List[lila.tournament.Winner],
|
||||
puzzle: Option[lila.puzzle.DailyPuzzle],
|
||||
streams: lila.streamer.LiveStreams.WithTitles,
|
||||
lastPost: List[lila.blog.MiniPost],
|
||||
playban: Option[lila.playban.TempBan],
|
||||
currentGame: Option[lila.app.mashup.Preload.CurrentGame],
|
||||
nbRounds: Int
|
||||
)(implicit ctx: Context) = views.html.base.layout(
|
||||
title = "",
|
||||
fullTitle = Some("lichess.org • " + trans.freeOnlineChess.txt()),
|
||||
baseline = Some(frag(
|
||||
a(id := "nb_connected_players", href := routes.User.list)(trans.nbPlayers(nbPlayersPlaceholder)),
|
||||
a(id := "nb_games_in_play", href := routes.Tv.games)(
|
||||
trans.nbGamesInPlay.plural(nbRounds, Html(s"<span>${nbRounds}</span>"))
|
||||
),
|
||||
ctx.isMobileBrowser option {
|
||||
if (HTTPRequest isAndroid ctx.req) views.html.mobile.bits.googlePlayButton
|
||||
else if (HTTPRequest isIOS ctx.req) views.html.mobile.bits.appleStoreButton
|
||||
else emptyFrag
|
||||
}
|
||||
)),
|
||||
side = Some(frag(
|
||||
NotForKids { div(id := "streams_on_air")(views.html.streamer liveStreams streams) },
|
||||
events map { views.html.event.homepageSpotlight(_) },
|
||||
!ctx.isBot option frag(
|
||||
lila.tournament.Spotlight.select(tours, ctx.me, 3) map { views.html.tournament.homepageSpotlight(_) },
|
||||
simuls.find(_.spotlightable) take 2 map { views.html.simul.homepageSpotlight(_) } toList
|
||||
),
|
||||
ctx.me map { u =>
|
||||
div(id := "timeline", attr("data-href") := routes.Timeline.home)(
|
||||
views.html.timeline entries userTimeline,
|
||||
div(cls := "links")(
|
||||
userTimeline.size >= 8 option
|
||||
a(cls := "more", href := routes.Timeline.home)(trans.more(), " »")
|
||||
)
|
||||
)
|
||||
} getOrElse {
|
||||
div(cls := "about-side")(
|
||||
trans.xIsAFreeYLibreOpenSourceChessServer("Lichess", Html(s"""<a class="blue" href="${routes.Plan.features}">${trans.really.txt()}</a>""")),
|
||||
a(cls := "blue", href := "/about")(trans.aboutX("lichess.org"), "...")
|
||||
)
|
||||
}
|
||||
)),
|
||||
moreJs = frag(
|
||||
jsAt(s"compiled/lichess.lobby${isProd ?? (".min")}.js", async = true),
|
||||
embedJs(s"""window.customWS = true;
|
||||
lichess_lobby = {
|
||||
data: ${safeJsonValue(data)},
|
||||
playban: ${htmlOrNull(playban)(pb => safeJson(Json.obj("minutes" -> pb.mins, "remainingSeconds" -> (pb.remainingSeconds + 3))))},
|
||||
currentGame: ${htmlOrNull(currentGame)(cg => safeJson(cg.json))},
|
||||
i18n: ${safeJsonValue(i18nJsObject(translations))},
|
||||
};""")
|
||||
),
|
||||
moreCss = cssTag("home.css"),
|
||||
underchat = Some(frag(
|
||||
div(id := "featured_game")(
|
||||
featured map { g =>
|
||||
frag(
|
||||
gameFen(Pov first g, tv = true),
|
||||
views.html.game.bits.vstext(Pov first g)(ctx.some)
|
||||
)
|
||||
}
|
||||
)
|
||||
)),
|
||||
chessground = false,
|
||||
openGraph = lila.app.ui.OpenGraph(
|
||||
image = staticUrl("images/large_tile.png").some,
|
||||
title = "The best free, adless Chess server",
|
||||
url = netBaseUrl,
|
||||
description = trans.siteDescription.txt()
|
||||
).some,
|
||||
asyncJs = true
|
||||
) {
|
||||
frag(
|
||||
div(cls := List(
|
||||
"lobby_and_ground" -> true,
|
||||
"playban" -> playban.isDefined,
|
||||
"current_game" -> currentGame.isDefined
|
||||
))(
|
||||
currentGame map { bits.currentGameInfo(_) },
|
||||
div(id := "hooks_wrap"),
|
||||
playban.map(ban => playbanInfo(ban.remainingSeconds)),
|
||||
div(id := "start_buttons", cls := "lichess_ground")(
|
||||
a(href := routes.Setup.hookForm, cls := List(
|
||||
"fat button config_hook" -> true,
|
||||
"disabled" -> (playban.isDefined || currentGame.isDefined || ctx.isBot)
|
||||
), trans.createAGame()),
|
||||
a(href := routes.Setup.friendForm(none), cls := List(
|
||||
"fat button config_friend" -> true,
|
||||
"disabled" -> currentGame.isDefined
|
||||
), trans.playWithAFriend()),
|
||||
a(href := routes.Setup.aiForm, cls := List(
|
||||
"fat button config_ai" -> true,
|
||||
"disabled" -> currentGame.isDefined
|
||||
), trans.playWithTheMachine())
|
||||
)
|
||||
),
|
||||
puzzle map { p =>
|
||||
div(id := "daily_puzzle", title := trans.clickToSolve.txt())(
|
||||
raw(p.html),
|
||||
div(cls := "vstext")(
|
||||
trans.puzzleOfTheDay(),
|
||||
br,
|
||||
p.color.fold(trans.whitePlays, trans.blackPlays)()
|
||||
)
|
||||
)
|
||||
},
|
||||
!ctx.isBot option bits.underboards(tours, simuls, leaderboard, tournamentWinners),
|
||||
NotForKids {
|
||||
div(cls := "new_posts undertable")(
|
||||
div(cls := "undertable_top")(
|
||||
a(cls := "more", href := routes.ForumCateg.index)(trans.more(), " »"),
|
||||
span(cls := "title text", dataIcon := "d")(trans.latestForumPosts())
|
||||
),
|
||||
div(cls := "undertable_inner scroll-shadow-hard")(
|
||||
div(cls := "content")(views.html.forum.post recent forumRecent)
|
||||
)
|
||||
)
|
||||
},
|
||||
bits.lastPosts(lastPost),
|
||||
div(cls := "donation undertable")(
|
||||
a(href := routes.Plan.index)(
|
||||
i(dataIcon := patronIconChar),
|
||||
strong("Lichess Patron"),
|
||||
span(trans.directlySupportLichess())
|
||||
),
|
||||
a(href := routes.Page.swag)(
|
||||
i(dataIcon := ""),
|
||||
strong("Swag Store"),
|
||||
span(trans.playChessInStyle())
|
||||
)
|
||||
),
|
||||
div(cls := "about-footer")(a(href := "/about")(trans.aboutX("lichess.org")))
|
||||
)
|
||||
}
|
||||
|
||||
private val translations = List(
|
||||
trans.realTime,
|
||||
trans.correspondence,
|
||||
trans.nbGamesInPlay,
|
||||
trans.player,
|
||||
trans.time,
|
||||
trans.joinTheGame,
|
||||
trans.cancel,
|
||||
trans.casual,
|
||||
trans.rated,
|
||||
trans.variant,
|
||||
trans.mode,
|
||||
trans.list,
|
||||
trans.graph,
|
||||
trans.filterGames,
|
||||
trans.youNeedAnAccountToDoThat,
|
||||
trans.oneDay,
|
||||
trans.nbDays,
|
||||
trans.aiNameLevelAiLevel,
|
||||
trans.yourTurn,
|
||||
trans.rating,
|
||||
trans.createAGame,
|
||||
trans.quickPairing,
|
||||
trans.lobby,
|
||||
trans.custom,
|
||||
trans.anonymous
|
||||
)
|
||||
|
||||
private val nbPlayersPlaceholder = Html("<strong>-,---</strong>")
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
@(data: play.api.libs.json.JsObject, userTimeline: Vector[lila.timeline.Entry], forumRecent: List[lila.forum.MiniForumPost], tours: List[Tournament], events: List[lila.event.Event], simuls: List[lila.simul.Simul], featured: Option[Game], leaderboard: List[User.LightPerf], tournamentWinners: List[lila.tournament.Winner], puzzle: Option[lila.puzzle.DailyPuzzle], streams: lila.streamer.LiveStreams.WithTitles, lastPost: List[lila.blog.MiniPost], playban: Option[lila.playban.TempBan], currentGame: Option[lila.app.mashup.Preload.CurrentGame], nbRounds: Int)(implicit ctx: Context)
|
||||
|
||||
@import play.api.libs.json.Json
|
||||
|
||||
@underchat = {
|
||||
<div id="featured_game">
|
||||
@featured.map { g =>
|
||||
@gameFen(Pov.first(g), tv = true)
|
||||
@game.bits.vstext(Pov.first(g))(ctx.some).toHtml
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@side = {
|
||||
@NotForKids {
|
||||
<div id="streams_on_air">@streamer.liveStreams(streams)</div>
|
||||
}
|
||||
@events.map { e =>
|
||||
@event.homepageSpotlight(e)
|
||||
}
|
||||
@if(!ctx.isBot) {
|
||||
@lila.tournament.Spotlight.select(tours, ctx.me, 3).map { tour =>
|
||||
@tournament.homepageSpotlight(tour)
|
||||
}
|
||||
@simuls.find(_.spotlightable).take(2).map { s =>
|
||||
@simul.homepageSpotlight(s)
|
||||
}
|
||||
}
|
||||
@ctx.me.map { u =>
|
||||
<div id="timeline" data-href="@routes.Timeline.home">
|
||||
@timeline.entries(userTimeline)
|
||||
<div class="links">
|
||||
@if(userTimeline.size >= 8) {
|
||||
<a class="more" href="@routes.Timeline.home">@trans.more() »</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}.getOrElse {
|
||||
<div class="about-side">
|
||||
@trans.xIsAFreeYLibreOpenSourceChessServer("Lichess", Html(s"""<a class="blue" href="${routes.Plan.features}">${trans.really.txt()}</a>"""))
|
||||
<a class="blue" href="/about">@trans.aboutX("lichess.org")...</a>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@baseline = {
|
||||
<a id="nb_connected_players" href="@routes.User.list">
|
||||
@trans.nbPlayers(Html("<strong>-,---</strong>"))
|
||||
</a>
|
||||
<a id="nb_games_in_play" href="@routes.Tv.games">
|
||||
@trans.nbGamesInPlay.plural(nbRounds, Html(s"<span>${nbRounds}</span>"))
|
||||
</a>
|
||||
@if(ctx.isMobileBrowser) {
|
||||
@if(lila.common.HTTPRequest.isAndroid(ctx.req)) {
|
||||
@mobile.googlePlayButton()
|
||||
} else {
|
||||
@if(lila.common.HTTPRequest.isIOS(ctx.req)) {
|
||||
@mobile.appleStoreButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@moreJs = {
|
||||
@jsAt(s"compiled/lichess.lobby${isProd??(".min")}.js", async = true)
|
||||
@embedJs {
|
||||
window.customWS = true;
|
||||
lichess_lobby = {
|
||||
data: @safeJson(data),
|
||||
playban: @htmlOrNull(playban) { pb =>
|
||||
@safeJson(Json.obj("minutes" -> pb.mins, "remainingSeconds" -> (pb.remainingSeconds + 3)))
|
||||
},
|
||||
currentGame: @htmlOrNull(currentGame) { cg =>
|
||||
@safeJson(cg.json)
|
||||
},
|
||||
i18n: @jsI18n()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@base.layout(
|
||||
title = "",
|
||||
fullTitle = Some("lichess.org • " + trans.freeOnlineChess.txt()),
|
||||
baseline = baseline.some,
|
||||
side = side.some,
|
||||
moreJs = moreJs,
|
||||
moreCss = cssTag("home.css"),
|
||||
underchat = underchat.some,
|
||||
chessground = false,
|
||||
openGraph = lila.app.ui.OpenGraph(
|
||||
image = staticUrl("images/large_tile.png").some,
|
||||
title = "The best free, adless Chess server",
|
||||
url = netBaseUrl,
|
||||
description = trans.siteDescription.txt()
|
||||
).some,
|
||||
asyncJs = true) {
|
||||
<div class="lobby_and_ground@if(playban.isDefined){ playban}@if(currentGame.isDefined){ current_game}">
|
||||
@currentGame.map(currentGameInfo(_))
|
||||
<div id="hooks_wrap"></div>
|
||||
@playban.map(ban => playbanInfo(ban.remainingSeconds))
|
||||
<div id="start_buttons" class="lichess_ground">
|
||||
<a class="fat button config_hook@if(playban.isDefined || currentGame.isDefined || ctx.isBot){ disabled}" href="@routes.Setup.hookForm">@trans.createAGame()</a>
|
||||
<a class="fat button config_friend@if(currentGame.isDefined){ disabled}" href="@routes.Setup.friendForm(none)">@trans.playWithAFriend()</a>
|
||||
<a class="fat button config_ai@if(currentGame.isDefined){ disabled}" href="@routes.Setup.aiForm">@trans.playWithTheMachine()</a>
|
||||
</div>
|
||||
</div>
|
||||
@puzzle.map { p =>
|
||||
<div id="daily_puzzle" title="@trans.clickToSolve()">
|
||||
@Html(p.html)
|
||||
<div class="vstext">
|
||||
@trans.puzzleOfTheDay()<br />
|
||||
@p.color.fold(trans.whitePlays, trans.blackPlays)()
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if(!ctx.isBot) {@bits.underboards(tours, simuls, leaderboard, tournamentWinners).toHtml}
|
||||
@NotForKids {
|
||||
<div class="new_posts undertable">
|
||||
<div class="undertable_top">
|
||||
<a class="more" href="@routes.ForumCateg.index()">@trans.more() »</a>
|
||||
<span class="title" data-icon="d"> @trans.latestForumPosts()</span>
|
||||
</div>
|
||||
<div class="undertable_inner scroll-shadow-hard">
|
||||
<div class="content">@forum.post.recent(forumRecent).toHtml</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@bits.lastPosts(lastPost).map(_.toHtml)
|
||||
<div class="donation undertable">
|
||||
<a href="@routes.Plan.index">
|
||||
<i data-icon="@patronIconChar"></i>
|
||||
<strong>Lichess Patron</strong>
|
||||
<span>@trans.directlySupportLichess()</span>
|
||||
</a>
|
||||
<a href="@routes.Page.swag">
|
||||
<i data-icon=""></i>
|
||||
<strong>Swag Store</strong>
|
||||
<span>@trans.playChessInStyle()</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="about-footer"><a href="/about">@trans.aboutX("lichess.org")</a></div>
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
@()(implicit ctx: Context)
|
||||
@safeJson(i18nJsObject(
|
||||
trans.realTime,
|
||||
trans.correspondence,
|
||||
trans.nbGamesInPlay,
|
||||
trans.player,
|
||||
trans.time,
|
||||
trans.joinTheGame,
|
||||
trans.cancel,
|
||||
trans.casual,
|
||||
trans.rated,
|
||||
trans.variant,
|
||||
trans.mode,
|
||||
trans.list,
|
||||
trans.graph,
|
||||
trans.filterGames,
|
||||
trans.youNeedAnAccountToDoThat,
|
||||
trans.oneDay,
|
||||
trans.nbDays,
|
||||
trans.aiNameLevelAiLevel,
|
||||
trans.yourTurn,
|
||||
trans.rating,
|
||||
trans.createAGame,
|
||||
trans.quickPairing,
|
||||
trans.lobby,
|
||||
trans.custom,
|
||||
trans.anonymous
|
||||
))
|
|
@ -1,7 +0,0 @@
|
|||
<a class="store"
|
||||
href="https://itunes.apple.com/us/app/lichess-free-online-chess/id968371784">
|
||||
<img alt="Download on the Apple App Store"
|
||||
width="172"
|
||||
height="50"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/3c/Download_on_the_App_Store_Badge.svg" />
|
||||
</a>
|
|
@ -0,0 +1,32 @@
|
|||
package views.html.mobile
|
||||
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.i18n.{ I18nKeys => trans }
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object bits {
|
||||
|
||||
lazy val appleStoreButton = raw("""
|
||||
<a class="store"
|
||||
href="https://itunes.apple.com/us/app/lichess-free-online-chess/id968371784">
|
||||
<img alt="Download on the Apple App Store"
|
||||
width="172"
|
||||
height="50"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/3c/Download_on_the_App_Store_Badge.svg" />
|
||||
</a>
|
||||
""")
|
||||
|
||||
lazy val googlePlayButton = raw("""
|
||||
<a class="store"
|
||||
href="https://play.google.com/store/apps/details?id=org.lichess.mobileapp">
|
||||
<img alt="Android app on Google Play"
|
||||
width="192"
|
||||
height="74"
|
||||
src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" />
|
||||
</a>
|
||||
""")
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<a class="store"
|
||||
href="https://play.google.com/store/apps/details?id=org.lichess.mobileapp">
|
||||
<img alt="Android app on Google Play"
|
||||
width="192"
|
||||
height="74"
|
||||
src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" />
|
||||
</a>
|
|
@ -10,8 +10,8 @@ moreCss = cssTag("mobile.css")) {
|
|||
</div>
|
||||
<div class="left-side">
|
||||
<h1>@trans.playChessEverywhere()</h1>
|
||||
@googlePlayButton()
|
||||
@appleStoreButton()
|
||||
@bits.googlePlayButton.toHtml
|
||||
@bits.appleStoreButton.toHtml
|
||||
<div class="apk" style="margin-top: 20px">
|
||||
@Html(~apkDoc.getHtml("doc.content", resolver))
|
||||
</div>
|
||||
|
|
|
@ -131,7 +131,7 @@ lazy val evaluation = module("evaluation", Seq(
|
|||
// )
|
||||
|
||||
lazy val common = module("common", Seq()).settings(
|
||||
libraryDependencies ++= provided(play.api, play.test, reactivemongo.driver, kamon.core)
|
||||
libraryDependencies ++= provided(play.api, play.test, reactivemongo.driver, kamon.core, scalatags)
|
||||
)
|
||||
|
||||
lazy val rating = module("rating", Seq(common, db)).settings(
|
||||
|
|
Loading…
Reference in New Issue