@connectorvol/tree 4.1.0 → 4.3.0

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.
Files changed (38) hide show
  1. package/dist/(classes)/chessTree.svelte.d.ts +2 -0
  2. package/dist/(classes)/chessTree.svelte.js +7 -1
  3. package/dist/(components)/Move.svelte +346 -310
  4. package/dist/(components)/MoveWithIcon.svelte +79 -48
  5. package/dist/(components)/NagBadges.svelte +30 -30
  6. package/dist/(components)/TreeViewer.svelte +878 -842
  7. package/dist/(components)/TreeViewerPanelManager.svelte +99 -98
  8. package/dist/(components)/VariantDropdownNavigator.svelte +177 -173
  9. package/dist/(components)/VariantDropdownNavigator.svelte.d.ts +3 -0
  10. package/dist/(utils)/parseSanMove.d.ts +6 -0
  11. package/dist/(utils)/parseSanMove.js +40 -7
  12. package/dist/components/ui/checkbox/checkbox.svelte +39 -0
  13. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +4 -0
  14. package/dist/components/ui/checkbox/index.d.ts +2 -0
  15. package/dist/components/ui/checkbox/index.js +4 -0
  16. package/dist/components/ui/popover/index.d.ts +9 -0
  17. package/dist/components/ui/popover/index.js +11 -0
  18. package/dist/components/ui/popover/popover-close.svelte +7 -0
  19. package/dist/components/ui/popover/popover-close.svelte.d.ts +4 -0
  20. package/dist/components/ui/popover/popover-content.svelte +31 -0
  21. package/dist/components/ui/popover/popover-content.svelte.d.ts +10 -0
  22. package/dist/components/ui/popover/popover-description.svelte +20 -0
  23. package/dist/components/ui/popover/popover-description.svelte.d.ts +5 -0
  24. package/dist/components/ui/popover/popover-header.svelte +20 -0
  25. package/dist/components/ui/popover/popover-header.svelte.d.ts +5 -0
  26. package/dist/components/ui/popover/popover-portal.svelte +7 -0
  27. package/dist/components/ui/popover/popover-portal.svelte.d.ts +3 -0
  28. package/dist/components/ui/popover/popover-title.svelte +20 -0
  29. package/dist/components/ui/popover/popover-title.svelte.d.ts +5 -0
  30. package/dist/components/ui/popover/popover-trigger.svelte +17 -0
  31. package/dist/components/ui/popover/popover-trigger.svelte.d.ts +4 -0
  32. package/dist/components/ui/popover/popover.svelte +7 -0
  33. package/dist/components/ui/popover/popover.svelte.d.ts +3 -0
  34. package/dist/components/ui/toggle/index.d.ts +3 -0
  35. package/dist/components/ui/toggle/index.js +5 -0
  36. package/dist/components/ui/toggle/toggle.svelte +51 -0
  37. package/dist/components/ui/toggle/toggle.svelte.d.ts +43 -0
  38. package/package.json +11 -9
@@ -1,354 +1,390 @@
1
1
  <script lang="ts">
