kingkont 0.20.54 → 0.20.56

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.54",
3
+ "version": "0.20.56",
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
@@ -4110,7 +4110,10 @@ async function createNodeEl(node) {
4110
4110
  // (ensureNodeDescriptionEl идемпотентно создаёт/обновляет/удаляет).
4111
4111
  // Вызывается ЗДЕСЬ, чтобы покрыть все вызовы createNodeEl: renderCanvas
4112
4112
  // / generate.js (новые ноды) / timeline.js / drawings.js / chat.js.
4113
- if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node);
4113
+ // Передаём el-hint .node ещё не в canvas DOM (caller сделает appendChild
4114
+ // после return), и без hint'а measure'а .node-footer не сработает →
4115
+ // placeholder перекрыл бы regen-кнопки.
4116
+ if (typeof ensureNodeDescriptionEl === 'function') ensureNodeDescriptionEl(node, el);
4114
4117
  return el;
4115
4118
  }
4116
4119
  // =================== Контекстное меню ноды (ПКМ) ===================
@@ -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
 
@@ -1908,7 +1908,10 @@
1908
1908
  .modal.hidden { display: none; }
1909
1909
  .modal-card {
1910
1910
  background: #2a2a2a; border: 1px solid #444; border-radius: 12px;
1911
- padding: 24px; width: 540px; max-width: 92vw; max-height: 90vh;
1911
+ /* padding-bottom=0: .modal-actions сама даёт нижний паддинг через свой
1912
+ padding-bottom — нужно чтобы sticky-bottom:0 ровно совпал с краем
1913
+ модалки. */
1914
+ padding: 24px 24px 0; width: 540px; max-width: 92vw; max-height: 90vh;
1912
1915
  overflow-y: auto; display: flex; flex-direction: column; gap: 14px;
1913
1916
  position: relative;
1914
1917
  }
@@ -1928,7 +1931,20 @@
1928
1931
  }
1929
1932
  .modal-card input:focus, .modal-card textarea:focus, .modal-card select:focus { border-color: #6a8aaa; }
1930
1933
  .modal-card textarea { resize: vertical; min-height: 100px; }
1931
- .modal-actions { display: flex; gap: 8px; align-items: center; margin-top: 4px; }
1934
+ /* Кнопки внизу модалки залипают к её низу юзер: «сделай чтобы кнопки
1935
+ прилипали к нижней части модалки и были всегда видны, во всех модалках».
1936
+ Sticky bottom:0 пинит к нижнему краю scroll-контейнера (modal-card),
1937
+ negative margin-left/right компенсирует padding modal-card'а (24px),
1938
+ padding 14px 24px 24px даёт собственный bottom-pad. */
1939
+ .modal-actions {
1940
+ display: flex; gap: 8px; align-items: center;
1941
+ position: sticky; bottom: 0;
1942
+ margin: 14px -24px 0;
1943
+ padding: 14px 24px 24px;
1944
+ background: #2a2a2a;
1945
+ border-top: 1px solid #383838;
1946
+ z-index: 5;
1947
+ }
1932
1948
  .modal-actions .spacer { flex: 1; }
1933
1949
  .seg-control { display: flex; }
1934
1950
  .seg-control .seg { flex: 1; background: #1e1e1e; border: 1px solid #383838; border-radius: 0; }