lila/ui/puzzle/src/view/main.ts

186 lines
5.4 KiB
TypeScript
Raw Normal View History

2020-11-29 16:27:06 -07:00
import * as control from '../control';
import * as side from './side';
2020-12-03 09:51:17 -07:00
import theme from './theme';
import chessground from './chessground';
import feedbackView from './feedback';
2020-03-22 12:09:33 -06:00
import { Controller } from '../interfaces';
2021-04-05 01:10:35 -06:00
import { h, VNode } from 'snabbdom';
2021-08-21 06:27:23 -06:00
import { onInsert, bindMobileMousedown, bindNonPassive } from 'common/snabbdom';
2020-11-29 16:27:06 -07:00
import { render as treeView } from './tree';
import { view as cevalView } from 'ceval';
2020-01-02 08:51:13 -07:00
function renderAnalyse(ctrl: Controller): VNode {
2021-02-06 06:26:05 -07:00
return h('div.puzzle__moves.areplay', [treeView(ctrl)]);
}
2020-03-30 08:19:35 -06:00
function wheel(ctrl: Controller, e: WheelEvent): false | undefined {
const target = e.target as HTMLElement;
2019-05-12 23:44:17 -06:00
if (target.tagName !== 'PIECE' && target.tagName !== 'SQUARE' && target.tagName !== 'CG-BOARD') return;
e.preventDefault();
if (e.deltaY > 0) control.next(ctrl);
else if (e.deltaY < 0) control.prev(ctrl);
ctrl.redraw();
return false;
}
function dataAct(e: Event): string | null {
const target = e.target as HTMLElement;
return target.getAttribute('data-act') || (target.parentNode as HTMLElement).getAttribute('data-act');
}
function jumpButton(icon: string, effect: string, disabled: boolean, glowing = false): VNode {
2019-03-04 01:57:30 -07:00
return h('button.fbt', {
2020-12-13 01:04:54 -07:00
class: { disabled, glowing },
attrs: {
'data-act': effect,
2021-02-06 06:26:05 -07:00
'data-icon': icon,
},
});
}
2020-01-02 08:51:13 -07:00
function controls(ctrl: Controller): VNode {
2020-12-09 03:18:18 -07:00
const node = ctrl.vm.node;
2020-12-13 01:04:54 -07:00
const nextNode = node.children[0];
2020-12-14 10:23:16 -07:00
const goNext = ctrl.vm.mode == 'play' && nextNode && nextNode.puzzle != 'fail';
2021-02-06 06:26:05 -07:00
return h(
'div.puzzle__controls.analyse-controls',
{
hook: onInsert(el => {
bindMobileMousedown(
el,
e => {
const action = dataAct(e);
if (action === 'prev') control.prev(ctrl);
else if (action === 'next') control.next(ctrl);
else if (action === 'first') control.first(ctrl);
else if (action === 'last') control.last(ctrl);
},
ctrl.redraw
);
}),
},
[
h('div.jumps', [
jumpButton('', 'first', !node.ply),
jumpButton('', 'prev', !node.ply),
jumpButton('', 'next', !nextNode, goNext),
jumpButton('', 'last', !nextNode, goNext),
2021-02-06 06:26:05 -07:00
]),
]
);
}
let cevalShown = false;
2021-02-06 06:26:05 -07:00
export default function (ctrl: Controller): VNode {
2021-06-06 05:40:03 -06:00
if (ctrl.nvui) return ctrl.nvui.render(ctrl);
const showCeval = ctrl.vm.showComputer(),
gaugeOn = ctrl.showEvalGauge();
if (cevalShown !== showCeval) {
if (!cevalShown) ctrl.vm.autoScrollNow = true;
cevalShown = showCeval;
}
2021-02-06 06:26:05 -07:00
return h(
`main.puzzle.puzzle-${ctrl.getData().replay ? 'replay' : 'play'}${ctrl.streak ? '.puzzle--streak' : ''}`,
2021-02-06 06:26:05 -07:00
{
class: { 'gauge-on': gaugeOn },
hook: {
postpatch(old, vnode) {
if (old.data!.gaugeOn !== gaugeOn) {
2021-04-20 12:37:16 -06:00
if (ctrl.pref.coords === Prefs.Coords.Outside) {
2021-02-06 06:26:05 -07:00
$('body').toggleClass('coords-in', gaugeOn).toggleClass('coords-out', !gaugeOn);
}
document.body.dispatchEvent(new Event('chessground.resize'));
}
2021-02-06 06:26:05 -07:00
vnode.data!.gaugeOn = gaugeOn;
},
},
},
[
h('aside.puzzle__side', [
side.replay(ctrl),
side.puzzleBox(ctrl),
2021-03-28 14:05:03 -06:00
ctrl.streak ? side.streakBox(ctrl) : side.userBox(ctrl),
2021-02-06 06:26:05 -07:00
side.config(ctrl),
theme(ctrl),
]),
h(
'div.puzzle__board.main-board' + (ctrl.pref.blindfold ? '.blindfold' : ''),
{
hook:
'ontouchstart' in window || lichess.storage.get('scrollMoves') == '0'
? undefined
2021-08-21 06:27:23 -06:00
: bindNonPassive('wheel', e => wheel(ctrl, e as WheelEvent)),
2021-02-06 06:26:05 -07:00
},
[chessground(ctrl), ctrl.promotion.view()]
),
cevalView.renderGauge(ctrl),
h('div.puzzle__tools', [
// we need the wrapping div here
// so the siblings are only updated when ceval is added
h(
'div.ceval-wrap',
{
class: { none: !showCeval },
},
showCeval ? [cevalView.renderCeval(ctrl), cevalView.renderPvs(ctrl)] : []
),
renderAnalyse(ctrl),
feedbackView(ctrl),
]),
controls(ctrl),
session(ctrl),
]
);
2019-02-14 05:24:58 -07:00
}
2020-11-29 16:27:06 -07:00
function session(ctrl: Controller) {
2020-11-30 02:30:07 -07:00
const rounds = ctrl.session.get().rounds,
current = ctrl.getData().puzzle.id;
return h('div.puzzle__session', [
2020-12-23 07:22:09 -07:00
...rounds.map(round => {
2021-10-21 04:56:34 -06:00
const rd =
round.ratingDiff && ctrl.showRatings
? round.ratingDiff > 0
? '+' + round.ratingDiff
: round.ratingDiff
: null;
2021-02-06 06:26:05 -07:00
return h(
`a.result-${round.result}${rd ? '' : '.result-empty'}`,
{
key: round.id,
class: {
current: current == round.id,
},
attrs: {
href: `/training/${ctrl.session.theme}/${round.id}`,
2021-06-24 02:47:25 -06:00
...(ctrl.streak ? { target: '_blank', rel: 'noopener' } : {}),
2021-02-06 06:26:05 -07:00
},
2020-11-29 16:27:06 -07:00
},
2021-02-06 06:26:05 -07:00
rd
);
2020-12-23 07:22:09 -07:00
}),
2021-02-06 06:26:05 -07:00
rounds.find(r => r.id == current)
2021-03-28 14:05:03 -06:00
? ctrl.streak
? null
: h('a.session-new', {
key: 'new',
attrs: {
href: `/training/${ctrl.session.theme}`,
},
})
2021-03-29 10:02:22 -06:00
: h(
'a.result-cursor.current',
{
key: current,
attrs: ctrl.streak
? {}
: {
href: `/training/${ctrl.session.theme}/${current}`,
},
},
ctrl.streak?.data.index
),
2020-11-30 02:30:07 -07:00
]);
2020-11-29 16:27:06 -07:00
}