From 5f2dd8be370037b9aaa61a4097d57b8abf92385b Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Thu, 28 Mar 2024 21:53:52 -0700 Subject: [PATCH 01/31] keyboardMove preference honored on analyze page --- app/views/analyse/replay.scala | 1 + modules/round/src/main/JsonView.scala | 3 ++- ui/analyse/src/interfaces.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/analyse/replay.scala b/app/views/analyse/replay.scala index c91bba6446eb3..0ad46588e3a44 100644 --- a/app/views/analyse/replay.scala +++ b/app/views/analyse/replay.scala @@ -119,6 +119,7 @@ object replay: moreCss = frag( cssTag("analyse.round"), (pov.game.variant == Crazyhouse).option(cssTag("analyse.zh")), + ctx.pref.hasKeyboardMove.option(cssTag("keyboardMove")), ctx.blind.option(cssTag("round.nvui")) ), moreJs = analyseNvuiTag, diff --git a/modules/round/src/main/JsonView.scala b/modules/round/src/main/JsonView.scala index 24f9d16fa7696..357041b42e9bf 100644 --- a/modules/round/src/main/JsonView.scala +++ b/modules/round/src/main/JsonView.scala @@ -206,7 +206,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) diff --git a/ui/analyse/src/interfaces.ts b/ui/analyse/src/interfaces.ts index 06bd8fe34439c..065fbf2854332 100644 --- a/ui/analyse/src/interfaces.ts +++ b/ui/analyse/src/interfaces.ts @@ -65,6 +65,7 @@ export interface AnalysePref { highlight?: boolean; showCaptured?: boolean; animationDuration?: number; + keyboardMove: boolean; moveEvent: Prefs.MoveEvent; } From dd7573f59126affcc9ab36b579a1eda338c45287 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Thu, 28 Mar 2024 21:55:22 -0700 Subject: [PATCH 02/31] first pass at keyboard move on analyzed page --- pnpm-lock.yaml | 3 +++ ui/analyse/css/_layout.scss | 6 ++++++ ui/analyse/package.json | 1 + ui/analyse/src/ctrl.ts | 12 +++++++++++ ui/analyse/src/ground.ts | 23 +++++++++++++++++++++ ui/analyse/src/view/main.ts | 2 ++ ui/keyboardMove/src/plugins/keyboardMove.ts | 2 ++ 7 files changed, 49 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75b5533c5f08f..111606df7d2f3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,6 +103,9 @@ importers: game: specifier: workspace:* version: link:../game + keyboardMove: + specifier: workspace:* + version: link:../keyboardMove nvui: specifier: workspace:* version: link:../nvui diff --git a/ui/analyse/css/_layout.scss b/ui/analyse/css/_layout.scss index 4457e15af0f6f..8a1e2ae9d4c4c 100644 --- a/ui/analyse/css/_layout.scss +++ b/ui/analyse/css/_layout.scss @@ -38,6 +38,10 @@ body { grid-area: controls; } + .keyboard-move { + grid-area: kb-move; + } + &__underboard { grid-area: under; @@ -88,6 +92,7 @@ body { grid-template-rows: fit-content(0); grid-template-areas: 'board gauge tools' + 'kb-move . .' 'under . controls' 'under . round-training' 'under . side' @@ -121,6 +126,7 @@ body { grid-template-areas: 'side . board gauge tools' 'chat . board gauge tools' + 'uchat . kb-move . controls' 'uchat . under . controls' 'uchat . under . round-training'; diff --git a/ui/analyse/package.json b/ui/analyse/package.json index 0d240591217ea..091416dd58c77 100644 --- a/ui/analyse/package.json +++ b/ui/analyse/package.json @@ -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", diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 2f38b2b68a748..579774c1f4836 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -51,6 +51,7 @@ import { uciToMove } from 'chessground/util'; import Persistence from './persistence'; import pgnImport from './pgnImport'; import ForecastCtrl from './forecast/forecastCtrl'; +import { KeyboardMove } from 'keyboardMove'; export default class AnalyseCtrl { data: AnalyseData; @@ -123,6 +124,7 @@ export default class AnalyseCtrl { cgConfig: any; // latest chessground config (useful for revert) nvui?: NvuiPlugin; pvUciQueue: Uci[] = []; + keyboardMove?: KeyboardMove; constructor( readonly opts: AnalyseOpts, @@ -398,6 +400,7 @@ export default class AnalyseCtrl { } site.pubsub.emit('ply', this.node.ply, this.tree.lastMainlineNode(this.path).ply === this.node.ply); this.showGround(); + this.auxUpdate(this.node.fen); } userJump = (path: Tree.Path): void => { @@ -555,6 +558,7 @@ export default class AnalyseCtrl { this.tree.addDests(dests, path); if (path === this.path) { this.showGround(); + this.auxUpdate(this.node.fen); if (this.outcome()) this.ceval.stop(); } this.withCg(cg => cg.playPremove()); @@ -947,4 +951,12 @@ export default class AnalyseCtrl { withCg = (f: (cg: ChessgroundApi) => A): A | undefined => this.chessground && this.cgVersion.js === this.cgVersion.dom ? f(this.chessground) : undefined; + + auxMove = () => {}; + // auxMove=(orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => {}; + flipNow = () => {}; + + auxUpdate = (fen: string) => { + this.keyboardMove?.update({ fen, canMove: true }); + }; } diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index 35272d58cd02d..f44583d9f5787 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -6,12 +6,35 @@ import { DrawShape } from 'chessground/draw'; import resizeHandle from 'common/resize'; import AnalyseCtrl from './ctrl'; import * as Prefs from 'common/prefs'; +import { ctrl as makeKeyboardMove } from 'keyboardMove'; 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)); + if (ctrl.data.pref.keyboardMove) { + ctrl.keyboardMove ??= makeKeyboardMove({ + ...ctrl, + sendMove: (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined, meta: cg.MoveMetadata) => { + console.log(orig, dest, prom, meta); + // ctrl.sendMove( + // orig, + // dest, + // meta.captured && { + // ...meta.captured, + // promoted: false, // TODO + // }, + // prom, + // ); + }, + }); + ctrl.keyboardMove.update({ + fen: ctrl.node.fen, + canMove: true, // TODO + cg: ctrl.chessground, + }); + } ctrl.setAutoShapes(); if (ctrl.node.shapes) ctrl.chessground.setShapes(ctrl.node.shapes as DrawShape[]); ctrl.cgVersion.dom = ctrl.cgVersion.js; diff --git a/ui/analyse/src/view/main.ts b/ui/analyse/src/view/main.ts index 05e3af29df555..ddda189a0ab41 100644 --- a/ui/analyse/src/view/main.ts +++ b/ui/analyse/src/view/main.ts @@ -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 { @@ -36,6 +37,7 @@ function analyseView(ctrl: AnalyseCtrl, deps?: typeof studyDeps): VNode { ctrl.keyboardHelp && keyboardView(ctrl), study && deps?.studyView.overboard(study), renderBoard(ctx), + ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove), gaugeOn && cevalView.renderGauge(ctrl), !menuIsOpen && crazyView(ctrl, ctrl.topColor(), 'top'), gamebookPlayView || renderTools(ctx), diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index 6d82191be336a..3cb14c30e1a6d 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -35,6 +35,7 @@ export function initModule(opts: Opts) { const isKey = (v: string): v is Key => !!v.match(keyRegex); const submit: Submit = (v: string, submitOpts: SubmitOpts) => { + console.log('submitted', v); if (!submitOpts.isTrusted) return; // consider 0's as O's for castling v = v.replace(/0/g, 'O'); @@ -146,6 +147,7 @@ export function initModule(opts: Opts) { makeBindings(opts, submit, clear); // returns a function that is called when any move is played return (fen: string, dests: Dests | undefined, yourMove: boolean) => { + // console.log('move played, new dests', dests); legalSans = dests && dests.size > 0 ? sanWriter(fen, destsToUcis(dests)) : null; // this plays a premove if it is available in the input submit(opts.input.value, { From f5663ad3c22a7e45e4ce832bfa4ca04ae0d4665e Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 31 Mar 2024 03:27:28 -0700 Subject: [PATCH 03/31] code golf --- ui/keyboardMove/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/keyboardMove/src/main.ts b/ui/keyboardMove/src/main.ts index 1ffac143b9a5b..3b4895719d707 100644 --- a/ui/keyboardMove/src/main.ts +++ b/ui/keyboardMove/src/main.ts @@ -123,7 +123,7 @@ export function ctrl(root: KeyboardMoveRootCtrl): KeyboardMove { confirmMove: () => (root.submitMove ? root.submitMove(true) : null), usedSan, jump(plyDelta: number) { - root.userJumpPlyDelta && root.userJumpPlyDelta(plyDelta); + root.userJumpPlyDelta?.(plyDelta); root.redraw(); }, justSelected: () => performance.now() - lastSelect < 500, From 03a4439c1c6d4530519a99351fe0d50dc63490cb Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 31 Mar 2024 03:41:57 -0700 Subject: [PATCH 04/31] more keyboard move functionally --- ui/analyse/src/ground.ts | 7 +++++++ ui/keyboardMove/src/plugins/keyboardMove.ts | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index f44583d9f5787..cfa8dd26d1e03 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -7,6 +7,7 @@ import resizeHandle from 'common/resize'; import AnalyseCtrl from './ctrl'; import * as Prefs from 'common/prefs'; import { ctrl as makeKeyboardMove } from 'keyboardMove'; +import * as control from './control'; export const render = (ctrl: AnalyseCtrl): VNode => h('div.cg-wrap.cgv' + ctrl.cgVersion.js, { @@ -28,6 +29,12 @@ export const render = (ctrl: AnalyseCtrl): VNode => // prom, // ); }, + userJumpPlyDelta: (plyDelta: number) => { + if (plyDelta === -1) control.prev(ctrl); + else if (plyDelta === 1) control.next(ctrl); + else if (plyDelta > 1) control.last(ctrl); + else if (plyDelta < -1) control.first(ctrl); + }, }); ctrl.keyboardMove.update({ fen: ctrl.node.fen, diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index 3cb14c30e1a6d..712e1138f3945 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -147,7 +147,6 @@ export function initModule(opts: Opts) { makeBindings(opts, submit, clear); // returns a function that is called when any move is played return (fen: string, dests: Dests | undefined, yourMove: boolean) => { - // console.log('move played, new dests', dests); legalSans = dests && dests.size > 0 ? sanWriter(fen, destsToUcis(dests)) : null; // this plays a premove if it is available in the input submit(opts.input.value, { From 269431f153392644bad2d7aba66fd5a4d7bff992 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 31 Mar 2024 15:13:09 -0700 Subject: [PATCH 05/31] implement keyboard move on study page --- app/views/study/show.scala | 5 ++++- modules/round/src/main/JsonView.scala | 3 ++- ui/analyse/css/study/_layout.scss | 4 ++++ ui/analyse/src/ctrl.ts | 15 ++++++++++++--- ui/analyse/src/ground.ts | 26 +++----------------------- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/app/views/study/show.scala b/app/views/study/show.scala index 9f35f9b3a9768..0dbc62fc693fd 100644 --- a/app/views/study/show.scala +++ b/app/views/study/show.scala @@ -19,7 +19,10 @@ object show: )(using ctx: PageContext) = views.html.base.layout( title = s.name.value, - moreCss = cssTag("analyse.study"), + moreCss = frag( + cssTag("analyse.study"), + ctx.pref.hasKeyboardMove.option(cssTag("keyboardMove")), + ), moreJs = analyseNvuiTag, pageModule = PageModule( "analysisBoard.study", diff --git a/modules/round/src/main/JsonView.scala b/modules/round/src/main/JsonView.scala index 357041b42e9bf..0d646d6ebb4b6 100644 --- a/modules/round/src/main/JsonView.scala +++ b/modules/round/src/main/JsonView.scala @@ -288,7 +288,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) diff --git a/ui/analyse/css/study/_layout.scss b/ui/analyse/css/study/_layout.scss index 7b3c7a5a52172..a3087842fe40e 100644 --- a/ui/analyse/css/study/_layout.scss +++ b/ui/analyse/css/study/_layout.scss @@ -1,3 +1,7 @@ .analyse__underboard { margin-top: calc($analyse-block-gap / 2); } + +.keyboard-move { + margin-top: calc($analyse-block-gap * 3 / 2); +} diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 579774c1f4836..0508e5d18f687 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -52,6 +52,7 @@ import Persistence from './persistence'; import pgnImport from './pgnImport'; import ForecastCtrl from './forecast/forecastCtrl'; import { KeyboardMove } from 'keyboardMove'; +import * as control from './control'; export default class AnalyseCtrl { data: AnalyseData; @@ -952,9 +953,17 @@ export default class AnalyseCtrl { withCg = (f: (cg: ChessgroundApi) => A): A | undefined => this.chessground && this.cgVersion.js === this.cgVersion.dom ? f(this.chessground) : undefined; - auxMove = () => {}; - // auxMove=(orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => {}; - flipNow = () => {}; + userJumpPlyDelta = (plyDelta: number) => { + if (plyDelta === -1) control.prev(this); + else if (plyDelta === 1) control.next(this); + else if (plyDelta > 1) control.last(this); + else if (plyDelta < -1) control.first(this); + }; + + auxMove = (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => { + const capture = this.chessground.state.pieces.get(dest); + this.sendMove(orig, dest, capture, prom); + }; auxUpdate = (fen: string) => { this.keyboardMove?.update({ fen, canMove: true }); diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index cfa8dd26d1e03..b1a029a45a71f 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -7,7 +7,6 @@ import resizeHandle from 'common/resize'; import AnalyseCtrl from './ctrl'; import * as Prefs from 'common/prefs'; import { ctrl as makeKeyboardMove } from 'keyboardMove'; -import * as control from './control'; export const render = (ctrl: AnalyseCtrl): VNode => h('div.cg-wrap.cgv' + ctrl.cgVersion.js, { @@ -15,32 +14,13 @@ export const render = (ctrl: AnalyseCtrl): VNode => insert: vnode => { ctrl.chessground = site.makeChessground(vnode.elm as HTMLElement, makeConfig(ctrl)); if (ctrl.data.pref.keyboardMove) { - ctrl.keyboardMove ??= makeKeyboardMove({ - ...ctrl, - sendMove: (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined, meta: cg.MoveMetadata) => { - console.log(orig, dest, prom, meta); - // ctrl.sendMove( - // orig, - // dest, - // meta.captured && { - // ...meta.captured, - // promoted: false, // TODO - // }, - // prom, - // ); - }, - userJumpPlyDelta: (plyDelta: number) => { - if (plyDelta === -1) control.prev(ctrl); - else if (plyDelta === 1) control.next(ctrl); - else if (plyDelta > 1) control.last(ctrl); - else if (plyDelta < -1) control.first(ctrl); - }, - }); + ctrl.keyboardMove ??= makeKeyboardMove({ ...ctrl, flipNow: ctrl.flip }); ctrl.keyboardMove.update({ fen: ctrl.node.fen, - canMove: true, // TODO + canMove: true, cg: ctrl.chessground, }); + requestAnimationFrame(() => ctrl.redraw()); } ctrl.setAutoShapes(); if (ctrl.node.shapes) ctrl.chessground.setShapes(ctrl.node.shapes as DrawShape[]); From d899200da31e49151bd0ae5058768b0d67648316 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 2 Apr 2024 03:12:10 -0700 Subject: [PATCH 06/31] rename function for clarity --- ui/analyse/src/ctrl.ts | 6 +++--- ui/analyse/src/retrospect/retroCtrl.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 0508e5d18f687..f42a33ce1175c 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -422,12 +422,12 @@ export default class AnalyseCtrl { if (this.canJumpTo(path)) this.userJump(path); } - mainlinePathToPly(ply: Ply): Tree.Path { + mainlinePlyToPath(ply: Ply): Tree.Path { 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 => { @@ -459,7 +459,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; diff --git a/ui/analyse/src/retrospect/retroCtrl.ts b/ui/analyse/src/retrospect/retroCtrl.ts index 4d03e113f9d0a..648ce038e385d 100644 --- a/ui/analyse/src/retrospect/retroCtrl.ts +++ b/ui/analyse/src/retrospect/retroCtrl.ts @@ -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 = { From e677a01ac8b776cec44195c344558115353ca600 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 2 Apr 2024 03:12:56 -0700 Subject: [PATCH 07/31] remove unused sendMove keyboardMove function --- ui/keyboardMove/src/main.ts | 1 - ui/puzzle/src/ctrl.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/ui/keyboardMove/src/main.ts b/ui/keyboardMove/src/main.ts index 3b4895719d707..1f99fdd6abdc2 100644 --- a/ui/keyboardMove/src/main.ts +++ b/ui/keyboardMove/src/main.ts @@ -56,7 +56,6 @@ export interface RootData { export interface KeyboardMoveRootCtrl extends MoveRootCtrl { sendNewPiece?: (role: cg.Role, key: cg.Key, isPredrop: boolean) => void; userJumpPlyDelta?: (plyDelta: Ply) => void; - sendMove?: (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined, meta: cg.MoveMetadata) => void; submitMove?: (v: boolean) => void; crazyValid?: (role: cg.Role, key: cg.Key) => boolean; data: RootData; diff --git a/ui/puzzle/src/ctrl.ts b/ui/puzzle/src/ctrl.ts index a89f40f658594..257df6df68a1c 100644 --- a/ui/puzzle/src/ctrl.ts +++ b/ui/puzzle/src/ctrl.ts @@ -137,7 +137,6 @@ export default class PuzzleCtrl implements ParentCtrl { game: { variant: { key: 'standard' } }, player: { color: this.pov }, }, - sendMove: this.playUserMove, auxMove: this.auxMove, redraw: this.redraw, flipNow: this.flip, From 4a8326051a13180d078e3e043294fdb12ac376aa Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 2 Apr 2024 03:14:30 -0700 Subject: [PATCH 08/31] clear keyboardMove input when no opponent and who command used --- ui/keyboardMove/src/plugins/keyboardMove.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index 712e1138f3945..86ecaae277bd0 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -98,8 +98,8 @@ export function initModule(opts: Opts) { clear(); } } else if (v.length > 0 && 'who'.startsWith(v.toLowerCase())) { - if ('who' === v.toLowerCase() && opts.ctrl.opponent) { - site.sound.say(opts.ctrl.opponent, false, true); + if ('who' === v.toLowerCase()) { + if (opts.ctrl.opponent) site.sound.say(opts.ctrl.opponent, false, true); clear(); } } else if (v.length > 0 && 'draw'.startsWith(v.toLowerCase())) { From 5cfc135a2bb58fbe172a1009d2b66831aad41ea3 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 00:07:31 -0700 Subject: [PATCH 09/31] implement crazyhouse keyboardMove functionality on analysis page --- ui/analyse/src/ctrl.ts | 13 +++++++++++++ ui/analyse/src/ground.ts | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index f42a33ce1175c..f2a570c4d027a 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -478,6 +478,19 @@ 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) + ); + }; + + 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; diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index b1a029a45a71f..c11446ef7b7e3 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -14,7 +14,11 @@ export const render = (ctrl: AnalyseCtrl): VNode => insert: vnode => { ctrl.chessground = site.makeChessground(vnode.elm as HTMLElement, makeConfig(ctrl)); if (ctrl.data.pref.keyboardMove) { - ctrl.keyboardMove ??= makeKeyboardMove({ ...ctrl, flipNow: ctrl.flip }); + ctrl.keyboardMove ??= makeKeyboardMove({ + ...ctrl, + data: { ...ctrl.data, crazyhouse: ctrl.node.crazy }, + flipNow: ctrl.flip, + }); ctrl.keyboardMove.update({ fen: ctrl.node.fen, canMove: true, From c5b80c161264c338be25c2bf44967d9a2bc206f5 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 00:08:03 -0700 Subject: [PATCH 10/31] remove console log --- ui/keyboardMove/src/plugins/keyboardMove.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index 86ecaae277bd0..b01cf76345e96 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -35,7 +35,6 @@ export function initModule(opts: Opts) { const isKey = (v: string): v is Key => !!v.match(keyRegex); const submit: Submit = (v: string, submitOpts: SubmitOpts) => { - console.log('submitted', v); if (!submitOpts.isTrusted) return; // consider 0's as O's for castling v = v.replace(/0/g, 'O'); From e11dc11c74fbc91f37e858b6b346f8273db2edfb Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 18:21:31 -0700 Subject: [PATCH 11/31] ensure that keyboardMove updates only occur when controller and cg state agree --- ui/analyse/src/ctrl.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index f2a570c4d027a..b7bc7a12ecc52 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -979,6 +979,10 @@ export default class AnalyseCtrl { }; auxUpdate = (fen: string) => { + // if controller and chessground board state differ, ignore this update. once the chessground + // state is updated to match, auxUpdate will be called again. + if (!fen.startsWith(this.chessground?.getFen())) return; + this.keyboardMove?.update({ fen, canMove: true }); }; } From 7da7fd8c92ef711ac02d808b68500618da347087 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 18:24:44 -0700 Subject: [PATCH 12/31] augment keyboardMove root data --- ui/analyse/src/ground.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index c11446ef7b7e3..afee46a157ca6 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -16,7 +16,12 @@ export const render = (ctrl: AnalyseCtrl): VNode => if (ctrl.data.pref.keyboardMove) { ctrl.keyboardMove ??= makeKeyboardMove({ ...ctrl, - data: { ...ctrl.data, crazyhouse: ctrl.node.crazy }, + data: { + ...ctrl.data, + // TODO: improve this disgraceful shoehorning + player: ctrl.chessground.state.movable as { color: Color }, + crazyhouse: ctrl.node.crazy, + }, flipNow: ctrl.flip, }); ctrl.keyboardMove.update({ From b55095646ef7b08082cb1d12e451ea7190fde635 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 18:43:07 -0700 Subject: [PATCH 13/31] do another pass on css --- ui/analyse/css/_layout.scss | 18 +++++++++--------- ui/analyse/css/_zh.scss | 14 ++++++++------ ui/analyse/css/study/_layout.scss | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/ui/analyse/css/_layout.scss b/ui/analyse/css/_layout.scss index 8a1e2ae9d4c4c..0d1e55851185e 100644 --- a/ui/analyse/css/_layout.scss +++ b/ui/analyse/css/_layout.scss @@ -38,10 +38,6 @@ body { grid-area: controls; } - .keyboard-move { - grid-area: kb-move; - } - &__underboard { grid-area: under; @@ -67,6 +63,10 @@ body { display: none; } + .keyboard-move { + grid-area: kb-move; + } + --chat-height: fit-content(0); &--wiki { --chat-height: 0; @@ -92,7 +92,7 @@ body { grid-template-rows: fit-content(0); grid-template-areas: 'board gauge tools' - 'kb-move . .' + 'kb-move . controls' 'under . controls' 'under . round-training' 'under . side' @@ -124,11 +124,11 @@ body { 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-areas: - 'side . board gauge tools' - 'chat . board gauge tools' + 'side . board gauge tools' + 'chat . board gauge tools' 'uchat . kb-move . controls' - 'uchat . under . controls' - 'uchat . under . round-training'; + 'uchat . under . controls' + 'uchat . under . round-training'; &__side { margin-top: 0; diff --git a/ui/analyse/css/_zh.scss b/ui/analyse/css/_zh.scss index 90106de1df982..45140e83f34b0 100644 --- a/ui/analyse/css/_zh.scss +++ b/ui/analyse/css/_zh.scss @@ -37,6 +37,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' @@ -47,12 +48,13 @@ $pocket-height: 60px; @include mq-at-least-col3 { grid-template-rows: $pocket-height $meta-height $chat-height $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'; } } diff --git a/ui/analyse/css/study/_layout.scss b/ui/analyse/css/study/_layout.scss index a3087842fe40e..4d102400bd18b 100644 --- a/ui/analyse/css/study/_layout.scss +++ b/ui/analyse/css/study/_layout.scss @@ -3,5 +3,5 @@ } .keyboard-move { - margin-top: calc($analyse-block-gap * 3 / 2); + margin-top: calc($analyse-block-gap * 2); } From 17bf59cfd4634a0f88d56c5814414fa622bfb46e Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 18:49:13 -0700 Subject: [PATCH 14/31] include keyboardMove in tsconfig --- ui/analyse/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/analyse/tsconfig.json b/ui/analyse/tsconfig.json index 001ae80d34790..8def919153a86 100644 --- a/ui/analyse/tsconfig.json +++ b/ui/analyse/tsconfig.json @@ -11,6 +11,7 @@ { "path": "../chess/tsconfig.json" }, { "path": "../common/tsconfig.json" }, { "path": "../game/tsconfig.json" }, + { "path": "../keyboardMove/tsconfig.json" }, { "path": "../nvui/tsconfig.json" }, { "path": "../tree/tsconfig.json" } ], From d47eca7d9c580dec25580572ce15adb416daf762 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Fri, 5 Apr 2024 18:52:56 -0700 Subject: [PATCH 15/31] sbt scalafmt --- app/views/study/show.scala | 2 +- modules/round/src/main/JsonView.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/study/show.scala b/app/views/study/show.scala index 0dbc62fc693fd..3ad852375a4c9 100644 --- a/app/views/study/show.scala +++ b/app/views/study/show.scala @@ -21,7 +21,7 @@ object show: title = s.name.value, moreCss = frag( cssTag("analyse.study"), - ctx.pref.hasKeyboardMove.option(cssTag("keyboardMove")), + ctx.pref.hasKeyboardMove.option(cssTag("keyboardMove")) ), moreJs = analyseNvuiTag, pageModule = PageModule( diff --git a/modules/round/src/main/JsonView.scala b/modules/round/src/main/JsonView.scala index 0d646d6ebb4b6..ac52972ca1e59 100644 --- a/modules/round/src/main/JsonView.scala +++ b/modules/round/src/main/JsonView.scala @@ -207,7 +207,7 @@ final class JsonView( "resizeHandle" -> pref.resizeHandle, "replay" -> pref.replay, "clockTenths" -> pref.clockTenths, - "keyboardMove" -> pref.hasKeyboardMove + "keyboardMove" -> pref.hasKeyboardMove ) .add("is3d" -> pref.is3d) .add("clockBar" -> pref.clockBar) @@ -289,7 +289,7 @@ final class JsonView( "coords" -> pref.coords, "moveEvent" -> pref.moveEvent, "showCaptured" -> pref.captured, - "keyboardMove" -> pref.hasKeyboardMove + "keyboardMove" -> pref.hasKeyboardMove ) .add("rookCastle" -> (pref.rookCastle == Pref.RookCastle.YES)) .add("is3d" -> pref.is3d) From 4298eb97bbfa5c2d67770491a35f1312fde1e70f Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 7 Apr 2024 16:34:57 -0700 Subject: [PATCH 16/31] retrieve crazyhouse pockets dynamically --- ui/analyse/src/ground.ts | 8 ++------ ui/keyboardMove/src/main.ts | 14 ++++++++------ ui/round/src/ctrl.ts | 2 ++ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index afee46a157ca6..6a2bee61f3169 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -16,12 +16,8 @@ export const render = (ctrl: AnalyseCtrl): VNode => if (ctrl.data.pref.keyboardMove) { ctrl.keyboardMove ??= makeKeyboardMove({ ...ctrl, - data: { - ...ctrl.data, - // TODO: improve this disgraceful shoehorning - player: ctrl.chessground.state.movable as { color: Color }, - crazyhouse: ctrl.node.crazy, - }, + data: { ...ctrl.data, player: { color: 'both' } }, + getCrazyhousePockets: () => ctrl.node.crazy?.pockets, flipNow: ctrl.flip, }); ctrl.keyboardMove.update({ diff --git a/ui/keyboardMove/src/main.ts b/ui/keyboardMove/src/main.ts index 1f99fdd6abdc2..dc731e412f3f6 100644 --- a/ui/keyboardMove/src/main.ts +++ b/ui/keyboardMove/src/main.ts @@ -47,9 +47,8 @@ interface CrazyPocket { } export interface RootData { - crazyhouse?: { pockets: [CrazyPocket, CrazyPocket] }; game: { variant: { key: VariantKey } }; - player: { color: Color }; + player: { color: Color | 'both' }; opponent?: { color: Color; user?: { username: string } }; } @@ -58,6 +57,7 @@ export interface KeyboardMoveRootCtrl extends MoveRootCtrl { userJumpPlyDelta?: (plyDelta: Ply) => void; submitMove?: (v: boolean) => void; crazyValid?: (role: cg.Role, key: cg.Key) => boolean; + getCrazyhousePockets?: () => [CrazyPocket, CrazyPocket] | undefined; data: RootData; } @@ -79,14 +79,16 @@ export function ctrl(root: KeyboardMoveRootCtrl): KeyboardMove { return { drop(key, piece) { const role = sanToRole[piece]; - const crazyData = root.data.crazyhouse; - const color = root.data.player.color; + const crazyhousePockets = root.getCrazyhousePockets?.(); + const color = root.data.player.color === 'both' ? cg.state.movable.color : root.data.player.color; + // Unable to determine what color we are + if (!color || color === 'both') return; // Crazyhouse not set up properly if (!root.crazyValid || !root.sendNewPiece) return; // Square occupied - if (!role || !crazyData || cg.state.pieces.has(key)) return; + if (!role || !crazyhousePockets || cg.state.pieces.has(key)) return; // Piece not in Pocket - if (!crazyData.pockets[color === 'white' ? 0 : 1][role]) return; + if (!crazyhousePockets[color === 'white' ? 0 : 1][role]) return; if (!root.crazyValid(role, key)) return; cg.cancelMove(); cg.newPiece({ role, color }, key); diff --git a/ui/round/src/ctrl.ts b/ui/round/src/ctrl.ts index d06be12fa9b0f..91d470df5b1fd 100644 --- a/ui/round/src/ctrl.ts +++ b/ui/round/src/ctrl.ts @@ -509,6 +509,8 @@ export default class RoundController implements MoveRootCtrl { crazyValid = (role: cg.Role, key: cg.Key) => crazyValid(this.data, role, key); + getCrazyhousePockets = () => this.data.crazyhouse?.pockets; + private playPredrop = () => { return this.chessground.playPredrop(drop => { return crazyValid(this.data, drop.role, drop.key); From 6f17c16674984cd33d2ed92d244eeed548b31c78 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 8 Apr 2024 17:07:15 +0200 Subject: [PATCH 17/31] remove unnecessary `?? ''` --- ui/analyse/src/ctrl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index b7bc7a12ecc52..417bf8c4ee235 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -479,7 +479,7 @@ export default class AnalyseCtrl { } crazyValid = (role: cg.Role, key: cg.Key): boolean => { - const color = this.chessground.state.movable.color ?? ''; + const color = this.chessground.state.movable.color; return ( (color === 'white' || color === 'black') && crazyValid(this.chessground, this.node.drops, { color, role }, key) From 42bbde4427d21ae2e05fb7629117d4ca40d08bd2 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 8 Apr 2024 17:07:56 +0200 Subject: [PATCH 18/31] and another one --- ui/analyse/src/ctrl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 417bf8c4ee235..1fa2801a24936 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -487,7 +487,7 @@ export default class AnalyseCtrl { }; sendNewPiece = (role: cg.Role, key: cg.Key): void => { - const color = this.chessground.state.movable.color ?? ''; + const color = this.chessground.state.movable.color; if (color === 'white' || color === 'black') this.userNewPiece({ color, role }, key); }; From fcbf24f59b6619fe64e81584e1fdda71efb82f40 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 9 Apr 2024 00:07:18 -0700 Subject: [PATCH 19/31] move creation of keyboardMove into controller --- ui/analyse/src/ctrl.ts | 22 +++++++++++++++++++++- ui/analyse/src/ground.ts | 23 +---------------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 1fa2801a24936..13d6bbbf663e2 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -51,7 +51,7 @@ import { uciToMove } from 'chessground/util'; import Persistence from './persistence'; import pgnImport from './pgnImport'; import ForecastCtrl from './forecast/forecastCtrl'; -import { KeyboardMove } from 'keyboardMove'; +import { KeyboardMove, ctrl as makeKeyboardMove } from 'keyboardMove'; import * as control from './control'; export default class AnalyseCtrl { @@ -362,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); }); @@ -486,6 +504,8 @@ export default class AnalyseCtrl { ); }; + 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); diff --git a/ui/analyse/src/ground.ts b/ui/analyse/src/ground.ts index 6a2bee61f3169..775555db52c34 100644 --- a/ui/analyse/src/ground.ts +++ b/ui/analyse/src/ground.ts @@ -2,35 +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'; -import { ctrl as makeKeyboardMove } from 'keyboardMove'; 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)); - if (ctrl.data.pref.keyboardMove) { - ctrl.keyboardMove ??= makeKeyboardMove({ - ...ctrl, - data: { ...ctrl.data, player: { color: 'both' } }, - getCrazyhousePockets: () => ctrl.node.crazy?.pockets, - flipNow: ctrl.flip, - }); - ctrl.keyboardMove.update({ - fen: ctrl.node.fen, - canMove: true, - cg: ctrl.chessground, - }); - requestAnimationFrame(() => ctrl.redraw()); - } - 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(), }, }); From a5558c1aa5720499ebacf2c6ee97ddb19eae5a10 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 9 Apr 2024 00:24:23 -0700 Subject: [PATCH 20/31] extract helper function for clarity --- ui/keyboardMove/src/plugins/keyboardMove.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index b01cf76345e96..785ac13be04cb 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -11,6 +11,8 @@ const promotionRegex = /^([a-h]x?)?[a-h](1|8)=?[nbrqkNBRQK]$/; // accept partial ICCF because submit runs on every keypress const iccfRegex = /^[1-8][1-8]?[1-5]?$/; +const isKey = (v: string): v is Key => !!v.match(keyRegex); + interface SubmitOpts { isTrusted: boolean; force?: boolean; @@ -32,8 +34,6 @@ export function initModule(opts: Opts) { opts.input.classList.add('ready'); let legalSans: SanToUci | null = null; - const isKey = (v: string): v is Key => !!v.match(keyRegex); - const submit: Submit = (v: string, submitOpts: SubmitOpts) => { if (!submitOpts.isTrusted) return; // consider 0's as O's for castling From 10b0d242fbdc789a9679f0db86ea091f8858b258 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 9 Apr 2024 00:31:30 -0700 Subject: [PATCH 21/31] rename aux => plugin --- ui/analyse/src/ctrl.ts | 10 +++++----- ui/chess/src/moveRootCtrl.ts | 2 +- ui/keyboardMove/src/main.ts | 2 +- ui/puzzle/src/ctrl.ts | 10 +++++----- ui/round/src/ctrl.ts | 10 +++++----- ui/voice/src/move/moveCtrl.ts | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 13d6bbbf663e2..74f440392bd1a 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -419,7 +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.auxUpdate(this.node.fen); + this.pluginUpdate(this.node.fen); } userJump = (path: Tree.Path): void => { @@ -592,7 +592,7 @@ export default class AnalyseCtrl { this.tree.addDests(dests, path); if (path === this.path) { this.showGround(); - this.auxUpdate(this.node.fen); + this.pluginUpdate(this.node.fen); if (this.outcome()) this.ceval.stop(); } this.withCg(cg => cg.playPremove()); @@ -993,14 +993,14 @@ export default class AnalyseCtrl { else if (plyDelta < -1) control.first(this); }; - auxMove = (orig: cg.Key, dest: cg.Key, prom: cg.Role | undefined) => { + 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); }; - auxUpdate = (fen: string) => { + pluginUpdate = (fen: string) => { // if controller and chessground board state differ, ignore this update. once the chessground - // state is updated to match, auxUpdate will be called again. + // state is updated to match, pluginUpdate will be called again. if (!fen.startsWith(this.chessground?.getFen())) return; this.keyboardMove?.update({ fen, canMove: true }); diff --git a/ui/chess/src/moveRootCtrl.ts b/ui/chess/src/moveRootCtrl.ts index 0e346801d280e..d01ef94d3084a 100644 --- a/ui/chess/src/moveRootCtrl.ts +++ b/ui/chess/src/moveRootCtrl.ts @@ -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; diff --git a/ui/keyboardMove/src/main.ts b/ui/keyboardMove/src/main.ts index dc731e412f3f6..b2f4442ee735c 100644 --- a/ui/keyboardMove/src/main.ts +++ b/ui/keyboardMove/src/main.ts @@ -100,7 +100,7 @@ export function ctrl(root: KeyboardMoveRootCtrl): KeyboardMove { if (!role || role == 'pawn' || (role == 'king' && variant !== 'antichess')) return; cg.cancelMove(); promote(cg, dest, role); - root.auxMove(orig, dest, role); + root.pluginMove(orig, dest, role); }, update(up: MoveUpdate) { if (up.cg) cg = up.cg; diff --git a/ui/puzzle/src/ctrl.ts b/ui/puzzle/src/ctrl.ts index 257df6df68a1c..5426b15f2ecfd 100644 --- a/ui/puzzle/src/ctrl.ts +++ b/ui/puzzle/src/ctrl.ts @@ -137,7 +137,7 @@ export default class PuzzleCtrl implements ParentCtrl { game: { variant: { key: 'standard' } }, player: { color: this.pov }, }, - auxMove: this.auxMove, + pluginMove: this.pluginMove, redraw: this.redraw, flipNow: this.flip, userJumpPlyDelta: this.userJumpPlyDelta, @@ -251,7 +251,7 @@ export default class PuzzleCtrl implements ParentCtrl { showGround = (g: CgApi): void => g.set(this.makeCgOpts()); - auxMove = (orig: Key, dest: Key, role?: Role) => { + pluginMove = (orig: Key, dest: Key, role?: Role) => { if (role) this.playUserMove(orig, dest, role); else this.withGround(g => { @@ -261,7 +261,7 @@ export default class PuzzleCtrl implements ParentCtrl { }); }; - auxUpdate = (fen: string): void => { + pluginUpdate = (fen: string): void => { this.voiceMove?.update({ fen, canMove: true }); this.keyboardMove?.update({ fen, canMove: true }); }; @@ -272,7 +272,7 @@ export default class PuzzleCtrl implements ParentCtrl { !this.promotion.start(orig, dest, { submit: this.playUserMove, show: this.voiceMove?.promotionHook() }) ) this.playUserMove(orig, dest); - this.auxUpdate(this.node.fen); + this.pluginUpdate(this.node.fen); }; playUci = (uci: Uci): void => this.sendMove(parseUci(uci)!); @@ -539,7 +539,7 @@ export default class PuzzleCtrl implements ParentCtrl { this.promotion.cancel(); this.justPlayed = undefined; this.autoScrollRequested = true; - this.auxUpdate(this.node.fen); + this.pluginUpdate(this.node.fen); site.pubsub.emit('ply', this.node.ply); }; diff --git a/ui/round/src/ctrl.ts b/ui/round/src/ctrl.ts index 91d470df5b1fd..cda747c1e917d 100644 --- a/ui/round/src/ctrl.ts +++ b/ui/round/src/ctrl.ts @@ -278,7 +278,7 @@ export default class RoundController implements MoveRootCtrl { this.chessground.set(config); if (s.san && isForwardStep) site.sound.move(s); this.autoScroll(); - this.auxUpdate(s.fen); + this.pluginUpdate(s.fen); site.pubsub.emit('ply', ply); return true; }; @@ -335,7 +335,7 @@ export default class RoundController implements MoveRootCtrl { this.redraw(); }; - auxMove = (orig: cg.Key, dest: cg.Key, role?: cg.Role) => { + pluginMove = (orig: cg.Key, dest: cg.Key, role?: cg.Role) => { if (!role) { this.chessground.move(orig, dest); // TODO look into possibility of making cg.Api.move function update player turn itself. @@ -347,7 +347,7 @@ export default class RoundController implements MoveRootCtrl { this.sendMove(orig, dest, role, { premove: false }); }; - auxUpdate = (fen: string) => { + pluginUpdate = (fen: string) => { this.voiceMove?.update({ fen, canMove: this.canMove() }); this.keyboardMove?.update({ fen, canMove: this.canMove() }); }; @@ -501,7 +501,7 @@ export default class RoundController implements MoveRootCtrl { } this.autoScroll(); this.onChange(); - this.auxUpdate(step.fen); + this.pluginUpdate(step.fen); site.sound.move({ ...o, filter: 'music' }); site.sound.saySan(step.san); return true; // prevents default socket pubsub @@ -539,7 +539,7 @@ export default class RoundController implements MoveRootCtrl { this.autoScroll(); this.onChange(); this.setLoading(false); - this.auxUpdate(d.steps[d.steps.length - 1].fen); + this.pluginUpdate(d.steps[d.steps.length - 1].fen); }; endWithData = (o: ApiEnd): void => { diff --git a/ui/voice/src/move/moveCtrl.ts b/ui/voice/src/move/moveCtrl.ts index 94947e9abdff3..435412df92b12 100644 --- a/ui/voice/src/move/moveCtrl.ts +++ b/ui/voice/src/move/moveCtrl.ts @@ -366,7 +366,7 @@ export function initModule(opts: { root: MoveRootCtrl; ui: VoiceCtrl; initial: M const role = cs.promo(uci) as cs.Role; cg.cancelMove(); if (role) promote(cg, dest(uci), role); - root.auxMove(src(uci), dest(uci), role); + root.pluginMove(src(uci), dest(uci), role); return true; } From 66f4608140a8d06075f5cccaef313a9d5aae1744 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Tue, 9 Apr 2024 01:29:39 -0700 Subject: [PATCH 22/31] small styling fix ups --- ui/analyse/css/_layout.scss | 6 +++++- ui/analyse/css/study/_layout.scss | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/analyse/css/_layout.scss b/ui/analyse/css/_layout.scss index dc1f6653fe220..0100b993be53c 100644 --- a/ui/analyse/css/_layout.scss +++ b/ui/analyse/css/_layout.scss @@ -114,6 +114,10 @@ body { .eval-gauge { display: block; } + + .keyboard-move { + margin-top: $analyse-block-gap; + } } @include mq-is-col2-squeeze { @@ -122,7 +126,7 @@ 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' diff --git a/ui/analyse/css/study/_layout.scss b/ui/analyse/css/study/_layout.scss index 4d102400bd18b..bd71eb48c336c 100644 --- a/ui/analyse/css/study/_layout.scss +++ b/ui/analyse/css/study/_layout.scss @@ -2,6 +2,7 @@ margin-top: calc($analyse-block-gap / 2); } -.keyboard-move { +.analyse .keyboard-move { margin-top: calc($analyse-block-gap * 2); + margin-bottom: calc($analyse-block-gap * -1); } From 1a4004b185924b653d2e3c515d2a913dc290b315 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sat, 13 Apr 2024 22:30:40 -0700 Subject: [PATCH 23/31] move arrow key handling logic into root controller --- ui/analyse/src/ctrl.ts | 17 +++++++++----- ui/keyboardMove/src/main.ts | 23 +++++++++++++++---- .../src/plugins/keyboardMove.test.ts | 2 +- ui/keyboardMove/src/plugins/keyboardMove.ts | 9 +++----- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 74f440392bd1a..5eb96319bd928 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -51,7 +51,7 @@ import { uciToMove } from 'chessground/util'; import Persistence from './persistence'; import pgnImport from './pgnImport'; import ForecastCtrl from './forecast/forecastCtrl'; -import { KeyboardMove, ctrl as makeKeyboardMove } from 'keyboardMove'; +import { ArrowKey, KeyboardMove, ctrl as makeKeyboardMove } from 'keyboardMove'; import * as control from './control'; export default class AnalyseCtrl { @@ -986,11 +986,16 @@ export default class AnalyseCtrl { withCg = (f: (cg: ChessgroundApi) => A): A | undefined => this.chessground && this.cgVersion.js === this.cgVersion.dom ? f(this.chessground) : undefined; - userJumpPlyDelta = (plyDelta: number) => { - if (plyDelta === -1) control.prev(this); - else if (plyDelta === 1) control.next(this); - else if (plyDelta > 1) control.last(this); - else if (plyDelta < -1) control.first(this); + 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) => { diff --git a/ui/keyboardMove/src/main.ts b/ui/keyboardMove/src/main.ts index b2f4442ee735c..12d7aa417575a 100644 --- a/ui/keyboardMove/src/main.ts +++ b/ui/keyboardMove/src/main.ts @@ -9,6 +9,10 @@ import KeyboardChecker from './plugins/keyboardChecker'; export type KeyboardMoveHandler = (fen: cg.FEN, dests?: cg.Dests, yourMove?: boolean) => void; +export const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'] as const; +export type ArrowKey = (typeof arrowKeys)[number]; +export const isArrowKey = (v: string): v is ArrowKey => arrowKeys.includes(v as ArrowKey); + export interface KeyboardMove { drop(key: cg.Key, piece: string): void; promote(orig: cg.Key, dest: cg.Key, piece: string): void; @@ -20,7 +24,7 @@ export interface KeyboardMove { hasSelected(): cg.Key | undefined; confirmMove(): void; usedSan: boolean; - jump(delta: number): void; + arrowNavigate(arrowKey: ArrowKey): void; justSelected(): boolean; draw(): void; next(): void; @@ -55,6 +59,7 @@ export interface RootData { export interface KeyboardMoveRootCtrl extends MoveRootCtrl { sendNewPiece?: (role: cg.Role, key: cg.Key, isPredrop: boolean) => void; userJumpPlyDelta?: (plyDelta: Ply) => void; + handleArrowKey?: (arrowKey: ArrowKey) => void; submitMove?: (v: boolean) => void; crazyValid?: (role: cg.Role, key: cg.Key) => boolean; getCrazyhousePockets?: () => [CrazyPocket, CrazyPocket] | undefined; @@ -123,9 +128,19 @@ export function ctrl(root: KeyboardMoveRootCtrl): KeyboardMove { hasSelected: () => cg.state.selected, confirmMove: () => (root.submitMove ? root.submitMove(true) : null), usedSan, - jump(plyDelta: number) { - root.userJumpPlyDelta?.(plyDelta); - root.redraw(); + arrowNavigate(arrowKey: ArrowKey) { + if (root.handleArrowKey) { + root.handleArrowKey?.(arrowKey); + return; + } + + const arrowKeyToPlyDelta = { + ArrowUp: -999, + ArrowDown: 999, + ArrowLeft: -1, + ArrowRight: 1, + }; + root.userJumpPlyDelta?.(arrowKeyToPlyDelta[arrowKey]); }, justSelected: () => performance.now() - lastSelect < 500, draw: () => (root.offerDraw ? root.offerDraw(true, true) : null), diff --git a/ui/keyboardMove/src/plugins/keyboardMove.test.ts b/ui/keyboardMove/src/plugins/keyboardMove.test.ts index fe81a08d41b28..6545f5d701905 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.test.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.test.ts @@ -25,7 +25,7 @@ const defaultCtrl = { vote: unexpectedErrorThrower('vote'), drop: unexpectedErrorThrower('drop'), hasSelected: () => undefined, - jump: () => null, + arrowNavigate: unexpectedErrorThrower('arrowNavigate'), justSelected: () => true, promote: unexpectedErrorThrower('promote'), registerHandler: () => null, diff --git a/ui/keyboardMove/src/plugins/keyboardMove.ts b/ui/keyboardMove/src/plugins/keyboardMove.ts index 785ac13be04cb..769aff4c77a8d 100644 --- a/ui/keyboardMove/src/plugins/keyboardMove.ts +++ b/ui/keyboardMove/src/plugins/keyboardMove.ts @@ -1,6 +1,6 @@ import { Dests, files } from 'chessground/types'; import { sanWriter, SanToUci, destsToUcis } from 'chess'; -import { KeyboardMoveHandler, KeyboardMove } from '../main'; +import { KeyboardMoveHandler, KeyboardMove, isArrowKey } from '../main'; const keyRegex = /^[a-h][1-8]$/; const fileRegex = /^[a-h]$/; @@ -189,11 +189,8 @@ function makeBindings(opts: Opts, submit: Submit, clear: () => void) { opts.input.addEventListener('blur', () => opts.ctrl.isFocused(false)); // prevent default on arrow keys: they only replay moves opts.input.addEventListener('keydown', (e: KeyboardEvent) => { - if (e.which > 36 && e.which < 41) { - if (e.which == 37) opts.ctrl.jump(-1); - else if (e.which == 38) opts.ctrl.jump(-999); - else if (e.which == 39) opts.ctrl.jump(1); - else opts.ctrl.jump(999); + if (isArrowKey(e.key)) { + opts.ctrl.arrowNavigate(e.key); e.preventDefault(); } }); From 06b84be2183db752c39aa4f292bd24e5bcb0a6ca Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 14 Apr 2024 00:03:32 -0700 Subject: [PATCH 24/31] put keyboard move towards end of tab order --- ui/analyse/src/view/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/analyse/src/view/main.ts b/ui/analyse/src/view/main.ts index ddda189a0ab41..aa95cf9e6be78 100644 --- a/ui/analyse/src/view/main.ts +++ b/ui/analyse/src/view/main.ts @@ -37,12 +37,12 @@ function analyseView(ctrl: AnalyseCtrl, deps?: typeof studyDeps): VNode { ctrl.keyboardHelp && keyboardView(ctrl), study && deps?.studyView.overboard(study), renderBoard(ctx), - ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove), gaugeOn && cevalView.renderGauge(ctrl), !menuIsOpen && crazyView(ctrl, ctrl.topColor(), 'top'), gamebookPlayView || renderTools(ctx), !menuIsOpen && crazyView(ctrl, ctrl.bottomColor(), 'bottom'), !gamebookPlayView && renderControls(ctrl), + ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove), renderUnderboard(ctx), trainingView(ctrl), ctrl.studyPractice From 7f4517e87d9a56a530442952ff58be543d13f2e4 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Sun, 14 Apr 2024 00:04:01 -0700 Subject: [PATCH 25/31] allow toggling ceval via enter when focused --- ui/ceval/src/view/main.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/ceval/src/view/main.ts b/ui/ceval/src/view/main.ts index 77228cc00a347..addf901d518c2 100644 --- a/ui/ceval/src/view/main.ts +++ b/ui/ceval/src/view/main.ts @@ -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'; @@ -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' } }), ]); From eda9c797c44c8c7fe78d5e1390fea388ac64b036 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Wed, 1 May 2024 16:28:53 +0200 Subject: [PATCH 26/31] remove duplicated code probably coming from a merge --- app/views/analyse/replay.scala | 123 +++++++++++++++------------------ 1 file changed, 57 insertions(+), 66 deletions(-) diff --git a/app/views/analyse/replay.scala b/app/views/analyse/replay.scala index ae24c09c117fa..e903ca88a12b0 100644 --- a/app/views/analyse/replay.scala +++ b/app/views/analyse/replay.scala @@ -173,78 +173,69 @@ object replay: ) ) ), - (!game.isPgnImport).option( - frag( - (game.ply > 1) - .option(span(role := "tab", dataPanel := "move-times")(trans.site.moveTimes())), - cross.isDefined.option( - span(role := "tab", dataPanel := "ctable")(trans.site.crosstable()) - ) - ) + span(role := "tab", dataPanel := "fen-pgn")(trans.study.shareAndExport()) ), - span(role := "tab", dataPanel := "fen-pgn")(trans.study.shareAndExport()) - ), - div(cls := "analyse__underboard__panels")( - lila.game.GameExt - .analysable(game) - .option( - div(cls := "computer-analysis")( - if analysis.isDefined || analysisStarted then - div(id := "acpl-chart-container")(canvas(id := "acpl-chart")) - else - postForm( - cls := s"future-game-analysis${ctx.isAnon.so(" must-login")}", - action := routes.Analyse.requestAnalysis(gameId) - ): - submitButton(cls := "button text"): - span(cls := "is3 text", dataIcon := Icon.BarChart)( - trans.site.requestAComputerAnalysis() - ) - ) - ), - div(cls := "move-times")( - (game.ply > 1) - .option(div(id := "movetimes-chart-container")(canvas(id := "movetimes-chart"))) - ), - div(cls := "fen-pgn")( - div( - strong("FEN"), - input( - readonly, - spellcheck := false, - cls := "copyable autoselect like-text analyse__underboard__fen" - ) + div(cls := "analyse__underboard__panels")( + lila.game.GameExt + .analysable(game) + .option( + div(cls := "computer-analysis")( + if analysis.isDefined || analysisStarted then + div(id := "acpl-chart-container")(canvas(id := "acpl-chart")) + else + postForm( + cls := s"future-game-analysis${ctx.isAnon.so(" must-login")}", + action := routes.Analyse.requestAnalysis(gameId) + ): + submitButton(cls := "button text"): + span(cls := "is3 text", dataIcon := Icon.BarChart)( + trans.site.requestAComputerAnalysis() + ) + ) + ), + div(cls := "move-times")( + (game.ply > 1) + .option(div(id := "movetimes-chart-container")(canvas(id := "movetimes-chart"))) ), - ctx.noBlind.option( + div(cls := "fen-pgn")( div( - strong("Image"), - imageLinks - ) - ), - div( - strong("Share"), - shareLinks - ), - div( - strong("PGN"), - pgnLinks + strong("FEN"), + input( + readonly, + spellcheck := false, + cls := "copyable autoselect like-text analyse__underboard__fen" + ) + ), + ctx.noBlind.option( + div( + strong("Image"), + imageLinks + ) + ), + div( + strong("Share"), + shareLinks + ), + div( + strong("PGN"), + pgnLinks + ), + div(cls := "pgn")(pgn) ), - div(cls := "pgn")(pgn) - ), - cross.map: c => - div(cls := "ctable"): - views.game.ui.crosstable(pov.player.userId.fold(c)(c.fromPov), pov.gameId.some) + cross.map: c => + div(cls := "ctable"): + views.game.ui.crosstable(pov.player.userId.fold(c)(c.fromPov), pov.gameId.some) + ) ) ) ) - ) - ), - ctx.blind.option( - div(cls := "blind-content none")( - h2("PGN downloads"), - pgnLinks, - button(cls := "copy-pgn", attr("data-pgn") := pgn): - "Copy PGN to clipboard" + ), + ctx.blind.option( + div(cls := "blind-content none")( + h2("PGN downloads"), + pgnLinks, + button(cls := "copy-pgn", attr("data-pgn") := pgn): + "Copy PGN to clipboard" + ) ) ) - ) From 104f9371eda255f889c4d0062f1ec36802b3d10a Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Wed, 1 May 2024 16:42:21 +0200 Subject: [PATCH 27/31] only hide dasher board reset when actually resetting --- ui/dasher/src/board.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/dasher/src/board.ts b/ui/dasher/src/board.ts index 76c935636e24d..b2ee5a87e79ac 100644 --- a/ui/dasher/src/board.ts +++ b/ui/dasher/src/board.ts @@ -1,5 +1,5 @@ import { header } from './util'; -import { hyphenToCamel } from 'common'; +import { hyphenToCamel, toggle } from 'common'; import debounce from 'common/debounce'; import * as licon from 'common/licon'; import * as xhr from 'common/xhr'; @@ -47,7 +47,7 @@ export class BoardCtrl extends PaneCtrl { ), ]), ...this.propSliders(), - !this.isDefault() && + this.showReset() && h( 'button.text.reset', { @@ -100,6 +100,7 @@ export class BoardCtrl extends PaneCtrl { this.setVar(prop, v); setTimeout(() => this.postPref(prop), i * 1100); // hack around debounce }); + this.showReset(false); this.sliderKey = Date.now(); document.body.classList.add('simple-board'); this.redraw(); @@ -109,6 +110,7 @@ export class BoardCtrl extends PaneCtrl { parseInt(window.getComputedStyle(document.body).getPropertyValue(`---${prop}`)); private setVar = (prop: string, v: number) => { + this.showReset(this.showReset() || !this.isDefault()); document.body.style.setProperty(`---${prop}`, v.toString()); document.body.classList.toggle('simple-board', this.isDefault()); if (prop === 'zoom') window.dispatchEvent(new Event('resize')); @@ -151,6 +153,7 @@ export class BoardCtrl extends PaneCtrl { ]; private isDefault = () => this.defaults.every(([prop, v]) => this.getVar(prop) === v); + private showReset = toggle(!this.isDefault()); private propSliders = () => { const sliders = []; From b32612e9f4e389fc35229d0e62e4c06609b6ad0f Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Thu, 2 May 2024 02:25:32 -0700 Subject: [PATCH 28/31] fix rendering bug with tab order change --- ui/analyse/src/view/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/analyse/src/view/main.ts b/ui/analyse/src/view/main.ts index aa95cf9e6be78..b52b70ffe83ed 100644 --- a/ui/analyse/src/view/main.ts +++ b/ui/analyse/src/view/main.ts @@ -42,8 +42,8 @@ function analyseView(ctrl: AnalyseCtrl, deps?: typeof studyDeps): VNode { gamebookPlayView || renderTools(ctx), !menuIsOpen && crazyView(ctrl, ctrl.bottomColor(), 'bottom'), !gamebookPlayView && renderControls(ctrl), - ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove), renderUnderboard(ctx), + ctrl.keyboardMove && renderKeyboardMove(ctrl.keyboardMove), trainingView(ctrl), ctrl.studyPractice ? deps?.studyPracticeView.side(study!) From 812f0c72bd23c5e18c1a64d9b41b9386dae38aa5 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Thu, 2 May 2024 02:36:19 -0700 Subject: [PATCH 29/31] optionally include keyboardMove styling on user analysis page --- app/views/board/userAnalysis.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/board/userAnalysis.scala b/app/views/board/userAnalysis.scala index 40f47a726c27b..7eee032550a64 100644 --- a/app/views/board/userAnalysis.scala +++ b/app/views/board/userAnalysis.scala @@ -21,6 +21,7 @@ object userAnalysis: .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")) .js(analyseNvuiTag) .js( views.analyse.bits From 650176c70a628f75507f6947e2d6cd1afc5c5301 Mon Sep 17 00:00:00 2001 From: Ben Rollin Date: Thu, 2 May 2024 03:09:11 -0700 Subject: [PATCH 30/31] one column styling fixes --- ui/analyse/css/_layout.scss | 6 ++++-- ui/analyse/css/_zh.scss | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/analyse/css/_layout.scss b/ui/analyse/css/_layout.scss index 9c2d0f78f9f1f..4d380989bc0d4 100644 --- a/ui/analyse/css/_layout.scss +++ b/ui/analyse/css/_layout.scss @@ -65,6 +65,7 @@ body { .keyboard-move { grid-area: kb-move; + margin: $analyse-block-gap; } ---chat-height: fit-content(0); @@ -76,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' @@ -116,7 +118,7 @@ body { } .keyboard-move { - margin-top: $analyse-block-gap; + margin: calc($analyse-block-gap / 2) 0 0 0; } } diff --git a/ui/analyse/css/_zh.scss b/ui/analyse/css/_zh.scss index 4210041d8bba2..b3ef7c565f8e8 100644 --- a/ui/analyse/css/_zh.scss +++ b/ui/analyse/css/_zh.scss @@ -23,6 +23,7 @@ $pocket-height: 60px; 'pocket-top' 'board' 'pocket-bot' + 'kb-move' 'controls' 'tools' 'side' From a31f32789d903973d89bca9b0702395135b908a4 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Fri, 3 May 2024 11:44:17 +0200 Subject: [PATCH 31/31] fix previous merge --- modules/analyse/src/main/ui/AnalyseUi.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/analyse/src/main/ui/AnalyseUi.scala b/modules/analyse/src/main/ui/AnalyseUi.scala index 4179683ff9e60..f30e379296298 100644 --- a/modules/analyse/src/main/ui/AnalyseUi.scala +++ b/modules/analyse/src/main/ui/AnalyseUi.scala @@ -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",