@connectorvol/tree 1.1.0 → 1.2.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/package.json +30 -29
- package/dist/(classes)/chessTree.svelte.d.ts +0 -51
- package/dist/(classes)/chessTree.svelte.js +0 -160
- package/dist/(components)/ImportToPgn.svelte +0 -16
- package/dist/(components)/ImportToPgn.svelte.d.ts +0 -7
- package/dist/(components)/Move.svelte +0 -285
- package/dist/(components)/Move.svelte.d.ts +0 -14
- package/dist/(components)/MoveWithIcon.svelte +0 -48
- package/dist/(components)/MoveWithIcon.svelte.d.ts +0 -14
- package/dist/(components)/PieceIcon.svelte +0 -44
- package/dist/(components)/PieceIcon.svelte.d.ts +0 -15
- package/dist/(components)/TreeViewer.svelte +0 -82
- package/dist/(components)/TreeViewer.svelte.d.ts +0 -17
- package/dist/(components)/TreeViewerPanelManager.svelte +0 -246
- package/dist/(components)/TreeViewerPanelManager.svelte.d.ts +0 -13
- package/dist/(constants)/png.d.ts +0 -11
- package/dist/(constants)/png.js +0 -126
- package/dist/(models)/chessTreeNode.d.ts +0 -15
- package/dist/(models)/chessTreeNode.js +0 -1
- package/dist/(models)/pgnNodeCustomData.d.ts +0 -10
- package/dist/(models)/pgnNodeCustomData.js +0 -1
- package/dist/(utils)/context.d.ts +0 -13
- package/dist/(utils)/context.js +0 -17
- package/dist/(utils)/createPgnFromTree.d.ts +0 -2
- package/dist/(utils)/createPgnFromTree.js +0 -5
- package/dist/(utils)/parseSanMove.d.ts +0 -27
- package/dist/(utils)/parseSanMove.js +0 -84
- package/dist/(utils)/scrollToActiveMove.d.ts +0 -7
- package/dist/(utils)/scrollToActiveMove.js +0 -72
- package/dist/(utils)/scrollToStart.d.ts +0 -6
- package/dist/(utils)/scrollToStart.js +0 -46
- package/dist/(utils)/transformNag.d.ts +0 -1
- package/dist/(utils)/transformNag.js +0 -34
- package/dist/(utils)/transformPgnToChessNode.d.ts +0 -7
- package/dist/(utils)/transformPgnToChessNode.js +0 -56
- package/dist/components/ui/button/button.svelte +0 -82
- package/dist/components/ui/button/button.svelte.d.ts +0 -64
- package/dist/components/ui/button/index.d.ts +0 -2
- package/dist/components/ui/button/index.js +0 -4
- package/dist/components/ui/button-group/button-group-separator.svelte +0 -20
- package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +0 -13
- package/dist/components/ui/button-group/button-group-text.svelte +0 -30
- package/dist/components/ui/button-group/button-group-text.svelte.d.ts +0 -11
- package/dist/components/ui/button-group/button-group.svelte +0 -46
- package/dist/components/ui/button-group/button-group.svelte.d.ts +0 -26
- package/dist/components/ui/button-group/index.d.ts +0 -4
- package/dist/components/ui/button-group/index.js +0 -6
- package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +0 -38
- package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte.d.ts +0 -9
- package/dist/components/ui/context-menu/context-menu-content.svelte +0 -25
- package/dist/components/ui/context-menu/context-menu-content.svelte.d.ts +0 -7
- package/dist/components/ui/context-menu/context-menu-group-heading.svelte +0 -21
- package/dist/components/ui/context-menu/context-menu-group-heading.svelte.d.ts +0 -7
- package/dist/components/ui/context-menu/context-menu-group.svelte +0 -7
- package/dist/components/ui/context-menu/context-menu-group.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/context-menu-item.svelte +0 -27
- package/dist/components/ui/context-menu/context-menu-item.svelte.d.ts +0 -8
- package/dist/components/ui/context-menu/context-menu-label.svelte +0 -24
- package/dist/components/ui/context-menu/context-menu-label.svelte.d.ts +0 -8
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte +0 -16
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/context-menu-radio-item.svelte +0 -31
- package/dist/components/ui/context-menu/context-menu-radio-item.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/context-menu-separator.svelte +0 -17
- package/dist/components/ui/context-menu/context-menu-separator.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/context-menu-shortcut.svelte +0 -20
- package/dist/components/ui/context-menu/context-menu-shortcut.svelte.d.ts +0 -5
- package/dist/components/ui/context-menu/context-menu-sub-content.svelte +0 -20
- package/dist/components/ui/context-menu/context-menu-sub-content.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +0 -29
- package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte.d.ts +0 -8
- package/dist/components/ui/context-menu/context-menu-trigger.svelte +0 -7
- package/dist/components/ui/context-menu/context-menu-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/context-menu/index.d.ts +0 -16
- package/dist/components/ui/context-menu/index.js +0 -19
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -41
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +0 -9
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -22
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -27
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -24
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +0 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -31
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -20
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +0 -5
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -20
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -29
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/dropdown-menu/index.js +0 -17
- package/dist/components/ui/separator/index.d.ts +0 -2
- package/dist/components/ui/separator/index.js +0 -4
- package/dist/components/ui/separator/separator.svelte +0 -21
- package/dist/components/ui/separator/separator.svelte.d.ts +0 -4
- package/dist/components/ui/sonner/index.d.ts +0 -1
- package/dist/components/ui/sonner/index.js +0 -1
- package/dist/components/ui/sonner/sonner.svelte +0 -13
- package/dist/components/ui/sonner/sonner.svelte.d.ts +0 -4
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -7
- package/dist/utils.d.ts +0 -12
- package/dist/utils.js +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@connectorvol/tree",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"!dist/**/*.test.*",
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "vite",
|
|
23
23
|
"dev": "vite",
|
|
24
|
-
"build": "vite build
|
|
24
|
+
"build": "vite build",
|
|
25
25
|
"preview": "vite preview",
|
|
26
|
-
"package": "
|
|
27
|
-
"
|
|
26
|
+
"package": "vite build && bun pm pack",
|
|
27
|
+
"publish": "bun publish",
|
|
28
|
+
"prepublishOnly": "bun pm pack",
|
|
28
29
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
29
30
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
30
31
|
"format": "oxfmt --write . && prettier --write \"**/*.svelte\"",
|
|
@@ -35,42 +36,42 @@
|
|
|
35
36
|
"test:ui": "npx playwright test --ui"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
|
-
"@connectorvol/shared": "
|
|
39
|
+
"@connectorvol/shared": "1.0.1",
|
|
39
40
|
"bits-ui": "^2.11.4",
|
|
40
41
|
"clsx": "^2.1.1",
|
|
41
42
|
"tailwind-merge": "^3.3.1",
|
|
42
43
|
"tailwind-variants": "^3.1.1"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"@
|
|
46
|
+
"@connectorvol/chessboard": "1.0.1",
|
|
47
|
+
"@connectorvol/chessops": "0.15.1",
|
|
48
|
+
"@ianvs/prettier-plugin-sort-imports": "4.5.1",
|
|
49
|
+
"@internationalized/date": "3.9.0",
|
|
47
50
|
"@lucide/svelte": "^0.548.0",
|
|
48
|
-
"@playwright/test": "
|
|
49
|
-
"@sveltejs/adapter-static": "
|
|
50
|
-
"@sveltejs/kit": "
|
|
51
|
-
"@sveltejs/package": "
|
|
52
|
-
"@sveltejs/vite-plugin-svelte": "
|
|
53
|
-
"@tailwindcss/forms": "
|
|
54
|
-
"@tailwindcss/postcss": "
|
|
55
|
-
"@tailwindcss/typography": "
|
|
56
|
-
"@tailwindcss/vite": "
|
|
57
|
-
"
|
|
58
|
-
"@connectorvol/chessops": "workspace:*",
|
|
59
|
-
"autoprefixer": "catalog:",
|
|
51
|
+
"@playwright/test": "1.54.1",
|
|
52
|
+
"@sveltejs/adapter-static": "3.0.10",
|
|
53
|
+
"@sveltejs/kit": "2.48.0",
|
|
54
|
+
"@sveltejs/package": "2.4.0",
|
|
55
|
+
"@sveltejs/vite-plugin-svelte": "6.0.0",
|
|
56
|
+
"@tailwindcss/forms": "0.5.10",
|
|
57
|
+
"@tailwindcss/postcss": "4.1.11",
|
|
58
|
+
"@tailwindcss/typography": "0.5.16",
|
|
59
|
+
"@tailwindcss/vite": "4.1.11",
|
|
60
|
+
"autoprefixer": "10.4.21",
|
|
60
61
|
"mode-watcher": "^1.1.0",
|
|
61
|
-
"prettier": "
|
|
62
|
-
"prettier-plugin-svelte": "
|
|
63
|
-
"prettier-plugin-tailwindcss": "
|
|
64
|
-
"svelte-check": "
|
|
62
|
+
"prettier": "3.6.2",
|
|
63
|
+
"prettier-plugin-svelte": "3.4.0",
|
|
64
|
+
"prettier-plugin-tailwindcss": "0.6.14",
|
|
65
|
+
"svelte-check": "4.3.2",
|
|
65
66
|
"svelte-sonner": "^1.0.5",
|
|
66
|
-
"tailwindcss": "
|
|
67
|
+
"tailwindcss": "4.1.11",
|
|
67
68
|
"tw-animate-css": "^1.4.0",
|
|
68
|
-
"typescript": "
|
|
69
|
-
"vite": "
|
|
70
|
-
"vite-plugin-checker": "
|
|
71
|
-
"vite-plugin-svelte-checker": "
|
|
69
|
+
"typescript": "5.9.2",
|
|
70
|
+
"vite": "^8.0.0",
|
|
71
|
+
"vite-plugin-checker": "0.12.0",
|
|
72
|
+
"vite-plugin-svelte-checker": "0.1.2"
|
|
72
73
|
},
|
|
73
74
|
"peerDependencies": {
|
|
74
|
-
"svelte": "
|
|
75
|
+
"svelte": "^5.43.0"
|
|
75
76
|
}
|
|
76
77
|
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { ChessTreeNode, TChessTree } from "../(models)/chessTreeNode.js";
|
|
2
|
-
export declare class ChessTree {
|
|
3
|
-
rootNode: TChessTree;
|
|
4
|
-
currentNode: ChessTreeNode;
|
|
5
|
-
forcedNodeId: string | null;
|
|
6
|
-
/** Представляет индекс узлов по id для O(1) доступа к родителю по parentId. */
|
|
7
|
-
private nodeById;
|
|
8
|
-
constructor(rootNode: TChessTree);
|
|
9
|
-
/** Представляет перестроение индекса nodeById по всему дереву. */
|
|
10
|
-
private rebuildNodeById;
|
|
11
|
-
/** Представляет добавление узла и всех потомков в индекс nodeById. */
|
|
12
|
-
private addNodeToMap;
|
|
13
|
-
/** Представляет удаление узла и всех потомков из индекса nodeById. */
|
|
14
|
-
private removeNodeFromMap;
|
|
15
|
-
addNodeToCurrent(node: ChessTreeNode): void;
|
|
16
|
-
/**
|
|
17
|
-
* Представляет функцию поднятия приоритета варианта.
|
|
18
|
-
* Перемещает узел в начало списка детей его родителя.
|
|
19
|
-
* Если узел уже первый, поднимается по дереву вверх и ищет родителя,
|
|
20
|
-
* который не является первым среди своих детей.
|
|
21
|
-
*/
|
|
22
|
-
upPriority(node: ChessTreeNode): void;
|
|
23
|
-
/**
|
|
24
|
-
* Представляет функцию превращения варианта в главный.
|
|
25
|
-
* Поднимает приоритет узла до тех пор, пока все его предки
|
|
26
|
-
* не станут первыми в списке детей своих родителей.
|
|
27
|
-
*/
|
|
28
|
-
makeMainVariant(node: ChessTreeNode): void;
|
|
29
|
-
/**
|
|
30
|
-
* Представляет получение родителя текущего узла.
|
|
31
|
-
* Возвращает родительский узел или null, если текущий узел — корень.
|
|
32
|
-
*/
|
|
33
|
-
getCurrentNodeParent(): ChessTreeNode | null;
|
|
34
|
-
/**
|
|
35
|
-
* Представляет функцию удаления варианта из дерева.
|
|
36
|
-
* Удаляет указанный узел и все его дочерние узлы.
|
|
37
|
-
* Если удаляется текущий узел, перемещает указатель на родительский узел.
|
|
38
|
-
*/
|
|
39
|
-
deleteVariant(node: ChessTreeNode): void;
|
|
40
|
-
/**
|
|
41
|
-
* Представляет вспомогательную функцию для проверки, является ли узел предком указанного узла по ID.
|
|
42
|
-
* Возвращает true, если node является предком узла с targetNodeId.
|
|
43
|
-
*/
|
|
44
|
-
private isNodeAncestorOf;
|
|
45
|
-
/**
|
|
46
|
-
* Представляет вспомогательную функцию для поиска родительского узла.
|
|
47
|
-
* Возвращает родительский узел для заданного узла или null (корень / родитель не в индексе).
|
|
48
|
-
* Поиск по индексу nodeById по targetNode.parentId — O(1).
|
|
49
|
-
*/
|
|
50
|
-
private findParentNode;
|
|
51
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { generateId } from "@connectorvol/shared";
|
|
2
|
-
export class ChessTree {
|
|
3
|
-
rootNode;
|
|
4
|
-
currentNode;
|
|
5
|
-
// Заставляет узел отображаться как побочная линия, а не главный вариант
|
|
6
|
-
forcedNodeId;
|
|
7
|
-
/** Представляет индекс узлов по id для O(1) доступа к родителю по parentId. */
|
|
8
|
-
nodeById = new Map();
|
|
9
|
-
constructor(rootNode) {
|
|
10
|
-
this.rootNode = $state(rootNode);
|
|
11
|
-
this.currentNode = $state.raw(this.rootNode.moves);
|
|
12
|
-
this.forcedNodeId = $state(null);
|
|
13
|
-
this.rebuildNodeById();
|
|
14
|
-
}
|
|
15
|
-
/** Представляет перестроение индекса nodeById по всему дереву. */
|
|
16
|
-
rebuildNodeById() {
|
|
17
|
-
this.nodeById.clear();
|
|
18
|
-
const addToMap = (node) => {
|
|
19
|
-
this.nodeById.set(node.id, node);
|
|
20
|
-
for (const child of node.children) {
|
|
21
|
-
addToMap(child);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
addToMap(this.rootNode.moves);
|
|
25
|
-
}
|
|
26
|
-
/** Представляет добавление узла и всех потомков в индекс nodeById. */
|
|
27
|
-
addNodeToMap(node) {
|
|
28
|
-
this.nodeById.set(node.id, node);
|
|
29
|
-
for (const child of node.children) {
|
|
30
|
-
this.addNodeToMap(child);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/** Представляет удаление узла и всех потомков из индекса nodeById. */
|
|
34
|
-
removeNodeFromMap(node) {
|
|
35
|
-
this.nodeById.delete(node.id);
|
|
36
|
-
for (const child of node.children) {
|
|
37
|
-
this.removeNodeFromMap(child);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
addNodeToCurrent(node) {
|
|
41
|
-
const existingNode = this.currentNode.children.find((child) => child.data.san === node.data.san);
|
|
42
|
-
if (existingNode) {
|
|
43
|
-
this.currentNode = existingNode;
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const newNode = {
|
|
47
|
-
...node,
|
|
48
|
-
parentId: this.currentNode.id,
|
|
49
|
-
id: node.id || generateId(),
|
|
50
|
-
};
|
|
51
|
-
this.currentNode.children.push(newNode);
|
|
52
|
-
const addedNode = this.currentNode.children[this.currentNode.children.length - 1];
|
|
53
|
-
this.addNodeToMap(addedNode);
|
|
54
|
-
this.currentNode = addedNode;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Представляет функцию поднятия приоритета варианта.
|
|
58
|
-
* Перемещает узел в начало списка детей его родителя.
|
|
59
|
-
* Если узел уже первый, поднимается по дереву вверх и ищет родителя,
|
|
60
|
-
* который не является первым среди своих детей.
|
|
61
|
-
*/
|
|
62
|
-
upPriority(node) {
|
|
63
|
-
const parent = this.findParentNode(node);
|
|
64
|
-
if (!parent)
|
|
65
|
-
return; // Корневой узел не может быть поднят
|
|
66
|
-
const nodeIndex = parent.children.findIndex((child) => child.id === node.id);
|
|
67
|
-
if (nodeIndex === -1)
|
|
68
|
-
return; // Узел не найден среди детей родителя
|
|
69
|
-
// Если узел уже первый среди детей, идем вверх по дереву
|
|
70
|
-
if (nodeIndex === 0) {
|
|
71
|
-
this.upPriority(parent);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// Перемещаем узел в начало списка детей
|
|
75
|
-
const [movedNode] = parent.children.splice(nodeIndex, 1);
|
|
76
|
-
parent.children.unshift(movedNode);
|
|
77
|
-
this.forcedNodeId = null;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Представляет функцию превращения варианта в главный.
|
|
81
|
-
* Поднимает приоритет узла до тех пор, пока все его предки
|
|
82
|
-
* не станут первыми в списке детей своих родителей.
|
|
83
|
-
*/
|
|
84
|
-
makeMainVariant(node) {
|
|
85
|
-
let currentNode = node;
|
|
86
|
-
while (currentNode) {
|
|
87
|
-
const parent = this.findParentNode(currentNode);
|
|
88
|
-
if (!parent)
|
|
89
|
-
break; // Достигли корня
|
|
90
|
-
const nodeIndex = parent.children.findIndex((child) => child.id === currentNode.id);
|
|
91
|
-
if (nodeIndex === -1)
|
|
92
|
-
break; // Узел не найден
|
|
93
|
-
// Если узел уже первый, переходим к родителю
|
|
94
|
-
if (nodeIndex === 0) {
|
|
95
|
-
currentNode = parent;
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
// Перемещаем узел в начало списка детей
|
|
99
|
-
const [movedNode] = parent.children.splice(nodeIndex, 1);
|
|
100
|
-
parent.children.unshift(movedNode);
|
|
101
|
-
// Переходим к родителю
|
|
102
|
-
currentNode = parent;
|
|
103
|
-
}
|
|
104
|
-
this.forcedNodeId = null;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Представляет получение родителя текущего узла.
|
|
108
|
-
* Возвращает родительский узел или null, если текущий узел — корень.
|
|
109
|
-
*/
|
|
110
|
-
getCurrentNodeParent() {
|
|
111
|
-
return this.findParentNode(this.currentNode);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Представляет функцию удаления варианта из дерева.
|
|
115
|
-
* Удаляет указанный узел и все его дочерние узлы.
|
|
116
|
-
* Если удаляется текущий узел, перемещает указатель на родительский узел.
|
|
117
|
-
*/
|
|
118
|
-
deleteVariant(node) {
|
|
119
|
-
const parent = this.findParentNode(node);
|
|
120
|
-
if (!parent)
|
|
121
|
-
return; // Нельзя удалить корневой узел
|
|
122
|
-
const nodeIndex = parent.children.findIndex((child) => child.id === node.id);
|
|
123
|
-
if (nodeIndex === -1)
|
|
124
|
-
return; // Узел не найден среди детей родителя
|
|
125
|
-
this.currentNode = parent;
|
|
126
|
-
// Удаляем узел из списка детей родителя
|
|
127
|
-
parent.children.splice(nodeIndex, 1);
|
|
128
|
-
this.removeNodeFromMap(node);
|
|
129
|
-
// Сбрасываем forcedNodeId если он указывает на удаляемый узел или его потомков
|
|
130
|
-
if (this.forcedNodeId && this.isNodeAncestorOf(node, this.forcedNodeId)) {
|
|
131
|
-
this.forcedNodeId = null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Представляет вспомогательную функцию для проверки, является ли узел предком указанного узла по ID.
|
|
136
|
-
* Возвращает true, если node является предком узла с targetNodeId.
|
|
137
|
-
*/
|
|
138
|
-
isNodeAncestorOf(node, targetNodeId) {
|
|
139
|
-
if (node.id === targetNodeId) {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
for (const child of node.children) {
|
|
143
|
-
if (this.isNodeAncestorOf(child, targetNodeId)) {
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Представляет вспомогательную функцию для поиска родительского узла.
|
|
151
|
-
* Возвращает родительский узел для заданного узла или null (корень / родитель не в индексе).
|
|
152
|
-
* Поиск по индексу nodeById по targetNode.parentId — O(1).
|
|
153
|
-
*/
|
|
154
|
-
findParentNode(targetNode) {
|
|
155
|
-
const parentId = targetNode.parentId;
|
|
156
|
-
if (parentId === undefined)
|
|
157
|
-
return null;
|
|
158
|
-
return this.nodeById.get(parentId) ?? null;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { ChessTree } from "../(classes)/chessTree.svelte.js";
|
|
3
|
-
import { createPgnFromTree } from "../(utils)/createPgnFromTree.js";
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
chessTree: ChessTree;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { chessTree }: Props = $props();
|
|
10
|
-
|
|
11
|
-
const getPgn = () => {
|
|
12
|
-
navigator.clipboard.writeText(createPgnFromTree(chessTree.rootNode));
|
|
13
|
-
};
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<button onclick={getPgn}>Импортировать в PGN</button>
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ChessTree } from "../(classes)/chessTree.svelte.js";
|
|
2
|
-
interface Props {
|
|
3
|
-
chessTree: ChessTree;
|
|
4
|
-
}
|
|
5
|
-
declare const ImportToPgn: import("svelte").Component<Props, {}, "">;
|
|
6
|
-
type ImportToPgn = ReturnType<typeof ImportToPgn>;
|
|
7
|
-
export default ImportToPgn;
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
|
|
3
|
-
|
|
4
|
-
import ArrowUpIcon from "@lucide/svelte/icons/arrow-up";
|
|
5
|
-
import CheckCheckIcon from "@lucide/svelte/icons/check-check";
|
|
6
|
-
import FlagIcon from "@lucide/svelte/icons/flag";
|
|
7
|
-
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
|
8
|
-
import { parseComment } from "@connectorvol/chessops/pgn";
|
|
9
|
-
import * as ContextMenu from "../components/ui/context-menu/index.js";
|
|
10
|
-
|
|
11
|
-
import { getGameContext } from "../(utils)/context.js";
|
|
12
|
-
import { transformNag } from "../(utils)/transformNag.js";
|
|
13
|
-
import Move from "./Move.svelte";
|
|
14
|
-
import MoveWithIcon from "./MoveWithIcon.svelte";
|
|
15
|
-
import type { PieceSet } from "@connectorvol/shared";
|
|
16
|
-
import { ACTIVE_MOVE_CLASS } from "../(utils)/scrollToActiveMove.js";
|
|
17
|
-
|
|
18
|
-
const HIGHEST_LEVEL = 1;
|
|
19
|
-
|
|
20
|
-
interface Props {
|
|
21
|
-
chessNode: ChessTreeNode;
|
|
22
|
-
depth: number;
|
|
23
|
-
parentNode: ChessTreeNode | null;
|
|
24
|
-
needSpace: boolean;
|
|
25
|
-
needRenderParentChildrens?: boolean;
|
|
26
|
-
pieceSet: PieceSet;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const {
|
|
30
|
-
chessNode,
|
|
31
|
-
depth,
|
|
32
|
-
parentNode,
|
|
33
|
-
needSpace,
|
|
34
|
-
needRenderParentChildrens = true,
|
|
35
|
-
pieceSet,
|
|
36
|
-
}: Props = $props();
|
|
37
|
-
|
|
38
|
-
const { chessTree, onSelectNode, onDeleteVariant, selectable } = getGameContext();
|
|
39
|
-
|
|
40
|
-
function onmousedown() {
|
|
41
|
-
if (!selectable || !node) return;
|
|
42
|
-
chessTree.currentNode = chessNode;
|
|
43
|
-
|
|
44
|
-
onSelectNode();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const node = $derived(chessNode);
|
|
48
|
-
const isTheSameNode = $derived(chessNode.id === chessTree.currentNode.id);
|
|
49
|
-
const firstCommentParsed = $derived(
|
|
50
|
-
node.data.parsedFirstComment ?? (node.data.comments?.[0] ? parseComment(node.data.comments[0]) : null)
|
|
51
|
-
);
|
|
52
|
-
const firstCommentText = $derived(firstCommentParsed?.text);
|
|
53
|
-
const childMoves = $derived(chessNode.children);
|
|
54
|
-
const isForcedNodeId = $derived(chessNode.id === chessTree.forcedNodeId);
|
|
55
|
-
|
|
56
|
-
const spaceBlockClass = "p-8";
|
|
57
|
-
const spaceInlineBlockClass = "p-2";
|
|
58
|
-
|
|
59
|
-
const isHighestLevel = depth === HIGHEST_LEVEL;
|
|
60
|
-
</script>
|
|
61
|
-
|
|
62
|
-
{#snippet sanMove()}
|
|
63
|
-
{@const selectedOnHighestLevel = isTheSameNode && isHighestLevel}
|
|
64
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
65
|
-
<ContextMenu.Root>
|
|
66
|
-
<ContextMenu.Trigger
|
|
67
|
-
class={{
|
|
68
|
-
"cursor-pointer ": selectable,
|
|
69
|
-
"cursor-default": !selectable,
|
|
70
|
-
[`${spaceInlineBlockClass} text-center`]: isHighestLevel,
|
|
71
|
-
inline: !isHighestLevel,
|
|
72
|
-
[` outline-primary z-10 -outline-offset-2 outline-3 ${ACTIVE_MOVE_CLASS}`]:
|
|
73
|
-
selectedOnHighestLevel,
|
|
74
|
-
"outline-none": !selectedOnHighestLevel,
|
|
75
|
-
}}
|
|
76
|
-
{onmousedown}
|
|
77
|
-
>
|
|
78
|
-
{#if !isHighestLevel && node.data.fullMoves && node.data.ply % 2 === 1}
|
|
79
|
-
{node.data.fullMoves}.
|
|
80
|
-
{/if}
|
|
81
|
-
{#if !isHighestLevel && node.data.fullMoves && node.data.ply % 2 === 0 && parentNode?.children?.[0]?.id !== chessNode.id}
|
|
82
|
-
{node.data.fullMoves - 1}...
|
|
83
|
-
{/if}<span
|
|
84
|
-
class={{
|
|
85
|
-
" outline-primary outline-2": isTheSameNode && !isHighestLevel,
|
|
86
|
-
}}
|
|
87
|
-
>
|
|
88
|
-
<MoveWithIcon
|
|
89
|
-
san={node.data.san}
|
|
90
|
-
ply={node.data.ply}
|
|
91
|
-
{pieceSet}
|
|
92
|
-
/>{node.data.nags?.map(transformNag).join(" ")}
|
|
93
|
-
</span>
|
|
94
|
-
</ContextMenu.Trigger>
|
|
95
|
-
<ContextMenu.Content class="outline-none">
|
|
96
|
-
{#if !isHighestLevel}
|
|
97
|
-
<ContextMenu.Item
|
|
98
|
-
class="gap-4"
|
|
99
|
-
onclick={() => chessTree.makeMainVariant(chessNode)}
|
|
100
|
-
>Сделать вариант главной линией <ContextMenu.Shortcut
|
|
101
|
-
><CheckCheckIcon /></ContextMenu.Shortcut
|
|
102
|
-
></ContextMenu.Item
|
|
103
|
-
>
|
|
104
|
-
{#if depth > HIGHEST_LEVEL + 1}
|
|
105
|
-
<ContextMenu.Item
|
|
106
|
-
class="gap-4"
|
|
107
|
-
onclick={() => chessTree.upPriority(chessNode)}
|
|
108
|
-
>Поднять приоритет варианта <ContextMenu.Shortcut
|
|
109
|
-
><ArrowUpIcon /></ContextMenu.Shortcut
|
|
110
|
-
></ContextMenu.Item
|
|
111
|
-
>
|
|
112
|
-
{/if}
|
|
113
|
-
{:else}
|
|
114
|
-
<ContextMenu.Item
|
|
115
|
-
class="gap-4"
|
|
116
|
-
onclick={() => (chessTree.forcedNodeId = chessNode.parentId ?? null)}
|
|
117
|
-
>Завершить главную линию <ContextMenu.Shortcut
|
|
118
|
-
><FlagIcon /></ContextMenu.Shortcut
|
|
119
|
-
></ContextMenu.Item
|
|
120
|
-
>
|
|
121
|
-
{/if}
|
|
122
|
-
<ContextMenu.Separator />
|
|
123
|
-
<ContextMenu.Item
|
|
124
|
-
class="gap-4 "
|
|
125
|
-
onclick={() => {
|
|
126
|
-
chessTree.deleteVariant(chessNode);
|
|
127
|
-
// Обновляем состояние игры после удаления
|
|
128
|
-
onDeleteVariant();
|
|
129
|
-
}}
|
|
130
|
-
>Удалить вариант <ContextMenu.Shortcut
|
|
131
|
-
><Trash2Icon /></ContextMenu.Shortcut
|
|
132
|
-
></ContextMenu.Item
|
|
133
|
-
>
|
|
134
|
-
</ContextMenu.Content>
|
|
135
|
-
</ContextMenu.Root>
|
|
136
|
-
{/snippet}
|
|
137
|
-
|
|
138
|
-
{#snippet emptyMove()}
|
|
139
|
-
<div class="flex items-center justify-center text-center">...</div>
|
|
140
|
-
{/snippet}
|
|
141
|
-
|
|
142
|
-
{#snippet fullMovesCounter(minus: number = 0)}
|
|
143
|
-
<span
|
|
144
|
-
class={{
|
|
145
|
-
"flex items-center justify-center text-center": isHighestLevel,
|
|
146
|
-
inline: !isHighestLevel,
|
|
147
|
-
}}
|
|
148
|
-
>
|
|
149
|
-
{node.data.fullMoves - minus}{!isHighestLevel && node.data.ply % 2 === 1
|
|
150
|
-
? "..."
|
|
151
|
-
: !isHighestLevel && node.data.ply % 2 === 0
|
|
152
|
-
? "..."
|
|
153
|
-
: ""}
|
|
154
|
-
</span>
|
|
155
|
-
{/snippet}
|
|
156
|
-
|
|
157
|
-
{#snippet comment(text: string)}
|
|
158
|
-
<div
|
|
159
|
-
class={{
|
|
160
|
-
"select-text": true,
|
|
161
|
-
"col-span-3 flex flex-col": isHighestLevel,
|
|
162
|
-
inline: !isHighestLevel,
|
|
163
|
-
[spaceBlockClass]: isHighestLevel,
|
|
164
|
-
}}
|
|
165
|
-
>
|
|
166
|
-
{#each text.split("\n") as line, index}
|
|
167
|
-
{#if index > 0}<br />{/if}{line}
|
|
168
|
-
{/each}
|
|
169
|
-
</div>
|
|
170
|
-
{/snippet}
|
|
171
|
-
|
|
172
|
-
{#if isHighestLevel}
|
|
173
|
-
{#if node.data.ply % 2 === 1}
|
|
174
|
-
{@render fullMovesCounter()}
|
|
175
|
-
{/if}
|
|
176
|
-
|
|
177
|
-
{#if node.parentId}
|
|
178
|
-
{@render sanMove()}
|
|
179
|
-
{/if}
|
|
180
|
-
{#if (isForcedNodeId && node.data.ply % 2 === 1) || (parentNode?.children.length && parentNode?.children.length > 1 && node.data.ply % 2 === 1) || (firstCommentText && node.data.ply % 2 === 1)}
|
|
181
|
-
{@render emptyMove()}
|
|
182
|
-
{/if}
|
|
183
|
-
|
|
184
|
-
{#if firstCommentText}
|
|
185
|
-
{#if node.data.ply % 2 === 1}
|
|
186
|
-
{@render comment(firstCommentText)}
|
|
187
|
-
{#if !needSpace && childMoves?.[0] && !isForcedNodeId}
|
|
188
|
-
{@render fullMovesCounter()}
|
|
189
|
-
{@render emptyMove()}
|
|
190
|
-
{/if}
|
|
191
|
-
{/if}
|
|
192
|
-
|
|
193
|
-
{#if node.data.ply % 2 === 0}
|
|
194
|
-
{@render comment(firstCommentText)}
|
|
195
|
-
{/if}
|
|
196
|
-
{/if}
|
|
197
|
-
{:else}
|
|
198
|
-
{#if node.data.ply % 2 === 0 && chessTree.forcedNodeId === node.parentId && parentNode?.children[0].id === node.id}
|
|
199
|
-
{@render fullMovesCounter(1)}
|
|
200
|
-
{/if}
|
|
201
|
-
|
|
202
|
-
{@render sanMove()}
|
|
203
|
-
{#if firstCommentText}
|
|
204
|
-
{#if node.data.ply % 2 === 1}
|
|
205
|
-
{@render comment(firstCommentText)}
|
|
206
|
-
{#if !needSpace && childMoves?.[0]}
|
|
207
|
-
{@render fullMovesCounter()}
|
|
208
|
-
{/if}
|
|
209
|
-
{/if}
|
|
210
|
-
|
|
211
|
-
{#if node.data.ply % 2 === 0}
|
|
212
|
-
{@render comment(firstCommentText)}
|
|
213
|
-
{/if}
|
|
214
|
-
{/if}
|
|
215
|
-
{/if}
|
|
216
|
-
|
|
217
|
-
{#if parentNode && parentNode?.children.length > 1 && needRenderParentChildrens}
|
|
218
|
-
<div class={{ "col-span-3": isHighestLevel, inline: !isHighestLevel }}>
|
|
219
|
-
{#if !isHighestLevel}
|
|
220
|
-
<span>(</span>
|
|
221
|
-
{/if}
|
|
222
|
-
{#if parentNode?.children.length > 1}
|
|
223
|
-
{#each parentNode?.children as child, index (index)}
|
|
224
|
-
{#if index >= 1}
|
|
225
|
-
<div
|
|
226
|
-
class={{
|
|
227
|
-
inline: !isHighestLevel,
|
|
228
|
-
[spaceBlockClass]: isHighestLevel,
|
|
229
|
-
"tracking-tight": true,
|
|
230
|
-
}}
|
|
231
|
-
>
|
|
232
|
-
<Move
|
|
233
|
-
{pieceSet}
|
|
234
|
-
chessNode={child}
|
|
235
|
-
needSpace={parentNode?.children.length > 1}
|
|
236
|
-
depth={depth + 1}
|
|
237
|
-
needRenderParentChildrens={false}
|
|
238
|
-
{parentNode}
|
|
239
|
-
></Move>
|
|
240
|
-
</div>
|
|
241
|
-
{/if}
|
|
242
|
-
{/each}
|
|
243
|
-
{/if}
|
|
244
|
-
{#if !isHighestLevel}
|
|
245
|
-
<span>)</span>
|
|
246
|
-
{/if}
|
|
247
|
-
</div>
|
|
248
|
-
{/if}
|
|
249
|
-
|
|
250
|
-
{#if isForcedNodeId}
|
|
251
|
-
<div class={{ "col-span-3": isHighestLevel, inline: !isHighestLevel }}>
|
|
252
|
-
<div
|
|
253
|
-
class={{
|
|
254
|
-
inline: !isHighestLevel,
|
|
255
|
-
[spaceBlockClass]: isHighestLevel,
|
|
256
|
-
"tracking-tight": true,
|
|
257
|
-
}}
|
|
258
|
-
>
|
|
259
|
-
<Move
|
|
260
|
-
{pieceSet}
|
|
261
|
-
chessNode={chessNode.children[0]}
|
|
262
|
-
needSpace={chessNode.children.length > 1}
|
|
263
|
-
depth={depth + 1}
|
|
264
|
-
needRenderParentChildrens={true}
|
|
265
|
-
parentNode={chessNode}
|
|
266
|
-
></Move>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
{/if}
|
|
270
|
-
|
|
271
|
-
{#if needSpace && node.data.ply % 2 === 1 && isHighestLevel && !isForcedNodeId}
|
|
272
|
-
{@render fullMovesCounter()}
|
|
273
|
-
{@render emptyMove()}
|
|
274
|
-
{/if}
|
|
275
|
-
{#if childMoves?.[0]}
|
|
276
|
-
{#if !isForcedNodeId}
|
|
277
|
-
<Move
|
|
278
|
-
{pieceSet}
|
|
279
|
-
chessNode={chessNode.children[0]}
|
|
280
|
-
needSpace={childMoves?.length > 1}
|
|
281
|
-
{depth}
|
|
282
|
-
parentNode={chessNode}
|
|
283
|
-
></Move>
|
|
284
|
-
{/if}
|
|
285
|
-
{/if}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
|
|
2
|
-
import Move from "./Move.svelte";
|
|
3
|
-
import type { PieceSet } from "@connectorvol/shared";
|
|
4
|
-
interface Props {
|
|
5
|
-
chessNode: ChessTreeNode;
|
|
6
|
-
depth: number;
|
|
7
|
-
parentNode: ChessTreeNode | null;
|
|
8
|
-
needSpace: boolean;
|
|
9
|
-
needRenderParentChildrens?: boolean;
|
|
10
|
-
pieceSet: PieceSet;
|
|
11
|
-
}
|
|
12
|
-
declare const Move: import("svelte").Component<Props, {}, "">;
|
|
13
|
-
type Move = ReturnType<typeof Move>;
|
|
14
|
-
export default Move;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { PieceSet } from "@connectorvol/shared";
|
|
3
|
-
import type { ParsedSanMove } from "../(utils)/parseSanMove.js";
|
|
4
|
-
|
|
5
|
-
import { PieceType } from "@connectorvol/shared";
|
|
6
|
-
|
|
7
|
-
import { parseSanMove } from "../(utils)/parseSanMove.js";
|
|
8
|
-
import PieceIcon from "./PieceIcon.svelte";
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
/** SAN нотация хода */
|
|
12
|
-
san: string;
|
|
13
|
-
/** Номер полухода */
|
|
14
|
-
ply: number;
|
|
15
|
-
/** Размер иконки в пикселях */
|
|
16
|
-
iconSize?: number;
|
|
17
|
-
/** Набор фигур*/
|
|
18
|
-
pieceSet?: PieceSet;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const { san, ply, iconSize = 16, pieceSet }: Props = $props();
|
|
22
|
-
|
|
23
|
-
const parsedMove: ParsedSanMove = $derived(parseSanMove(san, ply));
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<span class="inline-flex items-baseline">
|
|
27
|
-
{#if parsedMove.isCastling || parsedMove.pieceType === PieceType.PAWN}
|
|
28
|
-
<!-- Для рокировки показываем только текст -->
|
|
29
|
-
<span>{san}</span>
|
|
30
|
-
{:else}
|
|
31
|
-
<!-- Для фигур показываем иконку + взятие + координаты -->
|
|
32
|
-
<PieceIcon
|
|
33
|
-
pieceType={parsedMove.pieceType}
|
|
34
|
-
color={parsedMove.color}
|
|
35
|
-
size={iconSize}
|
|
36
|
-
{pieceSet}
|
|
37
|
-
/>
|
|
38
|
-
{#if parsedMove.isCapture}
|
|
39
|
-
<span>x</span>
|
|
40
|
-
{/if}
|
|
41
|
-
<span>{parsedMove.destination}</span>
|
|
42
|
-
{#if parsedMove.isCheck}
|
|
43
|
-
<span>+</span>
|
|
44
|
-
{:else if parsedMove.isCheckmate}
|
|
45
|
-
<span>#</span>
|
|
46
|
-
{/if}
|
|
47
|
-
{/if}
|
|
48
|
-
</span>
|