living-ai-documentation 2.0.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/frontend/agents.js +288 -0
- package/dist/src/frontend/config.js +3 -2
- package/dist/src/frontend/diagram/color-picker.js +72 -0
- package/dist/src/frontend/diagram/defaults-modal.js +302 -0
- package/dist/src/frontend/diagram/edge-panel.js +110 -11
- package/dist/src/frontend/diagram/main.js +5 -8
- package/dist/src/frontend/diagram/network.js +16 -7
- package/dist/src/frontend/diagram/node-panel.js +104 -2
- package/dist/src/frontend/diagram.html +52 -29
- package/dist/src/frontend/i18n/en.json +43 -1
- package/dist/src/frontend/i18n/fr.json +43 -1
- package/dist/src/frontend/index.html +156 -33
- package/dist/src/frontend/workspace/app.js +439 -67
- package/dist/src/frontend/workspace/app.js.map +1 -1
- package/dist/src/frontend/workspace/app.ts +582 -84
- package/dist/src/frontend/workspace/index.html +232 -82
- package/dist/src/frontend/workspace/persistence.js +61 -0
- package/dist/src/frontend/workspace/persistence.js.map +1 -1
- package/dist/src/frontend/workspace/persistence.ts +111 -0
- package/dist/src/frontend/workspace/styles.css +293 -34
- package/dist/src/lib/config.d.ts +23 -0
- package/dist/src/lib/config.d.ts.map +1 -1
- package/dist/src/lib/config.js +16 -0
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/routes/config.d.ts.map +1 -1
- package/dist/src/routes/config.js +13 -0
- package/dist/src/routes/config.js.map +1 -1
- package/dist/src/routes/workspace.d.ts.map +1 -1
- package/dist/src/routes/workspace.js +528 -6
- package/dist/src/routes/workspace.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,13 +5,55 @@ import { st, markDirty } from './state.js';
|
|
|
5
5
|
import { visEdgeProps } from './edge-rendering.js';
|
|
6
6
|
import { pushSnapshot } from './history.js';
|
|
7
7
|
import { t } from './t.js';
|
|
8
|
+
import { getArrowDefaults } from './defaults-modal.js';
|
|
9
|
+
import { openColorPickerPopup } from './color-picker.js';
|
|
8
10
|
|
|
9
11
|
const DEFAULT_EDGE_COLOR = '#a8a29e';
|
|
10
12
|
const FREE_ARROW_STYLE_KEY = 'ld-free-arrow-style';
|
|
11
13
|
|
|
14
|
+
// Palette is injected at boot by diagram.html via initEdgeColorSwatch().
|
|
15
|
+
let _edgePaletteEntries = [];
|
|
16
|
+
|
|
17
|
+
function syncEdgeFontSizeValue() {
|
|
18
|
+
const el = document.getElementById('edgeFontSizeValue');
|
|
19
|
+
if (!el) return;
|
|
20
|
+
const sizes = (st.selectedEdgeIds || []).map((id) => {
|
|
21
|
+
const e = st.edges && st.edges.get(id);
|
|
22
|
+
return e ? (e.fontSize || 11) : null;
|
|
23
|
+
}).filter((s) => s !== null);
|
|
24
|
+
if (!sizes.length) { el.textContent = '–'; return; }
|
|
25
|
+
const first = sizes[0];
|
|
26
|
+
el.textContent = sizes.every((s) => s === first) ? String(first) : '–';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function syncEdgeColorSwatch(hexColor) {
|
|
30
|
+
const swatch = document.getElementById('edgeColorSwatch');
|
|
31
|
+
if (!swatch) return;
|
|
32
|
+
swatch.style.background = hexColor;
|
|
33
|
+
swatch.style.borderColor = hexColor;
|
|
34
|
+
swatch.dataset.currentColor = hexColor;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function initEdgeColorSwatch(palette) {
|
|
38
|
+
_edgePaletteEntries = palette.map((hex) => ({
|
|
39
|
+
value: hex, bg: hex, border: hex, label: hex,
|
|
40
|
+
}));
|
|
41
|
+
const swatch = document.getElementById('edgeColorSwatch');
|
|
42
|
+
if (!swatch) return;
|
|
43
|
+
swatch.addEventListener('click', (e) => {
|
|
44
|
+
e.stopPropagation();
|
|
45
|
+
const current = swatch.dataset.currentColor || DEFAULT_EDGE_COLOR;
|
|
46
|
+
openColorPickerPopup(swatch, _edgePaletteEntries, current, (entry) => {
|
|
47
|
+
setEdgeColor(entry.value);
|
|
48
|
+
}, { columns: _edgePaletteEntries.length });
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
12
52
|
// Persist the style of the first free arrow (anchor→anchor) in the current
|
|
13
53
|
// selection so the next double-click creation reuses it.
|
|
14
54
|
function persistFreeArrowStyle() {
|
|
55
|
+
// Persist from any selected edge — free arrows (anchor→anchor) take priority,
|
|
56
|
+
// but shape→shape edges also update the style memory.
|
|
15
57
|
const freeId = st.selectedEdgeIds.find((id) => {
|
|
16
58
|
const e = st.edges.get(id);
|
|
17
59
|
if (!e) return false;
|
|
@@ -19,19 +61,30 @@ function persistFreeArrowStyle() {
|
|
|
19
61
|
const toN = st.nodes && st.nodes.get(e.to);
|
|
20
62
|
return fromN && fromN.shapeType === 'anchor' && toN && toN.shapeType === 'anchor';
|
|
21
63
|
});
|
|
22
|
-
|
|
23
|
-
|
|
64
|
+
const edgeId = freeId || st.selectedEdgeIds[0];
|
|
65
|
+
if (!edgeId) return;
|
|
66
|
+
const e = st.edges.get(edgeId);
|
|
67
|
+
if (!e) return;
|
|
24
68
|
localStorage.setItem(FREE_ARROW_STYLE_KEY, JSON.stringify({
|
|
25
69
|
arrowDir: e.arrowDir || 'to',
|
|
26
70
|
dashes: e.dashes || false,
|
|
27
71
|
edgeColor: e.edgeColor || null,
|
|
28
72
|
edgeWidth: e.edgeWidth || null,
|
|
73
|
+
fontSize: e.fontSize || null,
|
|
29
74
|
}));
|
|
30
75
|
}
|
|
31
76
|
|
|
32
77
|
export function getLastFreeArrowStyle() {
|
|
33
|
-
try {
|
|
34
|
-
|
|
78
|
+
try {
|
|
79
|
+
const stored = JSON.parse(localStorage.getItem(FREE_ARROW_STYLE_KEY));
|
|
80
|
+
if (stored) {
|
|
81
|
+
// Merge with defaults: stored values override defaults, but null/undefined
|
|
82
|
+
// values in stored fall back to defaults (handles legacy keys without fontSize).
|
|
83
|
+
const clean = Object.fromEntries(Object.entries(stored).filter(([, v]) => v != null));
|
|
84
|
+
return { ...getArrowDefaults(), ...clean };
|
|
85
|
+
}
|
|
86
|
+
} catch { /* ignore */ }
|
|
87
|
+
return getArrowDefaults();
|
|
35
88
|
}
|
|
36
89
|
|
|
37
90
|
function isEdgeLocked(edge) {
|
|
@@ -97,13 +150,10 @@ export function showEdgePanel() {
|
|
|
97
150
|
document.getElementById(id).classList.remove('edge-btn-active'));
|
|
98
151
|
document.getElementById(dashes ? 'edgeBtnDashed' : 'edgeBtnSolid').classList.add('edge-btn-active');
|
|
99
152
|
|
|
100
|
-
//
|
|
101
|
-
const activeColor = (e.edgeColor || DEFAULT_EDGE_COLOR)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
btn.style.outline = isActive ? '2px solid #f97316' : '';
|
|
105
|
-
btn.style.outlineOffset = isActive ? '2px' : '';
|
|
106
|
-
});
|
|
153
|
+
// Sync edge color swatch and font size display.
|
|
154
|
+
const activeColor = (e.edgeColor || DEFAULT_EDGE_COLOR);
|
|
155
|
+
syncEdgeColorSwatch(activeColor);
|
|
156
|
+
syncEdgeFontSizeValue();
|
|
107
157
|
|
|
108
158
|
// Show/hide the clear-ports button based on whether this edge has ports.
|
|
109
159
|
const hasPorts = !!(e.fromPort || e.toPort);
|
|
@@ -180,6 +230,54 @@ export function setEdgeColor(hex) {
|
|
|
180
230
|
markDirty();
|
|
181
231
|
}
|
|
182
232
|
|
|
233
|
+
export async function saveEdgeAsDefault() {
|
|
234
|
+
const freeId = st.selectedEdgeIds.find((id) => {
|
|
235
|
+
const e = st.edges.get(id);
|
|
236
|
+
if (!e) return false;
|
|
237
|
+
const fromN = st.nodes && st.nodes.get(e.from);
|
|
238
|
+
const toN = st.nodes && st.nodes.get(e.to);
|
|
239
|
+
return fromN && fromN.shapeType === 'anchor' && toN && toN.shapeType === 'anchor';
|
|
240
|
+
});
|
|
241
|
+
const edgeId = freeId || st.selectedEdgeIds[0];
|
|
242
|
+
if (!edgeId) return;
|
|
243
|
+
const e = st.edges.get(edgeId);
|
|
244
|
+
if (!e) return;
|
|
245
|
+
|
|
246
|
+
const { getDiagramDefaults, initDiagramDefaults } = await import('./defaults-modal.js');
|
|
247
|
+
const current = getDiagramDefaults() || {};
|
|
248
|
+
const arrows = {
|
|
249
|
+
arrowDir: e.arrowDir || 'to',
|
|
250
|
+
dashes: e.dashes || false,
|
|
251
|
+
fontSize: e.fontSize || 11,
|
|
252
|
+
};
|
|
253
|
+
const updated = { arrows, shapes: current.shapes || null };
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
const res = await fetch('/api/config', {
|
|
257
|
+
method: 'PUT',
|
|
258
|
+
headers: { 'Content-Type': 'application/json' },
|
|
259
|
+
body: JSON.stringify({ diagramDefaults: updated }),
|
|
260
|
+
});
|
|
261
|
+
if (!res.ok) throw new Error(await res.text());
|
|
262
|
+
initDiagramDefaults({ diagramDefaults: updated });
|
|
263
|
+
// Sync localStorage so the next arrow creation uses the new default immediately
|
|
264
|
+
localStorage.setItem(FREE_ARROW_STYLE_KEY, JSON.stringify({
|
|
265
|
+
arrowDir: arrows.arrowDir,
|
|
266
|
+
dashes: arrows.dashes,
|
|
267
|
+
fontSize: arrows.fontSize,
|
|
268
|
+
edgeColor: null,
|
|
269
|
+
edgeWidth: null,
|
|
270
|
+
}));
|
|
271
|
+
const btn = document.getElementById('btnSaveEdgeDefault');
|
|
272
|
+
if (btn) {
|
|
273
|
+
btn.classList.add('tool-active');
|
|
274
|
+
setTimeout(() => btn.classList.remove('tool-active'), 800);
|
|
275
|
+
}
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.error('Failed to save edge default', err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
183
281
|
export function changeEdgeWidth(delta) {
|
|
184
282
|
if (!st.selectedEdgeIds.length) return;
|
|
185
283
|
pushSnapshot();
|
|
@@ -244,6 +342,7 @@ export function changeEdgeFontSize(delta) {
|
|
|
244
342
|
// Keep native label transparent — drawEdgeLabels() is the single render path.
|
|
245
343
|
st.edges.update({ id, fontSize: newSize, font: { size: newSize, align: 'middle', color: 'rgba(0,0,0,0)' } });
|
|
246
344
|
});
|
|
345
|
+
syncEdgeFontSizeValue();
|
|
247
346
|
markDirty();
|
|
248
347
|
}
|
|
249
348
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import { st, markDirty } from './state.js';
|
|
5
5
|
import { TOOL_BTN_MAP } from './constants.js';
|
|
6
|
-
import { showNodePanel, hideNodePanel, setNodeColor, setNodeBgOpacity, changeNodeFontSize, setTextAlign, setTextValign, setCustomShapeLabelPlacement, changeZOrder, activateStamp, cancelStamp, stepRotate, toggleNodeLock } from './node-panel.js';
|
|
6
|
+
import { showNodePanel, hideNodePanel, setNodeColor, setNodeBgOpacity, changeNodeFontSize, setTextAlign, setTextValign, setCustomShapeLabelPlacement, changeZOrder, activateStamp, cancelStamp, stepRotate, toggleNodeLock, saveShapeAsDefault } from './node-panel.js';
|
|
7
7
|
import { groupNodes, ungroupNodes } from './groups.js';
|
|
8
8
|
import { showLinkPanel, hideLinkPanel } from './link-panel.js';
|
|
9
|
-
import { hideEdgePanel, setEdgeArrow, setEdgeDashes, changeEdgeFontSize, stepEdgeLabelRotation, clearEdgePorts, setEdgeColor, changeEdgeWidth, toggleEdgeLock, resetEdgeLabelWidth, stepEdgeLabelOffset, resetEdgeLabelOffset } from './edge-panel.js';
|
|
9
|
+
import { hideEdgePanel, setEdgeArrow, setEdgeDashes, changeEdgeFontSize, stepEdgeLabelRotation, clearEdgePorts, setEdgeColor, changeEdgeWidth, toggleEdgeLock, resetEdgeLabelWidth, stepEdgeLabelOffset, resetEdgeLabelOffset, saveEdgeAsDefault } from './edge-panel.js';
|
|
10
10
|
import { startLabelEdit, startEdgeLabelEdit, hideLabelInput } from './label-editor.js';
|
|
11
11
|
import { hideSelectionOverlay, toggleResizeMode } from './selection-overlay.js';
|
|
12
12
|
import { toggleGrid } from './grid.js';
|
|
@@ -207,8 +207,6 @@ initEvidenceMode();
|
|
|
207
207
|
// ── Node panel wiring ─────────────────────────────────────────────────────────
|
|
208
208
|
|
|
209
209
|
document.getElementById('nodePanel').addEventListener('click', (e) => {
|
|
210
|
-
const colorBtn = e.target.closest('[data-color]');
|
|
211
|
-
if (colorBtn) setNodeColor(colorBtn.dataset.color);
|
|
212
210
|
const labelPlacementBtn = e.target.closest('[data-label-placement]');
|
|
213
211
|
if (labelPlacementBtn) setCustomShapeLabelPlacement(labelPlacementBtn.dataset.labelPlacement);
|
|
214
212
|
});
|
|
@@ -277,10 +275,9 @@ document.getElementById('btnEdgeLabelWidthReset').addEventListener('click', rese
|
|
|
277
275
|
document.getElementById('btnEdgeLock').addEventListener('click', toggleEdgeLock);
|
|
278
276
|
document.getElementById('btnEdgeWidthDecrease').addEventListener('click', () => changeEdgeWidth(-0.5));
|
|
279
277
|
document.getElementById('btnEdgeWidthIncrease').addEventListener('click', () => changeEdgeWidth(0.5));
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
});
|
|
278
|
+
// Edge color is handled by #edgeColorSwatch via initEdgeColorSwatch() in edge-panel.js
|
|
279
|
+
document.getElementById('btnSaveShapeDefault').addEventListener('click', saveShapeAsDefault);
|
|
280
|
+
document.getElementById('btnSaveEdgeDefault').addEventListener('click', saveEdgeAsDefault);
|
|
284
281
|
|
|
285
282
|
// ── Keyboard shortcuts ────────────────────────────────────────────────────────
|
|
286
283
|
|
|
@@ -205,14 +205,19 @@ export function initNetwork(savedNodes, savedEdges, edgesStraight = false) {
|
|
|
205
205
|
}
|
|
206
206
|
pushSnapshot();
|
|
207
207
|
data.id = "e" + Date.now();
|
|
208
|
-
|
|
209
|
-
data.
|
|
208
|
+
const edgeStyle = getLastFreeArrowStyle();
|
|
209
|
+
data.arrowDir = edgeStyle.arrowDir || "to";
|
|
210
|
+
data.dashes = edgeStyle.dashes || false;
|
|
211
|
+
if (edgeStyle.fontSize) {
|
|
212
|
+
data.fontSize = edgeStyle.fontSize;
|
|
213
|
+
data.font = { size: edgeStyle.fontSize, align: 'middle', color: 'rgba(0,0,0,0)' };
|
|
214
|
+
}
|
|
210
215
|
// Attach captured port selections — skip for anchor nodes.
|
|
211
216
|
const fromIsAnchor = fromNode.shapeType === "anchor";
|
|
212
217
|
const toIsAnchor = toNode.shapeType === "anchor";
|
|
213
218
|
if (!fromIsAnchor) data.fromPort = _addEdgeFromPort || null;
|
|
214
219
|
if (!toIsAnchor) data.toPort = _hoveredPortKey || null;
|
|
215
|
-
Object.assign(data, visEdgeProps(
|
|
220
|
+
Object.assign(data, visEdgeProps(data.arrowDir, data.dashes));
|
|
216
221
|
// Port edges: make vis-network's ghost transparent so only drawPortEdge is visible.
|
|
217
222
|
if (data.fromPort || data.toPort) {
|
|
218
223
|
data.color = {
|
|
@@ -1142,6 +1147,7 @@ export function initNetwork(savedNodes, savedEdges, edgesStraight = false) {
|
|
|
1142
1147
|
const lastStyle = getLastFreeArrowStyle();
|
|
1143
1148
|
const arrowDir = lastStyle.arrowDir || "to";
|
|
1144
1149
|
const dashes = lastStyle.dashes || false;
|
|
1150
|
+
const edgeFontSize = lastStyle.fontSize || null;
|
|
1145
1151
|
st.edges.add({
|
|
1146
1152
|
id: edgeId,
|
|
1147
1153
|
from: fromId,
|
|
@@ -1150,6 +1156,7 @@ export function initNetwork(savedNodes, savedEdges, edgesStraight = false) {
|
|
|
1150
1156
|
dashes,
|
|
1151
1157
|
edgeColor: lastStyle.edgeColor || null,
|
|
1152
1158
|
edgeWidth: lastStyle.edgeWidth || null,
|
|
1159
|
+
...(edgeFontSize ? { fontSize: edgeFontSize, font: { size: edgeFontSize, align: 'middle', color: 'rgba(0,0,0,0)' } } : {}),
|
|
1153
1160
|
smooth: { enabled: false },
|
|
1154
1161
|
...visEdgeProps(arrowDir, dashes),
|
|
1155
1162
|
...(lastStyle.edgeColor
|
|
@@ -1720,6 +1727,8 @@ function onDoubleClick(params) {
|
|
|
1720
1727
|
const fontSize = lastStyle.fontSize || null;
|
|
1721
1728
|
const textAlign = lastStyle.textAlign || null;
|
|
1722
1729
|
const textValign = lastStyle.textValign || null;
|
|
1730
|
+
const nodeWidth = lastStyle.width || defaults[0];
|
|
1731
|
+
const nodeHeight = lastStyle.height || defaults[1];
|
|
1723
1732
|
const rawPos = params.pointer.canvas;
|
|
1724
1733
|
const pos = st.gridEnabled ? snapToGrid(rawPos.x, rawPos.y) : rawPos;
|
|
1725
1734
|
st.nodes.add({
|
|
@@ -1733,8 +1742,8 @@ function onDoubleClick(params) {
|
|
|
1733
1742
|
shapeType,
|
|
1734
1743
|
customShapeId: customShapeId || null,
|
|
1735
1744
|
colorKey,
|
|
1736
|
-
nodeWidth
|
|
1737
|
-
nodeHeight
|
|
1745
|
+
nodeWidth,
|
|
1746
|
+
nodeHeight,
|
|
1738
1747
|
fontSize,
|
|
1739
1748
|
textAlign,
|
|
1740
1749
|
textValign,
|
|
@@ -1745,8 +1754,8 @@ function onDoubleClick(params) {
|
|
|
1745
1754
|
...visNodeProps(
|
|
1746
1755
|
shapeType,
|
|
1747
1756
|
colorKey,
|
|
1748
|
-
|
|
1749
|
-
|
|
1757
|
+
nodeWidth,
|
|
1758
|
+
nodeHeight,
|
|
1750
1759
|
fontSize,
|
|
1751
1760
|
textAlign,
|
|
1752
1761
|
textValign,
|
|
@@ -6,6 +6,37 @@ import { SHAPE_DEFAULTS } from './node-rendering.js';
|
|
|
6
6
|
import { CUSTOM_SHAPE_TYPE, getCustomShapeLabelPlacement } from './custom-shapes.js';
|
|
7
7
|
import { pushSnapshot } from './history.js';
|
|
8
8
|
import { t } from './t.js';
|
|
9
|
+
import { getShapeDefaults } from './defaults-modal.js';
|
|
10
|
+
import { NODE_COLORS, DEFAULT_NODE_PALETTE } from './constants.js';
|
|
11
|
+
import { openColorPickerPopup } from './color-picker.js';
|
|
12
|
+
|
|
13
|
+
// Reads the effective color for a key, respecting runtime overrides.
|
|
14
|
+
function getEffectiveNodeColor(key) {
|
|
15
|
+
return st.nodeColorOverrides[key] || NODE_COLORS[key] || NODE_COLORS['c-gray'];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Built dynamically so overrides applied at boot are reflected in the picker.
|
|
19
|
+
function buildNodeColorEntries() {
|
|
20
|
+
return DEFAULT_NODE_PALETTE.map((key) => {
|
|
21
|
+
const c = getEffectiveNodeColor(key);
|
|
22
|
+
return { value: key, bg: c.bg, border: c.border, label: key.replace('c-', '') };
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function syncNodeColorSwatch() {
|
|
27
|
+
const swatch = document.getElementById('nodeColorSwatch');
|
|
28
|
+
if (!swatch) return;
|
|
29
|
+
const firstId = (st.selectedNodeIds || []).find((id) => {
|
|
30
|
+
const n = st.nodes && st.nodes.get(id);
|
|
31
|
+
return n && n.shapeType !== 'anchor';
|
|
32
|
+
});
|
|
33
|
+
const n = firstId && st.nodes && st.nodes.get(firstId);
|
|
34
|
+
const key = (n && n.colorKey) || 'c-gray';
|
|
35
|
+
const c = getEffectiveNodeColor(key);
|
|
36
|
+
swatch.style.background = c.bg;
|
|
37
|
+
swatch.style.borderColor = c.border;
|
|
38
|
+
swatch.dataset.currentColor = key;
|
|
39
|
+
}
|
|
9
40
|
|
|
10
41
|
const CUSTOM_LABEL_PLACEMENTS = ['below', 'above', 'right', 'left', 'center'];
|
|
11
42
|
|
|
@@ -27,8 +58,16 @@ function persistNodeStyle() {
|
|
|
27
58
|
}
|
|
28
59
|
|
|
29
60
|
export function getLastNodeStyle(shapeType) {
|
|
30
|
-
try {
|
|
31
|
-
|
|
61
|
+
try {
|
|
62
|
+
const stored = JSON.parse(localStorage.getItem('ld-node-style-' + shapeType));
|
|
63
|
+
if (stored) {
|
|
64
|
+
// Merge with defaults: stored values override defaults, but null/undefined
|
|
65
|
+
// values in stored fall back to defaults (handles legacy keys without width/height).
|
|
66
|
+
const clean = Object.fromEntries(Object.entries(stored).filter(([, v]) => v != null));
|
|
67
|
+
return { ...getShapeDefaults(shapeType), ...clean };
|
|
68
|
+
}
|
|
69
|
+
} catch { /* ignore */ }
|
|
70
|
+
return getShapeDefaults(shapeType);
|
|
32
71
|
}
|
|
33
72
|
|
|
34
73
|
// All shapes are ctxRenderers — vis-network never re-reads the closure after
|
|
@@ -145,6 +184,7 @@ export function showNodePanel() {
|
|
|
145
184
|
syncNodeLockButton();
|
|
146
185
|
syncNodeFontSizeValue();
|
|
147
186
|
syncCustomShapeLabelPlacementControls();
|
|
187
|
+
syncNodeColorSwatch();
|
|
148
188
|
// Sync the opacity slider with the first selected node's current value so the
|
|
149
189
|
// slider reflects the live state rather than whatever position it was left at.
|
|
150
190
|
const slider = document.getElementById('nodeBgOpacity');
|
|
@@ -159,6 +199,67 @@ export function hideNodePanel() {
|
|
|
159
199
|
document.getElementById('nodePanel').classList.add('hidden');
|
|
160
200
|
}
|
|
161
201
|
|
|
202
|
+
export function initNodeColorSwatch() {
|
|
203
|
+
const swatch = document.getElementById('nodeColorSwatch');
|
|
204
|
+
if (!swatch) return;
|
|
205
|
+
swatch.addEventListener('click', (e) => {
|
|
206
|
+
e.stopPropagation();
|
|
207
|
+
const current = swatch.dataset.currentColor || 'c-gray';
|
|
208
|
+
openColorPickerPopup(swatch, buildNodeColorEntries(), current, (entry) => {
|
|
209
|
+
setNodeColor(entry.value);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export async function saveShapeAsDefault() {
|
|
215
|
+
const firstId = (st.selectedNodeIds || []).find((id) => {
|
|
216
|
+
const n = st.nodes && st.nodes.get(id);
|
|
217
|
+
return n && n.shapeType !== 'anchor' && n.shapeType !== CUSTOM_SHAPE_TYPE;
|
|
218
|
+
});
|
|
219
|
+
if (!firstId) return;
|
|
220
|
+
const n = st.nodes.get(firstId);
|
|
221
|
+
if (!n || !n.shapeType) return;
|
|
222
|
+
|
|
223
|
+
const { getDiagramDefaults } = await import('./defaults-modal.js');
|
|
224
|
+
const current = getDiagramDefaults() || {};
|
|
225
|
+
const shapes = Object.assign({}, current.shapes || {});
|
|
226
|
+
shapes[n.shapeType] = {
|
|
227
|
+
width: n.nodeWidth || SHAPE_DEFAULTS[n.shapeType]?.[0] || 100,
|
|
228
|
+
height: n.nodeHeight || SHAPE_DEFAULTS[n.shapeType]?.[1] || 40,
|
|
229
|
+
fontSize: n.fontSize || 13,
|
|
230
|
+
colorKey: n.colorKey || 'c-gray',
|
|
231
|
+
};
|
|
232
|
+
const updated = { arrows: current.arrows || null, shapes };
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const res = await fetch('/api/config', {
|
|
236
|
+
method: 'PUT',
|
|
237
|
+
headers: { 'Content-Type': 'application/json' },
|
|
238
|
+
body: JSON.stringify({ diagramDefaults: updated }),
|
|
239
|
+
});
|
|
240
|
+
if (!res.ok) throw new Error(await res.text());
|
|
241
|
+
const { initDiagramDefaults } = await import('./defaults-modal.js');
|
|
242
|
+
initDiagramDefaults({ diagramDefaults: updated });
|
|
243
|
+
// Sync localStorage so the next creation uses the new default immediately
|
|
244
|
+
localStorage.setItem('ld-node-style-' + n.shapeType, JSON.stringify({
|
|
245
|
+
colorKey: shapes[n.shapeType].colorKey,
|
|
246
|
+
fontSize: shapes[n.shapeType].fontSize,
|
|
247
|
+
width: shapes[n.shapeType].width,
|
|
248
|
+
height: shapes[n.shapeType].height,
|
|
249
|
+
textAlign: null,
|
|
250
|
+
textValign: null,
|
|
251
|
+
}));
|
|
252
|
+
// Visual feedback: flash the button orange briefly
|
|
253
|
+
const btn = document.getElementById('btnSaveShapeDefault');
|
|
254
|
+
if (btn) {
|
|
255
|
+
btn.classList.add('tool-active');
|
|
256
|
+
setTimeout(() => btn.classList.remove('tool-active'), 800);
|
|
257
|
+
}
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error('Failed to save shape default', err);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
162
263
|
export function toggleNodeLock() {
|
|
163
264
|
const { allLocked, nodeIds, edgeIds } = selectedLockState();
|
|
164
265
|
if (!nodeIds.length && !edgeIds.length) return;
|
|
@@ -195,6 +296,7 @@ export function setNodeColor(colorKey) {
|
|
|
195
296
|
persistNodeStyle();
|
|
196
297
|
forceRedraw();
|
|
197
298
|
markDirty();
|
|
299
|
+
syncNodeColorSwatch();
|
|
198
300
|
}
|
|
199
301
|
|
|
200
302
|
// The slider fires `input` on every step during a drag. The caller is expected
|
|
@@ -559,6 +559,16 @@
|
|
|
559
559
|
</button>
|
|
560
560
|
<div class="w-px h-6 bg-gray-200 dark:bg-gray-700 mx-0.5"></div>
|
|
561
561
|
|
|
562
|
+
<button
|
|
563
|
+
id="btnDiagramDefaults"
|
|
564
|
+
class="tool-btn"
|
|
565
|
+
data-i18n-title="diagram.toolbar.defaults"
|
|
566
|
+
>
|
|
567
|
+
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
|
568
|
+
<path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0"/>
|
|
569
|
+
<path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.474l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z"/>
|
|
570
|
+
</svg>
|
|
571
|
+
</button>
|
|
562
572
|
<button
|
|
563
573
|
id="btnAlign"
|
|
564
574
|
class="tool-btn"
|
|
@@ -812,7 +822,9 @@
|
|
|
812
822
|
>🔒</button>
|
|
813
823
|
<div class="panel-sep"></div>
|
|
814
824
|
<div id="nodePanelControls" class="contents">
|
|
815
|
-
<
|
|
825
|
+
<button id="nodeColorSwatch"
|
|
826
|
+
style="width:1.5rem;height:1.5rem;border-radius:0.25rem;border:2px solid #a8a29e;background:#f5f5f4;cursor:pointer;flex-shrink:0;"
|
|
827
|
+
data-i18n-title="diagram.node_panel.color"></button>
|
|
816
828
|
<div class="panel-sep"></div>
|
|
817
829
|
<input
|
|
818
830
|
id="nodeBgOpacity"
|
|
@@ -1158,6 +1170,19 @@
|
|
|
1158
1170
|
<rect x="19" y="4.5" width="3" height="5" rx="1" fill="currentColor"/>
|
|
1159
1171
|
</svg>
|
|
1160
1172
|
</button>
|
|
1173
|
+
<div class="panel-sep"></div>
|
|
1174
|
+
|
|
1175
|
+
<!-- Save as default for this shape type -->
|
|
1176
|
+
<button
|
|
1177
|
+
id="btnSaveShapeDefault"
|
|
1178
|
+
class="tool-btn !w-7 !h-6"
|
|
1179
|
+
data-i18n-title="diagram.node_panel.save_as_default"
|
|
1180
|
+
>
|
|
1181
|
+
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
|
1182
|
+
<path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0"/>
|
|
1183
|
+
<path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.474l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z"/>
|
|
1184
|
+
</svg>
|
|
1185
|
+
</button>
|
|
1161
1186
|
</div><!-- /nodePanelControls -->
|
|
1162
1187
|
</div>
|
|
1163
1188
|
|
|
@@ -1282,6 +1307,11 @@
|
|
|
1282
1307
|
>
|
|
1283
1308
|
Aa−
|
|
1284
1309
|
</button>
|
|
1310
|
+
<span
|
|
1311
|
+
id="edgeFontSizeValue"
|
|
1312
|
+
class="inline-flex items-center justify-center min-w-[2.25rem] h-6 px-1 text-[11px] font-mono text-gray-700 dark:text-gray-200 border border-gray-300 dark:border-gray-600 rounded bg-white/80 dark:bg-gray-800/80"
|
|
1313
|
+
data-i18n-title="diagram.edge_panel.font_size_value"
|
|
1314
|
+
>11</span>
|
|
1285
1315
|
<button
|
|
1286
1316
|
id="btnEdgeFontIncrease"
|
|
1287
1317
|
class="tool-btn !w-8 !h-6"
|
|
@@ -1350,7 +1380,9 @@
|
|
|
1350
1380
|
<button id="btnEdgeWidthDecrease" class="tool-btn !w-7 !h-6" style="font-size:10px" data-i18n-title="diagram.edge_panel.width_decrease">W−</button>
|
|
1351
1381
|
<button id="btnEdgeWidthIncrease" class="tool-btn !w-7 !h-6" style="font-size:10px" data-i18n-title="diagram.edge_panel.width_increase">W+</button>
|
|
1352
1382
|
<div class="panel-sep"></div>
|
|
1353
|
-
<
|
|
1383
|
+
<button id="edgeColorSwatch"
|
|
1384
|
+
style="width:1.5rem;height:1.5rem;border-radius:0.25rem;border:2px solid #a8a29e;background:#a8a29e;cursor:pointer;flex-shrink:0;"
|
|
1385
|
+
data-i18n-title="diagram.edge_panel.color"></button>
|
|
1354
1386
|
<div class="panel-sep"></div>
|
|
1355
1387
|
<button
|
|
1356
1388
|
id="btnEdgeClearPorts"
|
|
@@ -1359,6 +1391,17 @@
|
|
|
1359
1391
|
>
|
|
1360
1392
|
⊗
|
|
1361
1393
|
</button>
|
|
1394
|
+
<div class="panel-sep"></div>
|
|
1395
|
+
<button
|
|
1396
|
+
id="btnSaveEdgeDefault"
|
|
1397
|
+
class="tool-btn !w-7 !h-6"
|
|
1398
|
+
data-i18n-title="diagram.edge_panel.save_as_default"
|
|
1399
|
+
>
|
|
1400
|
+
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
|
1401
|
+
<path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0"/>
|
|
1402
|
+
<path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.474l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z"/>
|
|
1403
|
+
</svg>
|
|
1404
|
+
</button>
|
|
1362
1405
|
</div><!-- /edgePanelControls -->
|
|
1363
1406
|
</div>
|
|
1364
1407
|
|
|
@@ -1437,6 +1480,9 @@
|
|
|
1437
1480
|
import { st } from '/diagram/state.js';
|
|
1438
1481
|
import { loadDiagramList } from '/diagram/persistence.js';
|
|
1439
1482
|
import { loadCustomShapeLibraries, renderCustomShapeBar } from '/diagram/custom-shapes.js';
|
|
1483
|
+
import { initDiagramDefaults, openDefaultsModal } from '/diagram/defaults-modal.js';
|
|
1484
|
+
import { initNodeColorSwatch } from '/diagram/node-panel.js';
|
|
1485
|
+
import { initEdgeColorSwatch } from '/diagram/edge-panel.js';
|
|
1440
1486
|
(async () => {
|
|
1441
1487
|
// diagramNodePalette: array of 15 bg hex strings (positional, matching DEFAULT_NODE_PALETTE)
|
|
1442
1488
|
// diagramEdgePalette: array of hex strings
|
|
@@ -1447,6 +1493,7 @@
|
|
|
1447
1493
|
await window.initI18n(cfg.language);
|
|
1448
1494
|
if (Array.isArray(cfg.diagramNodePalette) && cfg.diagramNodePalette.length) nodeBgOverrides = cfg.diagramNodePalette;
|
|
1449
1495
|
if (Array.isArray(cfg.diagramEdgePalette) && cfg.diagramEdgePalette.length) edgePalette = cfg.diagramEdgePalette;
|
|
1496
|
+
initDiagramDefaults(cfg);
|
|
1450
1497
|
} catch { await window.initI18n('en'); /* config unavailable — use defaults */ }
|
|
1451
1498
|
|
|
1452
1499
|
// Apply node color overrides to shared state so renderers pick them up.
|
|
@@ -1457,36 +1504,12 @@
|
|
|
1457
1504
|
}
|
|
1458
1505
|
});
|
|
1459
1506
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
DEFAULT_NODE_PALETTE.forEach((key, i) => {
|
|
1463
|
-
if (!nc) return;
|
|
1464
|
-
const customBg = nodeBgOverrides && nodeBgOverrides[i];
|
|
1465
|
-
const c = (customBg ? deriveNodeColors(customBg, NODE_L_RATIOS[key] || 0.60) : null) || NODE_COLORS[key];
|
|
1466
|
-
const btn = document.createElement('button');
|
|
1467
|
-
btn.dataset.color = key;
|
|
1468
|
-
btn.className = 'w-5 h-5 rounded-full border-2 hover:scale-125 transition-transform';
|
|
1469
|
-
btn.style.background = c.bg;
|
|
1470
|
-
btn.style.borderColor = c.border;
|
|
1471
|
-
btn.title = key.replace('c-', '');
|
|
1472
|
-
nc.appendChild(btn);
|
|
1473
|
-
});
|
|
1474
|
-
|
|
1475
|
-
// Build edge palette buttons.
|
|
1476
|
-
const ec = document.getElementById('edgePaletteContainer');
|
|
1477
|
-
edgePalette.forEach((hex) => {
|
|
1478
|
-
if (!ec) return;
|
|
1479
|
-
const btn = document.createElement('button');
|
|
1480
|
-
btn.dataset.edgeColor = hex;
|
|
1481
|
-
btn.className = 'edge-color-btn w-4 h-4 rounded-full hover:scale-125 transition-transform';
|
|
1482
|
-
btn.style.background = hex;
|
|
1483
|
-
btn.style.border = '2px solid rgba(0,0,0,0.2)';
|
|
1484
|
-
btn.title = hex;
|
|
1485
|
-
ec.appendChild(btn);
|
|
1486
|
-
});
|
|
1507
|
+
initNodeColorSwatch();
|
|
1508
|
+
initEdgeColorSwatch(edgePalette);
|
|
1487
1509
|
await loadCustomShapeLibraries();
|
|
1488
1510
|
renderCustomShapeBar();
|
|
1489
1511
|
window.applyI18n();
|
|
1512
|
+
document.getElementById('btnDiagramDefaults').addEventListener('click', openDefaultsModal);
|
|
1490
1513
|
loadDiagramList();
|
|
1491
1514
|
})();
|
|
1492
1515
|
</script>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"nav.toggle_sidebar": "Toggle sidebar",
|
|
20
20
|
"nav.search_placeholder": "Search docs…",
|
|
21
21
|
"nav.search_mobile_placeholder": "Search…",
|
|
22
|
-
"nav.workspace": "Workspace",
|
|
22
|
+
"nav.workspace": "Agentic Workspace",
|
|
23
23
|
"nav.toggle_dark": "Toggle dark mode",
|
|
24
24
|
"nav.export": "Export",
|
|
25
25
|
"nav.toggle_categories": "Show/hide category grouping",
|
|
@@ -29,12 +29,30 @@
|
|
|
29
29
|
"nav.export_all_pdf": "Export all documents as PDF",
|
|
30
30
|
"nav.new_folder": "New folder",
|
|
31
31
|
"nav.new_document": "New document",
|
|
32
|
+
"nav.ai_agents": "Agents IA",
|
|
32
33
|
"nav.word_cloud": "☁ Word Cloud",
|
|
33
34
|
"nav.diagram": "◇ Diagram",
|
|
34
35
|
"nav.ai_context": "AI Context",
|
|
35
36
|
"nav.files": "📁 Attached files",
|
|
36
37
|
"nav.admin": "⚙ Admin",
|
|
37
38
|
|
|
39
|
+
"agents.title": "Agents IA",
|
|
40
|
+
"agents.subtitle": "Launch a configured workspace agent.",
|
|
41
|
+
"agents.empty": "No workspace agent is configured yet.",
|
|
42
|
+
"agents.ready": "Ready",
|
|
43
|
+
"agents.requires_input": "Requires input",
|
|
44
|
+
"agents.not_ready": "Configuration incomplete",
|
|
45
|
+
"agents.no_provider": "No LLM provider",
|
|
46
|
+
"agents.input_title": "Agent input",
|
|
47
|
+
"agents.input_hint": "Provide the input required for this run.",
|
|
48
|
+
"agents.run": "Run agent",
|
|
49
|
+
"agents.loading": "Running agent…",
|
|
50
|
+
"agents.success": "Agent run completed",
|
|
51
|
+
"agents.failure": "Agent run failed",
|
|
52
|
+
"agents.open_document": "Open document",
|
|
53
|
+
"agents.load_failed": "Failed to load workspace agents.",
|
|
54
|
+
"agents.run_failed": "Agent run failed.",
|
|
55
|
+
|
|
38
56
|
"files.title": "📁 Attached files",
|
|
39
57
|
"files.empty": "No files yet — upload one from a document editor (paperclip, drag & drop, or paste).",
|
|
40
58
|
"files.replace": "Replace",
|
|
@@ -591,7 +609,26 @@
|
|
|
591
609
|
"diagram.toolbar.shape_editor": "Custom shape editor",
|
|
592
610
|
"diagram.toolbar.arrow": "Arrow (F)",
|
|
593
611
|
"diagram.toolbar.delete": "Delete (Del)",
|
|
612
|
+
"diagram.toolbar.defaults": "Diagram defaults — configure default sizes, colors and styles",
|
|
594
613
|
"diagram.toolbar.align_guides": "Alignment guides — highlights same-type shape alignment",
|
|
614
|
+
"diagram.defaults.title": "Diagram defaults",
|
|
615
|
+
"diagram.defaults.section.arrows": "Arrows",
|
|
616
|
+
"diagram.defaults.section.shapes": "Shapes",
|
|
617
|
+
"diagram.defaults.field.direction": "Direction",
|
|
618
|
+
"diagram.defaults.field.style": "Style",
|
|
619
|
+
"diagram.defaults.field.font_size": "Font size",
|
|
620
|
+
"diagram.defaults.field.width": "W",
|
|
621
|
+
"diagram.defaults.field.height": "H",
|
|
622
|
+
"diagram.defaults.field.color": "Color",
|
|
623
|
+
"diagram.defaults.style.solid": "Solid",
|
|
624
|
+
"diagram.defaults.style.dashed": "Dashed",
|
|
625
|
+
"diagram.defaults.shape.box": "Rectangle",
|
|
626
|
+
"diagram.defaults.shape.ellipse": "Ellipse",
|
|
627
|
+
"diagram.defaults.shape.circle": "Circle",
|
|
628
|
+
"diagram.defaults.shape.database": "Database",
|
|
629
|
+
"diagram.defaults.shape.actor": "Actor",
|
|
630
|
+
"diagram.defaults.shape.postit": "Post-it",
|
|
631
|
+
"diagram.defaults.shape.text_free": "Free text",
|
|
595
632
|
"diagram.toolbar.grid": "Grid / Snap to grid (G)",
|
|
596
633
|
"diagram.toolbar.edge_style": "Toggle curved / straight arrows",
|
|
597
634
|
"diagram.toolbar.resize_corner": "Resize mode: fixed corner (click for fixed centre)",
|
|
@@ -609,6 +646,8 @@
|
|
|
609
646
|
"diagram.sidebar.empty": "No diagrams",
|
|
610
647
|
"diagram.sidebar.delete_title": "Delete",
|
|
611
648
|
|
|
649
|
+
"diagram.node_panel.color": "Shape color",
|
|
650
|
+
"diagram.node_panel.save_as_default": "Save as default for this shape type",
|
|
612
651
|
"diagram.node_panel.lock": "Lock selection",
|
|
613
652
|
"diagram.node_panel.unlock": "Unlock selection",
|
|
614
653
|
"diagram.node_panel.edit_label": "Edit text (double-click)",
|
|
@@ -648,6 +687,9 @@
|
|
|
648
687
|
"diagram.link_panel.save_btn": "Save",
|
|
649
688
|
"diagram.link_panel.remove_btn": "Remove",
|
|
650
689
|
|
|
690
|
+
"diagram.edge_panel.font_size_value": "Font size",
|
|
691
|
+
"diagram.edge_panel.color": "Arrow color",
|
|
692
|
+
"diagram.edge_panel.save_as_default": "Save as default for arrows",
|
|
651
693
|
"diagram.edge_panel.lock": "Lock arrow",
|
|
652
694
|
"diagram.edge_panel.unlock": "Unlock arrow",
|
|
653
695
|
"diagram.edge_panel.no_arrow": "Simple line",
|