kingkont 0.20.55 → 0.20.57

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.20.55",
3
+ "version": "0.20.57",
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
@@ -4065,6 +4065,15 @@ async function createNodeEl(node) {
4065
4065
  el.addEventListener('dblclick', e => {
4066
4066
  if (e.target.closest('textarea, input, video, button, .delete, .anchor, .resize-handle, [contenteditable]'))
4067
4067
  return;
4068
+ // Cmd/Ctrl + дабл-клик → модалка генерации (regenerateNode).
4069
+ // Юзер: «сделай чтобы дабл-клик на ноде с зажатым cmd показывал
4070
+ // модалку генерации». Полезно для уже сгенерированных image/video —
4071
+ // обычный дабл-клик открывает fullscreen, cmd-вариант даёт быстрый
4072
+ // путь к перегенерации без правого-клика.
4073
+ if ((e.metaKey || e.ctrlKey) && node.generated) {
4074
+ regenerateNode(node);
4075
+ return;
4076
+ }
4068
4077
  // Если у ноды есть link на сцену — переход важнее остальных действий.
4069
4078
  if (node.linkedBoard?.name) {
4070
4079
  goToLinkedBoard(node);
@@ -4110,7 +4119,10 @@ async function createNodeEl(node) {
4110
4119
  // (ensureNodeDescriptionEl идемпотентно создаёт/обновляет/удаляет).
4111
4120
  // Вызывается ЗДЕСЬ, чтобы покрыть все вызовы createNodeEl: renderCanvas
4112
4121
  // / generate.js (новые ноды) / timeline.js / drawings.js / chat.js.
4113
- if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node);
4122
+ // Передаём el-hint .node ещё не в canvas DOM (caller сделает appendChild
4123
+ // после return), и без hint'а measure'а .node-footer не сработает →
4124
+ // placeholder перекрыл бы regen-кнопки.
4125
+ if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node, el);
4114
4126
  return el;
4115
4127
  }
4116
4128
  // =================== Контекстное меню ноды (ПКМ) ===================
@@ -587,7 +587,7 @@ async function renderNodeBody(node, body) {
587
587
  // «попробуем показать описание ВНЕ этой ноды, но так чтобы оно с ней
588
588
  // перемещалось… совпадало с ней по ширине, а высота — сколько займет текст».
589
589
  // Идемпотентно: пересоздаёт DOM, если описание изменилось/добавилось/удалилось.
590
- function ensureNodeDescriptionEl(node) {
590
+ function ensureNodeDescriptionEl(node, nodeElHint) {
591
591
  if (!node) return null;
592
592
  const canvasEl = document.getElementById('canvas');
593
593
  if (!canvasEl) return null;
@@ -638,24 +638,29 @@ function ensureNodeDescriptionEl(node) {
638
638
  el.classList.remove('empty');
639
639
  if (el.textContent !== text) el.textContent = text;
640
640
  }
641
- positionNodeDescriptionEl(node, el);
641
+ positionNodeDescriptionEl(node, el, nodeElHint);
642
+ // Если в этот момент .node ещё не вставлен в canvas — querySelector
643
+ // вернёт null → footerH=0 → placeholder сел поверх footer'а. Через rAF
644
+ // делаем повторный pass: к этому моменту caller сделал appendChild,
645
+ // footer измерим, sidecar сдвинется чуть выше.
646
+ requestAnimationFrame(() => positionNodeDescriptionEl(node, el));
642
647
  return el;
643
648
  }
644
- function positionNodeDescriptionEl(node, el) {
649
+ function positionNodeDescriptionEl(node, el, nodeElHint) {
645
650
  if (!el) el = document.querySelector(`.node-description-outside[data-desc-for="${node.id}"]`);
646
651
  if (!el) return;
647
652
  const w = node.width || 280;
648
653
  const h = node.height || 200;
649
- // Описание прикреплено к НИЖНЕЙ части bbox самой ноды (НЕ ниже неё).
650
- // Раньше top = node.y + h + GAP — sidecar улетал вниз, и если сосед
651
- // был близко, описание перекрывало его. Юзер: «сейчас на ноде её
652
- // описание показывается над нодой которая расположена выше».
653
- // Теперь node.height расширен на descH (см. fitNodeHeightToMedia), и
654
- // sidecar помещён внутри bbox у самого низа. Соседняя нода физически
655
- // не может попасть в зону описания.
654
+ // У image/video с node.generated есть .node-footer (regen-btn, история ←/→)
655
+ // она у нижней грани. Поднимаем sidecar НАД footer'ом на footerH+2
656
+ // выше иначе placeholder «Добавить описание» перекрывал бы regen-кнопки
657
+ // (юзер: «после появления кнопки добавить описание из ноды пропал ряд
658
+ // кнопок который делал перегенерацию»).
659
+ const nodeEl = nodeElHint || document.querySelector(`.node[data-id="${node.id}"]`);
660
+ const footerH = nodeEl?.querySelector('.node-footer')?.offsetHeight || 0;
656
661
  const descH = el.offsetHeight || 0;
657
662
  el.style.left = node.x + 'px';
658
- el.style.top = (node.y + h - descH - 2) + 'px';
663
+ el.style.top = (node.y + h - footerH - descH - 2) + 'px';
659
664
  el.style.width = w + 'px';
660
665
  }
661
666
  function removeNodeDescriptionEl(nodeId) {
@@ -690,13 +695,13 @@ function fitNodeHeightToMedia(node, nodeEl, mediaEl) {
690
695
  if (Math.abs(newH - (node.height || 0)) <= 2) {
691
696
  // Высоту не меняем, но позицию sidecar'а всё равно обновим — а вдруг
692
697
  // описание появилось/изменилось до того как media догрузилось.
693
- positionNodeDescriptionEl(node);
698
+ positionNodeDescriptionEl(node, null, nodeEl);
694
699
  return;
695
700
  }
696
701
  node.height = newH;
697
702
  nodeEl.style.height = newH + 'px';
698
703
  if (typeof renderConnections === 'function') renderConnections();
699
- positionNodeDescriptionEl(node);
704
+ positionNodeDescriptionEl(node, null, nodeEl);
700
705
  scheduleSave();
701
706
  }
702
707