@connectorvol/chess-widgets 9.0.0 → 9.0.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/dist/(components)/BoardSettingsTrigger.svelte +10 -0
- package/dist/(components)/BoardSettingsTrigger.svelte.d.ts +18 -0
- package/dist/game-analyzer/GameAnalyzer.svelte +88 -74
- package/dist/game-analyzer/gameAnalyzer.svelte.js +2 -7
- package/dist/game-analyzer/types.d.ts +3 -6
- package/dist/index.d.ts +1 -1
- package/dist/puzzle/puzzlePreviewPathNags.js +1 -1
- package/dist/puzzle-creation/PuzzleBoardTreeViewerPane.svelte +199 -171
- package/dist/puzzle-creation/PuzzleBoardTreeViewerPane.svelte.d.ts +7 -3
- package/dist/puzzle-creation/PuzzleCreationWizard.svelte +184 -180
- package/dist/puzzle-creation/PuzzlePgnBoardTreeEditor.svelte +906 -870
- package/dist/puzzle-creation/StepMoves.svelte +209 -207
- package/dist/puzzle-creation/StepMoves.svelte.d.ts +1 -2
- package/dist/puzzle-creation/StepPosition.svelte +22 -2
- package/dist/puzzle-creation/puzzleWizardState.js +1 -1
- package/dist/puzzle-creation/types.d.ts +0 -4
- package/package.json +12 -10
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { BoardSettings } from "@connectorvol/chessboard";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<!--
|
|
6
|
+
`BoardSettings` без `bind:design` читает/пишет стор дизайна из контекста
|
|
7
|
+
(см. `+layout.svelte` → `setBoardDesignSettingsContext`). Все доски ниже по дереву
|
|
8
|
+
подписаны на тот же стор и реактивно подхватывают изменения.
|
|
9
|
+
-->
|
|
10
|
+
<BoardSettings />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const BoardSettingsTrigger: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type BoardSettingsTrigger = InstanceType<typeof BoardSettingsTrigger>;
|
|
18
|
+
export default BoardSettingsTrigger;
|
|
@@ -1,87 +1,101 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import type { TGameAnalyzerProps } from "./types.js";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
import {
|
|
5
|
+
Chessboard,
|
|
6
|
+
DEFAULT_DESIGN_SETTINGS,
|
|
7
|
+
getBoardDesignSettingsContext,
|
|
8
|
+
} from "@connectorvol/chessboard";
|
|
9
|
+
import {
|
|
10
|
+
TREE_VIEWER_DARK_THEME,
|
|
11
|
+
TREE_VIEWER_LIGHT_THEME,
|
|
12
|
+
TreeViewer,
|
|
13
|
+
TreeViewerPanelManager,
|
|
14
|
+
type TTreeViewerTheme,
|
|
15
|
+
} from "@connectorvol/tree";
|
|
16
|
+
import { Game } from "./gameAnalyzer.svelte.js";
|
|
17
|
+
import { untrack } from "svelte";
|
|
18
|
+
import { mode } from "mode-watcher";
|
|
19
|
+
import { DEFAULT_BOARD_APPEARANCE_SETTINGS } from "../constants/default-board-appearance-settings.js";
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}: TGameAnalyzerProps = $props();
|
|
21
|
+
let {
|
|
22
|
+
pgn,
|
|
23
|
+
onChangePGN,
|
|
24
|
+
boardAppearanceSettings = DEFAULT_BOARD_APPEARANCE_SETTINGS,
|
|
25
|
+
editMode = true,
|
|
26
|
+
treeViewerTheme,
|
|
27
|
+
class: className,
|
|
28
|
+
}: TGameAnalyzerProps = $props();
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// ponytail: автотема по mode-watcher, как в chess-tree/src/routes/game/+page.svelte.
|
|
31
|
+
// Явный проп `treeViewerTheme` побеждает авто-детект.
|
|
32
|
+
const resolvedTreeViewerTheme = $derived<TTreeViewerTheme>(
|
|
33
|
+
treeViewerTheme ??
|
|
34
|
+
(mode.current === "dark"
|
|
35
|
+
? TREE_VIEWER_DARK_THEME
|
|
36
|
+
: TREE_VIEWER_LIGHT_THEME),
|
|
37
|
+
);
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
let game = $derived(
|
|
40
|
+
new Game(
|
|
41
|
+
untrack(() => pgn),
|
|
42
|
+
boardAppearanceSettings?.play ?? {},
|
|
43
|
+
"chess",
|
|
44
|
+
),
|
|
45
|
+
);
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
let boardSize = $derived(
|
|
48
|
+
game.chessboard.getBoard().settingsService.boardSize,
|
|
49
|
+
);
|
|
50
|
+
let isAutoSize = $derived(boardSize === "auto");
|
|
51
|
+
|
|
52
|
+
function handleChangeDirty(_setIsDirty: (value: boolean) => void) {
|
|
53
|
+
console.log("handleChangeDirty");
|
|
54
|
+
const exported = game.exportPgn();
|
|
55
|
+
onChangePGN?.(exported);
|
|
56
|
+
}
|
|
43
57
|
</script>
|
|
44
58
|
|
|
45
59
|
<div class={["mx-4 lg:container lg:mx-auto gap-4", className]}>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
<div class="flex justify-center relative lg:gap-4 flex-col lg:flex-row">
|
|
61
|
+
<div
|
|
62
|
+
class={[
|
|
63
|
+
"w-full",
|
|
64
|
+
isAutoSize ? "lg:w-2/5" : "lg:w-auto lg:min-w-[3.75rem]",
|
|
65
|
+
]}
|
|
66
|
+
style={!isAutoSize && typeof boardSize === "number"
|
|
67
|
+
? `flex-basis: ${boardSize}rem;`
|
|
68
|
+
: ""}
|
|
69
|
+
>
|
|
70
|
+
<Chessboard facade={game.chessboard} />
|
|
71
|
+
</div>
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
<div
|
|
74
|
+
class={[
|
|
75
|
+
"w-full flex lg:flex-col flex-col-reverse h-full",
|
|
76
|
+
isAutoSize ? "lg:w-3/5" : "lg:flex-1 lg:min-w-[20rem]",
|
|
77
|
+
]}
|
|
78
|
+
>
|
|
79
|
+
<div class="h-full">
|
|
80
|
+
<TreeViewer
|
|
81
|
+
className="h-[calc(100dvh-8rem)] bg-[var(--tree-viewer-bg)]"
|
|
82
|
+
chessTree={game.chessTree}
|
|
83
|
+
onSelectNode={game.onSelectNode}
|
|
84
|
+
onDeleteVariant={game.onDeleteVariant}
|
|
85
|
+
setChessFen={game.setChessFen}
|
|
86
|
+
setChessboardFen={game.setChessboardFen}
|
|
87
|
+
{editMode}
|
|
88
|
+
theme={resolvedTreeViewerTheme}
|
|
89
|
+
onChangeDirty={handleChangeDirty}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
<TreeViewerPanelManager
|
|
94
|
+
className="flex w-full justify-center select-none col-span-1 my-4"
|
|
95
|
+
chessTree={game.chessTree}
|
|
96
|
+
setChessFen={game.setChessFen}
|
|
97
|
+
setChessboardFen={game.setChessboardFen}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
85
100
|
</div>
|
|
86
|
-
</div>
|
|
87
101
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Color, calculatePly, generateId } from "@connectorvol/shared";
|
|
2
|
-
import {
|
|
2
|
+
import { createBoardApi, DEFAULT_PLAY_SETTINGS, Draggable, syncMoveEvaluationNagBadge, } from "@connectorvol/chessboard";
|
|
3
3
|
import { PgnOps } from "@connectorvol/chessops/pgnOps.svelte";
|
|
4
4
|
import { transformPgnToChessNode, createPgnFromTree } from "@connectorvol/tree";
|
|
5
5
|
import { ChessTree } from "@connectorvol/tree";
|
|
@@ -11,14 +11,9 @@ export class Game {
|
|
|
11
11
|
previousNode;
|
|
12
12
|
playSettings;
|
|
13
13
|
variant;
|
|
14
|
-
|
|
15
|
-
/** Возвращает активную тему доски, реактивный `$state` для биндинга в UI. */
|
|
16
|
-
theme = $state(CHESSBOARD_THEMES.blue);
|
|
17
|
-
constructor(pgn, chessBoardSettings, variant = "chess", boardTheme) {
|
|
14
|
+
constructor(pgn, chessBoardSettings, variant = "chess") {
|
|
18
15
|
this.playSettings = { ...DEFAULT_PLAY_SETTINGS, ...chessBoardSettings };
|
|
19
16
|
this.variant = variant;
|
|
20
|
-
this.boardTheme = boardTheme ?? CHESSBOARD_THEMES.blue;
|
|
21
|
-
this.theme = this.boardTheme;
|
|
22
17
|
const { rootNode, initialFen: position } = transformPgnToChessNode(pgn);
|
|
23
18
|
this.chessTree = new ChessTree(rootNode);
|
|
24
19
|
this.chess = new PgnOps(position, variant);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ChessboardTheme } from "@connectorvol/chessboard";
|
|
2
1
|
import type { TChessBoardDesignSettings, TChessBoardPlaySettings } from "@connectorvol/chessboard";
|
|
3
2
|
import type { TTreeViewerTheme } from "@connectorvol/tree";
|
|
4
3
|
/**
|
|
@@ -20,10 +19,6 @@ export interface TGameAnalyzerProps {
|
|
|
20
19
|
* Возвращает колбэк при изменении дерева ходов (добавление/удаление ходов, комментариев, маркеров).
|
|
21
20
|
*/
|
|
22
21
|
onChangePGN?: (pgn: string) => void;
|
|
23
|
-
/**
|
|
24
|
-
* Возвращает тему оформления шахматной доски (по умолчанию синяя).
|
|
25
|
-
*/
|
|
26
|
-
boardTheme?: ChessboardTheme;
|
|
27
22
|
/**
|
|
28
23
|
* Возвращает дополнительные визуальные настройки шахматной доски (кроме `boardSize`, `orientation`, `draggable`).
|
|
29
24
|
*/
|
|
@@ -33,7 +28,9 @@ export interface TGameAnalyzerProps {
|
|
|
33
28
|
*/
|
|
34
29
|
editMode?: boolean;
|
|
35
30
|
/**
|
|
36
|
-
* Возвращает тему `TreeViewer` (фон, границы, текст). По умолчанию
|
|
31
|
+
* Возвращает тему `TreeViewer` (фон, границы, текст). По умолчанию
|
|
32
|
+
* подстраивается под `mode-watcher` (dark → `TREE_VIEWER_DARK_THEME`,
|
|
33
|
+
* иначе `TREE_VIEWER_LIGHT_THEME`).
|
|
37
34
|
*/
|
|
38
35
|
treeViewerTheme?: TTreeViewerTheme;
|
|
39
36
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { default as PuzzlePgnBoardTreeEditor } from "./puzzle-creation/PuzzlePgn
|
|
|
4
4
|
export type { TPuzzleCreationWizardProps, TPuzzlePgnBoardTreeEditorOutcome, TPuzzlePgnBoardTreeEditorProps, } from "./puzzle-creation/types.js";
|
|
5
5
|
export type { TPuzzleWizardCoreState, TPuzzleWizardState, } from "./puzzle-creation/puzzleWizardState.js";
|
|
6
6
|
export { PUZZLE_WIZARD_CORE_STEPS, PUZZLE_WIZARD_TAGS_STEP, createInitialPuzzleWizardCoreState, createInitialPuzzleWizardState, puzzleWizardSeedFen, } from "./puzzle-creation/puzzleWizardState.js";
|
|
7
|
-
export type { TWizardStep, TWizardStepContext
|
|
7
|
+
export type { TWizardStep, TWizardStepContext } from "@connectorvol/shared";
|
|
8
8
|
export { Wizard, getWizardContext, setWizardContext } from "@connectorvol/shared";
|
|
9
9
|
export type { TPuzzleCreatedPayload, TPuzzleTags } from "./puzzle/puzzleCreatedPayload.js";
|
|
10
10
|
export { puzzlePartsFromFullPgn } from "./puzzle/puzzleCreatedPayload.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_WRONG_NAG_ID
|
|
1
|
+
import { PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_WRONG_NAG_ID } from "@connectorvol/shared";
|
|
2
2
|
import { puzzlePreviewSideToMoveFromFen } from "./puzzleStepPreviewSolver.js";
|
|
3
3
|
/**
|
|
4
4
|
* Представляет синхронизацию NAG ✓ ходов решателя в дереве решения по пройденному пути превью.
|
|
@@ -1,184 +1,212 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Возвращает снимок дизайна, передаваемый в `<Chessboard design={...} />`.
|
|
25
|
-
*/
|
|
26
|
-
chessboardDesign: TChessBoardDesignSettings;
|
|
27
|
-
/**
|
|
28
|
-
* Возвращает экземпляр дерева ходов для `TreeViewer`.
|
|
29
|
-
*/
|
|
30
|
-
chessTree: ChessTree;
|
|
31
|
-
/**
|
|
32
|
-
* Возвращает обработчик выбора узла в дереве.
|
|
33
|
-
*/
|
|
34
|
-
onSelectNode: () => void;
|
|
35
|
-
/**
|
|
36
|
-
* Возвращает обработчик после удаления варианта.
|
|
37
|
-
*/
|
|
38
|
-
onDeleteVariant: () => void;
|
|
39
|
-
/**
|
|
40
|
-
* Возвращает функцию установки FEN в движке партии.
|
|
41
|
-
*/
|
|
42
|
-
setChessFen: (fen: string) => void;
|
|
43
|
-
/**
|
|
44
|
-
* Возвращает функцию синхронизации FEN и UI доски.
|
|
45
|
-
*/
|
|
46
|
-
setChessboardFen: (animationTime?: number) => void;
|
|
47
|
-
/**
|
|
48
|
-
* Возвращает признак режима правки дерева (`TreeViewer.editMode`).
|
|
49
|
-
*/
|
|
50
|
-
editMode?: boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Возвращает признак возможности выбора узлов в дереве.
|
|
53
|
-
*/
|
|
54
|
-
selectable?: boolean;
|
|
55
|
-
/**
|
|
56
|
-
* Возвращает true, если в режиме правки показывать группу NAG «Задача (развилка)»
|
|
57
|
-
* рядом с кнопками undo/redo на ходах из развилки.
|
|
58
|
-
*/
|
|
59
|
-
showPuzzleBranchNags?: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Возвращает тему `TreeViewer` (фон, границы, текст). Если не задана —
|
|
62
|
-
* используется `TREE_VIEWER_LIGHT_THEME`.
|
|
63
|
-
*/
|
|
64
|
-
theme?: TTreeViewerTheme;
|
|
65
|
-
/**
|
|
66
|
-
* Возвращает дополнительные классы Tailwind для корневого контейнера.
|
|
67
|
-
*/
|
|
68
|
-
class?: string;
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import { MediaQuery } from "svelte/reactivity";
|
|
4
|
+
import { mode } from "mode-watcher";
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
BoardApi,
|
|
8
|
+
TChessBoardDesignSettings,
|
|
9
|
+
} from "@connectorvol/chessboard";
|
|
10
|
+
import {
|
|
11
|
+
Chessboard,
|
|
12
|
+
getBoardDesignSettingsContext,
|
|
13
|
+
} from "@connectorvol/chessboard";
|
|
14
|
+
import type { ChessTree, TTreeViewerTheme } from "@connectorvol/tree";
|
|
15
|
+
import {
|
|
16
|
+
TREE_VIEWER_DARK_THEME,
|
|
17
|
+
TREE_VIEWER_LIGHT_THEME,
|
|
18
|
+
TreeViewer,
|
|
19
|
+
} from "@connectorvol/tree";
|
|
20
|
+
|
|
21
|
+
import { cn } from "../utils.js";
|
|
22
|
+
|
|
69
23
|
/**
|
|
70
|
-
*
|
|
24
|
+
* Представляет свойства панели разметки «доска и просмотр дерева партии».
|
|
71
25
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
26
|
+
interface Props {
|
|
27
|
+
/**
|
|
28
|
+
* Возвращает API шахматной доски для компонента `Chessboard`.
|
|
29
|
+
*/
|
|
30
|
+
chessboard: BoardApi;
|
|
31
|
+
/**
|
|
32
|
+
* Возвращает снимок дизайна, передаваемый в `<Chessboard design={...} />`.
|
|
33
|
+
* Опционально: если не передан, доска читает дизайн из контекста
|
|
34
|
+
* (`setBoardDesignSettingsContext`), что позволяет реактивно подхватывать
|
|
35
|
+
* изменения из `<BoardSettings />`.
|
|
36
|
+
*/
|
|
37
|
+
chessboardDesign?: TChessBoardDesignSettings;
|
|
38
|
+
/**
|
|
39
|
+
* Возвращает экземпляр дерева ходов для `TreeViewer`.
|
|
40
|
+
*/
|
|
41
|
+
chessTree: ChessTree;
|
|
42
|
+
/**
|
|
43
|
+
* Возвращает обработчик выбора узла в дереве.
|
|
44
|
+
*/
|
|
45
|
+
onSelectNode: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Возвращает обработчик после удаления варианта.
|
|
48
|
+
*/
|
|
49
|
+
onDeleteVariant: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Возвращает функцию установки FEN в движке партии.
|
|
52
|
+
*/
|
|
53
|
+
setChessFen: (fen: string) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Возвращает функцию синхронизации FEN и UI доски.
|
|
56
|
+
*/
|
|
57
|
+
setChessboardFen: (animationTime?: number) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Возвращает признак режима правки дерева (`TreeViewer.editMode`).
|
|
60
|
+
*/
|
|
61
|
+
editMode?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Возвращает признак возможности выбора узлов в дереве.
|
|
64
|
+
*/
|
|
65
|
+
selectable?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Возвращает true, если в режиме правки показывать группу NAG «Задача (развилка)»
|
|
68
|
+
* рядом с кнопками undo/redo на ходах из развилки.
|
|
69
|
+
*/
|
|
70
|
+
showPuzzleBranchNags?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Возвращает тему `TreeViewer` (фон, границы, текст). По умолчанию
|
|
73
|
+
* подстраивается под `mode-watcher` (dark → `TREE_VIEWER_DARK_THEME`,
|
|
74
|
+
* иначе `TREE_VIEWER_LIGHT_THEME`).
|
|
75
|
+
*/
|
|
76
|
+
theme?: TTreeViewerTheme;
|
|
77
|
+
/**
|
|
78
|
+
* Возвращает дополнительные классы Tailwind для корневого контейнера.
|
|
79
|
+
*/
|
|
80
|
+
class?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Возвращает фрагмент разметки под шахматной доской (например сообщение об ошибке в превью).
|
|
83
|
+
*/
|
|
84
|
+
belowChessboard?: Snippet;
|
|
125
85
|
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
let boardHeight = $state(0);
|
|
129
86
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
87
|
+
const {
|
|
88
|
+
chessboard,
|
|
89
|
+
chessboardDesign,
|
|
90
|
+
chessTree,
|
|
91
|
+
onSelectNode,
|
|
92
|
+
onDeleteVariant,
|
|
93
|
+
setChessFen,
|
|
94
|
+
setChessboardFen,
|
|
95
|
+
editMode = true,
|
|
96
|
+
selectable = true,
|
|
97
|
+
showPuzzleBranchNags = false,
|
|
98
|
+
theme,
|
|
99
|
+
class: className,
|
|
100
|
+
belowChessboard,
|
|
101
|
+
}: Props = $props();
|
|
102
|
+
|
|
103
|
+
// ponytail: автотема по mode-watcher вместо жёсткого светлого дефолта,
|
|
104
|
+
// как в chess-tree/src/routes/game/+page.svelte. Явный проп `theme` побеждает.
|
|
105
|
+
const resolvedTheme = $derived<TTreeViewerTheme>(
|
|
106
|
+
theme ??
|
|
107
|
+
(mode.current === "dark"
|
|
108
|
+
? TREE_VIEWER_DARK_THEME
|
|
109
|
+
: TREE_VIEWER_LIGHT_THEME),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
/** ponytail: совпадает с Tailwind `lg` (1024px), как в разметке панели. */
|
|
113
|
+
const isMobile = new MediaQuery("(max-width: 1023px)");
|
|
114
|
+
|
|
115
|
+
const boardSize = $derived(chessboard.getBoard().settingsService.boardSize);
|
|
116
|
+
const useAutoBoardLayout = $derived(
|
|
117
|
+
isMobile.current || boardSize === "auto",
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const boardColumnStyle = $derived(
|
|
121
|
+
!useAutoBoardLayout && typeof boardSize === "number"
|
|
122
|
+
? `flex: 0 0 min(100%, ${boardSize}rem);`
|
|
123
|
+
: undefined,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
let savedDesktopBoardSettings = $state<{
|
|
127
|
+
boardSize: number | "auto";
|
|
128
|
+
isResizable: boolean;
|
|
129
|
+
} | null>(null);
|
|
130
|
+
|
|
131
|
+
$effect(() => {
|
|
132
|
+
const mobile = isMobile.current;
|
|
133
|
+
const settings = chessboard.getBoard().settingsService;
|
|
134
|
+
|
|
135
|
+
if (mobile) {
|
|
136
|
+
if (savedDesktopBoardSettings === null) {
|
|
137
|
+
savedDesktopBoardSettings = {
|
|
138
|
+
boardSize: settings.boardSize,
|
|
139
|
+
isResizable: chessboard.isResizable,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
chessboard.isResizable = false;
|
|
143
|
+
settings.boardSize = "auto";
|
|
144
|
+
} else if (savedDesktopBoardSettings !== null) {
|
|
145
|
+
chessboard.isResizable = savedDesktopBoardSettings.isResizable;
|
|
146
|
+
settings.boardSize = savedDesktopBoardSettings.boardSize;
|
|
147
|
+
savedDesktopBoardSettings = null;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
let boardHeight = $state(0);
|
|
152
|
+
|
|
153
|
+
const treeHeightLocked = $derived(boardHeight > 0);
|
|
154
|
+
|
|
155
|
+
const treeColumnStyle = $derived(
|
|
156
|
+
treeHeightLocked ? `--pane-board-height: ${boardHeight}px` : undefined,
|
|
157
|
+
);
|
|
135
158
|
</script>
|
|
136
159
|
|
|
137
160
|
<div class={cn("flex w-full flex-col gap-2", className)}>
|
|
138
|
-
<div
|
|
139
|
-
class="relative flex min-h-0 flex-col gap-4 lg:flex-row lg:items-stretch"
|
|
140
|
-
>
|
|
141
|
-
<div
|
|
142
|
-
class={cn(
|
|
143
|
-
"order-1 flex w-full shrink-0 flex-col lg:order-1 lg:min-h-0",
|
|
144
|
-
useAutoBoardLayout && "lg:max-w-[min(100%,38rem)]",
|
|
145
|
-
)}
|
|
146
|
-
style={boardColumnStyle}
|
|
147
|
-
>
|
|
148
|
-
<div
|
|
149
|
-
class="aspect-square w-full shrink-0"
|
|
150
|
-
bind:clientHeight={boardHeight}
|
|
151
|
-
>
|
|
152
|
-
<Chessboard facade={chessboard} design={chessboardDesign} />
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
161
|
<div
|
|
157
|
-
|
|
158
|
-
"order-2 flex min-h-48 min-w-0 flex-1 flex-col lg:order-2 lg:min-w-[20rem] lg:shrink-0",
|
|
159
|
-
treeHeightLocked &&
|
|
160
|
-
"lg:h-[var(--pane-board-height)] lg:max-h-[var(--pane-board-height)] lg:min-h-0 lg:overflow-hidden",
|
|
161
|
-
)}
|
|
162
|
-
style={treeColumnStyle}
|
|
162
|
+
class="relative flex min-h-0 flex-col gap-4 lg:flex-row lg:items-stretch"
|
|
163
163
|
>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
164
|
+
<div
|
|
165
|
+
class={cn(
|
|
166
|
+
"order-1 flex w-full shrink-0 flex-col lg:order-1 lg:min-h-0",
|
|
167
|
+
useAutoBoardLayout && "lg:max-w-[min(100%,38rem)]",
|
|
168
|
+
)}
|
|
169
|
+
style={boardColumnStyle}
|
|
170
|
+
>
|
|
171
|
+
<div
|
|
172
|
+
class="aspect-square w-full shrink-0"
|
|
173
|
+
bind:clientHeight={boardHeight}
|
|
174
|
+
>
|
|
175
|
+
<Chessboard
|
|
176
|
+
facade={chessboard}
|
|
177
|
+
design={chessboardDesign ??
|
|
178
|
+
getBoardDesignSettingsContext() ??
|
|
179
|
+
undefined}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<div
|
|
185
|
+
class={cn(
|
|
186
|
+
"order-2 flex min-h-48 min-w-0 flex-1 flex-col lg:order-2 lg:min-w-[20rem] lg:shrink-0",
|
|
187
|
+
treeHeightLocked &&
|
|
188
|
+
"lg:h-[var(--pane-board-height)] lg:max-h-[var(--pane-board-height)] lg:min-h-0 lg:overflow-hidden",
|
|
189
|
+
)}
|
|
190
|
+
style={treeColumnStyle}
|
|
191
|
+
>
|
|
192
|
+
<div
|
|
193
|
+
class="flex min-h-0 flex-1 flex-col overflow-hidden border border-border"
|
|
194
|
+
>
|
|
195
|
+
<TreeViewer
|
|
196
|
+
{chessTree}
|
|
197
|
+
{onSelectNode}
|
|
198
|
+
{onDeleteVariant}
|
|
199
|
+
{setChessFen}
|
|
200
|
+
{setChessboardFen}
|
|
201
|
+
className="min-h-0 flex-1 rounded-none border-0 bg-[var(--tree-viewer-bg)]"
|
|
202
|
+
{editMode}
|
|
203
|
+
{selectable}
|
|
204
|
+
{showPuzzleBranchNags}
|
|
205
|
+
theme={resolvedTheme}
|
|
206
|
+
/>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
180
209
|
</div>
|
|
181
|
-
</div>
|
|
182
210
|
|
|
183
|
-
|
|
211
|
+
{@render belowChessboard?.()}
|
|
184
212
|
</div>
|