kingkont 0.7.93 → 0.7.95

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.7.93",
3
+ "version": "0.7.95",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -396,10 +396,22 @@ async function renderNodeBody(node, body) {
396
396
  media = document.createElement('img');
397
397
  media.src = url; media.alt = node.file; media.draggable = false;
398
398
  media.decoding = 'async';
399
+ // Auto-fit высоты ноды под aspect картинки. Иначе после генерации
400
+ // (где node.width/height заморожены до прихода файла) или после
401
+ // замены картинки через history новый <img> с object-fit:contain
402
+ // оставляет пустое место сверху/снизу — node.height не совпадает
403
+ // с display-height image'а.
404
+ media.addEventListener('load', () => fitNodeHeightToMedia(node, nodeEl, media), { once: true });
399
405
  } else {
400
406
  media = document.createElement(node.type);
401
407
  media.src = url;
402
- if (node.type === 'video') media.controls = true;
408
+ if (node.type === 'video') {
409
+ media.controls = true;
410
+ // То же для видео — но через loadedmetadata, который у preload:none
411
+ // выстрелит при первой попытке play. Когда юзер запустит — нода
412
+ // подстроится под реальный aspect.
413
+ media.addEventListener('loadedmetadata', () => fitNodeHeightToMedia(node, nodeEl, media), { once: true });
414
+ }
403
415
  // preload="none" — заголовки video/audio НЕ читаются пока юзер не запустит play.
404
416
  // Раньше "metadata" грузил chunk для duration/dimensions с каждой ноды на selectBoard.
405
417
  media.preload = 'none';
@@ -488,6 +500,32 @@ async function renderNodeBody(node, body) {
488
500
  }
489
501
  }
490
502
 
503
+ // Подгоняет node.height под natural-aspect медиа (image/video). Сохраняет
504
+ // текущую node.width, пересчитывает height = width * (natH/natW) + chrome.
505
+ // Без этого после генерации (или history-undo на ноду с другим aspect'ом)
506
+ // нода оставалась прежнего размера, и <img width:100%; height:auto> не
507
+ // заполнял её по высоте → пустое место снизу.
508
+ function fitNodeHeightToMedia(node, nodeEl, mediaEl) {
509
+ if (!nodeEl || !mediaEl) return;
510
+ const natW = mediaEl.naturalWidth || mediaEl.videoWidth || 0;
511
+ const natH = mediaEl.naturalHeight || mediaEl.videoHeight || 0;
512
+ if (!natW || !natH) return;
513
+ // Chrome — header + footer (если есть). image-node padding=0, ничего не отъедает.
514
+ const headerH = nodeEl.querySelector('.node-header')?.offsetHeight || 0;
515
+ const footerH = nodeEl.querySelector('.node-footer')?.offsetHeight || 0;
516
+ const chromeH = headerH + footerH;
517
+ // Берём актуальную width — node.width если задано, иначе текущий offsetWidth.
518
+ const w = node.width || nodeEl.offsetWidth;
519
+ if (!w) return;
520
+ const newH = Math.round(w * (natH / natW) + chromeH);
521
+ // 2px tolerance — не шумим в save/connections при суб-пиксельных колебаниях.
522
+ if (Math.abs(newH - (node.height || 0)) <= 2) return;
523
+ node.height = newH;
524
+ nodeEl.style.height = newH + 'px';
525
+ if (typeof renderConnections === 'function') renderConnections();
526
+ scheduleSave();
527
+ }
528
+
491
529
  function attachAnchor(node, el, anchor) {
492
530
  anchor.addEventListener('mousedown', e => {
493
531
  e.preventDefault();
@@ -700,15 +700,27 @@
700
700
  }
701
701
  .add-menu button:hover { background: #2c2c2c; }
702
702
 
703
- /* === Fullscreen viewer === */
703
+ /* === Fullscreen viewer ===
704
+ .fs-modal — фон + контейнер для absolute-позиционированных контролов
705
+ (× close, ← prev, → next).
706
+ .fs-stage — absolute inset:0 (гарантированный fill viewport'а), flex-
707
+ центровка картинки. Раньше .fs-modal был flex-row с align-items:center,
708
+ и .fs-stage с height:100% не растягивался на cross-axis (брал NATURAL
709
+ высоту), → картинка центрировалась не в полный viewport → казалось
710
+ что внизу куча пустого места. */
704
711
  .fs-modal {
705
712
  position: fixed; inset: 0; background: rgba(0,0,0,0.95);
706
- z-index: 1000; display: flex; align-items: center; justify-content: center;
713
+ z-index: 1000;
707
714
  }
708
715
  .fs-modal.hidden { display: none; }
709
- .fs-stage { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: 32px; }
716
+ .fs-stage {
717
+ position: absolute; inset: 0;
718
+ display: flex; align-items: center; justify-content: center;
719
+ padding: 16px 64px; /* по бокам — место под nav-кнопки */
720
+ }
710
721
  .fs-stage img, .fs-stage video {
711
722
  max-width: 100%; max-height: 100%; object-fit: contain;
723
+ display: block;
712
724
  }
713
725
  .fs-modal #fsClose {
714
726
  position: absolute; top: 16px; right: 16px;