kingkont 0.14.4 → 0.14.6
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 +18 -14
- package/renderer/chat.js +22 -3
- package/renderer/styles.css +15 -1
package/package.json
CHANGED
package/renderer/board.js
CHANGED
|
@@ -1873,9 +1873,20 @@ async function selectBoard(board) {
|
|
|
1873
1873
|
applyZoomStyles(state.zoom);
|
|
1874
1874
|
$('zoomLabel').textContent = Math.round(state.zoom * 100) + '%';
|
|
1875
1875
|
}
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1876
|
+
} else {
|
|
1877
|
+
state.zoom = 1;
|
|
1878
|
+
applyZoomStyles(1);
|
|
1879
|
+
$('zoomLabel').textContent = '100%';
|
|
1880
|
+
}
|
|
1881
|
+
// ВАЖНО: applyZoomStyles ресайзит frame через setTimeout 200ms. Если
|
|
1882
|
+
// ставить scrollLeft СРАЗУ — браузер клампит к старому frame.scrollWidth
|
|
1883
|
+
// (zoom<1 → frame маленький → scroll урезается). Поэтому сначала
|
|
1884
|
+
// форсим frame в полный размер прямо сейчас, потом ставим scroll.
|
|
1885
|
+
const z = state.zoom || 1;
|
|
1886
|
+
document.querySelector('.canvas-frame').style.width = (6000 * z + 2 * padX) + 'px';
|
|
1887
|
+
document.querySelector('.canvas-frame').style.height = (4000 * z + 2 * padY) + 'px';
|
|
1888
|
+
if (view) {
|
|
1889
|
+
// Backward-compat старых view (без padding) — добавляем.
|
|
1879
1890
|
if (typeof view.scrollLeft === 'number') {
|
|
1880
1891
|
canvasWrap.scrollLeft = view.scrollLeft >= padX ? view.scrollLeft : view.scrollLeft + padX;
|
|
1881
1892
|
} else canvasWrap.scrollLeft = padX;
|
|
@@ -1883,21 +1894,14 @@ async function selectBoard(board) {
|
|
|
1883
1894
|
canvasWrap.scrollTop = view.scrollTop >= padY ? view.scrollTop : view.scrollTop + padY;
|
|
1884
1895
|
} else canvasWrap.scrollTop = padY;
|
|
1885
1896
|
} else {
|
|
1886
|
-
state.zoom = 1;
|
|
1887
|
-
applyZoomStyles(1);
|
|
1888
|
-
$('zoomLabel').textContent = '100%';
|
|
1889
1897
|
canvasWrap.scrollLeft = padX;
|
|
1890
1898
|
canvasWrap.scrollTop = padY;
|
|
1891
1899
|
}
|
|
1892
1900
|
|
|
1893
|
-
// Auto-scroll к bbox нод
|
|
1894
|
-
//
|
|
1895
|
-
//
|
|
1896
|
-
|
|
1897
|
-
// невидимым, view перебивался → юзер терял сохранённую позицию.
|
|
1898
|
-
if (!view || (typeof view.scrollLeft !== 'number' && typeof view.scrollTop !== 'number')) {
|
|
1899
|
-
requestAnimationFrame(() => _autoScrollToNodesIfHidden(padX, padY));
|
|
1900
|
-
}
|
|
1901
|
+
// Auto-scroll к bbox нод если ни одна не попадает в viewport.
|
|
1902
|
+
// Frame уже ресайзнут синхронно выше, scroll проставлен корректно —
|
|
1903
|
+
// в next frame _autoScrollToNodesIfHidden имеет валидную картинку.
|
|
1904
|
+
requestAnimationFrame(() => _autoScrollToNodesIfHidden(padX, padY));
|
|
1901
1905
|
|
|
1902
1906
|
// Возобновить незавершённые джобы текущей доски
|
|
1903
1907
|
for (const n of state.currentBoard.metadata.nodes) {
|
package/renderer/chat.js
CHANGED
|
@@ -816,7 +816,8 @@
|
|
|
816
816
|
const parts = [];
|
|
817
817
|
if (ctx.scene) parts.push({ key: 'scene', label: `🎬 ${ctx.scene.name}`, removable: false });
|
|
818
818
|
// Группируем выделенные ноды по type. Если 1 — показываем имя/id;
|
|
819
|
-
// если 2+ — «N картинок» с локализацией.
|
|
819
|
+
// если 2+ — «N картинок» с локализацией. Клик по чипу — снимает
|
|
820
|
+
// выделение с этой ноды (или со всех нод этого type для группы).
|
|
820
821
|
const byType = {};
|
|
821
822
|
for (const sel of ctx.selected) {
|
|
822
823
|
(byType[sel.type] = byType[sel.type] || []).push(sel);
|
|
@@ -825,10 +826,28 @@
|
|
|
825
826
|
const icon = type === 'image' ? '🖼' : type === 'video' ? '🎬' : type === 'audio' ? '🎙' : type === 'text' ? '📝' : '◉';
|
|
826
827
|
if (items.length === 1) {
|
|
827
828
|
const s = items[0];
|
|
828
|
-
parts.push({
|
|
829
|
+
parts.push({
|
|
830
|
+
key: 'sel:' + s.id,
|
|
831
|
+
label: `${icon} ${s.name || s.id.slice(0, 6)}`,
|
|
832
|
+
removable: true,
|
|
833
|
+
onRemove: () => {
|
|
834
|
+
state.selectedNodeIds.delete(s.id);
|
|
835
|
+
if (typeof renderSelection === 'function') renderSelection();
|
|
836
|
+
renderContextRow();
|
|
837
|
+
},
|
|
838
|
+
});
|
|
829
839
|
} else {
|
|
830
840
|
const noun = _typeForms[type] || ['нода','ноды','нод'];
|
|
831
|
-
parts.push({
|
|
841
|
+
parts.push({
|
|
842
|
+
key: 'sel-grp:' + type,
|
|
843
|
+
label: `${icon} ${items.length} ${_ru_plural(items.length, noun)}`,
|
|
844
|
+
removable: true,
|
|
845
|
+
onRemove: () => {
|
|
846
|
+
for (const it of items) state.selectedNodeIds.delete(it.id);
|
|
847
|
+
if (typeof renderSelection === 'function') renderSelection();
|
|
848
|
+
renderContextRow();
|
|
849
|
+
},
|
|
850
|
+
});
|
|
832
851
|
}
|
|
833
852
|
}
|
|
834
853
|
for (const a of ctx.attachments) {
|
package/renderer/styles.css
CHANGED
|
@@ -260,6 +260,10 @@
|
|
|
260
260
|
box-shadow: -8px 0 32px rgba(0,0,0,0.4);
|
|
261
261
|
/* --chat-font задаётся inline в chat.js (Cmd+/Cmd-). Дефолт 13px. */
|
|
262
262
|
font-size: var(--chat-font, 13px);
|
|
263
|
+
/* Защита от horizontal-overflow: дочерние flex-элементы (длинные
|
|
264
|
+
имена чипов, tool-args в pre) могли push'ать ширину — fixed
|
|
265
|
+
position спасал, но без этого max-width дочерних не работал. */
|
|
266
|
+
overflow-x: hidden; box-sizing: border-box;
|
|
263
267
|
}
|
|
264
268
|
.chat-panel.chat-drag::before {
|
|
265
269
|
content: '📎 Отпусти, чтобы прикрепить файл к чату';
|
|
@@ -274,6 +278,11 @@
|
|
|
274
278
|
display: flex; flex-wrap: wrap; gap: 4px;
|
|
275
279
|
padding: 6px 10px;
|
|
276
280
|
background: #1a1a1a; border-top: 1px solid #2a2a2a;
|
|
281
|
+
/* min-width:0 — без этого flex-children не «сжимаются», и длинная
|
|
282
|
+
строка чипов раздвигает родителя (chat-panel получает горизонтальный
|
|
283
|
+
overflow). С flex-wrap:wrap + min-width:0 чипы корректно
|
|
284
|
+
переносятся на следующую строку. */
|
|
285
|
+
min-width: 0; max-width: 100%; box-sizing: border-box;
|
|
277
286
|
}
|
|
278
287
|
.chat-context-row:empty { display: none; }
|
|
279
288
|
.chat-chip {
|
|
@@ -281,7 +290,12 @@
|
|
|
281
290
|
background: #232a36; border: 1px solid #2c3848;
|
|
282
291
|
color: #aac; font-size: 11px;
|
|
283
292
|
padding: 2px 8px; border-radius: 999px;
|
|
284
|
-
max-width: 200px
|
|
293
|
+
max-width: 100%; /* был 200px — длинные имена ужимались, но
|
|
294
|
+
если width контейнера меньше 200px, чип всё
|
|
295
|
+
ещё мог push'нуть строку. 100% относительно
|
|
296
|
+
.chat-context-row → гарантированно влезает. */
|
|
297
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
298
|
+
min-width: 0; /* чтобы flex-shrink работал */
|
|
285
299
|
}
|
|
286
300
|
.chat-chip-x {
|
|
287
301
|
background: transparent; border: none; color: #889;
|