@connectorvol/tree 6.4.0 → 6.5.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.
- package/dist/(components)/TreeViewer.svelte +63 -33
- package/dist/(components)/TreeViewer.svelte.d.ts +2 -0
- package/dist/(components)/VariantDropdownNavigator.svelte +1 -1
- package/dist/(components)/VariationGroup.svelte +2 -2
- package/dist/(models)/nagCatalog.d.ts +2 -0
- package/dist/(models)/nagCatalog.js +11 -7
- package/dist/(utils)/transformPgnToChessNode.js +2 -2
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
import {
|
|
29
29
|
isPositionEvaluationNag,
|
|
30
30
|
nagDescription,
|
|
31
|
+
NAG_CATALOG_SECTIONS,
|
|
31
32
|
SELECTABLE_NAG_IDS_ORDERED,
|
|
32
33
|
} from "../(models)/nagCatalog.js";
|
|
33
34
|
import { setContext } from "svelte";
|
|
@@ -93,6 +94,8 @@
|
|
|
93
94
|
previewHoverDelayMs?: number | "off";
|
|
94
95
|
/** Возвращает true, если под деревом показываются комментарий и выбор NAG для текущей ноды. */
|
|
95
96
|
editMode?: boolean;
|
|
97
|
+
/** Возвращает true, если в режиме правки показывать группу NAG «Задача (развилка)». По умолчанию true. */
|
|
98
|
+
showPuzzleBranchNags?: boolean;
|
|
96
99
|
/** Возвращает функцию для установки признака несохранённости дерева. */
|
|
97
100
|
onChangeDirty?: (setIsDirty: (value: boolean) => void) => void;
|
|
98
101
|
};
|
|
@@ -111,6 +114,7 @@
|
|
|
111
114
|
setPreviewFen,
|
|
112
115
|
previewHoverDelayMs = 700,
|
|
113
116
|
editMode = false,
|
|
117
|
+
showPuzzleBranchNags = false,
|
|
114
118
|
onChangeDirty,
|
|
115
119
|
}: TTreeViewerProps = $props();
|
|
116
120
|
|
|
@@ -179,9 +183,21 @@
|
|
|
179
183
|
};
|
|
180
184
|
});
|
|
181
185
|
|
|
186
|
+
$effect(() => {
|
|
187
|
+
void chessTree.currentNode.id;
|
|
188
|
+
scrollToActiveMoveIfNeeded();
|
|
189
|
+
});
|
|
190
|
+
|
|
182
191
|
/** Представляет true, если доступно редактирование комментария и NAG (есть интерактивный выбор ноды). */
|
|
183
192
|
const canEditAnnotations = $derived(editMode && selectable);
|
|
184
193
|
|
|
194
|
+
/** Представляет видимые секции NAG с учётом настройки показа группы «Задача (развилка)». */
|
|
195
|
+
const visibleNagSections = $derived(
|
|
196
|
+
NAG_CATALOG_SECTIONS.filter((section) =>
|
|
197
|
+
showPuzzleBranchNags ? true : section.key !== "puzzle-branch",
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
|
|
185
201
|
let cachedPgn: string | null = $state(null);
|
|
186
202
|
let cachedPgnVersion = $state(-1);
|
|
187
203
|
|
|
@@ -614,6 +630,7 @@
|
|
|
614
630
|
|
|
615
631
|
node.data.nags = next.length > 0 ? next : undefined;
|
|
616
632
|
chessTree.mutationVersion++;
|
|
633
|
+
onSelectNode();
|
|
617
634
|
}
|
|
618
635
|
|
|
619
636
|
/** Представляет обновление признака вертикального переполнения дерева ходов. */
|
|
@@ -860,41 +877,54 @@
|
|
|
860
877
|
</label>
|
|
861
878
|
<div
|
|
862
879
|
class="relative flex flex-wrap gap-1.5 pb-0.5 pr-0.5"
|
|
863
|
-
role="group"
|
|
864
|
-
aria-label="Символы NAG"
|
|
865
880
|
>
|
|
866
|
-
{#each
|
|
867
|
-
{
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
{#if label}
|
|
873
|
-
<button
|
|
874
|
-
type="button"
|
|
875
|
-
disabled={!canEditAnnotations}
|
|
876
|
-
title={nagDescription(nagId)}
|
|
877
|
-
class={{
|
|
878
|
-
"inline-flex min-h-[1.5rem] min-w-[1.5rem] shrink-0 items-center justify-center rounded-full border px-2 py-0.5 text-center font-serif text-[0.625rem] font-semibold leading-none text-white shadow-[0_1px_2px_rgba(0,0,0,0.25)]": true,
|
|
879
|
-
"cursor-pointer": canEditAnnotations,
|
|
880
|
-
"cursor-not-allowed border-gray-300 bg-gray-300 text-gray-600 shadow-none":
|
|
881
|
-
!canEditAnnotations,
|
|
882
|
-
"border-white/25": canEditAnnotations,
|
|
883
|
-
}}
|
|
884
|
-
style:background={canEditAnnotations
|
|
885
|
-
? shadedActive
|
|
886
|
-
? nagBadgeBackground(nagId)
|
|
887
|
-
: "rgb(243 244 246)"
|
|
888
|
-
: undefined}
|
|
889
|
-
style:color={canEditAnnotations && !shadedActive
|
|
890
|
-
? "#374151"
|
|
891
|
-
: undefined}
|
|
892
|
-
aria-pressed={nagOnNode}
|
|
893
|
-
onclick={() => toggleNagAtCurrentNode(nagId)}
|
|
894
|
-
>
|
|
895
|
-
{label}
|
|
896
|
-
</button>
|
|
881
|
+
{#each visibleNagSections as section, index (section.key)}
|
|
882
|
+
{#if index > 0}
|
|
883
|
+
<div
|
|
884
|
+
class="mx-1.5 w-px self-stretch bg-gray-300"
|
|
885
|
+
aria-hidden="true"
|
|
886
|
+
></div>
|
|
897
887
|
{/if}
|
|
888
|
+
<div
|
|
889
|
+
class="flex flex-wrap gap-1.5"
|
|
890
|
+
role="group"
|
|
891
|
+
aria-label={section.title}
|
|
892
|
+
>
|
|
893
|
+
{#each section.items as entry (entry.id)}
|
|
894
|
+
{@const nagId = entry.id}
|
|
895
|
+
{@const label = transformNagId(nagId)}
|
|
896
|
+
{@const nagOnNode =
|
|
897
|
+
chessTree.currentNode.data.nags?.includes(nagId) ??
|
|
898
|
+
false}
|
|
899
|
+
{@const shadedActive = canEditAnnotations && nagOnNode}
|
|
900
|
+
{#if label}
|
|
901
|
+
<button
|
|
902
|
+
type="button"
|
|
903
|
+
disabled={!canEditAnnotations}
|
|
904
|
+
title={nagDescription(nagId)}
|
|
905
|
+
class={{
|
|
906
|
+
"inline-flex min-h-[1.5rem] min-w-[1.5rem] shrink-0 items-center justify-center rounded-full border px-2 py-0.5 text-center font-serif text-[0.625rem] font-semibold leading-none text-white shadow-[0_1px_2px_rgba(0,0,0,0.25)]": true,
|
|
907
|
+
"cursor-pointer": canEditAnnotations,
|
|
908
|
+
"cursor-not-allowed border-gray-300 bg-gray-300 text-gray-600 shadow-none":
|
|
909
|
+
!canEditAnnotations,
|
|
910
|
+
"border-white/25": canEditAnnotations,
|
|
911
|
+
}}
|
|
912
|
+
style:background={canEditAnnotations
|
|
913
|
+
? shadedActive
|
|
914
|
+
? nagBadgeBackground(nagId)
|
|
915
|
+
: "rgb(243 244 246)"
|
|
916
|
+
: undefined}
|
|
917
|
+
style:color={canEditAnnotations && !shadedActive
|
|
918
|
+
? "#374151"
|
|
919
|
+
: undefined}
|
|
920
|
+
aria-pressed={nagOnNode}
|
|
921
|
+
onclick={() => toggleNagAtCurrentNode(nagId)}
|
|
922
|
+
>
|
|
923
|
+
{label}
|
|
924
|
+
</button>
|
|
925
|
+
{/if}
|
|
926
|
+
{/each}
|
|
927
|
+
</div>
|
|
898
928
|
{/each}
|
|
899
929
|
{#if canEditAnnotations}
|
|
900
930
|
<span
|
|
@@ -35,6 +35,8 @@ type TTreeViewerProps = {
|
|
|
35
35
|
previewHoverDelayMs?: number | "off";
|
|
36
36
|
/** Возвращает true, если под деревом показываются комментарий и выбор NAG для текущей ноды. */
|
|
37
37
|
editMode?: boolean;
|
|
38
|
+
/** Возвращает true, если в режиме правки показывать группу NAG «Задача (развилка)». По умолчанию true. */
|
|
39
|
+
showPuzzleBranchNags?: boolean;
|
|
38
40
|
/** Возвращает функцию для установки признака несохранённости дерева. */
|
|
39
41
|
onChangeDirty?: (setIsDirty: (value: boolean) => void) => void;
|
|
40
42
|
};
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
{#if isOpen}
|
|
142
142
|
<div
|
|
143
143
|
data-variant-dropdown="1"
|
|
144
|
-
class="z-50 min-w-[14rem] rounded-md border bg-white p-1 shadow-
|
|
144
|
+
class="z-50 min-w-[14rem] rounded-md border bg-white p-1 shadow-none outline-none"
|
|
145
145
|
role="menu"
|
|
146
146
|
aria-label="Варианты следующего хода"
|
|
147
147
|
style={position
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
{#if parentNode.children.length > 1}
|
|
40
40
|
<div
|
|
41
41
|
class={{
|
|
42
|
-
"relative min-w-0 w-full max-w-full bg-gray-50/95": true,
|
|
43
|
-
" rounded-md
|
|
42
|
+
"relative min-w-0 w-full max-w-full bg-gray-50/95 ": true,
|
|
43
|
+
" rounded-md transition-[border-color,box-shadow] duration-150 [&:has(>[data-line-hit]:hover)>.flex>div[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:hover)>.flex>ul>li>span[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:focus-visible)>.flex>div[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:focus-visible)>.flex>ul>li>span[data-line-stroke]]:border-gray-600 ":
|
|
44
44
|
showVariationDrillExpand,
|
|
45
45
|
"pr-2": !showVariationDrillExpand,
|
|
46
46
|
}}
|
|
@@ -17,6 +17,8 @@ export type TNagCatalogEntry = {
|
|
|
17
17
|
* Представляет группу глифов Lichess (как в меню исследований).
|
|
18
18
|
*/
|
|
19
19
|
export type TNagCatalogSection = {
|
|
20
|
+
/** Возвращает ключ секции. */
|
|
21
|
+
key: string;
|
|
20
22
|
/** Возвращает заголовок секции. */
|
|
21
23
|
title: string;
|
|
22
24
|
/** Возвращает список глифов в секции. */
|
|
@@ -38,6 +38,15 @@ const MOVE_EVALUATION_NAMES = {
|
|
|
38
38
|
*/
|
|
39
39
|
export const NAG_CATALOG_SECTIONS = [
|
|
40
40
|
{
|
|
41
|
+
key: "puzzle-branch",
|
|
42
|
+
title: "Задача (развилка)",
|
|
43
|
+
items: [
|
|
44
|
+
{ id: 147, name: "Ветка: верное решение" },
|
|
45
|
+
{ id: 148, name: "Ветка: неверное решение" },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "move-evaluation",
|
|
41
50
|
title: "Оценка хода",
|
|
42
51
|
items: MOVE_EVALUATION_NAG_IDS.map((id) => ({
|
|
43
52
|
id,
|
|
@@ -45,6 +54,7 @@ export const NAG_CATALOG_SECTIONS = [
|
|
|
45
54
|
})),
|
|
46
55
|
},
|
|
47
56
|
{
|
|
57
|
+
key: "position-evaluation",
|
|
48
58
|
title: "Позиция",
|
|
49
59
|
items: POSITION_EVALUATION_NAG_IDS.map((id) => ({
|
|
50
60
|
id,
|
|
@@ -52,13 +62,7 @@ export const NAG_CATALOG_SECTIONS = [
|
|
|
52
62
|
})),
|
|
53
63
|
},
|
|
54
64
|
{
|
|
55
|
-
|
|
56
|
-
items: [
|
|
57
|
-
{ id: 147, name: "Ветка: верное решение" },
|
|
58
|
-
{ id: 148, name: "Ветка: неверное решение" },
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
{
|
|
65
|
+
key: "observation",
|
|
62
66
|
title: "Наблюдение",
|
|
63
67
|
items: [
|
|
64
68
|
{ id: 22, name: "Цугцванг" },
|
|
@@ -17,7 +17,7 @@ export function transformPgnToChessNode(pgn) {
|
|
|
17
17
|
const san = makeSanAndPlay(pos, move); // Mutating pos!
|
|
18
18
|
const fen = makeFen(pos.toSetup());
|
|
19
19
|
const { halfMoves, fullMoves } = calculatePly(fen);
|
|
20
|
-
const
|
|
20
|
+
const allComments = node.comments?.join(" ");
|
|
21
21
|
let lastMove;
|
|
22
22
|
if (isNormal(move)) {
|
|
23
23
|
lastMove = {
|
|
@@ -34,7 +34,7 @@ export function transformPgnToChessNode(pgn) {
|
|
|
34
34
|
fen,
|
|
35
35
|
ply: halfMoves,
|
|
36
36
|
fullMoves,
|
|
37
|
-
parsedFirstComment:
|
|
37
|
+
parsedFirstComment: allComments ? parseComment(allComments) : null,
|
|
38
38
|
...(lastMove !== undefined ? { lastMove } : {}),
|
|
39
39
|
};
|
|
40
40
|
});
|