Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5f2dd8b
keyboardMove preference honored on analyze page
brollin Mar 29, 2024
dd7573f
first pass at keyboard move on analyzed page
brollin Mar 29, 2024
f5663ad
code golf
brollin Mar 31, 2024
03a4439
more keyboard move functionally
brollin Mar 31, 2024
269431f
implement keyboard move on study page
brollin Mar 31, 2024
d899200
rename function for clarity
brollin Apr 2, 2024
e677a01
remove unused sendMove keyboardMove function
brollin Apr 2, 2024
4a83260
clear keyboardMove input when no opponent and who command used
brollin Apr 2, 2024
5cfc135
implement crazyhouse keyboardMove functionality on analysis page
brollin Apr 5, 2024
c5b80c1
remove console log
brollin Apr 5, 2024
e11dc11
ensure that keyboardMove updates only occur when controller and cg st…
brollin Apr 6, 2024
7da7fd8
augment keyboardMove root data
brollin Apr 6, 2024
b550956
do another pass on css
brollin Apr 6, 2024
17bf59c
include keyboardMove in tsconfig
brollin Apr 6, 2024
d47eca7
sbt scalafmt
brollin Apr 6, 2024
4298eb9
retrieve crazyhouse pockets dynamically
brollin Apr 7, 2024
5059e3e
Merge branch 'master' into analysis-keyboard-input
ornicar Apr 8, 2024
6f17c16
remove unnecessary `?? ''`
ornicar Apr 8, 2024
42bbde4
and another one
ornicar Apr 8, 2024
fcbf24f
move creation of keyboardMove into controller
brollin Apr 9, 2024
a5558c1
extract helper function for clarity
brollin Apr 9, 2024
10b0d24
rename aux => plugin
brollin Apr 9, 2024
66f4608
small styling fix ups
brollin Apr 9, 2024
1a4004b
move arrow key handling logic into root controller
brollin Apr 14, 2024
06b84be
put keyboard move towards end of tab order
brollin Apr 14, 2024
7f4517e
allow toggling ceval via enter when focused
brollin Apr 14, 2024
862a8d5
fix merge conflicts
schlawg Apr 28, 2024
70fa45e
Merge branch 'master' into analysis-keyboard-input
ornicar May 1, 2024
eda9c79
remove duplicated code probably coming from a merge
ornicar May 1, 2024
104f937
only hide dasher board reset when actually resetting
ornicar May 1, 2024
bad525a
Merge branch 'master' into analysis-keyboard-input
ornicar May 2, 2024
b32612e
fix rendering bug with tab order change
brollin May 2, 2024
812f0c7
optionally include keyboardMove styling on user analysis page
brollin May 2, 2024
650176c
one column styling fixes
brollin May 2, 2024
f45c60e
Merge branch 'master' into analysis-keyboard-input
ornicar May 2, 2024
dca9c2e
Merge branch 'analysis-keyboard-input' of https://github.com/brollin/…
ornicar May 2, 2024
d57c5fd
Merge branch 'master' into analysis-keyboard-input
ornicar May 3, 2024
a31f327
fix previous merge
ornicar May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/views/analyse/replay.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ object replay:
.cssTag("analyse.round")
.cssTag((pov.game.variant == Crazyhouse).option("analyse.zh"))
.cssTag(ctx.blind.option("round.nvui"))
.cssTag(ctx.pref.hasKeyboardMove.option("keyboardMove"))
.js(analyseNvuiTag)
.js(
bits.analyseModule(
Expand Down
1 change: 1 addition & 0 deletions app/views/study.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def show(
)(using ctx: Context) =
Page(s.name.value)
.cssTag("analyse.study")
.cssTag(ctx.pref.hasKeyboardMove.option("keyboardMove"))
.js(analyseNvuiTag)
.js(
PageModule(
Expand Down
1 change: 1 addition & 0 deletions modules/analyse/src/main/ui/AnalyseUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ final class AnalyseUi(helpers: Helpers)(externalEngineEndpoint: String):
.cssTag((pov.game.variant == Crazyhouse).option("analyse.zh"))
.cssTag(withForecast.option("analyse.forecast"))
.cssTag(ctx.blind.option("round.nvui"))
.cssTag(ctx.pref.hasKeyboardMove.option("keyboardMove"))
.csp(csp.compose(_.withExternalAnalysisApis))
.graph(
title = "Chess analysis board",
Expand Down
6 changes: 4 additions & 2 deletions modules/round/src/main/JsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ final class JsonView(
"coords" -> pref.coords,
"resizeHandle" -> pref.resizeHandle,
"replay" -> pref.replay,
"clockTenths" -> pref.clockTenths
"clockTenths" -> pref.clockTenths,
"keyboardMove" -> pref.hasKeyboardMove
)
.add("is3d" -> pref.is3d)
.add("clockBar" -> pref.clockBar)
Expand Down Expand Up @@ -288,7 +289,8 @@ final class JsonView(
"animationDuration" -> animationMillis(pov, pref),
"coords" -> pref.coords,
"moveEvent" -> pref.moveEvent,
"showCaptured" -> pref.captured
"showCaptured" -> pref.captured,
"keyboardMove" -> pref.hasKeyboardMove
)
.add("rookCastle" -> (pref.rookCastle == Pref.RookCastle.YES))
.add("is3d" -> pref.is3d)
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 18 additions & 6 deletions ui/analyse/css/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ body {
display: none;
}

.keyboard-move {
grid-area: kb-move;
margin: $analyse-block-gap;
}

---chat-height: fit-content(0);
&--wiki {
---chat-height: 0;
Expand All @@ -72,8 +77,9 @@ body {
margin: $analyse-block-gap 0 0 0;
}

grid-template-rows: auto auto minmax(20em, 30vh);
grid-template-rows: auto auto auto minmax(20em, 30vh);
grid-template-areas:
'kb-move'
'board'
'controls'
'tools'
Expand All @@ -88,6 +94,7 @@ body {
grid-template-rows: fit-content(0);
grid-template-areas:
'board gauge tools'
'kb-move . controls'
'under . controls'
'under . round-training'
'under . side'
Expand All @@ -109,6 +116,10 @@ body {
.eval-gauge {
display: block;
}

.keyboard-move {
margin: calc($analyse-block-gap / 2) 0 0 0;
}
}

@include mq-is-col2-squeeze {
Expand All @@ -117,12 +128,13 @@ body {

@include mq-at-least-col3 {
grid-template-columns: $col3-uniboard-side $analyse-block-gap var(---col3-uniboard-width) $analyse-block-gap $col3-uniboard-table;
grid-template-rows: auto $chat-height 2.5em 1fr;
grid-template-rows: auto $chat-height auto 2.5em 1fr;
grid-template-areas:
'side . board gauge tools'
'chat . board gauge tools'
'uchat . under . controls'
'uchat . under . round-training';
'side . board gauge tools'
'chat . board gauge tools'
'uchat . kb-move . controls'
'uchat . under . controls'
'uchat . under . round-training';

&__side {
margin-top: 0;
Expand Down
15 changes: 9 additions & 6 deletions ui/analyse/css/_zh.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ $pocket-height: 60px;
'pocket-top'
'board'
'pocket-bot'
'kb-move'
'controls'
'tools'
'side'
Expand All @@ -37,6 +38,7 @@ $pocket-height: 60px;
'board gauge pocket-top'
'board gauge tools'
'board gauge pocket-bot'
'kb-move . controls'
'under . controls'
'under . round-training'
'under . side'
Expand All @@ -47,12 +49,13 @@ $pocket-height: 60px;
@include mq-at-least-col3 {
grid-template-rows: $pocket-height auto auto $pocket-height;
grid-template-areas:
'side . board gauge pocket-top'
'side . board gauge tools'
'chat . board gauge tools'
'chat . board gauge pocket-bot'
'uchat . under . controls'
'uchat . under . round-training';
'side . board gauge pocket-top'
'side . board gauge tools'
'chat . board gauge tools'
'chat . board gauge pocket-bot'
'uchat . kb-move . controls'
'uchat . under . controls'
'uchat . under . round-training';
}
}

Expand Down
5 changes: 5 additions & 0 deletions ui/analyse/css/study/_layout.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.analyse__underboard {
margin-top: calc($analyse-block-gap / 2);
}

.analyse .keyboard-move {
margin-top: calc($analyse-block-gap * 2);
margin-bottom: calc($analyse-block-gap * -1);
}
1 change: 1 addition & 0 deletions ui/analyse/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"common": "workspace:*",
"debounce-promise": "^3.1.2",
"game": "workspace:*",
"keyboardMove": "workspace:*",
"nvui": "workspace:*",
"prop-types": "^15.8.1",
"shepherd.js": "^11.2.0",
Expand Down
69 changes: 66 additions & 3 deletions ui/analyse/src/ctrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ import { uciToMove } from 'chessground/util';
import Persistence from './persistence';
import pgnImport from './pgnImport';
import ForecastCtrl from './forecast/forecastCtrl';
import { ArrowKey, KeyboardMove, ctrl as makeKeyboardMove } from 'keyboardMove';
import * as control from './control';

export default class AnalyseCtrl {
data: AnalyseData;
Expand Down Expand Up @@ -123,6 +125,7 @@ export default class AnalyseCtrl {
cgConfig: any; // latest chessground config (useful for revert)
nvui?: NvuiPlugin;
pvUciQueue: Uci[] = [];
keyboardMove?: KeyboardMove;

constructor(
readonly opts: AnalyseOpts,
Expand Down Expand Up @@ -359,6 +362,24 @@ export default class AnalyseCtrl {
return config;
}

setChessground = (cg: CgApi) => {
this.chessground = cg;

if (this.data.pref.keyboardMove) {
this.keyboardMove ??= makeKeyboardMove({
...this,
data: { ...this.data, player: { color: 'both' } },
flipNow: this.flip,
});
this.keyboardMove.update({ fen: this.node.fen, canMove: true, cg });
requestAnimationFrame(() => this.redraw());
}

this.setAutoShapes();
if (this.node.shapes) this.chessground.setShapes(this.node.shapes as DrawShape[]);
this.cgVersion.dom = this.cgVersion.js;
};

private onChange: () => void = throttle(300, () => {
site.pubsub.emit('analysis.change', this.node.fen, this.path);
});
Expand Down Expand Up @@ -398,6 +419,7 @@ export default class AnalyseCtrl {
}
site.pubsub.emit('ply', this.node.ply, this.tree.lastMainlineNode(this.path).ply === this.node.ply);
this.showGround();
this.pluginUpdate(this.node.fen);
}

userJump = (path: Tree.Path): void => {
Expand All @@ -418,12 +440,12 @@ export default class AnalyseCtrl {
if (this.canJumpTo(path)) this.userJump(path);
}

mainlinePathToPly(ply: Ply): Tree.Path {
mainlinePlyToPath(ply: Ply): Tree.Path {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol good catch!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't unsee it 🙃

return treeOps.takePathWhile(this.mainline, n => n.ply <= ply);
}

jumpToMain = (ply: Ply): void => {
this.userJump(this.mainlinePathToPly(ply));
this.userJump(this.mainlinePlyToPath(ply));
};

jumpToIndex = (index: number): void => {
Expand Down Expand Up @@ -455,7 +477,7 @@ export default class AnalyseCtrl {
} as AnalyseData;
if (andReload) {
this.reloadData(data, false);
this.userJump(this.mainlinePathToPly(this.tree.lastPly()));
this.userJump(this.mainlinePlyToPath(this.tree.lastPly()));
this.redraw();
}
return data;
Expand All @@ -474,6 +496,21 @@ export default class AnalyseCtrl {
encodeURIComponent(fen).replace(/%20/g, '_').replace(/%2F/g, '/');
}

crazyValid = (role: cg.Role, key: cg.Key): boolean => {
const color = this.chessground.state.movable.color;
return (
(color === 'white' || color === 'black') &&
crazyValid(this.chessground, this.node.drops, { color, role }, key)
);
};

getCrazyhousePockets = () => this.node.crazy?.pockets;

sendNewPiece = (role: cg.Role, key: cg.Key): void => {
const color = this.chessground.state.movable.color;
if (color === 'white' || color === 'black') this.userNewPiece({ color, role }, key);
};

userNewPiece = (piece: cg.Piece, pos: Key): void => {
if (crazyValid(this.chessground, this.node.drops, piece, pos)) {
this.justPlayed = roleToChar(piece.role).toUpperCase() + '@' + pos;
Expand Down Expand Up @@ -555,6 +592,7 @@ export default class AnalyseCtrl {
this.tree.addDests(dests, path);
if (path === this.path) {
this.showGround();
this.pluginUpdate(this.node.fen);
if (this.outcome()) this.ceval.stop();
}
this.withCg(cg => cg.playPremove());
Expand Down Expand Up @@ -947,4 +985,29 @@ export default class AnalyseCtrl {

withCg = <A>(f: (cg: ChessgroundApi) => A): A | undefined =>
this.chessground && this.cgVersion.js === this.cgVersion.dom ? f(this.chessground) : undefined;

handleArrowKey = (arrowKey: ArrowKey) => {
if (arrowKey === 'ArrowUp') {
if (this.fork.prev()) this.setAutoShapes();
else control.first(this);
} else if (arrowKey === 'ArrowDown') {
if (this.fork.next()) this.setAutoShapes();
else control.last(this);
} else if (arrowKey === 'ArrowLeft') control.prev(this);
else if (arrowKey === 'ArrowRight') control.next(this);
this.redraw();
};

pluginMove = (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => {
const capture = this.chessground.state.pieces.get(dest);
this.sendMove(orig, dest, capture, prom);
};

pluginUpdate = (fen: string) => {
// if controller and chessground board state differ, ignore this update. once the chessground
// state is updated to match, pluginUpdate will be called again.
if (!fen.startsWith(this.chessground?.getFen())) return;

this.keyboardMove?.update({ fen, canMove: true });
};
}
8 changes: 1 addition & 7 deletions ui/analyse/src/ground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,14 @@ import { h, VNode } from 'snabbdom';
import { Api as CgApi } from 'chessground/api';
import { Config as CgConfig } from 'chessground/config';
import * as cg from 'chessground/types';
import { DrawShape } from 'chessground/draw';
import resizeHandle from 'common/resize';
import AnalyseCtrl from './ctrl';
import * as Prefs from 'common/prefs';

export const render = (ctrl: AnalyseCtrl): VNode =>
h('div.cg-wrap.cgv' + ctrl.cgVersion.js, {
hook: {
insert: vnode => {
ctrl.chessground = site.makeChessground(vnode.elm as HTMLElement, makeConfig(ctrl));
ctrl.setAutoShapes();
if (ctrl.node.shapes) ctrl.chessground.setShapes(ctrl.node.shapes as DrawShape[]);
ctrl.cgVersion.dom = ctrl.cgVersion.js;
},
insert: vnode => ctrl.setChessground(site.makeChessground(vnode.elm as HTMLElement, makeConfig(ctrl))),
destroy: _ => ctrl.chessground.destroy(),
},
});
Expand Down
1 change: 1 addition & 0 deletions ui/analyse/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface AnalysePref {
highlight?: boolean;
showCaptured?: boolean;
animationDuration?: number;
keyboardMove: boolean;
moveEvent: Prefs.MoveEvent;
}

Expand Down
2 changes: 1 addition & 1 deletion ui/analyse/src/retrospect/retroCtrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function make(root: AnalyseCtrl, color: Color): RetroCtrl {
}
const fault = {
node,
path: root.mainlinePathToPly(node.ply),
path: root.mainlinePlyToPath(node.ply),
};
const prevPath = treePath.init(fault.path);
const prev = {
Expand Down
2 changes: 2 additions & 0 deletions ui/analyse/src/view/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import crazyView from '../crazy/crazyView';
import AnalyseCtrl from '../ctrl';
import forecastView from '../forecast/forecastView';
import { view as keyboardView } from '../keyboard';
import { render as renderKeyboardMove } from 'keyboardMove';
import type * as studyDeps from '../study/studyDeps';
import { relayView } from '../study/relay/relayView';
import {
Expand Down Expand Up @@ -42,6 +43,7 @@ function analyseView(ctrl: AnalyseCtrl, deps?: typeof studyDeps): VNode {
!menuIsOpen && crazyView(ctrl, ctrl.bottomColor(), 'bottom'),
!gamebookPlayView && renderControls(ctrl),
renderUnderboard(ctx),
ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove),
trainingView(ctrl),
ctrl.studyPractice
? deps?.studyPracticeView.side(study!)
Expand Down
1 change: 1 addition & 0 deletions ui/analyse/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
{ "path": "../chess/tsconfig.json" },
{ "path": "../common/tsconfig.json" },
{ "path": "../game/tsconfig.json" },
{ "path": "../keyboardMove/tsconfig.json" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tsc dependency mechanism isn't documented anywhere so I'm impressed. I think you're the first to do this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't pretend to understand it, but I will pretend to be quite good at pattern matching 😎

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's actually straightforward. tsc doesn't care about our monorepo dependencies (package.json), so if you want correct behavior when type checking - you have to either compile everything in the correct order (bad) or express dependencies in tsconfig.json (better, but still not great).

{ "path": "../nvui/tsconfig.json" },
{ "path": "../tree/tsconfig.json" }
],
Expand Down
7 changes: 5 additions & 2 deletions ui/ceval/src/view/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as winningChances from '../winningChances';
import * as licon from 'common/licon';
import { stepwiseScroll } from 'common/scroll';
import { bind, LooseVNodes, looseH as h } from 'common/snabbdom';
import { onInsert, bind, LooseVNodes, looseH as h } from 'common/snabbdom';
import { defined, notNull } from 'common';
import { ParentCtrl, NodeEvals, CevalState } from '../types';
import { VNode } from 'snabbdom';
Expand Down Expand Up @@ -236,7 +236,10 @@ export function renderCeval(ctrl: ParentCtrl): LooseVNodes {
h('div.switch', { attrs: { title: trans.noarg('toggleLocalEvaluation') + ' (L)' } }, [
h('input#analyse-toggle-ceval.cmn-toggle.cmn-toggle--subtle', {
attrs: { type: 'checkbox', checked: enabled, disabled: !ceval.analysable },
hook: bind('change', ctrl.toggleCeval),
hook: onInsert((el: HTMLInputElement) => {
el.addEventListener('keydown', e => (e.key === 'Enter' || e.key === ' ') && ctrl.toggleCeval());
el.addEventListener('change', () => ctrl.toggleCeval());
}),
}),
h('label', { attrs: { for: 'analyse-toggle-ceval' } }),
]);
Expand Down
2 changes: 1 addition & 1 deletion ui/chess/src/moveRootCtrl.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as cg from 'chessground/types';

export interface MoveRootCtrl {
auxMove: (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => void;
pluginMove: (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => void;
redraw: () => void;
flipNow: () => void;
offerDraw?: (v: boolean, immediately?: boolean) => void;
Expand Down
Loading