simple but decent multiboard view

studyMultiboard
Thibault Duplessis 2018-11-22 14:30:54 +07:00
parent d21f602a73
commit e2f04bd4a5
7 changed files with 79 additions and 46 deletions

View File

@ -120,7 +120,7 @@ object JsonView {
implicit val chapterIdWrites: Writes[Chapter.Id] = stringIsoWriter(Chapter.idIso)
implicit val chapterNameWrites: Writes[Chapter.Name] = stringIsoWriter(Chapter.nameIso)
private implicit val uciWrites: Writes[Uci] = Writes[Uci] { u =>
private[study] implicit val uciWrites: Writes[Uci] = Writes[Uci] { u =>
JsString(u.uci)
}
private implicit val uciCharPairWrites: Writes[UciCharPair] = Writes[UciCharPair] { u =>

View File

@ -24,6 +24,7 @@ sealed trait RootOrNode {
def fullMoveNumber = 1 + ply / 2
def mainline: List[Node]
def color = chess.Color(ply % 2 == 0)
def moveOption: Option[Uci.WithSan]
}
case class Node(
@ -97,6 +98,8 @@ case class Node(
forceVariation = n.forceVariation || forceVariation
)
def moveOption = move.some
override def toString = s"$ply.${move.san} ${children.nodes}"
}
@ -295,6 +298,8 @@ object Node {
def mainlinePath = Path(mainline.map(_.id))
def lastMainlineNode: RootOrNode = children.lastMainlineNode getOrElse this
def moveOption = none
}
object Root {

View File

@ -4,8 +4,8 @@ import play.api.libs.json._
import reactivemongo.bson._
import chess.Color
import chess.format.FEN
import chess.format.pgn.{ Tag, Tags }
import chess.format.{ FEN, Uci }
import BSONHandlers._
import JsonView._
@ -33,15 +33,19 @@ final class StudyMultiBoard(
)
private implicit val previewBSONReader = new BSONDocumentReader[ChapterPreview] {
def read(doc: BSONDocument) = ChapterPreview(
id = doc.getAs[Chapter.Id]("_id") err "Preview missing id",
name = doc.getAs[Chapter.Name]("name") err "Preview missing name",
players = doc.getAs[Tags]("tags") flatMap ChapterPreview.players,
orientation = doc.getAs[Bdoc]("setup") flatMap { setup =>
setup.getAs[Color]("orientation")
} getOrElse Color.White,
fen = doc.getAs[Node.Root]("root").err("Preview missing root").lastMainlineNode.fen
)
def read(doc: BSONDocument) = {
val node = doc.getAs[Node.Root]("root").err("Preview missing root").lastMainlineNode
ChapterPreview(
id = doc.getAs[Chapter.Id]("_id") err "Preview missing id",
name = doc.getAs[Chapter.Name]("name") err "Preview missing name",
players = doc.getAs[Tags]("tags") flatMap ChapterPreview.players,
orientation = doc.getAs[Bdoc]("setup") flatMap { setup =>
setup.getAs[Color]("orientation")
} getOrElse Color.White,
fen = node.fen,
lastMove = node.moveOption.map(_.uci)
)
}
}
private implicit val previewPlayerWriter: Writes[ChapterPreview.Player] = Writes[ChapterPreview.Player] { p =>
@ -67,7 +71,8 @@ object StudyMultiBoard {
name: Chapter.Name,
players: Option[ChapterPreview.Players],
orientation: Color,
fen: FEN
fen: FEN,
lastMove: Option[Uci]
)
object ChapterPreview {

View File

@ -575,25 +575,32 @@ body.base .study_buttons .fbt.active {
margin-top: 2em;
}
.multi_board {
padding: 4px 0 0 4px;
display: flex;
flex-flow: row wrap;
#now_playing {
padding-left: 1px;
white-space: nowrap;
}
.multi_board .spinner {
#now_playing .spinner {
margin: 50px auto;
}
.multi_board > a {
padding: 4px;
#now_playing > a {
flex: 0 0 160px;
overflow: hidden;
padding: 5px;
transition: background 0.13s;
background: rgba(255, 255, 255, 0.6);
}
.multi_board > a:hover {
#now_playing > a:nth-child(even) {
background: rgba(128, 128, 128, 0.2);
}
#now_playing > a:hover {
background: rgba(191, 231, 255, 0.7);
}
.multi_board .cg-board-wrap {
width: 160px;
height: 160px;
#now_playing a.active {
background: rgba(99,155,36,0.8);
color: #fff;
}
#now_playing .player {
display: flex;
justify-content: space-between;
}
div.advice_summary {

View File

@ -1,9 +1,10 @@
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import { Chessground } from 'chessground';
import { ChapterPreview } from './interfaces';
import { opposite } from 'chessground/util';
import { StudyCtrl, ChapterPreview, ChapterPreviewPlayer } from './interfaces';
import { multiBoard as xhrLoad } from './studyXhr';
import { spinner } from '../util';
import { bind, spinner } from '../util';
interface MultiBoardData {
previews: [ChapterPreview]
@ -16,30 +17,45 @@ export class MultiBoardCtrl {
constructor(readonly studyId: string, readonly redraw: () => void) {
}
getData() {
if (!this.data) xhrLoad(this.studyId).then(d => {
reload() {
xhrLoad(this.studyId).then(d => {
this.data = d;
this.redraw();
});
return this.data;
}
}
export function view(ctrl: MultiBoardCtrl, study: StudyCtrl): VNode | undefined {
return h('div#now_playing', {
hook: {
insert() { ctrl.reload(); }
}
}, ctrl.data ? ctrl.data.previews.map(makePreview(study)) : [spinner()]);
}
function makePreview(study: StudyCtrl) {
return (preview: ChapterPreview) => {
const contents = preview.players ? [
makePlayer(preview.players[opposite(preview.orientation)]),
makeCg(preview),
makePlayer(preview.players[preview.orientation])
] : [makeCg(preview)];
return h('a.mini_board', {
class: { active: study.vm.chapterId == preview.id },
hook: bind('mousedown', _ => study.setChapter(preview.id))
}, contents);
};
}
export function view(ctrl: MultiBoardCtrl): VNode | undefined {
const data = ctrl.getData();
if (!data) return h('div.multi_board', spinner());
return h('div.multi_board',
data.previews.map(preview => {
return h('a.mini_board', [
makeCg(preview)
])
})
);
function makePlayer(player: ChapterPreviewPlayer): VNode {
return h('div.player', [
player.title ? `${player.title} ${player.name}` : player.name,
player.rating && h('span', '' + player.rating)
]);
}
function makeCg(preview: ChapterPreview) {
function makeCg(preview: ChapterPreview): VNode {
return h('div.cg-board-wrap', {
hook: {
insert(vnode) {
@ -51,7 +67,7 @@ function makeCg(preview: ChapterPreview) {
viewOnly: true,
orientation: preview.orientation,
fen: preview.fen,
lastMove: lm && ([lm[0] + lm[1], lm[2] + lm[3]] as Key[])
lastMove: lm ? ([lm[0] + lm[1], lm[2] + lm[3]] as Key[]) : undefined
});
}
}

View File

@ -537,11 +537,11 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
vm.justSetChapterId = id;
redraw();
},
toggleSticky: function() {
toggleSticky() {
vm.mode.sticky = !vm.mode.sticky && data.features.sticky;
xhrReload();
},
toggleWrite: function() {
toggleWrite() {
vm.mode.write = !vm.mode.write && members.canContribute();
xhrReload();
},

View File

@ -230,7 +230,7 @@ export function underboard(ctrl: AnalyseCtrl): MaybeVNodes {
panel = studyShareView(study.share);
break;
case 'multiBoard':
panel = multiBoardView(study.multiBoard);
panel = multiBoardView(study.multiBoard, study);
break;
}
return [