2
- import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
3
-
4
- import { parseComment } from "@connectorvol/chessops/pgn";
5
-
6
- import { createPreviewHover } from "../(utils)/createPreviewHover.js";
7
- import { getGameContext } from "../(utils)/context.js";
8
- import Move from "./Move.svelte";
9
- import MoveComment from "./MoveComment.svelte";
10
- import MoveSanWithMenu from "./MoveSanWithMenu.svelte";
11
- import VariationGroup from "./VariationGroup.svelte";
12
- import type { PieceSet } from "@connectorvol/shared";
13
-
14
- const HIGHEST_LEVEL = 1;
15
-
16
- type TMoveProps = {
17
- /** Возвращает узел хода в дереве партии. */
18
- chessNode: ChessTreeNode;
19
- /** Возвращает глубину вложенности относительно корня отображения. */
20
- depth: number;
21
- /** Возвращает родительский узел или null для корня. */
22
- parentNode: ChessTreeNode | null;
23
- /** Возвращает true, если нужна пустая ячейка хода (сетка верхнего уровня). */
24
- shouldReserveEmptyMoveCell: boolean;
25
- /** Возвращает true, если нужно отрисовать соседние варианты у развилки. */
26
- shouldRenderSiblingVariations?: boolean;
27
- /** Возвращает набор фигур для иконок SAN. */
28
- pieceSet: PieceSet;
29
- };
30
-
31
- const {
32
- chessNode,
33
- depth,
34
- parentNode,
35
- shouldReserveEmptyMoveCell,
36
- shouldRenderSiblingVariations = true,
37
- pieceSet,
38
- }: TMoveProps = $props();
39
-
40
- /** Контекст игры без деструктуризации — иначе selectable и chessTree «замораживаются» при первом рендере TreeViewer. */
41
- const game = getGameContext();
42
-
43
- /** Представляет обработчик выбора текущего узла по `mousedown`. */
44
- function handleMoveMouseDown() {
45
- if (!game.selectable || !moveNode) return;
46
- game.chessTree.currentNode = chessNode;
47
-
48
- game.onSelectNode();
49
- game.onChessNodeSelected?.(game.chessTree.currentNode);
50
- }
51
-
52
- const moveNode = $derived(chessNode);
53
- const previewHover = createPreviewHover({
54
- setPreviewFen: game.setPreviewFen,
55
- getFen: () => moveNode.data.fen,
56
- getLastMove: () => moveNode.data.lastMove ?? null,
57
- getDelayMs: () => game.previewHoverDelayMs,
58
- });
59
- const isCurrentMove = $derived(chessNode.id === game.chessTree.currentNode.id);
60
- /** Представляет текст первого PGN-комментария узла после разбора `comments[0]`, синхронно с правкой строки под деревом. */
61
- const firstCommentParsed = $derived(
62
- moveNode.data.comments?.[0] !== undefined
63
- ? parseComment(moveNode.data.comments[0])
64
- : null,
65
- );
66
- const firstCommentText = $derived(firstCommentParsed?.text);
67
- const childMoves = $derived(chessNode.children);
68
- const isForcedLineStart = $derived(chessNode.id === game.chessTree.forcedNodeId);
69
-
70
- /** Представляет признак активного drill-down «варианты отдельно». */
71
- const variationDrillDownActive = $derived(
72
- game.chessTree.isVariationDrillDownActive(),
73
- );
74
-
75
- /**
76
- * Представляет признак: развилка на этом уровне совпадает с узлом, для которого
77
- * `ChessTree` рассчитывает акцент направляющих при текущем выборе.
78
- */
79
- const isActiveForkForSelection = $derived(
80
- shouldRenderSiblingVariations &&
81
- parentNode !== null &&
82
- (parentNode.children?.length ?? 0) > 1 &&
83
- game.chessTree.currentGuideHighlightForkParent?.id === parentNode.id,
84
- );
85
-
86
- const spaceBlockClass = "px-3 py-2 !bg-gray-50/95";
87
- const spaceInlineBlockClass = "p-2";
88
-
89
- const isHighestLevel = $derived(depth === HIGHEST_LEVEL);
90
-
91
- /**
92
- * Представляет признак: в верхней сетке после белого полухода показывается пустая ячейка чёрных
93
- * без ноды (партия оборвалась на ходе белых) — нижнюю границу рисуем только под двумя первыми колонками.
94
- */
95
- const addsEmptyMainLineBlackCell = $derived(
96
- isHighestLevel &&
97
- moveNode.data.ply % 2 === 1 &&
98
- !isForcedLineStart &&
99
- (parentNode === null || parentNode.children.length <= 1) &&
100
- !firstCommentText &&
101
- (childMoves?.length ?? 0) === 0,
102
- );
103
-
104
- /**
105
- * Представляет признак: верхняя строка — первый полуход чёрных от корня партии (нотация «1... SAN»).
106
- */
107
- const isLeadingBlackHalfMoveFromRoot = $derived(
108
- isHighestLevel &&
109
- parentNode !== null &&
110
- parentNode.data.ply === 0 &&
111
- moveNode.data.ply % 2 === 0,
112
- );
113
-
114
- /** Представляет true, если в контекстном меню показывать «Поднять приоритет». */
115
- const showUpPriorityItem = $derived(depth > HIGHEST_LEVEL + 1);
116
-
117
- /**
118
- * Представляет признак: SAN главного варианта (children[0]) переносится в блок списка веток,
119
- * чтобы не дублировать его перед группой (например «8. g3» только среди g3 / f3 / a3).
120
- */
121
- const shouldRenderSanInsideVariationGroup = $derived(
122
- !isHighestLevel &&
123
- shouldRenderSiblingVariations &&
124
- parentNode !== null &&
125
- parentNode.children.length > 1 &&
126
- parentNode.children[0]?.id === chessNode.id,
127
- );
128
-
129
- /**
130
- * Представляет обработчик клика по зоне линий ветвления, открывающий режим «варианты отдельно».
131
- */
132
- function onVariationLinesHit(e: MouseEvent) {
133
- e.stopPropagation();
134
- if (parentNode === null) return;
135
- const selectFork = !game.chessTree.isCurrentNodeWithinForkSubtree(parentNode);
136
- game.chessTree.openVariationDrillDown(parentNode, { selectFork });
137
- game.onSelectNode();
138
- game.onChessNodeSelected?.(game.chessTree.currentNode);
139
- }
2
+ import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
3
+
4
+ import { parseComment } from "@connectorvol/chessops/pgn";
5
+
6
+ import { createPreviewHover } from "../(utils)/createPreviewHover.js";
7
+ import { getGameContext } from "../(utils)/context.js";
8
+ import Move from "./Move.svelte";
9
+ import MoveComment from "./MoveComment.svelte";
10
+ import MoveSanWithMenu from "./MoveSanWithMenu.svelte";
11
+ import VariationGroup from "./VariationGroup.svelte";
12
+ import type { PieceSet } from "@connectorvol/shared";
13
+
14
+ const HIGHEST_LEVEL = 1;
15
+
16
+ type TMoveProps = {
17
+ /** Возвращает узел хода в дереве партии. */
18
+ chessNode: ChessTreeNode;
19
+ /** Возвращает глубину вложенности относительно корня отображения. */
20
+ depth: number;
21
+ /** Возвращает родительский узел или null для корня. */
22
+ parentNode: ChessTreeNode | null;
23
+ /** Возвращает true, если нужна пустая ячейка хода (сетка верхнего уровня). */
24
+ shouldReserveEmptyMoveCell: boolean;
25
+ /** Возвращает true, если нужно отрисовать соседние варианты у развилки. */
26
+ shouldRenderSiblingVariations?: boolean;
27
+ /** Возвращает набор фигур для иконок SAN. */
28
+ pieceSet: PieceSet;
29
+ };
30
+
31
+ const {
32
+ chessNode,
33
+ depth,
34
+ parentNode,
35
+ shouldReserveEmptyMoveCell,
36
+ shouldRenderSiblingVariations = true,
37
+ pieceSet,
38
+ }: TMoveProps = $props();
39
+
40
+ /** Контекст игры без деструктуризации — иначе selectable и chessTree «замораживаются» при первом рендере TreeViewer. */
41
+ const game = getGameContext();
42
+
43
+ /** Представляет обработчик выбора текущего узла по `mousedown`. */
44
+ function handleMoveMouseDown() {
45
+ if (!game.selectable || !moveNode) return;
46
+ game.chessTree.currentNode = chessNode;
47
+
48
+ game.onSelectNode();
49
+ game.onChessNodeSelected?.(game.chessTree.currentNode);
50
+ }
51
+
52
+ const moveNode = $derived(chessNode);
53
+ const previewHover = createPreviewHover({
54
+ setPreviewFen: game.setPreviewFen,
55
+ getFen: () => moveNode.data.fen,
56
+ getLastMove: () => moveNode.data.lastMove ?? null,
57
+ getDelayMs: () => game.previewHoverDelayMs,
58
+ });
59
+ const isCurrentMove = $derived(
60
+ chessNode.id === game.chessTree.currentNode.id,
61
+ );
62
+ /** Представляет текст первого PGN-комментария узла после разбора `comments[0]`, синхронно с правкой строки под деревом. */
63
+ const commentParseCache = new Map<
64
+ string,
65
+ ReturnType<typeof parseComment>
66
+ >();
67
+
68
+ function getParsedComment(raw: string | undefined) {
69
+ if (raw === undefined) return null;
70
+ const cached = commentParseCache.get(raw);
71
+ if (cached) return cached;
72
+ const parsed = parseComment(raw);
73
+ commentParseCache.set(raw, parsed);
74
+ return parsed;
75
+ }
76
+
77
+ const firstCommentParsed = $derived(
78
+ getParsedComment(moveNode.data.comments?.[0]),
79
+ );
80
+ const firstCommentText = $derived(firstCommentParsed?.text);
81
+ const childMoves = $derived(chessNode.children);
82
+ const isForcedLineStart = $derived(
83
+ chessNode.id === game.chessTree.forcedNodeId,
84
+ );
85
+
86
+ /** Представляет признак активного drill-down «варианты отдельно». */
87
+ const variationDrillDownActive = $derived(
88
+ game.chessTree.isVariationDrillDownActive(),
89
+ );
90
+
91
+ /**
92
+ * Представляет признак: развилка на этом уровне совпадает с узлом, для которого
93
+ * `ChessTree` рассчитывает акцент направляющих при текущем выборе.
94
+ */
95
+ const isActiveForkForSelection = $derived(
96
+ shouldRenderSiblingVariations &&
97
+ parentNode !== null &&
98
+ (parentNode.children?.length ?? 0) > 1 &&
99
+ game.chessTree.currentGuideHighlightForkParent?.id ===
100
+ parentNode.id,
101
+ );
102
+
103
+ const spaceBlockClass = "px-3 py-2 !bg-gray-50/95";
104
+ const spaceInlineBlockClass = "p-2";
105
+
106
+ const isHighestLevel = $derived(depth === HIGHEST_LEVEL);
107
+
108
+ /**
109
+ * Представляет признак: в верхней сетке после белого полухода показывается пустая ячейка чёрных
110
+ * без ноды (партия оборвалась на ходе белых) — нижнюю границу рисуем только под двумя первыми колонками.
111
+ */
112
+ const addsEmptyMainLineBlackCell = $derived(
113
+ isHighestLevel &&
114
+ moveNode.data.ply % 2 === 1 &&
115
+ !isForcedLineStart &&
116
+ (parentNode === null || parentNode.children.length <= 1) &&
117
+ !firstCommentText &&
118
+ (childMoves?.length ?? 0) === 0,
119
+ );
120
+
121
+ /**
122
+ * Представляет признак: верхняя строка — первый полуход чёрных от корня партии (нотация «1... SAN»).
123
+ */
124
+ const isLeadingBlackHalfMoveFromRoot = $derived(
125
+ isHighestLevel &&
126
+ parentNode !== null &&
127
+ parentNode.data.ply === 0 &&
128
+ moveNode.data.ply % 2 === 0,
129
+ );
130
+
131
+ /** Представляет true, если в контекстном меню показывать «Поднять приоритет». */
132
+ const showUpPriorityItem = $derived(depth > HIGHEST_LEVEL + 1);
133
+
134
+ /**
135
+ * Представляет признак: SAN главного варианта (children[0]) переносится в блок списка веток,
136
+ * чтобы не дублировать его перед группой (например «8. g3» только среди g3 / f3 / a3).
137
+ */
138
+ const shouldRenderSanInsideVariationGroup = $derived(
139
+ !isHighestLevel &&
140
+ shouldRenderSiblingVariations &&
141
+ parentNode !== null &&
142
+ parentNode.children.length > 1 &&
143
+ parentNode.children[0]?.id === chessNode.id,
144
+ );
145
+
146
+ /**
147
+ * Представляет обработчик клика по зоне линий ветвления, открывающий режим «варианты отдельно».
148
+ */
149
+ function onVariationLinesHit(e: MouseEvent) {
150
+ e.stopPropagation();
151
+ if (parentNode === null) return;
152
+ const selectFork =
153
+ !game.chessTree.isCurrentNodeWithinForkSubtree(parentNode);
154
+ game.chessTree.openVariationDrillDown(parentNode, { selectFork });
155
+ game.onSelectNode();
156
+ game.onChessNodeSelected?.(game.chessTree.currentNode);
157
+ }
140
158
  </script>
