activity UI WIP
parent
92c7a5a001
commit
0a1e8c7637
|
@ -12,8 +12,8 @@ import lila.common.paginator.Paginator
|
||||||
import lila.common.{ IpAddress, HTTPRequest }
|
import lila.common.{ IpAddress, HTTPRequest }
|
||||||
import lila.game.{ GameRepo, Game => GameModel }
|
import lila.game.{ GameRepo, Game => GameModel }
|
||||||
import lila.rating.PerfType
|
import lila.rating.PerfType
|
||||||
import lila.user.{ User => UserModel, UserRepo }
|
|
||||||
import lila.socket.UserLagCache
|
import lila.socket.UserLagCache
|
||||||
|
import lila.user.{ User => UserModel, UserRepo }
|
||||||
import views._
|
import views._
|
||||||
|
|
||||||
object User extends LilaController {
|
object User extends LilaController {
|
||||||
|
@ -322,4 +322,12 @@ object User extends LilaController {
|
||||||
def myself = Auth { ctx => me =>
|
def myself = Auth { ctx => me =>
|
||||||
fuccess(Redirect(routes.User.show(me.username)))
|
fuccess(Redirect(routes.User.show(me.username)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def activity(username: String) = Open { implicit ctx =>
|
||||||
|
OptionFuResult(UserRepo named username) { user =>
|
||||||
|
Env.activity.read.recent(user.id, 3) map { as =>
|
||||||
|
Ok(html.activity.list(user, as))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package views.html.activity
|
||||||
|
|
||||||
|
import play.twirl.api.Html
|
||||||
|
|
||||||
|
import lila.activity.activities._
|
||||||
|
import lila.activity.model._
|
||||||
|
import lila.api.Context
|
||||||
|
import lila.i18n.{ I18nKey, I18nKeys => trans }
|
||||||
|
|
||||||
|
object ActivityHtml extends lila.Steroids {
|
||||||
|
|
||||||
|
def scoreHtml(s: Score)(implicit ctx: Context) = Html {
|
||||||
|
s"""<score>${scorePart("win", s.win, trans.nbWins)}${scorePart("draw", s.draw, trans.nbDraws)}${scorePart("loss", s.loss, trans.nbLosses)}</score>"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private def scorePart(tag: String, p: Int, name: I18nKey)(implicit ctx: Context) =
|
||||||
|
if (p == 0) ""
|
||||||
|
else s"""<$tag>${wrapNumber(name.pluralSameTxt(p))}</$tag>"""
|
||||||
|
|
||||||
|
private val wrapNumberRegex = """(\d+)""".r
|
||||||
|
private def wrapNumber(str: String) =
|
||||||
|
wrapNumberRegex.replaceAllIn(str, "<strong>$1</strong>")
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
@(u: User, as: List[lila.activity.ActivityView.AsTo])(implicit ctx: Context)
|
||||||
|
|
||||||
|
@import ActivityHtml._
|
||||||
|
|
||||||
|
@moreCss = {
|
||||||
|
@cssTag("activity.css")
|
||||||
|
}
|
||||||
|
|
||||||
|
@user.layout(
|
||||||
|
title = s"${u.username} activity",
|
||||||
|
evenMoreCss = moreCss) {
|
||||||
|
<div class="content_box no_padding activity">
|
||||||
|
<div class="content_box_top">
|
||||||
|
<h1 class="lichess_title">
|
||||||
|
<a href="@routes.User.show(u.username)">
|
||||||
|
@u.username activity
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="timeline">
|
||||||
|
@as.map {
|
||||||
|
case lila.activity.ActivityView.AsTo(date, a) => {
|
||||||
|
<section>
|
||||||
|
<h2>@semanticDate(date)</h2>
|
||||||
|
@defining(a.puzzles) { p =>
|
||||||
|
<div class="entry puzzles">
|
||||||
|
<strong>Played @p.score.size tactical puzzles</strong>
|
||||||
|
@scoreHtml(p.score)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@a.games.value.map {
|
||||||
|
case (pt, score) => {
|
||||||
|
<div class="entry games">
|
||||||
|
<strong>Played @score.size @pt.name games</strong>
|
||||||
|
@scoreHtml(score)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content_box_content">right here.</div>
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -55,6 +55,7 @@ GET /@/:username/mod controllers.User.mod(username: String)
|
||||||
POST /@/:username/note controllers.User.writeNote(username: String)
|
POST /@/:username/note controllers.User.writeNote(username: String)
|
||||||
GET /@/:username/mini controllers.User.showMini(username: String)
|
GET /@/:username/mini controllers.User.showMini(username: String)
|
||||||
GET /@/:username/tv controllers.User.tv(username: String)
|
GET /@/:username/tv controllers.User.tv(username: String)
|
||||||
|
GET /@/:username/activity controllers.User.activity(username: String)
|
||||||
GET /@/:username/studyTv controllers.User.studyTv(username: String)
|
GET /@/:username/studyTv controllers.User.studyTv(username: String)
|
||||||
GET /@/:username/perf/:perfKey controllers.User.perfStat(username: String, perfKey: String)
|
GET /@/:username/perf/:perfKey controllers.User.perfStat(username: String, perfKey: String)
|
||||||
GET /@/:username/:filterName controllers.User.showFilter(username: String, filterName: String, page: Int ?= 1)
|
GET /@/:username/:filterName controllers.User.showFilter(username: String, filterName: String, page: Int ?= 1)
|
||||||
|
|
|
@ -18,8 +18,7 @@ case class Activity(
|
||||||
corres: Corres
|
corres: Corres
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def userId = id.userId
|
def date = Activity.Day.genesis plusDays id.day.value
|
||||||
def day = id.day
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Activity {
|
object Activity {
|
||||||
|
@ -36,6 +35,9 @@ object Activity {
|
||||||
object Day {
|
object Day {
|
||||||
val genesis = new DateTime(2010, 1, 1, 0, 0).withTimeAtStartOfDay
|
val genesis = new DateTime(2010, 1, 1, 0, 0).withTimeAtStartOfDay
|
||||||
def today = Day(Days.daysBetween(genesis, DateTime.now.withTimeAtStartOfDay).getDays)
|
def today = Day(Days.daysBetween(genesis, DateTime.now.withTimeAtStartOfDay).getDays)
|
||||||
|
def recent(nb: Int): List[Day] = (0 to (nb - 1)).toList.map { delta =>
|
||||||
|
Day(Days.daysBetween(genesis, DateTime.now.minusDays(delta).withTimeAtStartOfDay).getDays)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def make(userId: User.ID) = Activity(
|
def make(userId: User.ID) = Activity(
|
||||||
|
|
|
@ -12,5 +12,16 @@ final class ActivityReadApi(coll: Coll) {
|
||||||
import BSONHandlers._
|
import BSONHandlers._
|
||||||
import activities._
|
import activities._
|
||||||
|
|
||||||
def get(userId: User.ID) = coll.byId[Activity, Id](Id today userId)
|
def recent(userId: User.ID, days: Int): Fu[List[ActivityView.AsTo]] =
|
||||||
|
coll.find($inIds(makeIds(userId, days))).list[Activity]() map { as =>
|
||||||
|
as.map { a =>
|
||||||
|
ActivityView.AsTo(
|
||||||
|
a.pp.date,
|
||||||
|
ActivityView(a.games, a.puzzles)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def makeIds(userId: User.ID, days: Int): List[Id] =
|
||||||
|
Day.recent(days).map { Id(userId, _) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package lila.activity
|
||||||
|
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
|
import lila.user.User
|
||||||
|
|
||||||
|
import activities._
|
||||||
|
|
||||||
|
case class ActivityView(
|
||||||
|
games: Games,
|
||||||
|
puzzles: Puzzles
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
object ActivityView {
|
||||||
|
|
||||||
|
case class AsTo(day: DateTime, activity: ActivityView)
|
||||||
|
}
|
|
@ -25,4 +25,4 @@ object Insight {
|
||||||
case class Stacked(points: List[(Metric.MetricValueName, Point)]) extends Insight
|
case class Stacked(points: List[(Metric.MetricValueName, Point)]) extends Insight
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Point(y: Double)
|
case class Point(y: Double) extends AnyVal
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
.activity section::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 15px;
|
||||||
|
z-index: -1;
|
||||||
|
display: block;
|
||||||
|
width: 2px;
|
||||||
|
content: "";
|
||||||
|
background-color: #e6ebf1;
|
||||||
|
}
|
||||||
|
.activity section h2 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.activity .entry {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.activity .entry strong {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.activity .score {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.activity .score strong {
|
||||||
|
}
|
Loading…
Reference in New Issue