chesspal 0.3.4 → 0.3.5
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/dist/page/app/app.js
CHANGED
|
@@ -11,7 +11,7 @@ import { piecesOf } from "../board/squares.js";
|
|
|
11
11
|
import { NewGameDialog } from "../dialogs/new-game.js";
|
|
12
12
|
import { NameButton, ProfileDialog, ProfilesDialog, Wizard } from "../dialogs/profiles.js";
|
|
13
13
|
import { SettingsPanel } from "../dialogs/settings.js";
|
|
14
|
-
import { playerIn, studiedSides } from "../dialogs/studied.js";
|
|
14
|
+
import { othersOf, playerIn, studiedSides } from "../dialogs/studied.js";
|
|
15
15
|
import { StudyDialog } from "../dialogs/study.js";
|
|
16
16
|
import { BadgeCounts } from "../game/badges.js";
|
|
17
17
|
import { stepped } from "../game/browse.js";
|
|
@@ -231,7 +231,7 @@ export function App({ start }) {
|
|
|
231
231
|
const playedName = game === undefined || game === null ? undefined : anchorName(game.name);
|
|
232
232
|
useAnchor({ ready: served !== undefined, shown: studied !== undefined ? anchorName(studied.name) : idle ? undefined : playedName, played: playedName, going }, viewing, (plies) => goTo(plies ?? total), async (wanted) => await post("/api/study", { game: wanted, look: true }, text, name) === undefined);
|
|
233
233
|
// The tab names the game and the move shown, as the cards name its players; between games, Chesspal alone.
|
|
234
|
-
const titled = idle || served === undefined ? undefined : studiedSides(live.record.tags, served.profile.name, playedAs, text.sides, served.profile.accounts);
|
|
234
|
+
const titled = idle || served === undefined ? undefined : studiedSides(live.record.tags, served.profile.name, playedAs, text.sides, served.profile.accounts, othersOf(served.profiles, served.profile.id));
|
|
235
235
|
useTabTitle(titled === undefined ? undefined : tabTitle(titled.white.name, titled.black.name, at === 0 ? undefined : plies[at - 1]));
|
|
236
236
|
// The header's theme switch picks the other of the two the page shows, leaving the system's.
|
|
237
237
|
const switchTheme = () => change({ ...settings, theme: document.documentElement.dataset.theme === "dark" ? "light" : "dark" });
|
|
@@ -281,7 +281,7 @@ export function App({ start }) {
|
|
|
281
281
|
const profile = served.profile;
|
|
282
282
|
const picture = _jsx(PlayerPicture, { profile: profile });
|
|
283
283
|
// In analysis the cards name the players of the game, the player's side at the bottom when they played it (D-69).
|
|
284
|
-
const sides = studied === undefined ? undefined : studiedSides(live.record.tags, profile.name, playedAs, text.sides, profile.accounts);
|
|
284
|
+
const sides = studied === undefined ? undefined : studiedSides(live.record.tags, profile.name, playedAs, text.sides, profile.accounts, othersOf(served.profiles, profile.id));
|
|
285
285
|
const player = sides?.bottom ?? (game === null || game.ai === "black" ? "white" : "black");
|
|
286
286
|
const ai = player === "white" ? "black" : "white";
|
|
287
287
|
// The Torretta's face on the move shown: the mood the AI gave, while it lasts (D-70); in analysis, of the side the AI played.
|
|
@@ -414,7 +414,7 @@ export function App({ start }) {
|
|
|
414
414
|
act("/api/new", { ai_colour: colour === "random" ? "random" : colour === "white" ? "black" : "white", level: chosen, ...(control === undefined ? {} : { clock: control }) });
|
|
415
415
|
};
|
|
416
416
|
// In analysis the AI's note goes with the other side's card and the talk with the player's, turned round with the board as in a game (D-101, Zoe).
|
|
417
|
-
const studiedCard = (side, place) => sides === undefined ? null : (_jsx(PlayerCard, { place: place, picture: pictureOf(sides[side], profile, 48, mood), name: sides[side].name, signed: sides[side].who === "ai" && playedBy !== undefined ? signature(playedBy.model, playedBy.effort) : undefined, side: side, taken: material.taken[side], ahead: ahead(side), badges: _jsx(BadgeCounts, { plies: plies, side: side, names: text.badges }), text: text }));
|
|
417
|
+
const studiedCard = (side, place) => sides === undefined ? null : (_jsx(PlayerCard, { place: place, picture: pictureOf(sides[side], profile, served.profiles, 48, mood), name: sides[side].name, signed: sides[side].who === "ai" && playedBy !== undefined ? signature(playedBy.model, playedBy.effort) : undefined, side: side, taken: material.taken[side], ahead: ahead(side), badges: _jsx(BadgeCounts, { plies: plies, side: side, names: text.badges }), text: text }));
|
|
418
418
|
// A game brought to analyse: the page shows it once the server has it in analysis; a refusal stays in the dialog. One the AI has to go over, with no
|
|
419
419
|
// chat at the table, opens the chat's window: the analyst works with the chat's model (D-109).
|
|
420
420
|
const studyGame = async (studied) => {
|
|
@@ -427,7 +427,7 @@ export function App({ start }) {
|
|
|
427
427
|
setDialog(toReview ? "chat" : undefined);
|
|
428
428
|
return undefined;
|
|
429
429
|
};
|
|
430
|
-
return (_jsx(ChosenSet.Provider, { value: settings.set, children: _jsxs(PointSquare.Provider, { value: pointSquare, children: [panel, _jsx(ProfileDialog, { open: dialog === "profile", profile: profile, onClose: () => setDialog(undefined), text: text }), _jsx(ProfilesDialog, { open: dialog === "profiles", profiles: served.profiles, active: profile, locked: going ? text.profile.whilePlaying : undefined, dataFolder: served.dataFolder, onEdit: () => setDialog("profile"), onClose: () => setDialog(undefined), text: text }), table === undefined ? null : _jsx(ChatDialog, { open: dialog === "chat", review: chatToReview, table: table, settings: settings, onChange: change, name: name, onClose: closeChat, text: text }), _jsx(NewGameDialog, { open: dialog === "new-game", choice: choice, going: going, onStart: startNewGame, onClose: () => setDialog(undefined), text: text }), guide, _jsx(StudyDialog, { open: dialog === "study", onStudy: studyGame, onClose: () => setDialog(undefined), onProfile: () => setDialog("profile"), you: profile.name, accounts: profile.accounts, ai: name, text: text }), served.update === undefined || served.table === undefined
|
|
430
|
+
return (_jsx(ChosenSet.Provider, { value: settings.set, children: _jsxs(PointSquare.Provider, { value: pointSquare, children: [panel, _jsx(ProfileDialog, { open: dialog === "profile", profile: profile, onClose: () => setDialog(undefined), text: text }), _jsx(ProfilesDialog, { open: dialog === "profiles", profiles: served.profiles, active: profile, locked: going ? text.profile.whilePlaying : undefined, dataFolder: served.dataFolder, onEdit: () => setDialog("profile"), onClose: () => setDialog(undefined), text: text }), table === undefined ? null : _jsx(ChatDialog, { open: dialog === "chat", review: chatToReview, table: table, settings: settings, onChange: change, name: name, onClose: closeChat, text: text }), _jsx(NewGameDialog, { open: dialog === "new-game", choice: choice, going: going, onStart: startNewGame, onClose: () => setDialog(undefined), text: text }), guide, _jsx(StudyDialog, { open: dialog === "study", onStudy: studyGame, onClose: () => setDialog(undefined), onProfile: () => setDialog("profile"), you: profile.name, accounts: profile.accounts, others: othersOf(served.profiles, profile.id), ai: name, text: text }), served.update === undefined || served.table === undefined
|
|
431
431
|
? null
|
|
432
432
|
: (_jsx(UpdateDialog, { open: dialog === "update", version: served.update.version, current: served.version, installing: served.update.installing === true, installed: served.update.installed === true, going: going, chat: served.table.chat ? (served.table.held ? "held" : "byHand") : undefined, name: name, onClose: () => setDialog(undefined), text: text })), offline ? _jsx("p", { class: "offline", role: "alert", children: text.offline(name) }) : null, served.outdated === true
|
|
433
433
|
? _jsx("p", { class: "outdated", role: "status", children: text.outdated(name) })
|
|
@@ -435,7 +435,7 @@ export function App({ start }) {
|
|
|
435
435
|
? _jsx(UpdateNotice, { version: served.update.version, name: name, text: text })
|
|
436
436
|
: null, _jsxs("main", { class: `app${flipped ? " flipped" : ""}${folds.talk === "open" ? "" : ` talk-${folds.talk}`}${folds.game === "folded" ? " folded" : ""}`, inert: offline, children: [header, sides === undefined
|
|
437
437
|
? (_jsx(TalkFaces, { name: name, aiPicture: thinker(40), you: profile.name, picture: picture, ...(idle ? {} : { ai, player }), aiMoves: going && !playerToMove, playerMoves: playerToMove, unread: unread || asleep, text: text }))
|
|
438
|
-
: (_jsx(TalkFaces, { name: sides[ai].name, aiPicture: pictureOf(sides[ai], profile, 40, mood), you: sides[player].name, picture: pictureOf(sides[player], profile, 40, mood), ai: ai, player: player, aiMoves: false, playerMoves: false, unread: asleep, text: text })), _jsx(FoldTab, { column: "talk", folded: folds.talk === "folded", label: thinking === undefined || folds.talk !== "folded" ? text.talk : `${text.talk}: ${text.thinking[thinking]}`, unread: (unread || asleep) && folds.talk === "folded", ...(thinking === undefined || folds.talk !== "folded" ? {} : { mark: _jsx(Thought, { thinking: thinking, words: text.thinking }) }), onFold: fold }), _jsx(FoldTab, { column: "game", folded: folds.game === "folded", label: text.game, onFold: fold }), _jsx("span", { class: "visually-hidden", "aria-live": "polite", children: unread ? text.wrote(name) : "" }), _jsx("div", { class: sides === undefined ? "talk" : "talk studied", id: "talk", children: sides !== undefined && studied !== undefined
|
|
438
|
+
: (_jsx(TalkFaces, { name: sides[ai].name, aiPicture: pictureOf(sides[ai], profile, served.profiles, 40, mood), you: sides[player].name, picture: pictureOf(sides[player], profile, served.profiles, 40, mood), ai: ai, player: player, aiMoves: false, playerMoves: false, unread: asleep, text: text })), _jsx(FoldTab, { column: "talk", folded: folds.talk === "folded", label: thinking === undefined || folds.talk !== "folded" ? text.talk : `${text.talk}: ${text.thinking[thinking]}`, unread: (unread || asleep) && folds.talk === "folded", ...(thinking === undefined || folds.talk !== "folded" ? {} : { mark: _jsx(Thought, { thinking: thinking, words: text.thinking }) }), onFold: fold }), _jsx(FoldTab, { column: "game", folded: folds.game === "folded", label: text.game, onFold: fold }), _jsx("span", { class: "visually-hidden", "aria-live": "polite", children: unread ? text.wrote(name) : "" }), _jsx("div", { class: sides === undefined ? "talk" : "talk studied", id: "talk", children: sides !== undefined && studied !== undefined
|
|
439
439
|
? (_jsxs(_Fragment, { children: [_jsxs("section", { class: "ai-block", "aria-label": sides[ai].name, children: [studiedCard(ai, "ai"), asleepNote, _jsx(AiNote, { ...(reviewed === undefined ? {} : { ply: reviewed }), ...(shownOpening === undefined ? {} : { opening: shownOpening }), ...(at === total && closing !== undefined ? { closing } : {}), ...(at === 0 && summary !== undefined ? { summary } : {}), ...(reviewing ? { reviewing: true } : {}), ...(completeIt === undefined ? {} : { onComplete: completeIt }), name: analyst, by: annotator, mood: mood, ...(settings.voice ? { voice: text } : {}), text: text })] }), _jsxs("section", { class: "you-block", "aria-label": sides[player].name, children: [_jsx("div", { class: "chat", children: _jsx(Compose, { lines: analysisTalk(talk, studied.name), newestFirst: false, spent: 0, draft: draft, onDraft: (words) => {
|
|
440
440
|
setDraft(words);
|
|
441
441
|
setUnsent(undefined);
|
|
@@ -460,9 +460,10 @@ export function App({ start }) {
|
|
|
460
460
|
},
|
|
461
461
|
}), shownPlies: at, onShow: goTo, onStep: step, ...(studied === undefined ? {} : { onDownload: () => download(studied.pgn, pgnName(live.record.tags, "analysis")) }), ...(total === 0 ? {} : { onSaveMoves: () => download(writePgn(movesOnly(live.record)), pgnName(live.record.tags)) }), ...(between && game !== null && replayed.record.moves.length > 0 ? { onAnalyse: () => void studyGame({ last: true }) } : {}), text: text }), _jsx(PageFoot, { version: served.version, text: text })] })] }) }));
|
|
462
462
|
}
|
|
463
|
-
/** The picture of a player of the game in analysis: the player's own, the AI's Torretta with its mood, or the plain face of someone else. */
|
|
464
|
-
function pictureOf({ who }, profile, size, mood) {
|
|
465
|
-
|
|
463
|
+
/** The picture of a player of the game in analysis: the player's own, the AI's Torretta with its mood, another profile's, or the plain face of someone else. */
|
|
464
|
+
function pictureOf({ who, profile: other }, profile, profiles, size, mood) {
|
|
465
|
+
const shown = who === "player" ? profile : profiles.find(({ id }) => id === other);
|
|
466
|
+
return who === "ai" ? _jsx(Torretta, { size: size, mood: mood, bust: true }) : _jsx(PlayerPicture, { profile: shown, size: size });
|
|
466
467
|
}
|
|
467
468
|
/**
|
|
468
469
|
* Plays the sound of each move the game gains while the page watches it, the AI's and the player's, of its end without a move and of a draw offered:
|
|
@@ -9,7 +9,7 @@ import { OutcomeBadge, outcomeOf } from "./outcome.js";
|
|
|
9
9
|
import { searched } from "./search.js";
|
|
10
10
|
import { playerIn, studiedSides } from "./studied.js";
|
|
11
11
|
/** The list, read anew at each opening: the search, the row that loads a game, then a row for each game found, with its menu or its question. */
|
|
12
|
-
export function Analyses({ onStudy, onLoad, you, accounts, ai, text }) {
|
|
12
|
+
export function Analyses({ onStudy, onLoad, you, accounts, others, ai, text }) {
|
|
13
13
|
const words = text.study;
|
|
14
14
|
const [analyses, reload] = useAnalyses();
|
|
15
15
|
const [query, setQuery] = useState("");
|
|
@@ -37,7 +37,7 @@ export function Analyses({ onStudy, onLoad, you, accounts, ai, text }) {
|
|
|
37
37
|
});
|
|
38
38
|
};
|
|
39
39
|
const rows = analyses.map((item) => {
|
|
40
|
-
const named = namedSides(item, you, accounts, ai, text);
|
|
40
|
+
const named = namedSides(item, you, accounts, others, ai, text);
|
|
41
41
|
// How it went only for the player's own games: played here, or loaded and named by their name on the site (D-93).
|
|
42
42
|
const played = item.name.startsWith("games/") ? named.you : accountSide(tagsOf(item), accounts);
|
|
43
43
|
const outcome = played === undefined ? undefined : outcomeOf(item.result, played);
|
|
@@ -98,9 +98,9 @@ function placeUnder(menu, anchor) {
|
|
|
98
98
|
menu.style.left = `${Math.max(edge, button.right - box.width)}px`;
|
|
99
99
|
}
|
|
100
100
|
/** Who played a game listed, as its analysis names them, «Stefano – Opus 5.5 · xhigh», and the player's side when they played one. */
|
|
101
|
-
function namedSides(item, you, accounts, ai, text) {
|
|
101
|
+
function namedSides(item, you, accounts, others, ai, text) {
|
|
102
102
|
const model = item.aiModel === undefined ? ai : signature(item.aiModel.model, item.aiModel.effort);
|
|
103
|
-
const sides = studiedSides(tagsOf(item), you, model, text.sides, accounts);
|
|
103
|
+
const sides = studiedSides(tagsOf(item), you, model, text.sides, accounts, others);
|
|
104
104
|
const side = playerIn(sides);
|
|
105
105
|
return { sides: `${sides.white.name} – ${sides.black.name}`, ...(side === undefined ? {} : { you: side }) };
|
|
106
106
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// The players of a game in analysis (D-69), as the page shows them: a game played here names them Player and AI, one played elsewhere by their names; the
|
|
2
|
-
// player's own, by their names on Lichess and chess.com (D-93).
|
|
2
|
+
// player's own, and another profile's, by their names on Lichess and chess.com (D-93), shown with the profile's name.
|
|
3
3
|
import { accountSide } from "../../core/index.js";
|
|
4
|
+
/** The profiles here other than the one in use. */
|
|
5
|
+
export function othersOf(profiles, inUse) {
|
|
6
|
+
return (profiles ?? []).filter(({ id }) => id !== inUse);
|
|
7
|
+
}
|
|
4
8
|
/** The player's side in a game in analysis: none when they played neither side, or both. */
|
|
5
9
|
export function playerIn(sides) {
|
|
6
10
|
const white = sides.white.who === "player";
|
|
@@ -8,16 +12,17 @@ export function playerIn(sides) {
|
|
|
8
12
|
}
|
|
9
13
|
/**
|
|
10
14
|
* Both sides of a game in analysis, and the one at the bottom: the player's, when one of them is, else White. The player is the side named Player, or by
|
|
11
|
-
* their name, or by their name on the site the game was played on (D-93).
|
|
15
|
+
* their name, or by their name on the site the game was played on (D-93); a side that is not theirs and bears another profile's name there is that profile.
|
|
12
16
|
*/
|
|
13
|
-
export function studiedSides(tags, you, ai, sides, accounts) {
|
|
17
|
+
export function studiedSides(tags, you, ai, sides, accounts, others = []) {
|
|
14
18
|
const sideOf = (side) => {
|
|
15
19
|
const tag = (side === "white" ? tags.White : tags.Black)?.trim() ?? "";
|
|
16
|
-
if (tag === "Player" || tag.toLowerCase() === you.trim().toLowerCase()) {
|
|
20
|
+
if (tag === "Player" || tag.toLowerCase() === you.trim().toLowerCase() || accountSide(tags, accounts) === side) {
|
|
17
21
|
return { name: you, who: "player" };
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
const other = others.find((profile) => accountSide(tags, profile.accounts) === side);
|
|
24
|
+
if (other !== undefined) {
|
|
25
|
+
return { name: other.name, who: "other", profile: other.id };
|
|
21
26
|
}
|
|
22
27
|
// A tag PGN leaves unknown names the side.
|
|
23
28
|
return tag === "AI" ? { name: ai, who: "ai" } : { name: /^[?\-\s]*$/.test(tag) ? sides[side] : tag, who: "other" };
|
|
@@ -9,7 +9,7 @@ import { SiteGameList } from "./site-games.js";
|
|
|
9
9
|
* The dialog the header's button opens; `onStudy` sends the choice and gives back why the server refused it, or undefined once it took it. The games played
|
|
10
10
|
* here name their sides as their analysis does: the player by `you`, the AI by its model when the game keeps it (D-82), else by `ai`.
|
|
11
11
|
*/
|
|
12
|
-
export function StudyDialog({ open, onStudy, onClose, onProfile, you, accounts, ai, text }) {
|
|
12
|
+
export function StudyDialog({ open, onStudy, onClose, onProfile, you, accounts, others, ai, text }) {
|
|
13
13
|
const [loading, setLoading] = useState(false);
|
|
14
14
|
// Each opening starts from the list.
|
|
15
15
|
useEffect(() => {
|
|
@@ -17,7 +17,7 @@ export function StudyDialog({ open, onStudy, onClose, onProfile, you, accounts,
|
|
|
17
17
|
setLoading(false);
|
|
18
18
|
}
|
|
19
19
|
}, [open]);
|
|
20
|
-
return (_jsx(Dialog, { open: open, title: loading ? text.study.bring : text.study.title, onBack: loading ? () => setLoading(false) : undefined, onClose: onClose, text: text, children: loading ? _jsx(LoadForm, { onStudy: onStudy, onProfile: onProfile, accounts: accounts, text: text }) : _jsx(Analyses, { onStudy: onStudy, onLoad: () => setLoading(true), you: you, accounts: accounts, ai: ai, text: text }) }));
|
|
20
|
+
return (_jsx(Dialog, { open: open, title: loading ? text.study.bring : text.study.title, onBack: loading ? () => setLoading(false) : undefined, onClose: onClose, text: text, children: loading ? _jsx(LoadForm, { onStudy: onStudy, onProfile: onProfile, accounts: accounts, text: text }) : _jsx(Analyses, { onStudy: onStudy, onLoad: () => setLoading(true), you: you, accounts: accounts, others: others, ai: ai, text: text }) }));
|
|
21
21
|
}
|
|
22
22
|
/** The step that loads a game played elsewhere: one of the latest on the sites, or its PGN pasted, or read from a file. */
|
|
23
23
|
function LoadForm({ onStudy, onProfile, accounts, text }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chesspal",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Play chess against an AI with a character, and learn with an AI coach: Chesspal keeps the rules, the board, the games and the memory; the AI plays, reasons and talks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|