141
159
 
142
160
  {#snippet emptyMove()}
143
- <div class="flex items-center justify-center text-center">...</div>
161
+ <div class="flex items-center justify-center text-center">...</div>
144
162
  {/snippet}
145
163
 
146
164
  {#snippet emptyMainLineBlackCell()}
147
- <div
148
- class="tree-viewer-tail-no-node-cell flex min-w-0 items-center justify-center border-b-0 p-2 text-center"
149
- ></div>
165
+ <div
166
+ class="tree-viewer-tail-no-node-cell flex min-w-0 items-center justify-center border-b-0 p-2 text-center"
167
+ ></div>
150
168
  {/snippet}
151
169
 
152
170
  {#snippet fullMovesCounter(minus: number = 0)}
153
- <span
154
- class={{
155
- "flex items-center justify-center text-center": isHighestLevel,
156
- inline: !isHighestLevel,
157
- "border-b border-gray-300": addsEmptyMainLineBlackCell && isHighestLevel,
158
- "tree-viewer-overflow-tail-border":
159
- addsEmptyMainLineBlackCell && isHighestLevel,
160
- }}
161
- >
162
- {moveNode.data.fullMoves - minus}{!isHighestLevel &&
163
- moveNode.data.ply % 2 === 1
164
- ? "..."
165
- : !isHighestLevel && moveNode.data.ply % 2 === 0
166
- ? "..."
167
- : ""}
168
- </span>
171
+ <span
172
+ class={{
173
+ "flex items-center justify-center text-center": isHighestLevel,
174
+ inline: !isHighestLevel,
175
+ "border-b border-gray-300":
176
+ addsEmptyMainLineBlackCell && isHighestLevel,
177
+ "tree-viewer-overflow-tail-border":
178
+ addsEmptyMainLineBlackCell && isHighestLevel,
179
+ }}
180
+ >
181
+ {moveNode.data.fullMoves - minus}{!isHighestLevel &&
182
+ moveNode.data.ply % 2 === 1
183
+ ? "..."
184
+ : !isHighestLevel && moveNode.data.ply % 2 === 0
185
+ ? "..."
186
+ : ""}
187
+ </span>
169
188
  {/snippet}
170
189
 
171
190
  {#snippet variationMoveRow(child: ChessTreeNode)}
172
- <Move
173
- {pieceSet}
174
- chessNode={child}
175
- shouldReserveEmptyMoveCell={parentNode !== null &&
176
- parentNode.children.length > 1}
177
- depth={depth + 1}
178
- shouldRenderSiblingVariations={false}
179
- {parentNode}
180
- />
191
+ <Move
192
+ {pieceSet}
193
+ chessNode={child}
194
+ shouldReserveEmptyMoveCell={parentNode !== null &&
195
+ parentNode.children.length > 1}
196
+ depth={depth + 1}
197
+ shouldRenderSiblingVariations={false}
198
+ {parentNode}
199
+ />
181
200
  {/snippet}
182
201
 
183
202
  {#if isHighestLevel}
184
- {#if moveNode.data.ply % 2 === 1}
185
- {@render fullMovesCounter()}
186
- {/if}
187
-
188
- {#if variationDrillDownActive && moveNode.data.ply % 2 === 0 && game.chessTree.drillForkParent !== null && game.chessTree.drillForkParent.children[0]?.id === chessNode.id && moveNode.parentId}
189
- <span
190
- class={{
191
- "flex items-center justify-center text-center": isHighestLevel,
192
- }}
193
- >
194
- {moveNode.data.fullMoves}
195
- </span>
196
- {@render emptyMove()}
197
- {/if}
203
+ {#if moveNode.data.ply % 2 === 1}
204
+ {@render fullMovesCounter()}
205
+ {/if}
198
206
 
199
- {#if isLeadingBlackHalfMoveFromRoot}
200
- <span
201
- class={{
202
- "flex items-center justify-center text-center": isHighestLevel,
203
- }}
204
- >
205
- {Math.max(1, moveNode.data.fullMoves - 1)}
206
- </span>
207
- {@render emptyMove()}
208
- {/if}
209
-
210
- {#if moveNode.parentId}
211
- <MoveSanWithMenu
212
- {chessNode}
213
- {parentNode}
214
- {pieceSet}
215
- selectable={game.selectable}
216
- {isHighestLevel}
217
- {isCurrentMove}
218
- previewHover={{
219
- onmouseenter: previewHover.onmouseenter,
220
- onmouseleave: previewHover.onmouseleave,
221
- }}
222
- onMoveMouseDown={handleMoveMouseDown}
223
- {spaceInlineBlockClass}
224
- nags={moveNode.data.nags}
225
- chessTree={game.chessTree}
226
- {showUpPriorityItem}
227
- onDeleteVariant={game.onDeleteVariant}
228
- mainRowBottomEdge={addsEmptyMainLineBlackCell}
229
- />
230
- {/if}
231
- {#if isHighestLevel && moveNode.data.ply % 2 === 1}
232
- {#if isForcedLineStart || (parentNode != null && parentNode.children.length > 1) || !!firstCommentText}
233
- {@render emptyMove()}
234
- {:else if (childMoves?.length ?? 0) === 0}
235
- {@render emptyMainLineBlackCell()}
207
+ {#if variationDrillDownActive && moveNode.data.ply % 2 === 0 && game.chessTree.drillForkParent !== null && game.chessTree.drillForkParent.children[0]?.id === chessNode.id && moveNode.parentId}
208
+ <span
209
+ class={{
210
+ "flex items-center justify-center text-center": isHighestLevel,
211
+ }}
212
+ >
213
+ {moveNode.data.fullMoves}
214
+ </span>
215
+ {@render emptyMove()}
236
216
  {/if}
237
- {/if}
238
217
 
239
- {#if firstCommentText}
240
- {#if moveNode.data.ply % 2 === 1}
241
- <MoveComment text={firstCommentText} {isHighestLevel} {spaceBlockClass} />
242
- {#if !shouldReserveEmptyMoveCell && childMoves?.[0] && !isForcedLineStart}
243
- {@render fullMovesCounter()}
218
+ {#if isLeadingBlackHalfMoveFromRoot}
219
+ <span
220
+ class={{
221
+ "flex items-center justify-center text-center": isHighestLevel,
222
+ }}
223
+ >
224
+ {Math.max(1, moveNode.data.fullMoves - 1)}
225
+ </span>
244
226
  {@render emptyMove()}
245
- {/if}
246
227
  {/if}
247
228
 
248
- {#if moveNode.data.ply % 2 === 0}
249
- <MoveComment text={firstCommentText} {isHighestLevel} {spaceBlockClass} />
229
+ {#if moveNode.parentId}
230
+ <MoveSanWithMenu
231
+ {chessNode}
232
+ {parentNode}
233
+ {pieceSet}
234
+ selectable={game.selectable}
235
+ {isHighestLevel}
236
+ {isCurrentMove}
237
+ previewHover={{
238
+ onmouseenter: previewHover.onmouseenter,
239
+ onmouseleave: previewHover.onmouseleave,
240
+ }}
241
+ onMoveMouseDown={handleMoveMouseDown}
242
+ {spaceInlineBlockClass}
243
+ nags={moveNode.data.nags}
244
+ chessTree={game.chessTree}
245
+ {showUpPriorityItem}
246
+ onDeleteVariant={game.onDeleteVariant}
247
+ mainRowBottomEdge={addsEmptyMainLineBlackCell}
248
+ />
249
+ {/if}
250
+ {#if isHighestLevel && moveNode.data.ply % 2 === 1}
251
+ {#if isForcedLineStart || (parentNode != null && parentNode.children.length > 1) || !!firstCommentText}
252
+ {@render emptyMove()}
253
+ {:else if (childMoves?.length ?? 0) === 0}
254
+ {@render emptyMainLineBlackCell()}
255
+ {/if}
256
+ {/if}
257
+
258
+ {#if firstCommentText}
259
+ {#if moveNode.data.ply % 2 === 1}
260
+ <MoveComment
261
+ text={firstCommentText}
262
+ {isHighestLevel}
263
+ {spaceBlockClass}
264
+ />
265
+ {#if !shouldReserveEmptyMoveCell && childMoves?.[0] && !isForcedLineStart}
266
+ {@render fullMovesCounter()}
267
+ {@render emptyMove()}
268
+ {/if}
269
+ {/if}
270
+
271
+ {#if moveNode.data.ply % 2 === 0}
272
+ <MoveComment
273
+ text={firstCommentText}
274
+ {isHighestLevel}
275
+ {spaceBlockClass}
276
+ />
277
+ {/if}
250
278
  {/if}
251
- {/if}
252
279
  {:else}
253
- {#if moveNode.data.ply % 2 === 0 && game.chessTree.forcedNodeId === moveNode.parentId && parentNode?.children[0].id === moveNode.id}
254
- {@render fullMovesCounter(1)}
255
- {/if}
256
-
257
- {#if !shouldRenderSanInsideVariationGroup}
258
- <MoveSanWithMenu
259
- {chessNode}
260
- {parentNode}
261
- {pieceSet}
262
- selectable={game.selectable}
263
- {isHighestLevel}
264
- {isCurrentMove}
265
- previewHover={{
266
- onmouseenter: previewHover.onmouseenter,
267
- onmouseleave: previewHover.onmouseleave,
268
- }}
269
- onMoveMouseDown={handleMoveMouseDown}
270
- {spaceInlineBlockClass}
271
- nags={moveNode.data.nags}
272
- chessTree={game.chessTree}
273
- {showUpPriorityItem}
274
- onDeleteVariant={game.onDeleteVariant}
275
- />
276
- {/if}
277
- {#if firstCommentText}
278
- {#if moveNode.data.ply % 2 === 1}
279
- <MoveComment text={firstCommentText} {isHighestLevel} {spaceBlockClass} />
280
- {#if !shouldReserveEmptyMoveCell && childMoves?.[0] && !shouldRenderSanInsideVariationGroup}
281
- {@render fullMovesCounter()}
282
- {/if}
280
+ {#if moveNode.data.ply % 2 === 0 && game.chessTree.forcedNodeId === moveNode.parentId && parentNode?.children[0].id === moveNode.id}
281
+ {@render fullMovesCounter(1)}
283
282
  {/if}
284
283
 
285
- {#if moveNode.data.ply % 2 === 0}
286
- <MoveComment text={firstCommentText} {isHighestLevel} {spaceBlockClass} />
284
+ {#if !shouldRenderSanInsideVariationGroup}
285
+ <MoveSanWithMenu
286
+ {chessNode}
287
+ {parentNode}
288
+ {pieceSet}
289
+ selectable={game.selectable}
290
+ {isHighestLevel}
291
+ {isCurrentMove}
292
+ previewHover={{
293
+ onmouseenter: previewHover.onmouseenter,
294
+ onmouseleave: previewHover.onmouseleave,
295
+ }}
296
+ onMoveMouseDown={handleMoveMouseDown}
297
+ {spaceInlineBlockClass}
298
+ nags={moveNode.data.nags}
299
+ chessTree={game.chessTree}
300
+ {showUpPriorityItem}
301
+ onDeleteVariant={game.onDeleteVariant}
302
+ />
303
+ {/if}
304
+ {#if firstCommentText}
305
+ {#if moveNode.data.ply % 2 === 1}
306
+ <MoveComment
307
+ text={firstCommentText}
308
+ {isHighestLevel}
309
+ {spaceBlockClass}
310
+ />
311
+ {#if !shouldReserveEmptyMoveCell && childMoves?.[0] && !shouldRenderSanInsideVariationGroup}
312
+ {@render fullMovesCounter()}
313
+ {/if}
314
+ {/if}
315
+
316
+ {#if moveNode.data.ply % 2 === 0}
317
+ <MoveComment
318
+ text={firstCommentText}
319
+ {isHighestLevel}
320
+ {spaceBlockClass}
321
+ />
322
+ {/if}
287
323
  {/if}
288
- {/if}
289
324
  {/if}
290
325
 
291
326
  {#if parentNode && parentNode?.children.length > 1 && shouldRenderSiblingVariations}
292
- {@const showVariationDrillExpand = !game.chessTree.isNodeOnMainLine(chessNode)}
293
- <VariationGroup
294
- {parentNode}
295
- {isHighestLevel}
296
- {isActiveForkForSelection}
297
- {showVariationDrillExpand}
298
- {onVariationLinesHit}
299
- {variationMoveRow}
300
- isBranchOnCurrentPath={(n) => game.chessTree.isCurrentOnPathFromNode(n)}
301
- />
327
+ {@const showVariationDrillExpand =
328
+ !game.chessTree.isNodeOnMainLine(chessNode)}
329
+ <VariationGroup
330
+ {parentNode}
331
+ {isHighestLevel}
332
+ {isActiveForkForSelection}
333
+ {showVariationDrillExpand}
334
+ {onVariationLinesHit}
335
+ {variationMoveRow}
336
+ isBranchOnCurrentPath={(n) => game.chessTree.isCurrentOnPathFromNode(n)}
337
+ />
302
338
  {/if}
303
339
 
304
340
  {#if isForcedLineStart}
305
- <div
306
- class={{
307
- "col-span-3 col-start-1 w-full min-w-0": isHighestLevel,
308
- "block w-full min-w-0 basis-full shrink-0": !isHighestLevel,
309
- }}
310
- >
311
341
  <div
312
- class={{
313
- "block w-full min-w-0": !isHighestLevel,
314
- [spaceBlockClass]: isHighestLevel,
315
- "tracking-tight": true,
316
- }}
342
+ class={{
343
+ "col-span-3 col-start-1 w-full min-w-0": isHighestLevel,
344
+ "block w-full min-w-0 basis-full shrink-0": !isHighestLevel,
345
+ }}
317
346
  >
318
- <Move
319
- {pieceSet}
320
- chessNode={chessNode.children[0]}
321
- shouldReserveEmptyMoveCell={chessNode.children.length > 1}
322
- depth={depth + 1}
323
- shouldRenderSiblingVariations={true}
324
- parentNode={chessNode}
325
- ></Move>
347
+ <div
348
+ class={{
349
+ "block w-full min-w-0": !isHighestLevel,
350
+ [spaceBlockClass]: isHighestLevel,
351
+ "tracking-tight": true,
352
+ }}
353
+ >
354
+ <Move
355
+ {pieceSet}
356
+ chessNode={chessNode.children[0]}
357
+ shouldReserveEmptyMoveCell={chessNode.children.length > 1}
358
+ depth={depth + 1}
359
+ shouldRenderSiblingVariations={true}
360
+ parentNode={chessNode}
361
+ ></Move>
362
+ </div>
326
363
  </div>
327
- </div>
328
364
  {/if}
329
365
 
330
366
  {#if shouldReserveEmptyMoveCell && moveNode.data.ply % 2 === 1 && isHighestLevel && !isForcedLineStart && childMoves?.[0]}
331
- {@render fullMovesCounter()}
332
- {@render emptyMove()}
367
+ {@render fullMovesCounter()}
368
+ {@render emptyMove()}
333
369
  {/if}
334
370
  {#if variationDrillDownActive && isHighestLevel && moveNode.data.ply % 2 === 1 && !shouldReserveEmptyMoveCell && childMoves?.[0] && !isForcedLineStart && game.chessTree.drillForkParent !== null && game.chessTree.drillForkParent.children[0]?.id === chessNode.id}
335
- <span
336
- class={{
337
- "flex items-center justify-center text-center": isHighestLevel,
338
- }}
339
- >
340
- {moveNode.data.fullMoves}
341
- </span>
342
- {@render emptyMove()}
371
+ <span
372
+ class={{
373
+ "flex items-center justify-center text-center": isHighestLevel,
374
+ }}
375
+ >
376
+ {moveNode.data.fullMoves}
377
+ </span>
378
+ {@render emptyMove()}
343
379
  {/if}
344
380
  {#if childMoves?.[0] && !shouldRenderSanInsideVariationGroup}
345
- {#if !isForcedLineStart}
346
- <Move
347
- {pieceSet}
348
- chessNode={chessNode.children[0]}
349
- shouldReserveEmptyMoveCell={childMoves?.length > 1}
350
- {depth}
351
- parentNode={chessNode}
352
- ></Move>
353
- {/if}
381
+ {#if !isForcedLineStart}
382
+ <Move
383
+ {pieceSet}
384
+ chessNode={chessNode.children[0]}
385
+ shouldReserveEmptyMoveCell={childMoves?.length > 1}
386
+ {depth}
387
+ parentNode={chessNode}
388
+ ></Move>
389
+ {/if}
354
390
  {/if}