gitmaps 1.1.0 → 1.1.1
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/README.md +267 -118
- package/app/[...slug]/page.client.tsx +1 -0
- package/app/[...slug]/page.tsx +6 -0
- package/app/analytics.db +0 -0
- package/app/api/analytics/route.ts +64 -0
- package/app/api/auth/positions/route.ts +95 -33
- package/app/api/build-info/route.ts +19 -0
- package/app/api/chat/route.ts +13 -2
- package/app/api/og-image/route.ts +14 -0
- package/app/api/repo/file-content/route.ts +73 -20
- package/app/api/repo/load/route.test.ts +62 -0
- package/app/api/repo/load/route.ts +41 -1
- package/app/api/repo/pdf-thumb/route.ts +127 -0
- package/app/api/repo/resolve-slug/route.ts +51 -0
- package/app/api/repo/tree/route.ts +188 -104
- package/app/api/version/route.ts +26 -0
- package/app/globals.css +5706 -4938
- package/app/layout.tsx +1279 -490
- package/app/lib/auto-arrange.test.ts +158 -0
- package/app/lib/auto-arrange.ts +147 -0
- package/app/lib/canvas-export.ts +358 -358
- package/app/lib/canvas.ts +625 -564
- package/app/lib/cards.tsx +1361 -916
- package/app/lib/chat.tsx +65 -9
- package/app/lib/code-editor.ts +86 -2
- package/app/lib/context.test.ts +32 -0
- package/app/lib/context.ts +19 -3
- package/app/lib/cursor-sharing.ts +34 -0
- package/app/lib/events.tsx +71 -93
- package/app/lib/export-canvas.ts +287 -0
- package/app/lib/file-card-plugin.ts +148 -148
- package/app/lib/file-modal.tsx +49 -0
- package/app/lib/file-preview.ts +486 -427
- package/app/lib/github-import.test.ts +424 -0
- package/app/lib/initial-route-hydration.test.ts +283 -0
- package/app/lib/initial-route-hydration.ts +202 -0
- package/app/lib/landing-reset.test.ts +99 -0
- package/app/lib/landing-reset.ts +106 -0
- package/app/lib/landing-shell.test.ts +75 -0
- package/app/lib/large-repo-optimization.ts +37 -0
- package/app/lib/layout-snapshots.ts +320 -0
- package/app/lib/loading.test.ts +69 -0
- package/app/lib/loading.tsx +160 -45
- package/app/lib/mount-cleanup.test.ts +52 -0
- package/app/lib/mount-cleanup.ts +34 -0
- package/app/lib/mount-init.test.ts +123 -0
- package/app/lib/mount-init.ts +107 -0
- package/app/lib/mount-lifecycle.test.ts +39 -0
- package/app/lib/mount-lifecycle.ts +12 -0
- package/app/lib/mount-route-wiring.test.ts +87 -0
- package/app/lib/mount-route-wiring.ts +84 -0
- package/app/lib/multi-repo.ts +14 -0
- package/app/lib/onboarding-tutorial.ts +278 -0
- package/app/lib/positions.ts +190 -121
- package/app/lib/recent-commits.test.ts +869 -0
- package/app/lib/recent-commits.ts +227 -0
- package/app/lib/repo-handoff.test.ts +23 -0
- package/app/lib/repo-handoff.ts +16 -0
- package/app/lib/repo-progressive.ts +119 -0
- package/app/lib/repo-select.test.ts +61 -0
- package/app/lib/repo-select.ts +74 -0
- package/app/lib/repo.tsx +1383 -987
- package/app/lib/role.ts +228 -0
- package/app/lib/route-catchall.test.ts +27 -0
- package/app/lib/route-repo-entry.test.ts +95 -0
- package/app/lib/route-repo-entry.ts +36 -0
- package/app/lib/router-contract.test.ts +22 -0
- package/app/lib/router-contract.ts +19 -0
- package/app/lib/shared-layout.test.ts +86 -0
- package/app/lib/shared-layout.ts +82 -0
- package/app/lib/status-bar.test.ts +118 -0
- package/app/lib/status-bar.ts +365 -128
- package/app/lib/sync-controls.test.ts +43 -0
- package/app/lib/sync-controls.tsx +303 -0
- package/app/lib/test-dom.ts +145 -0
- package/app/lib/test-fixtures/router-contract/[...slug]/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/api/health/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/api/version/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/galaxy-canvas/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/page.tsx +3 -0
- package/app/lib/transclusion-smoke.test.ts +163 -0
- package/app/lib/tutorial.ts +301 -0
- package/app/lib/version.ts +93 -0
- package/app/lib/viewport-culling.ts +740 -735
- package/app/lib/virtual-files.ts +456 -0
- package/app/lib/webgl-text.ts +189 -0
- package/app/lib/{galaxydraw-bridge.ts → xydraw-bridge.ts} +485 -482
- package/app/lib/{galaxydraw.test.ts → xydraw.test.ts} +228 -229
- package/app/og-image.png +0 -0
- package/app/page.client.tsx +70 -269
- package/app/page.tsx +15 -16
- package/app/state/machine.js +13 -0
- package/package.json +16 -7
- package/server.ts +10 -0
- package/app/[owner]/[repo]/page.tsx +0 -6
- package/app/[slug]/page.tsx +0 -6
- package/packages/galaxydraw/README.md +0 -296
- package/packages/galaxydraw/banner.png +0 -0
- package/packages/galaxydraw/demo/build-static.ts +0 -100
- package/packages/galaxydraw/demo/client.ts +0 -154
- package/packages/galaxydraw/demo/dist/client.js +0 -8
- package/packages/galaxydraw/demo/index.html +0 -256
- package/packages/galaxydraw/demo/server.ts +0 -96
- package/packages/galaxydraw/dist/index.js +0 -984
- package/packages/galaxydraw/dist/index.js.map +0 -16
- package/packages/galaxydraw/node_modules/.bin/tsc.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsc.exe +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.exe +0 -0
- package/packages/galaxydraw/package.json +0 -49
- package/packages/galaxydraw/perf.test.ts +0 -284
- package/packages/galaxydraw/src/core/cards.ts +0 -435
- package/packages/galaxydraw/src/core/engine.ts +0 -339
- package/packages/galaxydraw/src/core/events.ts +0 -81
- package/packages/galaxydraw/src/core/layout.ts +0 -136
- package/packages/galaxydraw/src/core/minimap.ts +0 -216
- package/packages/galaxydraw/src/core/state.ts +0 -177
- package/packages/galaxydraw/src/core/viewport.ts +0 -106
- package/packages/galaxydraw/src/galaxydraw.css +0 -166
- package/packages/galaxydraw/src/index.ts +0 -40
- package/packages/galaxydraw/tsconfig.json +0 -30
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* FileCardPlugin — bridges
|
|
4
|
-
* the existing file card rendering in cards.tsx.
|
|
5
|
-
*
|
|
6
|
-
* Phase 4 of the GalaxyDraw migration:
|
|
7
|
-
* - Wraps createAllFileCard() and createFileCard() as a CardPlugin
|
|
8
|
-
* - Enables CardManager to handle drag, resize, z-order, selection
|
|
9
|
-
* - Enables ViewportCuller to handle virtualized rendering
|
|
10
|
-
*
|
|
11
|
-
* The plugin doesn't replace cards.tsx — it delegates to it.
|
|
12
|
-
* This allows incremental migration without breaking the existing flow.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { CardPlugin, CardData } from '../../packages/galaxydraw/src/core/cards';
|
|
16
|
-
|
|
17
|
-
// ─── File Card Plugin ─────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
export const FILE_CARD_TYPE = 'file';
|
|
20
|
-
export const DIFF_CARD_TYPE = 'diff';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Plugin for rendering source code file cards on the canvas.
|
|
24
|
-
* Used by the "working tree" (all files) view.
|
|
25
|
-
*
|
|
26
|
-
* The render() method receives a CardData where:
|
|
27
|
-
* - meta.file: the file data object (path, name, content, etc.)
|
|
28
|
-
* - meta.ctx: the CanvasContext for interaction setup
|
|
29
|
-
* - meta.savedSize: optional saved dimensions
|
|
30
|
-
*/
|
|
31
|
-
export function createFileCardPlugin(): CardPlugin {
|
|
32
|
-
return {
|
|
33
|
-
type: FILE_CARD_TYPE,
|
|
34
|
-
|
|
35
|
-
render(data: CardData): HTMLElement {
|
|
36
|
-
const { file, ctx, savedSize } = data.meta || {};
|
|
37
|
-
if (!file || !ctx) {
|
|
38
|
-
// Fallback: empty placeholder card
|
|
39
|
-
const el = document.createElement('div');
|
|
40
|
-
el.className = 'file-card';
|
|
41
|
-
el.textContent = 'Missing file data';
|
|
42
|
-
return el;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Dynamically import to avoid circular dependencies
|
|
46
|
-
// The actual rendering is still in cards.tsx
|
|
47
|
-
// skipInteraction=true: CardManager handles drag/resize/z-order
|
|
48
|
-
const { createAllFileCard } = require('./cards');
|
|
49
|
-
const card = createAllFileCard(ctx, file, data.x, data.y, savedSize, true);
|
|
50
|
-
|
|
51
|
-
const { isDirCollapsed } = require('./card-groups');
|
|
52
|
-
const fileDir = file.path.includes('/') ? file.path.substring(0, file.path.lastIndexOf('/')) : '.';
|
|
53
|
-
if (isDirCollapsed(fileDir)) {
|
|
54
|
-
card.style.display = 'none';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return card;
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
onResize(card: HTMLElement, width: number, height: number) {
|
|
61
|
-
// Dispatch the resize event that cards.tsx already listens for
|
|
62
|
-
const path = card.dataset.path;
|
|
63
|
-
if (path) {
|
|
64
|
-
card.dispatchEvent(new CustomEvent('card-resized', {
|
|
65
|
-
detail: { path, width, height },
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
onDestroy(card: HTMLElement) {
|
|
71
|
-
// Clean up any scroll timers or event listeners
|
|
72
|
-
// The card DOM is removed by CardManager, but we should
|
|
73
|
-
// clean up any overlays or attached state
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
consumesWheel(target: HTMLElement): boolean {
|
|
77
|
-
// File card bodies are scrollable — pass wheel events through
|
|
78
|
-
return !!target.closest('.file-card-body');
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
consumesMouse(target: HTMLElement): boolean {
|
|
82
|
-
// Buttons, links, and interactive elements within cards
|
|
83
|
-
// should receive mouse events directly
|
|
84
|
-
return !!(
|
|
85
|
-
target.closest('button') ||
|
|
86
|
-
target.closest('a') ||
|
|
87
|
-
target.closest('.connect-btn') ||
|
|
88
|
-
target.closest('.line-num') ||
|
|
89
|
-
target.closest('.diff-hunk-header')
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Plugin for rendering commit diff cards on the canvas.
|
|
97
|
-
* Used by the "commit diff" view.
|
|
98
|
-
*/
|
|
99
|
-
export function createDiffCardPlugin(): CardPlugin {
|
|
100
|
-
return {
|
|
101
|
-
type: DIFF_CARD_TYPE,
|
|
102
|
-
|
|
103
|
-
render(data: CardData): HTMLElement {
|
|
104
|
-
const { file, ctx, commitHash } = data.meta || {};
|
|
105
|
-
if (!file || !ctx) {
|
|
106
|
-
const el = document.createElement('div');
|
|
107
|
-
el.className = 'file-card';
|
|
108
|
-
el.textContent = 'Missing diff data';
|
|
109
|
-
return el;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const { createFileCard } = require('./cards');
|
|
113
|
-
const card = createFileCard(ctx, file, data.x, data.y, commitHash, true);
|
|
114
|
-
|
|
115
|
-
const { isDirCollapsed } = require('./card-groups');
|
|
116
|
-
const fileDir = file.path.includes('/') ? file.path.substring(0, file.path.lastIndexOf('/')) : '.';
|
|
117
|
-
if (isDirCollapsed(fileDir)) {
|
|
118
|
-
card.style.display = 'none';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return card;
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
onResize(card: HTMLElement, width: number, height: number) {
|
|
125
|
-
const path = card.dataset.path;
|
|
126
|
-
if (path) {
|
|
127
|
-
card.dispatchEvent(new CustomEvent('card-resized', {
|
|
128
|
-
detail: { path, width, height },
|
|
129
|
-
}));
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
onDestroy() { },
|
|
134
|
-
|
|
135
|
-
consumesWheel(target: HTMLElement): boolean {
|
|
136
|
-
return !!target.closest('.file-card-body');
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
consumesMouse(target: HTMLElement): boolean {
|
|
140
|
-
return !!(
|
|
141
|
-
target.closest('button') ||
|
|
142
|
-
target.closest('a') ||
|
|
143
|
-
target.closest('.connect-btn') ||
|
|
144
|
-
target.closest('.diff-hunk-header')
|
|
145
|
-
);
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
}
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* FileCardPlugin — bridges xydraw's CardPlugin interface with
|
|
4
|
+
* the existing file card rendering in cards.tsx.
|
|
5
|
+
*
|
|
6
|
+
* Phase 4 of the GalaxyDraw migration:
|
|
7
|
+
* - Wraps createAllFileCard() and createFileCard() as a CardPlugin
|
|
8
|
+
* - Enables CardManager to handle drag, resize, z-order, selection
|
|
9
|
+
* - Enables ViewportCuller to handle virtualized rendering
|
|
10
|
+
*
|
|
11
|
+
* The plugin doesn't replace cards.tsx — it delegates to it.
|
|
12
|
+
* This allows incremental migration without breaking the existing flow.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { CardPlugin, CardData } from '../../packages/galaxydraw/src/core/cards';
|
|
16
|
+
|
|
17
|
+
// ─── File Card Plugin ─────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
export const FILE_CARD_TYPE = 'file';
|
|
20
|
+
export const DIFF_CARD_TYPE = 'diff';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Plugin for rendering source code file cards on the canvas.
|
|
24
|
+
* Used by the "working tree" (all files) view.
|
|
25
|
+
*
|
|
26
|
+
* The render() method receives a CardData where:
|
|
27
|
+
* - meta.file: the file data object (path, name, content, etc.)
|
|
28
|
+
* - meta.ctx: the CanvasContext for interaction setup
|
|
29
|
+
* - meta.savedSize: optional saved dimensions
|
|
30
|
+
*/
|
|
31
|
+
export function createFileCardPlugin(): CardPlugin {
|
|
32
|
+
return {
|
|
33
|
+
type: FILE_CARD_TYPE,
|
|
34
|
+
|
|
35
|
+
render(data: CardData): HTMLElement {
|
|
36
|
+
const { file, ctx, savedSize } = data.meta || {};
|
|
37
|
+
if (!file || !ctx) {
|
|
38
|
+
// Fallback: empty placeholder card
|
|
39
|
+
const el = document.createElement('div');
|
|
40
|
+
el.className = 'file-card';
|
|
41
|
+
el.textContent = 'Missing file data';
|
|
42
|
+
return el;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Dynamically import to avoid circular dependencies
|
|
46
|
+
// The actual rendering is still in cards.tsx
|
|
47
|
+
// skipInteraction=true: CardManager handles drag/resize/z-order
|
|
48
|
+
const { createAllFileCard } = require('./cards');
|
|
49
|
+
const card = createAllFileCard(ctx, file, data.x, data.y, savedSize, true);
|
|
50
|
+
|
|
51
|
+
const { isDirCollapsed } = require('./card-groups');
|
|
52
|
+
const fileDir = file.path.includes('/') ? file.path.substring(0, file.path.lastIndexOf('/')) : '.';
|
|
53
|
+
if (isDirCollapsed(fileDir)) {
|
|
54
|
+
card.style.display = 'none';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return card;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
onResize(card: HTMLElement, width: number, height: number) {
|
|
61
|
+
// Dispatch the resize event that cards.tsx already listens for
|
|
62
|
+
const path = card.dataset.path;
|
|
63
|
+
if (path) {
|
|
64
|
+
card.dispatchEvent(new CustomEvent('card-resized', {
|
|
65
|
+
detail: { path, width, height },
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
onDestroy(card: HTMLElement) {
|
|
71
|
+
// Clean up any scroll timers or event listeners
|
|
72
|
+
// The card DOM is removed by CardManager, but we should
|
|
73
|
+
// clean up any overlays or attached state
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
consumesWheel(target: HTMLElement): boolean {
|
|
77
|
+
// File card bodies are scrollable — pass wheel events through
|
|
78
|
+
return !!target.closest('.file-card-body');
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
consumesMouse(target: HTMLElement): boolean {
|
|
82
|
+
// Buttons, links, and interactive elements within cards
|
|
83
|
+
// should receive mouse events directly
|
|
84
|
+
return !!(
|
|
85
|
+
target.closest('button') ||
|
|
86
|
+
target.closest('a') ||
|
|
87
|
+
target.closest('.connect-btn') ||
|
|
88
|
+
target.closest('.line-num') ||
|
|
89
|
+
target.closest('.diff-hunk-header')
|
|
90
|
+
);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Plugin for rendering commit diff cards on the canvas.
|
|
97
|
+
* Used by the "commit diff" view.
|
|
98
|
+
*/
|
|
99
|
+
export function createDiffCardPlugin(): CardPlugin {
|
|
100
|
+
return {
|
|
101
|
+
type: DIFF_CARD_TYPE,
|
|
102
|
+
|
|
103
|
+
render(data: CardData): HTMLElement {
|
|
104
|
+
const { file, ctx, commitHash } = data.meta || {};
|
|
105
|
+
if (!file || !ctx) {
|
|
106
|
+
const el = document.createElement('div');
|
|
107
|
+
el.className = 'file-card';
|
|
108
|
+
el.textContent = 'Missing diff data';
|
|
109
|
+
return el;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const { createFileCard } = require('./cards');
|
|
113
|
+
const card = createFileCard(ctx, file, data.x, data.y, commitHash, true);
|
|
114
|
+
|
|
115
|
+
const { isDirCollapsed } = require('./card-groups');
|
|
116
|
+
const fileDir = file.path.includes('/') ? file.path.substring(0, file.path.lastIndexOf('/')) : '.';
|
|
117
|
+
if (isDirCollapsed(fileDir)) {
|
|
118
|
+
card.style.display = 'none';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return card;
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
onResize(card: HTMLElement, width: number, height: number) {
|
|
125
|
+
const path = card.dataset.path;
|
|
126
|
+
if (path) {
|
|
127
|
+
card.dispatchEvent(new CustomEvent('card-resized', {
|
|
128
|
+
detail: { path, width, height },
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
onDestroy() { },
|
|
134
|
+
|
|
135
|
+
consumesWheel(target: HTMLElement): boolean {
|
|
136
|
+
return !!target.closest('.file-card-body');
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
consumesMouse(target: HTMLElement): boolean {
|
|
140
|
+
return !!(
|
|
141
|
+
target.closest('button') ||
|
|
142
|
+
target.closest('a') ||
|
|
143
|
+
target.closest('.connect-btn') ||
|
|
144
|
+
target.closest('.diff-hunk-header')
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
package/app/lib/file-modal.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import { renderBreadcrumbs } from './breadcrumbs';
|
|
|
14
14
|
import { renderSymbolOutline } from './symbol-outline';
|
|
15
15
|
import { loadDraft, clearDraft, startAutoSave, stopAutoSave } from './auto-save';
|
|
16
16
|
import { isEditingAllowed, getProductionEditorNotice } from './production-mode';
|
|
17
|
+
import { onEditorSync, broadcastEditorSync, type EditorSyncData } from './cursor-sharing';
|
|
17
18
|
|
|
18
19
|
// ─── File expand modal ──────────────────────────────────
|
|
19
20
|
export function openFileModal(ctx: CanvasContext, file: any, initialView?: string, initialLine?: number) {
|
|
@@ -76,6 +77,41 @@ export function openFileModal(ctx: CanvasContext, file: any, initialView?: strin
|
|
|
76
77
|
let onNavKey: ((e: KeyboardEvent) => void) | null = null;
|
|
77
78
|
let originalContent = file.content || '';
|
|
78
79
|
|
|
80
|
+
let editorSyncCleanup: (() => void) | null = null;
|
|
81
|
+
const remoteCursorsMap = new Map<string, EditorSyncData>();
|
|
82
|
+
let typingTimeouts = new Map<string, any>();
|
|
83
|
+
|
|
84
|
+
editorSyncCleanup = onEditorSync(data => {
|
|
85
|
+
// use Active Tab's path instead of initial file path incase it switched
|
|
86
|
+
const activeTab = getActiveTab();
|
|
87
|
+
const activePath = activeTab ? activeTab.path : file.path;
|
|
88
|
+
|
|
89
|
+
if (data.file === activePath && currentView === 'edit') {
|
|
90
|
+
remoteCursorsMap.set(data.peerId, data);
|
|
91
|
+
|
|
92
|
+
if (data.typing) {
|
|
93
|
+
if (typingTimeouts.has(data.peerId)) clearTimeout(typingTimeouts.get(data.peerId));
|
|
94
|
+
typingTimeouts.set(data.peerId, setTimeout(() => {
|
|
95
|
+
const cursor = remoteCursorsMap.get(data.peerId);
|
|
96
|
+
if (cursor) {
|
|
97
|
+
cursor.typing = false;
|
|
98
|
+
updateRemoteCursors();
|
|
99
|
+
}
|
|
100
|
+
}, 1000));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
updateRemoteCursors();
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
function updateRemoteCursors() {
|
|
108
|
+
const editContainer = document.getElementById('modalEditContainer');
|
|
109
|
+
const editor = (editContainer as any)?._cmEditor;
|
|
110
|
+
if (editor) {
|
|
111
|
+
editor.setRemoteCursors(Array.from(remoteCursorsMap.values()));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
79
115
|
function hasUnsavedChanges(): boolean {
|
|
80
116
|
if (currentView !== 'edit') return false;
|
|
81
117
|
const editContainer = document.getElementById('modalEditContainer');
|
|
@@ -97,6 +133,11 @@ export function openFileModal(ctx: CanvasContext, file: any, initialView?: strin
|
|
|
97
133
|
document.removeEventListener('keydown', onEsc);
|
|
98
134
|
if (onNavKey) document.removeEventListener('keydown', onNavKey);
|
|
99
135
|
|
|
136
|
+
if (editorSyncCleanup) {
|
|
137
|
+
editorSyncCleanup();
|
|
138
|
+
editorSyncCleanup = null;
|
|
139
|
+
}
|
|
140
|
+
|
|
100
141
|
// Stop auto-save timer
|
|
101
142
|
stopAutoSave();
|
|
102
143
|
|
|
@@ -445,12 +486,20 @@ export function openFileModal(ctx: CanvasContext, file: any, initialView?: strin
|
|
|
445
486
|
onCursorMove: (line, col) => {
|
|
446
487
|
if (lineInfo) lineInfo.textContent = `Line ${line}, Col ${col}`;
|
|
447
488
|
},
|
|
489
|
+
onSelectionChange: (selections, isTyping) => {
|
|
490
|
+
const activeTab = getActiveTab();
|
|
491
|
+
const activePath = activeTab ? activeTab.path : file.path;
|
|
492
|
+
broadcastEditorSync(activePath, selections, isTyping);
|
|
493
|
+
}
|
|
448
494
|
});
|
|
449
495
|
|
|
450
496
|
// Store editor reference for content access
|
|
451
497
|
(editContainer as any)._cmEditor = editor;
|
|
452
498
|
editor.focus();
|
|
453
499
|
|
|
500
|
+
// Reapply any known remote cursors for this new view
|
|
501
|
+
updateRemoteCursors();
|
|
502
|
+
|
|
454
503
|
// Scroll to initial line if provided (preserves canvas view position)
|
|
455
504
|
if (initialLine && initialLine > 1) {
|
|
456
505
|
requestAnimationFrame(() => {
|