@hugobatist/smartcode 0.1.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/LICENSE +21 -0
- package/README.md +292 -0
- package/dist/cli.js +4324 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +1167 -0
- package/dist/index.js.map +1 -0
- package/dist/static/annotations-panel.js +133 -0
- package/dist/static/annotations-svg.js +108 -0
- package/dist/static/annotations.css +367 -0
- package/dist/static/annotations.js +367 -0
- package/dist/static/app-init.js +497 -0
- package/dist/static/breakpoints.css +69 -0
- package/dist/static/breakpoints.js +197 -0
- package/dist/static/clipboard.js +94 -0
- package/dist/static/collapse-ui.js +325 -0
- package/dist/static/command-history.js +89 -0
- package/dist/static/context-menu.js +334 -0
- package/dist/static/custom-renderer.js +201 -0
- package/dist/static/dagre-layout.js +291 -0
- package/dist/static/diagram-dom.js +241 -0
- package/dist/static/diagram-editor.js +368 -0
- package/dist/static/editor-panel.js +107 -0
- package/dist/static/editor-popovers.js +187 -0
- package/dist/static/event-bus.js +57 -0
- package/dist/static/export.js +181 -0
- package/dist/static/file-tree.js +470 -0
- package/dist/static/ghost-paths.js +397 -0
- package/dist/static/heatmap.css +116 -0
- package/dist/static/heatmap.js +308 -0
- package/dist/static/icons.js +66 -0
- package/dist/static/inline-edit.js +294 -0
- package/dist/static/interaction-state.js +155 -0
- package/dist/static/interaction-tracker.js +93 -0
- package/dist/static/live.html +239 -0
- package/dist/static/main-layout.css +220 -0
- package/dist/static/main.css +334 -0
- package/dist/static/mcp-sessions.js +202 -0
- package/dist/static/modal.css +109 -0
- package/dist/static/modal.js +171 -0
- package/dist/static/node-drag.js +293 -0
- package/dist/static/pan-zoom.js +199 -0
- package/dist/static/renderer.js +280 -0
- package/dist/static/search.css +103 -0
- package/dist/static/search.js +304 -0
- package/dist/static/selection.js +353 -0
- package/dist/static/session-player.css +137 -0
- package/dist/static/session-player.js +411 -0
- package/dist/static/sidebar.css +248 -0
- package/dist/static/svg-renderer.js +313 -0
- package/dist/static/svg-shapes.js +218 -0
- package/dist/static/tokens.css +76 -0
- package/dist/static/vendor/dagre-bundle.js +43 -0
- package/dist/static/vendor/dagre.min.js +3 -0
- package/dist/static/vendor/graphlib.min.js +2 -0
- package/dist/static/viewport-transform.js +107 -0
- package/dist/static/workspace-switcher.js +202 -0
- package/dist/static/ws-client.js +71 -0
- package/dist/static/ws-handler.js +125 -0
- package/package.json +74 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Interaction State Machine -- FSM for coordinating all UI interaction modes.
|
|
3
|
+
* Prevents conflicting interactions by defining valid states and transitions.
|
|
4
|
+
*
|
|
5
|
+
* Dependencies: event-bus.js (SmartCodeEventBus)
|
|
6
|
+
*
|
|
7
|
+
* States:
|
|
8
|
+
* idle - Default. Click selects, right-click opens menu, double-click edits, drag pans.
|
|
9
|
+
* selected - A node/edge is selected. Click elsewhere deselects, Delete removes.
|
|
10
|
+
* editing - Inline edit overlay is open. All other interactions blocked.
|
|
11
|
+
* context-menu - Context menu is open. Click outside or Escape closes.
|
|
12
|
+
* flagging - Flag mode is active (existing SmartCodeAnnotations behavior).
|
|
13
|
+
* add-node - Add node mode (existing MmdEditor behavior).
|
|
14
|
+
* add-edge - Add edge mode (existing MmdEditor behavior).
|
|
15
|
+
* panning - Active drag-pan in progress.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* SmartCodeInteraction.getState(); // 'idle'
|
|
19
|
+
* SmartCodeInteraction.transition('click_node', { id: 'A' }); // true if valid
|
|
20
|
+
* SmartCodeInteraction.getSelection(); // { id: 'A', type: 'node' }
|
|
21
|
+
* SmartCodeInteraction.isIdle(); // false
|
|
22
|
+
* SmartCodeInteraction.isBlocking(); // false
|
|
23
|
+
*/
|
|
24
|
+
(function() {
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
// ── Transition Table ──
|
|
28
|
+
var TRANSITIONS = {
|
|
29
|
+
idle: { click_node: 'selected', click_edge: 'selected', right_click: 'context-menu', dbl_click: 'editing', flag_toggle: 'flagging', add_node_toggle: 'add-node', add_edge_toggle: 'add-edge', pan_start: 'panning' },
|
|
30
|
+
selected: { click_empty: 'idle', click_node: 'selected', click_edge: 'selected', right_click: 'context-menu', dbl_click: 'editing', escape: 'idle', delete_node: 'idle', flag_toggle: 'flagging', pan_start: 'panning', drag_start: 'dragging' },
|
|
31
|
+
editing: { confirm: 'idle', cancel: 'idle' },
|
|
32
|
+
'context-menu': { action: 'idle', close: 'idle', edit_action: 'editing' },
|
|
33
|
+
flagging: { flag_toggle: 'idle', escape: 'idle' },
|
|
34
|
+
'add-node': { add_node_toggle: 'idle', escape: 'idle' },
|
|
35
|
+
'add-edge': { add_edge_toggle: 'idle', escape: 'idle' },
|
|
36
|
+
panning: { pan_end: 'idle', pan_end_selected: 'selected' },
|
|
37
|
+
dragging: { drag_end: 'selected', escape: 'idle' },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// ── Internal State ──
|
|
41
|
+
var currentState = 'idle';
|
|
42
|
+
var selectedId = null;
|
|
43
|
+
var selectedType = null; // 'node' | 'edge' | 'subgraph'
|
|
44
|
+
|
|
45
|
+
// ── Core Functions ──
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Attempt a state transition.
|
|
49
|
+
* @param {string} event - The event name (e.g. 'click_node', 'escape')
|
|
50
|
+
* @param {*} [payload] - Optional data passed to event listeners
|
|
51
|
+
* @returns {boolean} true if transition happened, false if invalid
|
|
52
|
+
*/
|
|
53
|
+
function transition(event, payload) {
|
|
54
|
+
var stateConfig = TRANSITIONS[currentState];
|
|
55
|
+
if (!stateConfig || !stateConfig[event]) return false;
|
|
56
|
+
|
|
57
|
+
var from = currentState;
|
|
58
|
+
var to = stateConfig[event];
|
|
59
|
+
currentState = to;
|
|
60
|
+
|
|
61
|
+
// Emit transition event on the event bus
|
|
62
|
+
if (window.SmartCodeEventBus) {
|
|
63
|
+
SmartCodeEventBus.emit('interaction:transition', {
|
|
64
|
+
from: from,
|
|
65
|
+
to: to,
|
|
66
|
+
event: event,
|
|
67
|
+
payload: payload
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns the current FSM state string.
|
|
76
|
+
* @returns {string}
|
|
77
|
+
*/
|
|
78
|
+
function getState() {
|
|
79
|
+
return currentState;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns the current selection info.
|
|
84
|
+
* @returns {{ id: string|null, type: string|null }}
|
|
85
|
+
*/
|
|
86
|
+
function getSelection() {
|
|
87
|
+
return { id: selectedId, type: selectedType };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set the selected element (called by selection.js when selecting).
|
|
92
|
+
* @param {string} id - The selected element ID
|
|
93
|
+
* @param {string} type - 'node' | 'edge' | 'subgraph'
|
|
94
|
+
*/
|
|
95
|
+
function select(id, type) {
|
|
96
|
+
selectedId = id;
|
|
97
|
+
selectedType = type;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Clear the current selection.
|
|
102
|
+
*/
|
|
103
|
+
function clearSelection() {
|
|
104
|
+
selectedId = null;
|
|
105
|
+
selectedType = null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Force-set the FSM state (for existing mode toggles in annotations/editor
|
|
110
|
+
* that need to sync their state with the FSM).
|
|
111
|
+
* @param {string} state - One of the 8 valid states
|
|
112
|
+
*/
|
|
113
|
+
function forceState(state) {
|
|
114
|
+
if (TRANSITIONS[state] !== undefined) {
|
|
115
|
+
var from = currentState;
|
|
116
|
+
currentState = state;
|
|
117
|
+
if (window.SmartCodeEventBus) {
|
|
118
|
+
SmartCodeEventBus.emit('interaction:transition', {
|
|
119
|
+
from: from,
|
|
120
|
+
to: state,
|
|
121
|
+
event: 'force',
|
|
122
|
+
payload: null
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Shorthand: is the FSM in idle state?
|
|
130
|
+
* @returns {boolean}
|
|
131
|
+
*/
|
|
132
|
+
function isIdle() {
|
|
133
|
+
return currentState === 'idle';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns true if in a blocking state (editing or context-menu).
|
|
138
|
+
* @returns {boolean}
|
|
139
|
+
*/
|
|
140
|
+
function isBlocking() {
|
|
141
|
+
return currentState === 'editing' || currentState === 'context-menu';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Public API ──
|
|
145
|
+
window.SmartCodeInteraction = {
|
|
146
|
+
getState: getState,
|
|
147
|
+
getSelection: getSelection,
|
|
148
|
+
transition: transition,
|
|
149
|
+
select: select,
|
|
150
|
+
clearSelection: clearSelection,
|
|
151
|
+
forceState: forceState,
|
|
152
|
+
isIdle: isIdle,
|
|
153
|
+
isBlocking: isBlocking,
|
|
154
|
+
};
|
|
155
|
+
})();
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Interaction Tracker -- batches node clicks and flushes to server.
|
|
3
|
+
* Provides automatic frequency data for the heatmap without MCP session setup.
|
|
4
|
+
*
|
|
5
|
+
* Dependencies: file-tree.js (SmartCodeFileTree), event-bus.js (SmartCodeEventBus)
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* SmartCodeInteractionTracker.init();
|
|
9
|
+
* SmartCodeInteractionTracker.trackClick('nodeId');
|
|
10
|
+
* SmartCodeInteractionTracker.flush(); // manual flush
|
|
11
|
+
* SmartCodeInteractionTracker.resetForFile(); // on file switch
|
|
12
|
+
*/
|
|
13
|
+
(function() {
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
var FLUSH_INTERVAL = 2000; // 2 seconds
|
|
17
|
+
|
|
18
|
+
var pendingCounts = {};
|
|
19
|
+
var flushTimer = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Track a click on a node. Increments the pending count.
|
|
23
|
+
* @param {string} nodeId
|
|
24
|
+
*/
|
|
25
|
+
function trackClick(nodeId) {
|
|
26
|
+
if (!nodeId || typeof nodeId !== 'string') return;
|
|
27
|
+
pendingCounts[nodeId] = (pendingCounts[nodeId] || 0) + 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Flush pending counts to the server via POST.
|
|
32
|
+
* Resets pendingCounts after sending.
|
|
33
|
+
*/
|
|
34
|
+
function flush() {
|
|
35
|
+
var keys = Object.keys(pendingCounts);
|
|
36
|
+
if (keys.length === 0) return;
|
|
37
|
+
|
|
38
|
+
var currentFile = window.SmartCodeFileTree ? SmartCodeFileTree.getCurrentFile() : '';
|
|
39
|
+
if (!currentFile) {
|
|
40
|
+
pendingCounts = {};
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var counts = pendingCounts;
|
|
45
|
+
pendingCounts = {};
|
|
46
|
+
|
|
47
|
+
var baseUrl = window.SmartCodeBaseUrl || '';
|
|
48
|
+
var url = baseUrl + '/api/heatmap/' + encodeURIComponent(currentFile) + '/increment';
|
|
49
|
+
|
|
50
|
+
fetch(url, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: { 'Content-Type': 'application/json' },
|
|
53
|
+
body: JSON.stringify({ counts: counts }),
|
|
54
|
+
}).catch(function() {
|
|
55
|
+
// Re-add counts on failure so they're retried on next flush
|
|
56
|
+
for (var k in counts) {
|
|
57
|
+
pendingCounts[k] = (pendingCounts[k] || 0) + counts[k];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Reset for file switch: flush current counts, clear pending.
|
|
64
|
+
*/
|
|
65
|
+
function resetForFile() {
|
|
66
|
+
flush();
|
|
67
|
+
pendingCounts = {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Start the periodic flush timer.
|
|
72
|
+
*/
|
|
73
|
+
function startFlushing() {
|
|
74
|
+
if (flushTimer) clearInterval(flushTimer);
|
|
75
|
+
flushTimer = setInterval(flush, FLUSH_INTERVAL);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Initialize the interaction tracker.
|
|
80
|
+
* Starts the flush timer.
|
|
81
|
+
*/
|
|
82
|
+
function init() {
|
|
83
|
+
startFlushing();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Public API ──
|
|
87
|
+
window.SmartCodeInteractionTracker = {
|
|
88
|
+
init: init,
|
|
89
|
+
trackClick: trackClick,
|
|
90
|
+
flush: flush,
|
|
91
|
+
resetForFile: resetForFile,
|
|
92
|
+
};
|
|
93
|
+
})();
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>SmartCode - Live Diagrams</title>
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%233b82f6'/><text x='16' y='22' text-anchor='middle' fill='white' font-family='sans-serif' font-weight='700' font-size='18'>S</text></svg>">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
+
<script src="vendor/dagre-bundle.js"></script>
|
|
11
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11.12.2/dist/mermaid.min.js"></script>
|
|
12
|
+
<link rel="stylesheet" href="tokens.css">
|
|
13
|
+
<link rel="stylesheet" href="main-layout.css">
|
|
14
|
+
<link rel="stylesheet" href="main.css">
|
|
15
|
+
<link rel="stylesheet" href="sidebar.css">
|
|
16
|
+
<link rel="stylesheet" href="annotations.css">
|
|
17
|
+
<link rel="stylesheet" href="breakpoints.css">
|
|
18
|
+
<link rel="stylesheet" href="heatmap.css">
|
|
19
|
+
<link rel="stylesheet" href="session-player.css">
|
|
20
|
+
<link rel="stylesheet" href="search.css">
|
|
21
|
+
<link rel="stylesheet" href="modal.css">
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
|
|
25
|
+
<!-- Top Bar -->
|
|
26
|
+
<div class="topbar">
|
|
27
|
+
<!-- Group 1: Navigation -->
|
|
28
|
+
<div class="toolbar-group">
|
|
29
|
+
<span class="logo">SmartCode</span>
|
|
30
|
+
<span id="workspaceSwitcher" class="workspace-switcher"></span>
|
|
31
|
+
<span class="file-name" id="currentFileName">Action Plan</span>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="toolbar-separator"></div>
|
|
35
|
+
|
|
36
|
+
<!-- Group 2: View -->
|
|
37
|
+
<div class="toolbar-group">
|
|
38
|
+
<button class="toolbar-btn" id="toggleSidebar" title="Toggle file explorer (Ctrl+B)"><span class="toolbar-icon" data-icon="sidebar"></span>Files</button>
|
|
39
|
+
<button class="toolbar-btn" id="toggleEditor" title="Toggle code editor (Ctrl+E)"><span class="toolbar-icon" data-icon="editor"></span>Editor</button>
|
|
40
|
+
<button class="toolbar-btn" id="toggleAutoSync" title="Toggle auto-sync with file changes"><span class="toolbar-icon" data-icon="sync"></span>Sync</button>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="toolbar-separator"></div>
|
|
44
|
+
|
|
45
|
+
<!-- Group 3: Edit -->
|
|
46
|
+
<div class="toolbar-group">
|
|
47
|
+
<button class="toolbar-btn toolbar-btn--primary" id="btnAddNode" onclick="MmdEditor.toggleAddNode()" title="Add node (N)"><span class="toolbar-icon" data-icon="node"></span>Node</button>
|
|
48
|
+
<button class="toolbar-btn toolbar-btn--primary" id="btnAddEdge" onclick="MmdEditor.toggleAddEdge()" title="Add edge (A)"><span class="toolbar-icon" data-icon="arrowRight"></span>Edge</button>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div class="toolbar-separator"></div>
|
|
52
|
+
|
|
53
|
+
<!-- Group 4: Inspect -->
|
|
54
|
+
<div class="toolbar-group">
|
|
55
|
+
<button class="toolbar-btn" id="btnFlags" onclick="SmartCodeAnnotations.toggleFlagMode()" title="Toggle flag mode (F)"><span class="toolbar-icon" data-icon="flag"></span>Flags <span class="toolbar-badge" id="flagCountBadge" data-count="0"></span></button>
|
|
56
|
+
<button class="toolbar-btn" id="toggleFlagPanel" onclick="SmartCodeAnnotations.togglePanel()" title="Toggle flags panel"><span class="toolbar-icon" data-icon="eye"></span>Panel</button>
|
|
57
|
+
<button class="toolbar-btn" id="btnGhostPaths" onclick="SmartCodeGhostPaths.toggle()" title="Toggle ghost paths"><span class="toolbar-icon" data-icon="ghost"></span>Ghost <span class="toolbar-badge" id="ghostCountBadge" data-count="0"></span></button>
|
|
58
|
+
<button class="toolbar-btn" id="btnHeatmap" onclick="SmartCodeHeatmap.toggle()" title="Toggle heatmap (H)"><span class="toolbar-icon" data-icon="heatmap"></span>Heat</button>
|
|
59
|
+
<span style="position:relative">
|
|
60
|
+
<button class="toolbar-btn" id="btnSessions" title="Session recordings"><span class="toolbar-icon" data-icon="play"></span>Recordings</button>
|
|
61
|
+
<div class="session-dropdown hidden" id="sessionDropdown"><div id="sessionList"></div></div>
|
|
62
|
+
</span>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div class="toolbar-spacer"></div>
|
|
66
|
+
|
|
67
|
+
<!-- Group 5: Export + Status (right-aligned) -->
|
|
68
|
+
<div class="toolbar-group">
|
|
69
|
+
<button class="toolbar-btn" onclick="saveCurrentFile()" title="Save file (Ctrl+S)"><span class="toolbar-icon" data-icon="save"></span>Save</button>
|
|
70
|
+
<button class="toolbar-btn" onclick="exportSVG()" title="Export as SVG"><span class="toolbar-icon" data-icon="download"></span>SVG</button>
|
|
71
|
+
<button class="toolbar-btn" onclick="exportPNG()" title="Export as PNG"><span class="toolbar-icon" data-icon="image"></span>PNG</button>
|
|
72
|
+
<button class="toolbar-btn toolbar-btn--ghost" onclick="showHelp()" title="Help & shortcuts (?)"><span class="toolbar-icon" data-icon="help"></span>?</button>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="status">
|
|
76
|
+
<div class="status-dot" id="statusDot"></div>
|
|
77
|
+
<span id="statusText">Watching...</span>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<!-- Main -->
|
|
82
|
+
<div class="main">
|
|
83
|
+
<!-- Sidebar -->
|
|
84
|
+
<div class="sidebar" id="sidebar">
|
|
85
|
+
<div class="sidebar-header">
|
|
86
|
+
<div class="sidebar-tabs">
|
|
87
|
+
<button class="sidebar-tab active" id="tabFiles" onclick="SmartCodeMcpSessions.setViewMode('files')">Files</button>
|
|
88
|
+
<button class="sidebar-tab" id="tabSessions" onclick="SmartCodeMcpSessions.setViewMode('sessions')">Sessions</button>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="actions">
|
|
91
|
+
<button id="btnNewFolder" onclick="createNewFolder()" title="New folder"></button>
|
|
92
|
+
<button id="btnNewFile" onclick="createNewFile()" title="New diagram"></button>
|
|
93
|
+
<button id="btnSaveFile" onclick="saveCurrentFile()" title="Save (Ctrl+S)"></button>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div id="fileTree" style="flex:1;overflow-y:auto;padding:4px 0"></div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<!-- Content -->
|
|
100
|
+
<div class="content">
|
|
101
|
+
<!-- Editor (hidden by default) -->
|
|
102
|
+
<div class="editor-panel hidden" id="editorPanel">
|
|
103
|
+
<div class="panel-header">
|
|
104
|
+
<span class="tab active">Mermaid</span>
|
|
105
|
+
<span style="margin-left:auto; font-size:11px; color:var(--text-secondary)">
|
|
106
|
+
<kbd>Ctrl</kbd>+<kbd>Enter</kbd> render
|
|
107
|
+
</span>
|
|
108
|
+
</div>
|
|
109
|
+
<textarea id="editor" spellcheck="false" placeholder="Paste or write Mermaid here..."></textarea>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Resize handle (hidden when editor hidden) -->
|
|
113
|
+
<div class="resize-handle" id="resizeHandle" style="display:none"></div>
|
|
114
|
+
|
|
115
|
+
<!-- Preview (LIGHT background, full width) -->
|
|
116
|
+
<div class="preview-panel" id="previewPanel">
|
|
117
|
+
<div id="preview-container">
|
|
118
|
+
<div id="preview"></div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="session-player hidden" id="sessionPlayer">
|
|
121
|
+
<button class="sp-btn" id="spPlayPause" title="Play/Pause">Play</button>
|
|
122
|
+
<input type="range" class="sp-scrubber" id="spScrubber" min="0" max="0" value="0">
|
|
123
|
+
<span class="sp-time" id="spTime">0 / 0</span>
|
|
124
|
+
<select class="sp-speed" id="spSpeed">
|
|
125
|
+
<option value="1">1x</option>
|
|
126
|
+
<option value="2">2x</option>
|
|
127
|
+
<option value="4">4x</option>
|
|
128
|
+
</select>
|
|
129
|
+
<button class="sp-btn" id="spClose" title="Close replay">Close</button>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="fit-hint" id="fitHint">Scroll to zoom | Drag to pan</div>
|
|
132
|
+
<div class="zoom-controls">
|
|
133
|
+
<button class="zoom-btn" onclick="zoomOut()">-</button>
|
|
134
|
+
<span class="zoom-label" id="zoomLabel">100%</span>
|
|
135
|
+
<button class="zoom-btn" onclick="zoomIn()">+</button>
|
|
136
|
+
<button class="zoom-btn" onclick="zoomFit()" style="font-size:12px">Fit</button>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<!-- Flag Panel (right side) -->
|
|
141
|
+
<div class="flag-panel hidden" id="flagPanel">
|
|
142
|
+
<div class="flag-panel-header">
|
|
143
|
+
<span>Flags</span>
|
|
144
|
+
<span class="flag-panel-count" id="flagPanelCount" style="display:none">0</span>
|
|
145
|
+
</div>
|
|
146
|
+
<div class="flag-panel-list" id="flagPanelList"></div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<!-- Toast -->
|
|
152
|
+
<div class="toast" id="toast"></div>
|
|
153
|
+
|
|
154
|
+
<!-- Help -->
|
|
155
|
+
<div class="help-overlay" id="helpOverlay" onclick="this.classList.remove('show')">
|
|
156
|
+
<div class="help-box" onclick="event.stopPropagation()">
|
|
157
|
+
<h2>Shortcuts</h2>
|
|
158
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>Enter</kbd></span><span>Render</span></div>
|
|
159
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>E</kbd></span><span>Toggle editor</span></div>
|
|
160
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>B</kbd></span><span>Toggle sidebar</span></div>
|
|
161
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>+</kbd> / <kbd>-</kbd></span><span>Zoom in/out</span></div>
|
|
162
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>0</kbd></span><span>Zoom fit</span></div>
|
|
163
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>S</kbd></span><span>Save file</span></div>
|
|
164
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>F</kbd></span><span>Search node</span></div>
|
|
165
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>Z</kbd></span><span>Undo</span></div>
|
|
166
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></span><span>Redo</span></div>
|
|
167
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>C</kbd></span><span>Copy node</span></div>
|
|
168
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>V</kbd></span><span>Paste node</span></div>
|
|
169
|
+
<div class="help-row"><span><kbd>Ctrl</kbd>+<kbd>D</kbd></span><span>Duplicate node</span></div>
|
|
170
|
+
<div class="help-row"><span>Scroll</span><span>Zoom</span></div>
|
|
171
|
+
<div class="help-row"><span>Drag</span><span>Pan</span></div>
|
|
172
|
+
<div class="help-row"><span><kbd>N</kbd></span><span>Add node</span></div>
|
|
173
|
+
<div class="help-row"><span><kbd>A</kbd></span><span>Add edge</span></div>
|
|
174
|
+
<div class="help-row"><span><kbd>F</kbd></span><span>Toggle Flag Mode</span></div>
|
|
175
|
+
<div class="help-row"><span>Click on node</span><span>Select</span></div>
|
|
176
|
+
<div class="help-row"><span>Right-click</span><span>Context menu</span></div>
|
|
177
|
+
<div class="help-row"><span>Double-click on node</span><span>Edit text inline</span></div>
|
|
178
|
+
<div class="help-row"><span><kbd>Del</kbd> / <kbd>Backspace</kbd></span><span>Delete selected</span></div>
|
|
179
|
+
<div class="help-row"><span>Double-click</span><span>Focus on subgraph</span></div>
|
|
180
|
+
<div class="help-row"><span><kbd>Esc</kbd></span><span>Exit Focus Mode</span></div>
|
|
181
|
+
<div class="help-row"><span><kbd>B</kbd></span><span>Toggle Breakpoint (selected node)</span></div>
|
|
182
|
+
<div class="help-row"><span>Right-click > Toggle Breakpoint</span><span>Toggle Breakpoint</span></div>
|
|
183
|
+
<div class="help-row"><span>Ghost button</span><span>Toggle ghost path visibility</span></div>
|
|
184
|
+
<div class="help-row"><span><kbd>H</kbd></span><span>Toggle heatmap</span></div>
|
|
185
|
+
<div class="help-row"><span><kbd>Space</kbd></span><span>Play/pause replay (session player)</span></div>
|
|
186
|
+
<div class="help-row"><span><kbd>Left</kbd> / <kbd>Right</kbd></span><span>Step frame (session player)</span></div>
|
|
187
|
+
<div class="help-row"><span><kbd>?</kbd></span><span>Help</span></div>
|
|
188
|
+
<br>
|
|
189
|
+
<h2>How it works</h2>
|
|
190
|
+
<p style="font-size:13px;color:var(--text-secondary);line-height:1.6">
|
|
191
|
+
Claude updates the <code>.mmd</code> files in the <code>diagrams/</code> folder.
|
|
192
|
+
With Auto-Sync enabled, this page updates in real time via WebSocket.
|
|
193
|
+
Click <strong>Editor</strong> to edit directly in the browser.
|
|
194
|
+
</p>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<!-- Module scripts (load order matters) -->
|
|
199
|
+
<script src="workspace-switcher.js"></script>
|
|
200
|
+
<script src="event-bus.js"></script>
|
|
201
|
+
<script src="diagram-dom.js"></script>
|
|
202
|
+
<script src="renderer.js"></script>
|
|
203
|
+
<script src="pan-zoom.js"></script>
|
|
204
|
+
<script src="export.js"></script>
|
|
205
|
+
<script src="icons.js"></script>
|
|
206
|
+
<script src="file-tree.js"></script>
|
|
207
|
+
<script src="editor-panel.js"></script>
|
|
208
|
+
<script src="ws-client.js"></script>
|
|
209
|
+
<script src="collapse-ui.js"></script>
|
|
210
|
+
<script src="annotations-svg.js"></script>
|
|
211
|
+
<script src="annotations-panel.js"></script>
|
|
212
|
+
<script src="annotations.js"></script>
|
|
213
|
+
<script src="command-history.js"></script>
|
|
214
|
+
<script src="diagram-editor.js"></script>
|
|
215
|
+
<script src="editor-popovers.js"></script>
|
|
216
|
+
<script src="search.js"></script>
|
|
217
|
+
<script src="interaction-state.js"></script>
|
|
218
|
+
<script src="selection.js"></script>
|
|
219
|
+
<script src="node-drag.js"></script>
|
|
220
|
+
<script src="context-menu.js"></script>
|
|
221
|
+
<script src="inline-edit.js"></script>
|
|
222
|
+
<script src="clipboard.js"></script>
|
|
223
|
+
<script src="viewport-transform.js"></script>
|
|
224
|
+
<script src="dagre-layout.js"></script>
|
|
225
|
+
<script src="svg-shapes.js"></script>
|
|
226
|
+
<script src="svg-renderer.js"></script>
|
|
227
|
+
<script src="custom-renderer.js"></script>
|
|
228
|
+
<script src="breakpoints.js"></script>
|
|
229
|
+
<script src="ghost-paths.js"></script>
|
|
230
|
+
<script src="heatmap.js"></script>
|
|
231
|
+
<script src="interaction-tracker.js"></script>
|
|
232
|
+
<script src="session-player.js"></script>
|
|
233
|
+
<script src="ws-handler.js"></script>
|
|
234
|
+
<script src="mcp-sessions.js"></script>
|
|
235
|
+
<script src="modal.js"></script>
|
|
236
|
+
<script src="app-init.js"></script>
|
|
237
|
+
|
|
238
|
+
</body>
|
|
239
|
+
</html>
|