chesspal 0.3.0 → 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.d.ts → registry/context.d.ts} +2 -0
- 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 +44 -20
- 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 +3 -7
- 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 -36
- 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 +2 -1
- package/dist/page/table/table.css +192 -0
- package/dist/page/table/update.js +82 -0
- package/dist/page/table/window.js +130 -0
- package/dist/page/talk/chat.css +19 -8
- package/dist/page/talk/talk.css +17 -67
- package/dist/page/talk/talk.js +7 -7
- package/dist/page/talk/voice.js +47 -9
- package/dist/page/text.js +118 -22
- 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/chat.d.ts +5 -0
- package/dist/server/page/chat.js +9 -1
- 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 +16 -3
- package/dist/server/page/page.js +18 -4
- package/dist/server/page/table.d.ts +40 -15
- package/dist/server/page/table.js +203 -19
- 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 +7 -4
- 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 +15 -4
- package/dist/server/table/hosts/play.js +75 -11
- package/dist/server/table/hosts/seat.d.ts +17 -5
- package/dist/server/table/hosts/seat.js +21 -15
- 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 +4 -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/page/table/opener.css +0 -65
- package/dist/page/table/opener.js +0 -59
- /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/{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;
|
|
@@ -602,32 +657,6 @@
|
|
|
602
657
|
min-height: 0;
|
|
603
658
|
overflow-y: auto;
|
|
604
659
|
}
|
|
605
|
-
|
|
606
|
-
/* On a short column the table's note keeps its buttons and drops the commands to type, then the box and the words go: they wait for a chat anyway.
|
|
607
|
-
In analysis the cards are taller and the AI's note needs room too */
|
|
608
|
-
@container talk (max-height: 560px) {
|
|
609
|
-
.opener-command {
|
|
610
|
-
display: none;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
@container talk (max-height: 500px) {
|
|
615
|
-
.ai-block:has(> .opener) + .you-block > :is(.sent, .compose) {
|
|
616
|
-
display: none;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
@container talk (max-height: 640px) {
|
|
621
|
-
.talk.studied .opener-command {
|
|
622
|
-
display: none;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
@container talk (max-height: 580px) {
|
|
627
|
-
.talk.studied > .ai-block:has(> .opener) + .you-block > .chat {
|
|
628
|
-
display: none;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
660
|
}
|
|
632
661
|
|
|
633
662
|
/* The game's column, which folds from its tab */
|
|
@@ -640,6 +669,14 @@
|
|
|
640
669
|
min-height: 0;
|
|
641
670
|
}
|
|
642
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
|
+
|
|
643
680
|
.board-steps,
|
|
644
681
|
.board-map {
|
|
645
682
|
display: none;
|
|
@@ -690,6 +727,38 @@
|
|
|
690
727
|
.side > * {
|
|
691
728
|
width: var(--right);
|
|
692
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
|
+
}
|
|
693
762
|
}
|
|
694
763
|
|
|
695
764
|
/* Where three columns would leave the board small, the game's column goes under the board, always open */
|
|
@@ -935,6 +1004,15 @@
|
|
|
935
1004
|
box-shadow: 0 8px 24px rgb(0 0 0 / 16%);
|
|
936
1005
|
}
|
|
937
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
|
+
|
|
938
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
|
|
939
1017
|
sound and the theme stay in the settings */
|
|
940
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
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
@import "board/board.css";
|
|
6
6
|
@import "talk/talk.css";
|
|
7
7
|
@import "talk/chat.css";
|
|
8
|
-
@import "table/
|
|
8
|
+
@import "table/table.css";
|
|
9
9
|
@import "game/game.css";
|
|
10
10
|
@import "helps/helps.css";
|
|
11
11
|
@import "legend/legend.css";
|
|
12
12
|
@import "dialogs/dialogs.css";
|
|
13
13
|
@import "guide/guide.css";
|
|
14
|
+
@import "guide/drawings/drawings.css";
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/* The chat's window (D-107): narrow, a row for each host, its button with the tick of the one at the table and its model and effort under their titles,
|
|
2
|
+
their columns shared through the subgrid; the command to type instead */
|
|
3
|
+
.dialog:has(> .chat-hosts) {
|
|
4
|
+
width: min(460px, calc(100vw - 32px));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.chat-hosts {
|
|
8
|
+
display: grid;
|
|
9
|
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
10
|
+
gap: 6px;
|
|
11
|
+
margin: 8px 0 12px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.chat-head,
|
|
15
|
+
.chat-host {
|
|
16
|
+
display: grid;
|
|
17
|
+
grid-column: 1 / -1;
|
|
18
|
+
grid-template-columns: subgrid;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.chat-head {
|
|
22
|
+
color: var(--soft);
|
|
23
|
+
font-size: 12px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.chat-host .choice {
|
|
27
|
+
min-width: 0;
|
|
28
|
+
font-size: 15px;
|
|
29
|
+
text-align: left;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.chat-host .choice span {
|
|
33
|
+
flex: 1;
|
|
34
|
+
min-width: 0;
|
|
35
|
+
overflow: hidden;
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
text-overflow: ellipsis;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.chat-host .in-use {
|
|
41
|
+
flex: none;
|
|
42
|
+
width: 18px;
|
|
43
|
+
height: 18px;
|
|
44
|
+
color: var(--accent);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.chat-host .choice[aria-disabled="true"] {
|
|
48
|
+
border-color: var(--line);
|
|
49
|
+
opacity: 0.6;
|
|
50
|
+
cursor: default;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.chat-host select {
|
|
54
|
+
padding: 4px;
|
|
55
|
+
border: 1px solid var(--line);
|
|
56
|
+
border-radius: 6px;
|
|
57
|
+
background: var(--card);
|
|
58
|
+
color: var(--ink);
|
|
59
|
+
font: inherit;
|
|
60
|
+
font-size: 13px;
|
|
61
|
+
}
|
|
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
|
+
|
|
132
|
+
/* Empty, the state takes no room */
|
|
133
|
+
.chat-state:empty {
|
|
134
|
+
display: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.chat-command {
|
|
138
|
+
color: var(--soft);
|
|
139
|
+
font-size: 12.5px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Each command whole on its line; two families, so the browser does not shrink the monospace */
|
|
143
|
+
.chat-command code {
|
|
144
|
+
font-family: ui-monospace, monospace;
|
|
145
|
+
white-space: nowrap;
|
|
146
|
+
user-select: all;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* The note on a start again that waits, with its ↻ and ×; in a game with no chat at the table, a line that opens the chat's window */
|
|
150
|
+
.table-note {
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: 6px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.table-note > span {
|
|
157
|
+
flex: 1;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.table-note .icon-button {
|
|
161
|
+
flex: none;
|
|
162
|
+
width: 30px;
|
|
163
|
+
height: 30px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.over-board > .table-note button {
|
|
167
|
+
pointer-events: auto;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.no-chat-line {
|
|
171
|
+
display: inline-flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
padding: 0;
|
|
174
|
+
border: 0;
|
|
175
|
+
background: none;
|
|
176
|
+
color: inherit;
|
|
177
|
+
font: inherit;
|
|
178
|
+
text-align: left;
|
|
179
|
+
text-decoration: underline;
|
|
180
|
+
text-underline-offset: 3px;
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* No chat at the table: a hollow ring before the AI's name, and before the line that says so */
|
|
185
|
+
.no-chat {
|
|
186
|
+
flex: none;
|
|
187
|
+
width: 8px;
|
|
188
|
+
height: 8px;
|
|
189
|
+
margin-right: 5px;
|
|
190
|
+
border: 1.5px solid var(--soft);
|
|
191
|
+
border-radius: 50%;
|
|
192
|
+
}
|
|
@@ -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
|
+
}
|