kingkont 0.20.6 → 0.20.7
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/index.html +1 -1
- package/package.json +1 -1
- package/renderer/board.js +22 -2
- package/renderer/cloudProjects.js +2 -0
- package/renderer/generate.js +31 -0
package/index.html
CHANGED
package/package.json
CHANGED
package/renderer/board.js
CHANGED
|
@@ -1467,6 +1467,8 @@ async function openFilm(handle) {
|
|
|
1467
1467
|
// Подзаголовок шапки = имя открытого проекта (вместо «Видео-редактор»).
|
|
1468
1468
|
const sub = $('brandSub');
|
|
1469
1469
|
if (sub) { sub.textContent = handle.name; sub.classList.add('has-project'); }
|
|
1470
|
+
// Tab title = «<имя> — KingKont».
|
|
1471
|
+
document.title = (handle.name || 'Project') + ' — KingKont';
|
|
1470
1472
|
// Для cloud-проектов имя авторитетное на сервере (manifest.name). Если
|
|
1471
1473
|
// юзер пришёл по уведомлению / прямой ссылке — handle.name мог быть
|
|
1472
1474
|
// id или старое имя; подтягиваем актуальное и обновляем шапку +
|
|
@@ -1477,6 +1479,7 @@ async function openFilm(handle) {
|
|
|
1477
1479
|
.then(proj => {
|
|
1478
1480
|
if (!proj?.name || state.cloudProjectId !== proj.id) return;
|
|
1479
1481
|
if (sub && proj.name !== sub.textContent) sub.textContent = proj.name;
|
|
1482
|
+
document.title = proj.name + ' — KingKont';
|
|
1480
1483
|
// Patch handle.name (используется sidebar/recents и т.п.).
|
|
1481
1484
|
try { handle.name = proj.name; } catch {}
|
|
1482
1485
|
// Sync cache.
|
|
@@ -1518,6 +1521,7 @@ async function openFilm(handle) {
|
|
|
1518
1521
|
}
|
|
1519
1522
|
|
|
1520
1523
|
const raw = localStorage.getItem(`lastBoard:${handle.name}`);
|
|
1524
|
+
let restored = false;
|
|
1521
1525
|
if (raw) {
|
|
1522
1526
|
try {
|
|
1523
1527
|
const last = JSON.parse(raw);
|
|
@@ -1525,8 +1529,18 @@ async function openFilm(handle) {
|
|
|
1525
1529
|
: last.kind === 'location' ? await listLocations(handle)
|
|
1526
1530
|
: await listEpisodes(handle);
|
|
1527
1531
|
const found = list.find(x => x.name === last.name);
|
|
1528
|
-
if (found) await selectBoard({ kind: last.kind, ...found });
|
|
1529
|
-
} catch {}
|
|
1532
|
+
if (found) { await selectBoard({ kind: last.kind, ...found }); restored = true; }
|
|
1533
|
+
} catch (e) { console.warn('[openFilm] restore lastBoard failed:', e?.message || e); }
|
|
1534
|
+
}
|
|
1535
|
+
// Нет запомненной доски (первый open проекта) — авто-открываем первую сцену.
|
|
1536
|
+
// Без этого юзер видит пустой canvas с подсказкой «выбери сцену» и должен
|
|
1537
|
+
// лишний раз кликать в сайдбаре.
|
|
1538
|
+
if (!restored && !state.currentBoard) {
|
|
1539
|
+
try {
|
|
1540
|
+
const eps = await listEpisodes(handle);
|
|
1541
|
+
console.log('[openFilm] auto-select first scene:', eps.length, 'episodes');
|
|
1542
|
+
if (eps.length) await selectBoard({ kind: 'episode', ...eps[0] });
|
|
1543
|
+
} catch (e) { console.warn('[openFilm] auto-select failed:', e?.message || e); }
|
|
1530
1544
|
}
|
|
1531
1545
|
|
|
1532
1546
|
// Сканируем все доски на незавершённые задачи генерации (после перезагрузки)
|
|
@@ -1605,6 +1619,12 @@ async function closeProject() {
|
|
|
1605
1619
|
safe('dispatch project-changed', () => {
|
|
1606
1620
|
window.dispatchEvent(new CustomEvent('project-changed'));
|
|
1607
1621
|
});
|
|
1622
|
+
// Web: чистим hash (мы вернулись на welcome).
|
|
1623
|
+
if (window.__KINGKONT_WEB__ && location.hash.startsWith('#project=')) {
|
|
1624
|
+
history.replaceState(null, '', location.pathname + location.search);
|
|
1625
|
+
}
|
|
1626
|
+
// Reset tab title.
|
|
1627
|
+
document.title = 'KingKont';
|
|
1608
1628
|
state.charactersInfo = [];
|
|
1609
1629
|
state.locationsInfo = [];
|
|
1610
1630
|
state.selectedNodeIds.clear();
|
|
@@ -279,6 +279,7 @@
|
|
|
279
279
|
touchCloudOpened(projectId);
|
|
280
280
|
await openFilm(handle);
|
|
281
281
|
setCloudButtonsVisibility();
|
|
282
|
+
if (window.__KINGKONT_WEB__) location.hash = '#project=' + projectId;
|
|
282
283
|
return;
|
|
283
284
|
}
|
|
284
285
|
}
|
|
@@ -398,6 +399,7 @@
|
|
|
398
399
|
touchCloudOpened(projectId);
|
|
399
400
|
await openFilm(handle);
|
|
400
401
|
setCloudButtonsVisibility();
|
|
402
|
+
if (window.__KINGKONT_WEB__) location.hash = '#project=' + projectId;
|
|
401
403
|
PROGRESS.hide();
|
|
402
404
|
} catch (e) {
|
|
403
405
|
PROGRESS.hide();
|
package/renderer/generate.js
CHANGED
|
@@ -24,6 +24,14 @@ canvasWrap.addEventListener('contextmenu', e => {
|
|
|
24
24
|
// Rubber-band селектор + сброс выделения по клику в пустое место
|
|
25
25
|
canvasWrap.addEventListener('mousedown', e => {
|
|
26
26
|
if (!state.currentBoard) return;
|
|
27
|
+
// Middle-button (button=1) → pan-режим. Дефолтное поведение браузера —
|
|
28
|
+
// auto-scroll режим со специальным курсором; перехватываем чтобы пана
|
|
29
|
+
// через drag, без активации auto-scroll.
|
|
30
|
+
if (e.button === 1) {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
startMiddleMousePan(e);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
27
35
|
if (e.button !== 0) return;
|
|
28
36
|
if (e.target.closest('.node, .conn, .anchor, .resize-handle, button, input, textarea, select, .modal, #addMenu, #nodeMenu')) return;
|
|
29
37
|
// Если без модификатора — сбрасываем старое выделение
|
|
@@ -36,6 +44,29 @@ canvasWrap.addEventListener('mousedown', e => {
|
|
|
36
44
|
startRubberBand(e, additive);
|
|
37
45
|
});
|
|
38
46
|
|
|
47
|
+
// Pan через зажатую среднюю кнопку. Курсор меняем на grab во время дrag'а.
|
|
48
|
+
function startMiddleMousePan(e) {
|
|
49
|
+
const startX = e.clientX, startY = e.clientY;
|
|
50
|
+
const startScrollLeft = canvasWrap.scrollLeft;
|
|
51
|
+
const startScrollTop = canvasWrap.scrollTop;
|
|
52
|
+
const prevCursor = canvasWrap.style.cursor;
|
|
53
|
+
canvasWrap.style.cursor = 'grabbing';
|
|
54
|
+
document.body.style.userSelect = 'none';
|
|
55
|
+
const onMove = ev => {
|
|
56
|
+
canvasWrap.scrollLeft = startScrollLeft - (ev.clientX - startX);
|
|
57
|
+
canvasWrap.scrollTop = startScrollTop - (ev.clientY - startY);
|
|
58
|
+
};
|
|
59
|
+
const onUp = ev => {
|
|
60
|
+
if (ev.button !== 1) return;
|
|
61
|
+
document.removeEventListener('mousemove', onMove);
|
|
62
|
+
document.removeEventListener('mouseup', onUp);
|
|
63
|
+
canvasWrap.style.cursor = prevCursor;
|
|
64
|
+
document.body.style.userSelect = '';
|
|
65
|
+
};
|
|
66
|
+
document.addEventListener('mousemove', onMove);
|
|
67
|
+
document.addEventListener('mouseup', onUp);
|
|
68
|
+
}
|
|
69
|
+
|
|
39
70
|
function startRubberBand(e, additive) {
|
|
40
71
|
const rectStart = canvas.getBoundingClientRect();
|
|
41
72
|
const startC = { x: (e.clientX - rectStart.left) / state.zoom, y: (e.clientY - rectStart.top) / state.zoom };
|