chesspal 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/cli.js +6 -6
- package/dist/commands/{analyse-game.d.ts → analysis/analyse.d.ts} +2 -2
- package/dist/commands/{analyse-game.js → analysis/analyse.js} +7 -11
- package/dist/commands/{annotate-game.d.ts → analysis/annotate.d.ts} +1 -1
- package/dist/commands/{annotate-game.js → analysis/annotate.js} +6 -9
- package/dist/commands/{delete-review.d.ts → analysis/delete-review.d.ts} +1 -1
- package/dist/commands/{delete-review.js → analysis/delete-review.js} +5 -5
- package/dist/commands/analysis/index.d.ts +4 -0
- package/dist/commands/analysis/index.js +5 -0
- package/dist/commands/{study-games.d.ts → analysis/study-games.d.ts} +1 -1
- package/dist/commands/{study-games.js → analysis/study-games.js} +4 -5
- package/dist/commands/{agents.d.ts → answers/agents.d.ts} +3 -3
- package/dist/commands/{agents.js → answers/agents.js} +5 -5
- package/dist/commands/{clock.d.ts → answers/clock.d.ts} +2 -2
- package/dist/commands/{clock.js → answers/clock.js} +2 -2
- package/dist/commands/{drawings.d.ts → answers/drawings.d.ts} +1 -1
- package/dist/commands/{drawings.js → answers/drawings.js} +1 -1
- package/dist/commands/answers/index.d.ts +12 -0
- package/dist/commands/answers/index.js +14 -0
- package/dist/commands/{lead-input.d.ts → answers/lead-input.d.ts} +1 -1
- package/dist/commands/{lead-input.js → answers/lead-input.js} +1 -1
- package/dist/commands/{answer-lines.d.ts → answers/lines.d.ts} +2 -2
- package/dist/commands/{answer-lines.js → answers/lines.js} +4 -4
- package/dist/commands/{opening-book.d.ts → answers/opening-book.d.ts} +1 -1
- package/dist/commands/{opening-book.js → answers/opening-book.js} +3 -3
- package/dist/commands/{play-move.d.ts → answers/play-move.d.ts} +2 -2
- package/dist/commands/{play-move.js → answers/play-move.js} +3 -3
- package/dist/commands/{say.d.ts → answers/say.d.ts} +3 -3
- package/dist/commands/{say.js → answers/say.js} +4 -4
- package/dist/commands/{speech.js → answers/speech.js} +1 -1
- package/dist/commands/{study.d.ts → answers/study.d.ts} +3 -3
- package/dist/commands/{study.js → answers/study.js} +3 -3
- package/dist/commands/{game-summary.d.ts → answers/summary.d.ts} +2 -2
- package/dist/commands/{game-summary.js → answers/summary.js} +4 -4
- package/dist/commands/{view.d.ts → answers/view.d.ts} +1 -1
- package/dist/commands/{ai-move.d.ts → game/ai-move.d.ts} +2 -2
- package/dist/commands/{ai-move.js → game/ai-move.js} +6 -11
- package/dist/commands/{coach.d.ts → game/coach.d.ts} +1 -1
- package/dist/commands/{coach.js → game/coach.js} +7 -13
- package/dist/commands/{draw-offer.d.ts → game/draw-offer.d.ts} +1 -1
- package/dist/commands/{draw-offer.js → game/draw-offer.js} +4 -4
- package/dist/commands/{end-game.d.ts → game/end.d.ts} +2 -2
- package/dist/commands/{end-game.js → game/end.js} +5 -9
- package/dist/commands/{export-game.d.ts → game/export.d.ts} +1 -1
- package/dist/commands/{export-game.js → game/export.js} +4 -4
- package/dist/commands/game/index.d.ts +11 -0
- package/dist/commands/game/index.js +13 -0
- package/dist/commands/{levels.d.ts → game/levels.d.ts} +3 -3
- package/dist/commands/{levels.js → game/levels.js} +3 -3
- package/dist/commands/{look.d.ts → game/look.d.ts} +3 -4
- package/dist/commands/{look.js → game/look.js} +5 -10
- package/dist/commands/{new-game.d.ts → game/new.d.ts} +3 -4
- package/dist/commands/{new-game.js → game/new.js} +17 -13
- package/dist/commands/{page-link.d.ts → game/page-link.d.ts} +1 -1
- package/dist/commands/{player-move.d.ts → game/player-move.d.ts} +2 -2
- package/dist/commands/{player-move.js → game/player-move.js} +4 -8
- package/dist/commands/{ponder.d.ts → game/ponder.d.ts} +3 -3
- package/dist/commands/{ponder.js → game/ponder.js} +6 -9
- package/dist/commands/{position.d.ts → game/position.d.ts} +2 -2
- package/dist/commands/{position.js → game/position.js} +5 -7
- package/dist/commands/{status.d.ts → game/status.d.ts} +2 -4
- package/dist/commands/{status.js → game/status.js} +12 -17
- package/dist/commands/index.d.ts +6 -17
- package/dist/commands/index.js +11 -38
- package/dist/commands/{delete-game.d.ts → profiles/delete-game.d.ts} +1 -1
- package/dist/commands/{delete-game.js → profiles/delete-game.js} +3 -3
- package/dist/commands/profiles/index.d.ts +4 -0
- package/dist/commands/profiles/index.js +5 -0
- package/dist/commands/{past-games.d.ts → profiles/past-games.d.ts} +1 -1
- package/dist/commands/{past-games.js → profiles/past-games.js} +5 -5
- package/dist/commands/{profiles.d.ts → profiles/profiles.d.ts} +7 -7
- package/dist/commands/{profiles.js → profiles/profiles.js} +4 -4
- package/dist/commands/{ratings.d.ts → profiles/ratings.d.ts} +1 -1
- package/dist/commands/{ratings.js → profiles/ratings.js} +2 -2
- package/dist/commands/{context.js → registry/context.js} +2 -2
- package/dist/commands/registry/index.d.ts +2 -0
- package/dist/commands/registry/index.js +3 -0
- package/dist/commands/setup/index.d.ts +2 -0
- package/dist/commands/setup/index.js +3 -0
- package/dist/commands/{init.d.ts → setup/init.d.ts} +1 -1
- package/dist/commands/{init.js → setup/init.js} +2 -3
- package/dist/commands/{instructions.d.ts → setup/instructions.d.ts} +2 -2
- package/dist/commands/{instructions.js → setup/instructions.js} +3 -3
- package/dist/commands/{ai-say.d.ts → talk/ai-say.d.ts} +2 -3
- package/dist/commands/{ai-say.js → talk/ai-say.js} +5 -9
- package/dist/commands/talk/index.d.ts +2 -0
- package/dist/commands/talk/index.js +3 -0
- package/dist/commands/{player-say.d.ts → talk/player-say.d.ts} +1 -1
- package/dist/commands/{player-say.js → talk/player-say.js} +4 -4
- package/dist/page/app/app.js +19 -11
- package/dist/page/app/served.js +7 -0
- package/dist/page/avatars/torretta.js +10 -3
- package/dist/page/dialogs/dialogs.css +10 -0
- package/dist/page/dialogs/profiles.js +1 -5
- package/dist/page/dialogs/settings.js +18 -4
- package/dist/page/game/column.js +1 -1
- package/dist/page/game/game.css +1 -1
- package/dist/page/guide/blocks.js +13 -2
- package/dist/page/guide/credits.js +6 -0
- package/dist/page/guide/drawings/analysis.js +13 -0
- package/dist/page/guide/drawings/drawings.css +329 -0
- package/dist/page/guide/drawings/drawings.js +15 -0
- package/dist/page/guide/drawings/game.js +15 -0
- package/dist/page/guide/drawings/helps.js +13 -0
- package/dist/page/guide/drawings/how-it-works.js +13 -0
- package/dist/page/guide/drawings/parts.js +103 -0
- package/dist/page/guide/drawings/players.js +19 -0
- package/dist/page/guide/drawings/talk.js +9 -0
- package/dist/page/guide/en.md +39 -25
- package/dist/page/guide/guide.css +123 -91
- package/dist/page/guide/guide.js +47 -25
- package/dist/page/guide/it.md +39 -25
- package/dist/page/guide/markdown.js +5 -0
- package/dist/page/helps/helps.css +127 -83
- package/dist/page/helps/helps.js +45 -26
- package/dist/page/helps/view.js +13 -3
- package/dist/page/{guide/foot.js → layout/footer.js} +7 -8
- package/dist/page/layout/header.js +5 -3
- package/dist/page/layout/layout.css +114 -10
- package/dist/page/layout/window.js +6 -26
- package/dist/page/main.js +1 -1
- package/dist/page/pieces/pieces.js +5 -2
- package/dist/page/style.css +1 -0
- package/dist/page/table/table.css +69 -0
- package/dist/page/table/update.js +82 -0
- package/dist/page/talk/chat.css +6 -6
- package/dist/page/talk/talk.css +17 -67
- package/dist/page/talk/talk.js +5 -5
- package/dist/page/talk/voice.js +12 -0
- package/dist/page/text.js +66 -18
- package/dist/page/theme.css +2 -0
- package/dist/server/{bell.js → bell/bell.js} +3 -3
- package/dist/server/bell/index.d.ts +1 -0
- package/dist/server/bell/index.js +2 -0
- package/dist/server/{caller.d.ts → mcp/caller.d.ts} +1 -1
- package/dist/server/{caller.js → mcp/caller.js} +1 -1
- package/dist/server/mcp/index.d.ts +1 -0
- package/dist/server/mcp/index.js +2 -0
- package/dist/server/{mcp.d.ts → mcp/mcp.d.ts} +1 -1
- package/dist/server/{mcp.js → mcp/mcp.js} +9 -9
- package/dist/server/page/game.js +16 -3
- package/dist/server/page/http.d.ts +1 -1
- package/dist/server/page/index.d.ts +3 -0
- package/dist/server/page/index.js +3 -0
- package/dist/server/page/page.d.ts +12 -3
- package/dist/server/page/page.js +13 -4
- package/dist/server/page/table.d.ts +7 -1
- package/dist/server/page/table.js +79 -3
- package/dist/server/page/update.d.ts +18 -0
- package/dist/server/page/update.js +40 -0
- package/dist/server/table/browser.d.ts +1 -1
- package/dist/server/table/browser.js +1 -1
- package/dist/server/table/hosts/chats.d.ts +1 -1
- package/dist/server/table/hosts/chats.js +2 -2
- package/dist/server/table/hosts/index.d.ts +1 -1
- package/dist/server/table/hosts/index.js +1 -1
- package/dist/server/table/hosts/play.d.ts +8 -1
- package/dist/server/table/hosts/play.js +40 -4
- package/dist/server/table/hosts/seat.d.ts +5 -1
- package/dist/server/table/hosts/seat.js +1 -1
- package/dist/server/table/index.d.ts +3 -2
- package/dist/server/table/index.js +3 -2
- package/dist/server/table/launch.d.ts +5 -2
- package/dist/server/table/launch.js +6 -3
- package/dist/server/table/link.d.ts +1 -1
- package/dist/server/table/link.js +3 -3
- package/dist/server/table/table.d.ts +4 -5
- package/dist/server/table/table.js +15 -12
- package/dist/server/table/update.d.ts +17 -0
- package/dist/server/table/update.js +77 -0
- package/dist/sites/index.d.ts +1 -1
- package/dist/sites/index.js +2 -2
- package/dist/version.d.ts +4 -0
- package/dist/version.js +12 -1
- package/package.json +1 -1
- /package/dist/commands/{speech.d.ts → answers/speech.d.ts} +0 -0
- /package/dist/commands/{view.js → answers/view.js} +0 -0
- /package/dist/commands/{page-link.js → game/page-link.js} +0 -0
- /package/dist/commands/{context.d.ts → registry/context.d.ts} +0 -0
- /package/dist/commands/{registry.d.ts → registry/registry.d.ts} +0 -0
- /package/dist/commands/{registry.js → registry/registry.js} +0 -0
- /package/dist/server/{bell.d.ts → bell/bell.d.ts} +0 -0
|
@@ -81,8 +81,9 @@
|
|
|
81
81
|
display: none;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
/* Beside a narrow board the offer and its answer take the room of the other commands, which come back once it is answered */
|
|
85
|
-
.top:has(.answer) .command:not(.answer)
|
|
84
|
+
/* Beside a narrow board the offer and its answer take the room of the other commands and the flip, which come back once it is answered */
|
|
85
|
+
.top:has(.answer) .command:not(.answer),
|
|
86
|
+
.top:has(.answer) .flip-button {
|
|
86
87
|
display: none;
|
|
87
88
|
}
|
|
88
89
|
}
|
|
@@ -114,6 +115,13 @@
|
|
|
114
115
|
white-space: nowrap;
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
/* The board turned round: the flip stands pressed, its edge in the soft ink that reads on both themes (Zoe) */
|
|
119
|
+
.top .flip-button[aria-pressed="true"] {
|
|
120
|
+
color: var(--ink);
|
|
121
|
+
border-color: var(--soft);
|
|
122
|
+
background: var(--card);
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
/* The player's picture, round and borderless, at the end of the header: it opens the menu of the players */
|
|
118
126
|
.top .player {
|
|
119
127
|
border-color: transparent;
|
|
@@ -152,10 +160,6 @@
|
|
|
152
160
|
}
|
|
153
161
|
}
|
|
154
162
|
|
|
155
|
-
.top:has(.verdict.idle, .verdict.over) .command:has(.icon.flip) span {
|
|
156
|
-
display: none;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
163
|
/* On a phone the player's card is under the board, below the fold: between games the header's new game stands out too, on the first screen */
|
|
160
164
|
@media (max-width: 840px) {
|
|
161
165
|
.top:has(.verdict.idle, .verdict.over) .command:has(.icon.new) {
|
|
@@ -205,10 +209,54 @@
|
|
|
205
209
|
position: relative;
|
|
206
210
|
/* 12.5cqw is a square, for the lifted piece too */
|
|
207
211
|
container-type: inline-size;
|
|
208
|
-
width: min(calc(100vw - var(--left-now) - var(--right-now) - 2 * var(--gap) - 2 * var(--between)), max(var(--least), calc(100vh - var(--bar) -
|
|
212
|
+
width: min(calc(100vw - var(--left-now) - var(--right-now) - 2 * var(--gap) - 2 * var(--between)), max(var(--least), calc(100vh - var(--bar) - var(--foot) - 4 * var(--between))));
|
|
209
213
|
transition: width 200ms cubic-bezier(0.2, 0, 0, 1);
|
|
210
214
|
}
|
|
211
215
|
|
|
216
|
+
/* The page's foot, a thin line under the board and as wide as it, in a row of its own under the others at every width (Stefano); it never widens the board's
|
|
217
|
+
column */
|
|
218
|
+
.page-foot {
|
|
219
|
+
grid-column: board;
|
|
220
|
+
grid-row: -1 / span 1;
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-wrap: wrap;
|
|
223
|
+
align-items: center;
|
|
224
|
+
justify-content: space-between;
|
|
225
|
+
gap: 4px 14px;
|
|
226
|
+
min-height: var(--foot);
|
|
227
|
+
contain: inline-size;
|
|
228
|
+
color: var(--soft);
|
|
229
|
+
font-size: 12px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.page-foot a {
|
|
233
|
+
display: inline-flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 5px;
|
|
236
|
+
color: inherit;
|
|
237
|
+
text-decoration: none;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.page-foot a:hover,
|
|
241
|
+
.page-foot a:focus-visible {
|
|
242
|
+
color: var(--ink);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.foot-links {
|
|
246
|
+
display: inline-flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: 14px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.page-foot .icon {
|
|
252
|
+
width: 15px;
|
|
253
|
+
height: 15px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.foot-support .icon {
|
|
257
|
+
color: var(--low-time);
|
|
258
|
+
}
|
|
259
|
+
|
|
212
260
|
.talk {
|
|
213
261
|
grid-area: talk;
|
|
214
262
|
display: flex;
|
|
@@ -422,6 +470,13 @@
|
|
|
422
470
|
box-shadow: 0 0 0 2px var(--page);
|
|
423
471
|
}
|
|
424
472
|
|
|
473
|
+
/* On the Torretta's disc, clear of its battlement, ringed in the card's colour */
|
|
474
|
+
.face.unread::after {
|
|
475
|
+
top: -2px;
|
|
476
|
+
right: -2px;
|
|
477
|
+
box-shadow: 0 0 0 2px var(--card);
|
|
478
|
+
}
|
|
479
|
+
|
|
425
480
|
.fold-tab button.unread::after {
|
|
426
481
|
top: -4px;
|
|
427
482
|
right: auto;
|
|
@@ -436,11 +491,11 @@
|
|
|
436
491
|
flex: none;
|
|
437
492
|
}
|
|
438
493
|
|
|
439
|
-
/*
|
|
494
|
+
/* The trail's dot on the disc's edge, clear of the battlement */
|
|
440
495
|
.thought {
|
|
441
496
|
position: absolute;
|
|
442
|
-
top: -
|
|
443
|
-
left: -
|
|
497
|
+
top: -9px;
|
|
498
|
+
left: -12px;
|
|
444
499
|
width: 24px;
|
|
445
500
|
height: 20px;
|
|
446
501
|
overflow: visible;
|
|
@@ -614,6 +669,14 @@
|
|
|
614
669
|
min-height: 0;
|
|
615
670
|
}
|
|
616
671
|
|
|
672
|
+
/* The cards, then the foot: the moves, the saves and the steps */
|
|
673
|
+
.side-cards,
|
|
674
|
+
.side-foot {
|
|
675
|
+
display: flex;
|
|
676
|
+
flex-direction: column;
|
|
677
|
+
gap: var(--between);
|
|
678
|
+
}
|
|
679
|
+
|
|
617
680
|
.board-steps,
|
|
618
681
|
.board-map {
|
|
619
682
|
display: none;
|
|
@@ -664,6 +727,38 @@
|
|
|
664
727
|
.side > * {
|
|
665
728
|
width: var(--right);
|
|
666
729
|
}
|
|
730
|
+
|
|
731
|
+
/* Beside the board the moves, the saves and the steps take the room the cards leave, by the board's lower edge, and the moves keep four rows at least; a
|
|
732
|
+
column too short for both scrolls the cards under the wheel, with no scrollbar, and the cards never give way themselves (Stefano, Zoe). A halo round
|
|
733
|
+
them keeps their shadows, which the scroll would cut, and they fade at the board's top edge and over the moves */
|
|
734
|
+
.side > .side-cards {
|
|
735
|
+
--halo: 16px;
|
|
736
|
+
flex: 0 1 auto;
|
|
737
|
+
min-height: 0;
|
|
738
|
+
width: calc(var(--right) + 2 * var(--halo));
|
|
739
|
+
margin: calc(-1 * var(--halo)) calc(-1 * var(--halo)) calc(-1 * var(--between));
|
|
740
|
+
padding: var(--halo) var(--halo) var(--between);
|
|
741
|
+
overflow: hidden auto;
|
|
742
|
+
scrollbar-width: none;
|
|
743
|
+
mask-image: linear-gradient(transparent, #000 var(--halo), #000 calc(100% - var(--between)), transparent);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.side > .side-cards > * {
|
|
747
|
+
flex-shrink: 0;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.side > .side-foot {
|
|
751
|
+
flex: 1 1 auto;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.side-foot > .moves-card:not(.folded) {
|
|
755
|
+
min-height: 150px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/* A long game asks no room of its own: its moves scroll in what the cards leave */
|
|
759
|
+
.side-foot .moves {
|
|
760
|
+
contain: size;
|
|
761
|
+
}
|
|
667
762
|
}
|
|
668
763
|
|
|
669
764
|
/* Where three columns would leave the board small, the game's column goes under the board, always open */
|
|
@@ -909,6 +1004,15 @@
|
|
|
909
1004
|
box-shadow: 0 8px 24px rgb(0 0 0 / 16%);
|
|
910
1005
|
}
|
|
911
1006
|
|
|
1007
|
+
/* On a phone it would cover the chat's line at the foot: it stands at the top of the column instead (Zoe) */
|
|
1008
|
+
@media (max-width: 840px) {
|
|
1009
|
+
.outdated {
|
|
1010
|
+
position: static;
|
|
1011
|
+
margin: var(--between) var(--gap) 0;
|
|
1012
|
+
box-shadow: none;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
912
1016
|
/* On a phone the header's first line holds the Torretta, which stands for the name, and every button down to the player's picture, a little closer; the
|
|
913
1017
|
sound and the theme stay in the settings */
|
|
914
1018
|
@media (max-width: 420px) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
// The table's window
|
|
2
|
-
//
|
|
1
|
+
// The table's window as it opens (D-104): 16:9, 1600×900 or what the screen has, centred, every time the table opens it. Chrome and Edge keep one size for
|
|
2
|
+
// every application window on 127.0.0.1, whatever its port, so the size they would give is any page's, often half a screen (Stefano).
|
|
3
3
|
// The mark the table puts on the address of the window it opens (server/table/browser.ts).
|
|
4
4
|
const mark = "opened";
|
|
5
|
-
const sizedKey = "chesspal-window-sized";
|
|
6
5
|
const wanted = { width: 1600, height: 900 };
|
|
7
|
-
/** Sizes the window the table opened
|
|
6
|
+
/** Sizes the window the table opened and takes the mark off the address, so that a reload keeps the size the player gave it. */
|
|
8
7
|
export function fitOpenedWindow() {
|
|
9
8
|
const address = new URL(location.href);
|
|
10
9
|
if (!address.searchParams.has(mark)) {
|
|
@@ -12,13 +11,11 @@ export function fitOpenedWindow() {
|
|
|
12
11
|
}
|
|
13
12
|
address.searchParams.delete(mark);
|
|
14
13
|
history.replaceState(history.state, "", address.pathname + address.search + address.hash);
|
|
15
|
-
if (sizedBefore()) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
14
|
const place = windowPlace(screen.availWidth, screen.availHeight);
|
|
15
|
+
// Chrome and Edge say where the window's screen starts: on a second screen the window stays there (Zoe).
|
|
16
|
+
const { availLeft = 0, availTop = 0 } = screen;
|
|
19
17
|
window.resizeTo(place.width, place.height);
|
|
20
|
-
window.moveTo(place.left, place.top);
|
|
21
|
-
noteSized();
|
|
18
|
+
window.moveTo(availLeft + place.left, availTop + place.top);
|
|
22
19
|
}
|
|
23
20
|
/** Where the window goes on a screen with this much room: 1600×900, or less on a smaller screen, centred. */
|
|
24
21
|
export function windowPlace(roomWidth, roomHeight) {
|
|
@@ -26,20 +23,3 @@ export function windowPlace(roomWidth, roomHeight) {
|
|
|
26
23
|
const height = Math.min(wanted.height, roomHeight);
|
|
27
24
|
return { width, height, left: Math.round((roomWidth - width) / 2), top: Math.round((roomHeight - height) / 2) };
|
|
28
25
|
}
|
|
29
|
-
function sizedBefore() {
|
|
30
|
-
try {
|
|
31
|
-
return localStorage.getItem(sizedKey) !== null;
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// A browser that keeps nothing for the page: sizing it at every opening is the lesser harm.
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function noteSized() {
|
|
39
|
-
try {
|
|
40
|
-
localStorage.setItem(sizedKey, "1");
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
// Nothing kept: the next opening sizes the window again.
|
|
44
|
-
}
|
|
45
|
-
}
|
package/dist/page/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
// The page's start: the window the table opened sized
|
|
2
|
+
// The page's start: the window the table opened sized as it opens, the settings this browser remembers, shown before the first frame, then the app
|
|
3
3
|
// drawn into its place.
|
|
4
4
|
import { render } from "preact";
|
|
5
5
|
import { App } from "./app/app.js";
|
|
@@ -12,8 +12,11 @@ const folder = "/page/pieces/";
|
|
|
12
12
|
*/
|
|
13
13
|
export function Piece({ letter, set, small = false }) {
|
|
14
14
|
const chosen = useContext(ChosenSet);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
return _jsx(Drawing, { href: pieceSymbol(letter, set ?? chosen, small), class: `piece ${letter === letter.toUpperCase() ? "white" : "black"}` });
|
|
16
|
+
}
|
|
17
|
+
/** Where a piece is drawn, by its FEN letter: its symbol in the set's map, or in the map of the set's small pieces. */
|
|
18
|
+
export function pieceSymbol(letter, set, small = false) {
|
|
19
|
+
return `${folder}${set}${small ? "-small" : ""}.svg#${letter === letter.toUpperCase() ? "w" : "b"}${letter.toUpperCase()}`;
|
|
17
20
|
}
|
|
18
21
|
/** A piece as the notation shows it (D-50): the chosen set's small piece, White's white and Black's black. */
|
|
19
22
|
export function Figurine({ letter, side }) {
|
package/dist/page/style.css
CHANGED
|
@@ -60,6 +60,75 @@
|
|
|
60
60
|
font-size: 13px;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/* The header's mark of a newer Chesspal (D-108): its border as the other buttons', not the accent, which reads as focus; inside, a full accent disc with a
|
|
64
|
+
white arrow (Zoe) */
|
|
65
|
+
.top .update-button .icon circle {
|
|
66
|
+
fill: var(--accent);
|
|
67
|
+
stroke: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.top .update-button .icon path {
|
|
71
|
+
stroke: var(--on-accent);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* One button more: under 360px the header's buttons come a little closer, or the last one goes past the edge */
|
|
75
|
+
@media (max-width: 359px) {
|
|
76
|
+
.top {
|
|
77
|
+
column-gap: 2px;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Its window, as narrow as the chat's; the spinner beside what npm does; npm's failure with a cross, and each command on its line */
|
|
82
|
+
.dialog:has(> .update-offer) {
|
|
83
|
+
width: min(460px, calc(100vw - 32px));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.update-state {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 8px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.update-failed p {
|
|
93
|
+
margin: 0 0 6px;
|
|
94
|
+
color: var(--ink);
|
|
95
|
+
font-size: 14px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.update-cross {
|
|
99
|
+
color: var(--low-time);
|
|
100
|
+
font-weight: 700;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.update-failed code,
|
|
104
|
+
.update-notice code {
|
|
105
|
+
display: block;
|
|
106
|
+
margin-top: 4px;
|
|
107
|
+
font-family: ui-monospace, monospace;
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
user-select: all;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* On a chat's own page, news and no warning: the card's ground and an accent border, the words beside the × that hides it */
|
|
113
|
+
.outdated.update-notice {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: flex-start;
|
|
116
|
+
gap: 8px;
|
|
117
|
+
border-color: var(--accent);
|
|
118
|
+
background: var(--card);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.update-notice > span {
|
|
122
|
+
flex: 1;
|
|
123
|
+
min-width: 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.update-notice .icon-button {
|
|
127
|
+
flex: none;
|
|
128
|
+
width: 30px;
|
|
129
|
+
height: 30px;
|
|
130
|
+
}
|
|
131
|
+
|
|
63
132
|
/* Empty, the state takes no room */
|
|
64
133
|
.chat-state:empty {
|
|
65
134
|
display: none;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
// A newer Chesspal (D-108): on the table's page the header's mark opens this window, which installs it between games; the table and its chat then start
|
|
3
|
+
// again from it, and the page loads again by itself.
|
|
4
|
+
import { useEffect, useState } from "preact/hooks";
|
|
5
|
+
import { Dialog } from "../dialogs/dialog.js";
|
|
6
|
+
/**
|
|
7
|
+
* The window that installs the newer Chesspal: its button waits while a game goes on and while npm installs; installed, the table waits for the game to
|
|
8
|
+
* end; when npm fails, a cross and the commands to type.
|
|
9
|
+
*/
|
|
10
|
+
export function UpdateDialog({ open, version, current, installing, installed, going, chat, name, onClose, text }) {
|
|
11
|
+
const [sent, setSent] = useState(false);
|
|
12
|
+
const [answer, setAnswer] = useState(undefined);
|
|
13
|
+
useEffect(() => setAnswer(undefined), [open]);
|
|
14
|
+
const words = text.update;
|
|
15
|
+
// Once npm has installed it the table closes to start again: the page waits for it, and loads again.
|
|
16
|
+
const waiting = installing || (sent && answer === undefined) || (answer?.installed === true && !installed);
|
|
17
|
+
const failed = answer?.installed === false;
|
|
18
|
+
const install = async () => {
|
|
19
|
+
setSent(true);
|
|
20
|
+
setAnswer(undefined);
|
|
21
|
+
setAnswer(await askToInstall(text, name));
|
|
22
|
+
setSent(false);
|
|
23
|
+
};
|
|
24
|
+
const stopped = waiting || installed || going;
|
|
25
|
+
return (_jsxs(Dialog, { open: open, title: words.title, onClose: onClose, text: text, children: [_jsxs("p", { class: "note update-offer", children: [words.offer(version, current), chat === "held" ? ` ${words.chatAgain(name)}` : chat === "byHand" ? ` ${words.byHand(name)}` : ""] }), _jsx("button", { class: `command${failed ? "" : " primary"}`, type: "button", "aria-disabled": stopped, onClick: stopped ? undefined : () => void install(), children: words.install }), _jsx("p", { class: "chat-state update-state", role: "status", children: waiting
|
|
26
|
+
? (_jsxs(_Fragment, { children: [_jsx("span", { class: "spinner", "aria-hidden": "true" }), words.installing(version)] }))
|
|
27
|
+
: installed
|
|
28
|
+
? words.installed
|
|
29
|
+
: answer?.refused ?? (going ? words.whilePlaying : null) }), failed
|
|
30
|
+
? (_jsxs("div", { class: "update-failed", role: "alert", children: [_jsxs("p", { children: [_jsx("span", { class: "update-cross", "aria-hidden": "true", children: "\u2715" }), " ", words.failed] }), _jsx("code", { children: "npm install -g chesspal" }), _jsx("code", { children: "chesspal" })] }))
|
|
31
|
+
: null] }));
|
|
32
|
+
}
|
|
33
|
+
/** The header's mark of a newer Chesspal, on the table's page: it opens the window that installs it; while npm installs, or the table waits, it spins. */
|
|
34
|
+
export function UpdateMark({ version, installing, onOpen, text }) {
|
|
35
|
+
const title = installing ? text.update.installing(version) : text.update.mark(version);
|
|
36
|
+
return (_jsx("button", { class: "icon-button update-button", type: "button", title: title, "aria-label": title, "aria-haspopup": "dialog", onClick: onOpen, children: installing ? _jsx("span", { class: "spinner", "aria-hidden": "true" }) : (_jsxs("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 16.5V7.5M8 11.5L12 7.5L16 11.5" })] })) }));
|
|
37
|
+
}
|
|
38
|
+
/** On a chat's own page, the strip with the command that installs the newer Chesspal; its × hides it until a newer one still is out. */
|
|
39
|
+
export function UpdateNotice({ version, name, text }) {
|
|
40
|
+
const [hidden, setHidden] = useState(hiddenVersion);
|
|
41
|
+
if (hidden === version) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const hide = () => {
|
|
45
|
+
rememberHidden(version);
|
|
46
|
+
setHidden(version);
|
|
47
|
+
};
|
|
48
|
+
return (_jsxs("p", { class: "outdated update-notice", role: "status", children: [_jsxs("span", { children: [text.update.notice(version, name), _jsx("code", { children: "npm install -g chesspal" })] }), _jsx("button", { class: "icon-button", type: "button", title: text.update.hide, "aria-label": text.update.hide, onClick: hide, children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 6L18 18M18 6L6 18" }) }) })] }));
|
|
49
|
+
}
|
|
50
|
+
const hiddenKey = "chesspal-update-hidden";
|
|
51
|
+
function hiddenVersion() {
|
|
52
|
+
try {
|
|
53
|
+
return localStorage.getItem(hiddenKey) ?? undefined;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// A browser that keeps nothing for the page: the strip shows.
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function rememberHidden(version) {
|
|
61
|
+
try {
|
|
62
|
+
localStorage.setItem(hiddenKey, version);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Hidden as long as the page.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function askToInstall(text, name) {
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch("/api/table/update", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" });
|
|
71
|
+
const body = (await response.json());
|
|
72
|
+
if (response.ok) {
|
|
73
|
+
return { installed: body.installed === true };
|
|
74
|
+
}
|
|
75
|
+
const known = body.refusal === undefined ? undefined : text.refused[body.refusal];
|
|
76
|
+
return { refused: known?.(0, name) ?? body.error ?? response.statusText };
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// The table closed to start again before its answer came.
|
|
80
|
+
return { installed: true };
|
|
81
|
+
}
|
|
82
|
+
}
|
package/dist/page/talk/chat.css
CHANGED
|
@@ -5,15 +5,13 @@
|
|
|
5
5
|
max-height: none;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
/*
|
|
8
|
+
/* Under the AI's note, with no line between them (Stefano) */
|
|
9
9
|
.talk.studied > section > .chat {
|
|
10
10
|
display: flex;
|
|
11
11
|
flex-direction: column;
|
|
12
12
|
flex: 1 1 auto;
|
|
13
13
|
min-height: 0;
|
|
14
14
|
margin-top: 12px;
|
|
15
|
-
padding-top: 10px;
|
|
16
|
-
border-top: 1px solid var(--line);
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
.chat > .compose {
|
|
@@ -49,9 +47,11 @@
|
|
|
49
47
|
|
|
50
48
|
.flipped .talk.studied > section > .chat {
|
|
51
49
|
margin: 0 0 12px;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Turned round, the note's room goes under its bubbles, which would touch the AI's card or the note that no chat listens (Zoe) */
|
|
53
|
+
.flipped .talk.studied .ai-note {
|
|
54
|
+
margin: 0 0 12px;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
package/dist/page/talk/talk.css
CHANGED
|
@@ -233,65 +233,6 @@
|
|
|
233
233
|
background: var(--say);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
.me {
|
|
237
|
-
position: relative;
|
|
238
|
-
flex: none;
|
|
239
|
-
padding: 0;
|
|
240
|
-
border: 0;
|
|
241
|
-
border-radius: 50%;
|
|
242
|
-
background: none;
|
|
243
|
-
line-height: 0;
|
|
244
|
-
cursor: pointer;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.me-cover {
|
|
248
|
-
position: absolute;
|
|
249
|
-
inset: 0;
|
|
250
|
-
display: grid;
|
|
251
|
-
place-items: center;
|
|
252
|
-
border-radius: 50%;
|
|
253
|
-
background: rgba(0, 0, 0, 0.45);
|
|
254
|
-
color: #fff;
|
|
255
|
-
opacity: 0;
|
|
256
|
-
transition: opacity 0.12s;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.me-cover .icon {
|
|
260
|
-
width: 45%;
|
|
261
|
-
height: 45%;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
.me:hover .me-cover,
|
|
265
|
-
.me:focus-visible .me-cover {
|
|
266
|
-
opacity: 1;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/* Where nothing hovers, a camera in the corner says the picture changes */
|
|
270
|
-
.me-badge {
|
|
271
|
-
position: absolute;
|
|
272
|
-
right: -2px;
|
|
273
|
-
bottom: -2px;
|
|
274
|
-
display: none;
|
|
275
|
-
place-items: center;
|
|
276
|
-
width: 18px;
|
|
277
|
-
height: 18px;
|
|
278
|
-
border-radius: 50%;
|
|
279
|
-
background: var(--accent);
|
|
280
|
-
color: var(--on-accent);
|
|
281
|
-
box-shadow: 0 0 0 2px var(--card);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
.me-badge .icon {
|
|
285
|
-
width: 12px;
|
|
286
|
-
height: 12px;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
@media (hover: none) {
|
|
290
|
-
.me-badge {
|
|
291
|
-
display: grid;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
236
|
.profile-name {
|
|
296
237
|
display: inline-flex;
|
|
297
238
|
align-items: center;
|
|
@@ -369,6 +310,15 @@
|
|
|
369
310
|
}
|
|
370
311
|
}
|
|
371
312
|
|
|
313
|
+
/* Its bust on a player's card: a disc of the player's picture's colour, which cuts what falls out of it */
|
|
314
|
+
.torretta.bust {
|
|
315
|
+
clip-path: circle(50%);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.torretta .back {
|
|
319
|
+
fill: var(--say);
|
|
320
|
+
}
|
|
321
|
+
|
|
372
322
|
.torretta .shade {
|
|
373
323
|
fill: var(--torretta-shade);
|
|
374
324
|
}
|
|
@@ -701,23 +651,23 @@
|
|
|
701
651
|
overflow-wrap: anywhere;
|
|
702
652
|
}
|
|
703
653
|
|
|
704
|
-
/* Only the note's
|
|
654
|
+
/* Only the note's first bubble has a tail, pointing up at the Torretta beside the AI's name, the board turned round or not (Stefano) */
|
|
705
655
|
.ai-note > .say::before,
|
|
706
656
|
.ai-note > .say::after {
|
|
707
657
|
content: none;
|
|
708
658
|
}
|
|
709
659
|
|
|
710
|
-
.ai-note > .
|
|
660
|
+
.ai-note > .who + .say::before {
|
|
711
661
|
content: "";
|
|
712
662
|
position: absolute;
|
|
713
663
|
left: 8px;
|
|
714
|
-
|
|
664
|
+
top: -9px;
|
|
715
665
|
border: 10px solid transparent;
|
|
716
|
-
border-
|
|
717
|
-
border-
|
|
666
|
+
border-top: 0;
|
|
667
|
+
border-bottom-color: var(--say);
|
|
718
668
|
}
|
|
719
669
|
|
|
720
|
-
.ai-note > .
|
|
670
|
+
.ai-note > .who + .say {
|
|
721
671
|
margin-top: 4px;
|
|
722
672
|
}
|
|
723
673
|
|
|
@@ -866,8 +816,8 @@
|
|
|
866
816
|
margin: 0 0 var(--between);
|
|
867
817
|
}
|
|
868
818
|
|
|
869
|
-
.ai-block:has(> .asleep) .say::before,
|
|
870
|
-
.ai-block:has(> .asleep) .say::after {
|
|
819
|
+
.ai-block:has(> .asleep) .says .say::before,
|
|
820
|
+
.ai-block:has(> .asleep) .says .say::after {
|
|
871
821
|
content: none;
|
|
872
822
|
}
|
|
873
823
|
|
package/dist/page/talk/talk.js
CHANGED
|
@@ -16,7 +16,7 @@ export function AiWords({ words, newestFirst, voice }) {
|
|
|
16
16
|
return (_jsx("ol", { ref: list, class: "says", "aria-live": "polite", children: inOrder(words.map((word, index) => (_jsx("li", { class: "say", style: aged(words.length - 1 - index), children: _jsx(Marked, { text: word }) }, index))), newestFirst) }));
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* The AI's word on the move shown of a game in analysis (D-69), in a bubble
|
|
19
|
+
* The AI's word on the move shown of a game in analysis (D-69), in a bubble under the Torretta beside the AI's name, pointing up at it: the move, its badge by name,
|
|
20
20
|
* and its note when it wrote one; read out as the player steps through the game. The Torretta and the name stay when the move has no word.
|
|
21
21
|
*/
|
|
22
22
|
export function AiNote({ ply, opening, closing, summary, reviewing, name, by, mood, voice, text }) {
|
|
@@ -32,10 +32,10 @@ export function AiNote({ ply, opening, closing, summary, reviewing, name, by, mo
|
|
|
32
32
|
}
|
|
33
33
|
return hush;
|
|
34
34
|
}, [spoken, voice]);
|
|
35
|
-
// The Torretta stays in sight through the whole analysis,
|
|
36
|
-
return (_jsxs("div", { class: "ai-note", "aria-live": "polite", children: [ply === undefined || shown === undefined ? null : (_jsxs("p", { class: `say move-note ${shown.badge ?? ""}`, children: [_jsxs("span", { class: "head", children: [shown.badge === undefined ? _jsx(NoteIcon, {}) : _jsx(BadgeIcon, { badge: shown.badge }), _jsxs("b", { children: [_jsxs("span", { class: "visually-hidden", children: [ply.number, ply.side === "white" ? "." : "...", ply.san] }), _jsxs("span", { "aria-hidden": "true", children: [_jsxs("span", { class: "move-number", children: [ply.number, ply.side === "white" ? "." : "..."] }), _jsx(Figurines, { san: ply.san, side: ply.side })] })] }), " ", title] }), note === undefined ? null : (_jsx("span", { class: "note", children: _jsx(Marked, { text: note }) })), shown.arrows === undefined && shown.squares === undefined ? null : _jsx(Legend, { review: shown, words: text.drawn })] })), summary === undefined ? null : _jsx(GameReview, { by: name, summary: summary, text: text }), closing === undefined ? null : (_jsx("p", { class: "say closing", children: _jsx(Marked, { text: closing }) })), reviewing === true
|
|
35
|
+
// The Torretta stays in sight through the whole analysis, over its bubbles, which show only where it wrote something.
|
|
36
|
+
return (_jsxs("div", { class: "ai-note", "aria-live": "polite", children: [_jsxs("p", { class: "who", children: [_jsx(Torretta, { size: 36, mood: mood }), _jsxs("span", { class: "signed", children: [name, by === undefined ? null : _jsx("small", { children: signature(by.annotator, by.effort) })] })] }), ply === undefined || shown === undefined ? null : (_jsxs("p", { class: `say move-note ${shown.badge ?? ""}`, children: [_jsxs("span", { class: "head", children: [shown.badge === undefined ? _jsx(NoteIcon, {}) : _jsx(BadgeIcon, { badge: shown.badge }), _jsxs("b", { children: [_jsxs("span", { class: "visually-hidden", children: [ply.number, ply.side === "white" ? "." : "...", ply.san] }), _jsxs("span", { "aria-hidden": "true", children: [_jsxs("span", { class: "move-number", children: [ply.number, ply.side === "white" ? "." : "..."] }), _jsx(Figurines, { san: ply.san, side: ply.side })] })] }), " ", title] }), note === undefined ? null : (_jsx("span", { class: "note", children: _jsx(Marked, { text: note }) })), shown.arrows === undefined && shown.squares === undefined ? null : _jsx(Legend, { review: shown, words: text.drawn })] })), summary === undefined ? null : _jsx(GameReview, { by: name, summary: summary, text: text }), closing === undefined ? null : (_jsx("p", { class: "say closing", children: _jsx(Marked, { text: closing }) })), reviewing === true
|
|
37
37
|
? (_jsxs("p", { class: "say reviewing", children: [_jsx("span", { class: "spinner", "aria-hidden": "true" }), text.reviewing(name)] }))
|
|
38
|
-
: null
|
|
38
|
+
: null] }));
|
|
39
39
|
}
|
|
40
40
|
/** The squares and moves in the AI's words, such as e3, Cxe4, 7.Nd4 or O-O: in bold, as the player looks for them on the board. */
|
|
41
41
|
export function Marked({ text }) {
|
|
@@ -94,7 +94,7 @@ export function Compose({ lines, newestFirst, spent, draft, onDraft, onSend, can
|
|
|
94
94
|
* whoever moves and a dot on the Torretta when the AI spoke meanwhile.
|
|
95
95
|
*/
|
|
96
96
|
export function TalkFaces({ name, aiPicture, you, picture, ai, player, aiMoves, playerMoves, unread, text }) {
|
|
97
|
-
return (_jsxs("div", { class: "faces", children: [_jsx(RailPlayer, { place: "ai", picture: aiPicture ?? _jsx(Torretta, { size: 40 }), name: name, ...(ai === undefined ? {} : { side: text.sides[ai] }), moves: aiMoves, unread: unread }), _jsx(RailPlayer, { place: "you", picture: picture, name: you, ...(player === undefined ? {} : { side: text.sides[player] }), moves: playerMoves })] }));
|
|
97
|
+
return (_jsxs("div", { class: "faces", children: [_jsx(RailPlayer, { place: "ai", picture: aiPicture ?? _jsx(Torretta, { size: 40, bust: true }), name: name, ...(ai === undefined ? {} : { side: text.sides[ai] }), moves: aiMoves, unread: unread }), _jsx(RailPlayer, { place: "you", picture: picture, name: you, ...(player === undefined ? {} : { side: text.sides[player] }), moves: playerMoves })] }));
|
|
98
98
|
}
|
|
99
99
|
/** The move a line of the player's was written on, 14.♘f3, small at the line's head: a press shows it on the board again (Zoe). */
|
|
100
100
|
function ShownMove({ move, onShow, text }) {
|
package/dist/page/talk/voice.js
CHANGED
|
@@ -28,6 +28,18 @@ export function hush() {
|
|
|
28
28
|
speechSynthesis.cancel();
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
/** Whether the browser has a voice for the language: without one the words cannot be read. */
|
|
32
|
+
export function hasVoice(language) {
|
|
33
|
+
return typeof speechSynthesis !== "undefined" && readerFor(language) !== undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Calls the listener whenever the browser's voices change, since Chrome lists them late: what it returns stops it. */
|
|
36
|
+
export function onVoices(listener) {
|
|
37
|
+
if (typeof speechSynthesis === "undefined") {
|
|
38
|
+
return () => undefined;
|
|
39
|
+
}
|
|
40
|
+
speechSynthesis.addEventListener("voiceschanged", listener);
|
|
41
|
+
return () => speechSynthesis.removeEventListener("voiceschanged", listener);
|
|
42
|
+
}
|
|
31
43
|
/**
|
|
32
44
|
* The words with each move the AI wrote said in words, since a voice reads ♟g4 as "chess pawn g4": ♞xf6+, Nxf6+, exd5, O-O, e8=♛. A square alone, e4,
|
|
33
45
|
* stays as it is; a pawn's move becomes words only with its figurine, a capture, a promotion or a check, and without the file it takes from.
|