kingkont 0.20.46 → 0.20.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/renderer/board.js +34 -16
- package/renderer/generate.js +4 -2
- package/renderer/settings.js +35 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.48",
|
|
4
4
|
"description": "KingKont \u00b7 Chatium \u2014 \u043d\u043e\u0434-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0441\u0446\u0435\u043d \u0441 AI-\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 (\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438/\u0432\u0438\u0434\u0435\u043e/\u0433\u043e\u043b\u043e\u0441/SFX/\u043c\u0443\u0437\u044b\u043a\u0430/\u0442\u0435\u043a\u0441\u0442)",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"bin": {
|
package/renderer/board.js
CHANGED
|
@@ -1671,7 +1671,14 @@ async function openShareModal(p) {
|
|
|
1671
1671
|
// там приложение живёт на kingkont.ru. В web используем origin.
|
|
1672
1672
|
const isLocal = /^https?:\/\/(localhost|127\.0\.0\.1)/.test(location.origin);
|
|
1673
1673
|
const base = isLocal ? 'https://kingkont.ru' : location.origin;
|
|
1674
|
-
|
|
1674
|
+
// Раньше: /static/web.html — но chatium-edge кэширует этот путь
|
|
1675
|
+
// НАВЕЧНО, и юзеры получали старую версию HTML со старыми хешами
|
|
1676
|
+
// скриптов. Старые cloudProjects.js не имеют R2 pub→worker rewrite
|
|
1677
|
+
// → картинки 503 → «Файл не найден».
|
|
1678
|
+
// Сейчас: /app/spaces/client/ — auth-aware stub, который JS'ом
|
|
1679
|
+
// редиректит на свежий /static/web-<sha>.html (новое имя файла =
|
|
1680
|
+
// свежий cache-entry на каждом deploy).
|
|
1681
|
+
return base + '/app/spaces/client/#template=' + proj.id;
|
|
1675
1682
|
}
|
|
1676
1683
|
function render() {
|
|
1677
1684
|
const isPub = !!proj.isPublic;
|
|
@@ -2589,6 +2596,31 @@ async function promptBoardAspectRatio(kind, item) {
|
|
|
2589
2596
|
}
|
|
2590
2597
|
console.log(`[board] ${kind}/${item.name} aspectRatio → ${chosen}`);
|
|
2591
2598
|
}
|
|
2599
|
+
// Открыть редактор описания image/video-ноды.
|
|
2600
|
+
// Юзер: «дабл-клик на описании ноды должен открывать его редактирование».
|
|
2601
|
+
// Также используется из ПКМ ноды (📝 Изменить/Добавить описание).
|
|
2602
|
+
async function editNodeDescription(node) {
|
|
2603
|
+
if (!node || (node.type !== 'image' && node.type !== 'video')) return;
|
|
2604
|
+
const next = await askName(
|
|
2605
|
+
'Описание ноды (Cmd+Enter — сохранить):',
|
|
2606
|
+
'Например: лес ночью, луна за облаками, тишина',
|
|
2607
|
+
node.description || '',
|
|
2608
|
+
{ multiline: true, okText: 'Сохранить' },
|
|
2609
|
+
);
|
|
2610
|
+
if (next == null) return;
|
|
2611
|
+
node.description = next;
|
|
2612
|
+
scheduleSave();
|
|
2613
|
+
if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node);
|
|
2614
|
+
// Перерасчёт node.height — описание участвует в bbox'е (см.
|
|
2615
|
+
// fitNodeHeightToMedia в settings.js → расширяет node.height на descH).
|
|
2616
|
+
const el = canvas.querySelector(`.node[data-id="${node.id}"]`);
|
|
2617
|
+
const media = el?.querySelector('img, video');
|
|
2618
|
+
if (typeof fitNodeHeightToMedia === 'function' && el && media) {
|
|
2619
|
+
fitNodeHeightToMedia(node, el, media);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
window.editNodeDescription = editNodeDescription;
|
|
2623
|
+
|
|
2592
2624
|
// Скопировать / вставить настройки сцены (aspectRatio + defaultPrompts).
|
|
2593
2625
|
// Хранение — in-memory state.clipboardSceneSettings (живёт до closeProject).
|
|
2594
2626
|
// Юзер: «сделай возможность скопировать настройки из одной сцены в другую».
|
|
@@ -4242,21 +4274,7 @@ function showNodeContextMenu(node, clientX, clientY) {
|
|
|
4242
4274
|
// (см. renderNodeBody), это удобный picker для крупного редактирования.
|
|
4243
4275
|
if (node.type === 'image' || node.type === 'video') {
|
|
4244
4276
|
const hasDesc = !!(node.description && node.description.trim());
|
|
4245
|
-
add(hasDesc ? '📝 Изменить описание…' : '📝 Добавить описание…',
|
|
4246
|
-
const next = await askName(
|
|
4247
|
-
'Описание ноды (Cmd+Enter — сохранить):',
|
|
4248
|
-
'Например: лес ночью, луна за облаками, тишина',
|
|
4249
|
-
node.description || '',
|
|
4250
|
-
{ multiline: true, okText: 'Сохранить' },
|
|
4251
|
-
);
|
|
4252
|
-
if (next == null) return;
|
|
4253
|
-
node.description = next;
|
|
4254
|
-
scheduleSave();
|
|
4255
|
-
// Sidecar-описание — отдельный элемент на canvas'е, см.
|
|
4256
|
-
// ensureNodeDescriptionEl в settings.js. Идемпотентно: пересоздаёт/
|
|
4257
|
-
// удаляет/обновляет в зависимости от того, есть ли текст.
|
|
4258
|
-
if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node);
|
|
4259
|
-
});
|
|
4277
|
+
add(hasDesc ? '📝 Изменить описание…' : '📝 Добавить описание…', () => editNodeDescription(node));
|
|
4260
4278
|
}
|
|
4261
4279
|
// Image-нода как обложка проекта — копируется в `<project>/.cover.<ext>`,
|
|
4262
4280
|
// оттуда подхватывается generateProjectThumb (для recents и шаблонов).
|
package/renderer/generate.js
CHANGED
|
@@ -1211,8 +1211,10 @@ function renderLocPickSelect() {
|
|
|
1211
1211
|
}
|
|
1212
1212
|
|
|
1213
1213
|
function syncCharLocRows() {
|
|
1214
|
-
|
|
1215
|
-
|
|
1214
|
+
// «Персонажи» picker убран (юзер: «убери Персонажи из общего»).
|
|
1215
|
+
// Юзер берёт референс персонажа через @-mention в самом промпте —
|
|
1216
|
+
// это универсальнее (несколько рефов, кастомные ноды-персонажи и т.д.).
|
|
1217
|
+
$('charsPickRow').style.display = 'none';
|
|
1216
1218
|
// «Из общего» теперь только для видео — для image юзер берёт референс
|
|
1217
1219
|
// через @-mention из «Эта сцена»/общих досок (так универсальнее).
|
|
1218
1220
|
$('locPickRow').style.display = state.genKind === 'video' ? '' : 'none';
|
package/renderer/settings.js
CHANGED
|
@@ -604,6 +604,17 @@ function ensureNodeDescriptionEl(node) {
|
|
|
604
604
|
el.className = 'node-description-outside';
|
|
605
605
|
el.dataset.descFor = node.id;
|
|
606
606
|
canvasEl.appendChild(el);
|
|
607
|
+
// Дабл-клик по описанию → редактор (юзер: «дабл-клик на описании ноды
|
|
608
|
+
// должен открывать его редактирование»). editNodeDescription —
|
|
609
|
+
// глобал из board.js. e.stopPropagation — иначе дабл-клик пробрасывался
|
|
610
|
+
// в .node и срабатывало fullscreen-просмотр.
|
|
611
|
+
el.addEventListener('dblclick', e => {
|
|
612
|
+
e.stopPropagation();
|
|
613
|
+
e.preventDefault();
|
|
614
|
+
if (typeof window.editNodeDescription === 'function') {
|
|
615
|
+
window.editNodeDescription(node);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
607
618
|
}
|
|
608
619
|
if (el.textContent !== text) el.textContent = text;
|
|
609
620
|
positionNodeDescriptionEl(node, el);
|
|
@@ -614,9 +625,16 @@ function positionNodeDescriptionEl(node, el) {
|
|
|
614
625
|
if (!el) return;
|
|
615
626
|
const w = node.width || 280;
|
|
616
627
|
const h = node.height || 200;
|
|
617
|
-
|
|
628
|
+
// Описание прикреплено к НИЖНЕЙ части bbox самой ноды (НЕ ниже неё).
|
|
629
|
+
// Раньше top = node.y + h + GAP — sidecar улетал вниз, и если сосед
|
|
630
|
+
// был близко, описание перекрывало его. Юзер: «сейчас на ноде её
|
|
631
|
+
// описание показывается над нодой которая расположена выше».
|
|
632
|
+
// Теперь node.height расширен на descH (см. fitNodeHeightToMedia), и
|
|
633
|
+
// sidecar помещён внутри bbox у самого низа. Соседняя нода физически
|
|
634
|
+
// не может попасть в зону описания.
|
|
635
|
+
const descH = el.offsetHeight || 0;
|
|
618
636
|
el.style.left = node.x + 'px';
|
|
619
|
-
el.style.top = (node.y + h
|
|
637
|
+
el.style.top = (node.y + h - descH - 2) + 'px';
|
|
620
638
|
el.style.width = w + 'px';
|
|
621
639
|
}
|
|
622
640
|
function removeNodeDescriptionEl(nodeId) {
|
|
@@ -640,9 +658,22 @@ function fitNodeHeightToMedia(node, nodeEl, mediaEl) {
|
|
|
640
658
|
// Берём актуальную width — node.width если задано, иначе текущий offsetWidth.
|
|
641
659
|
const w = node.width || nodeEl.offsetWidth;
|
|
642
660
|
if (!w) return;
|
|
643
|
-
|
|
661
|
+
// Высота описания (если есть) — описание занимает нижнюю часть bbox'а
|
|
662
|
+
// ноды (см. positionNodeDescriptionEl). Без этого описание выходило за
|
|
663
|
+
// пределы node.height и «накладывалось» на соседнюю ноду снизу. Юзер:
|
|
664
|
+
// «на ноде её описание показывается над нодой которая расположена выше».
|
|
665
|
+
const descEl = (node.description || '').trim()
|
|
666
|
+
? document.querySelector(`.node-description-outside[data-desc-for="${node.id}"]`)
|
|
667
|
+
: null;
|
|
668
|
+
const descH = descEl ? descEl.offsetHeight + 4 : 0; // +4 чтобы зрительно отделять
|
|
669
|
+
const newH = Math.round(w * (natH / natW) + chromeH + descH);
|
|
644
670
|
// 2px tolerance — не шумим в save/connections при суб-пиксельных колебаниях.
|
|
645
|
-
if (Math.abs(newH - (node.height || 0)) <= 2)
|
|
671
|
+
if (Math.abs(newH - (node.height || 0)) <= 2) {
|
|
672
|
+
// Высоту не меняем, но позицию sidecar'а всё равно обновим — а вдруг
|
|
673
|
+
// описание появилось/изменилось до того как media догрузилось.
|
|
674
|
+
positionNodeDescriptionEl(node);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
646
677
|
node.height = newH;
|
|
647
678
|
nodeEl.style.height = newH + 'px';
|
|
648
679
|
if (typeof renderConnections === 'function') renderConnections();
|