kingkont 0.20.44 → 0.20.46
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/index.html +20 -3
- package/package.json +1 -1
- package/renderer/board.js +92 -8
- package/renderer/notifyPanel.js +21 -1
package/index.html
CHANGED
|
@@ -568,11 +568,28 @@
|
|
|
568
568
|
</div>
|
|
569
569
|
</div>
|
|
570
570
|
|
|
571
|
-
<!-- =====
|
|
571
|
+
<!-- ===== Настройки сцены: aspect ratio + дефолтные промпты ===== -->
|
|
572
572
|
<div class="modal hidden" id="defaultPromptsModal">
|
|
573
573
|
<div class="modal-card" style="min-width:600px; max-width:760px;">
|
|
574
|
-
<h3 id="defaultPromptsTitle"
|
|
575
|
-
|
|
574
|
+
<h3 id="defaultPromptsTitle">Настройки сцены</h3>
|
|
575
|
+
<!-- Соотношение сторон по умолчанию для image/video-генераций -->
|
|
576
|
+
<div class="field-row" style="margin-bottom:16px;">Соотношение сторон по умолчанию
|
|
577
|
+
<div class="seg-control" id="bsAspectCtl" style="flex-wrap:wrap;">
|
|
578
|
+
<button class="seg" data-bs-asp="9:16" type="button">9:16</button>
|
|
579
|
+
<button class="seg" data-bs-asp="16:9" type="button">16:9</button>
|
|
580
|
+
<button class="seg" data-bs-asp="1:1" type="button">1:1</button>
|
|
581
|
+
<button class="seg" data-bs-asp="4:5" type="button">4:5</button>
|
|
582
|
+
<button class="seg" data-bs-asp="5:4" type="button">5:4</button>
|
|
583
|
+
<button class="seg" data-bs-asp="4:3" type="button">4:3</button>
|
|
584
|
+
<button class="seg" data-bs-asp="3:4" type="button">3:4</button>
|
|
585
|
+
<button class="seg" data-bs-asp="2:3" type="button">2:3</button>
|
|
586
|
+
<button class="seg" data-bs-asp="3:2" type="button">3:2</button>
|
|
587
|
+
<button class="seg" data-bs-asp="21:9" type="button">21:9</button>
|
|
588
|
+
</div>
|
|
589
|
+
</div>
|
|
590
|
+
<!-- Дефолтные промпты (multi, с тегами kind) -->
|
|
591
|
+
<h4 style="margin:0 0 6px; font-size:13px; color:#bbb;">Дефолтные промпты</h4>
|
|
592
|
+
<div class="hint" style="margin-bottom:10px;">
|
|
576
593
|
Промпты добавляются к каждой генерации соответствующего типа в этой
|
|
577
594
|
сцене (НЕ редактируются в поле промпта — применяются в момент генерации).
|
|
578
595
|
В gen-модалке каждый можно отдельно включать/отключать.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.46",
|
|
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
|
@@ -2486,6 +2486,13 @@ function makeBoardItem(it, kind) {
|
|
|
2486
2486
|
nameSpan.textContent = it.name;
|
|
2487
2487
|
el.appendChild(nameSpan);
|
|
2488
2488
|
el.addEventListener('click', () => selectBoard({ kind, ...it }));
|
|
2489
|
+
// Дабл-клик по названию сцены — настройки сцены (aspect + defaultPrompts).
|
|
2490
|
+
// Юзер: «показывай форму настроек по дабл-клику на название сцены в сайдбаре».
|
|
2491
|
+
el.addEventListener('dblclick', e => {
|
|
2492
|
+
e.preventDefault();
|
|
2493
|
+
if (document.body.classList.contains('view-only-mode')) return;
|
|
2494
|
+
openDefaultPromptsDialog(kind, it);
|
|
2495
|
+
});
|
|
2489
2496
|
el.addEventListener('contextmenu', e => {
|
|
2490
2497
|
e.preventDefault();
|
|
2491
2498
|
// View-only: меню (rename/delete) бесполезно, см. node-comment выше.
|
|
@@ -2518,12 +2525,18 @@ function showBoardContextMenu(kind, item, clientX, clientY) {
|
|
|
2518
2525
|
alert('Не удалось переименовать: ' + (err?.message || err));
|
|
2519
2526
|
}
|
|
2520
2527
|
});
|
|
2521
|
-
//
|
|
2522
|
-
//
|
|
2523
|
-
//
|
|
2524
|
-
//
|
|
2525
|
-
add('
|
|
2526
|
-
|
|
2528
|
+
// Единая форма «Настройки сцены»: aspectRatio + defaultPrompts.
|
|
2529
|
+
// Раньше было два пункта (▭ Соотношение сторон + 📝 Дефолтные промпты),
|
|
2530
|
+
// юзер: «объедини дефолтные промпты и соотношение сторон в одну форму».
|
|
2531
|
+
// Доступно также по дабл-клику на названии сцены в сайдбаре.
|
|
2532
|
+
add('⚙ Настройки сцены…', () => openDefaultPromptsDialog(kind, item));
|
|
2533
|
+
// Скопировать / Вставить настройки между сценами.
|
|
2534
|
+
// Юзер: «сделай возможность скопировать настройки из одной сцены в другую».
|
|
2535
|
+
// state.clipboardSceneSettings — in-memory, живёт до закрытия проекта.
|
|
2536
|
+
add('📋 Скопировать настройки', () => copyBoardSettings(kind, item));
|
|
2537
|
+
if (state.clipboardSceneSettings) {
|
|
2538
|
+
add('📥 Вставить настройки', () => pasteBoardSettings(kind, item));
|
|
2539
|
+
}
|
|
2527
2540
|
if (kind === 'character') {
|
|
2528
2541
|
add('⚙ Свойства персонажа', () => {
|
|
2529
2542
|
// Открываем панель этого персонажа и потом её character-modal
|
|
@@ -2576,6 +2589,56 @@ async function promptBoardAspectRatio(kind, item) {
|
|
|
2576
2589
|
}
|
|
2577
2590
|
console.log(`[board] ${kind}/${item.name} aspectRatio → ${chosen}`);
|
|
2578
2591
|
}
|
|
2592
|
+
// Скопировать / вставить настройки сцены (aspectRatio + defaultPrompts).
|
|
2593
|
+
// Хранение — in-memory state.clipboardSceneSettings (живёт до closeProject).
|
|
2594
|
+
// Юзер: «сделай возможность скопировать настройки из одной сцены в другую».
|
|
2595
|
+
async function copyBoardSettings(kind, item) {
|
|
2596
|
+
const isActive = state.currentBoard?.kind === kind && state.currentBoard.name === item.name;
|
|
2597
|
+
const metaSettings = isActive
|
|
2598
|
+
? (state.currentBoard.metadata.settings || {})
|
|
2599
|
+
: ((await loadBoardMetadata(item.handle)).settings || {});
|
|
2600
|
+
// Deep-copy чтобы дальнейшие правки исходной сцены не вмешивались.
|
|
2601
|
+
state.clipboardSceneSettings = JSON.parse(JSON.stringify({
|
|
2602
|
+
aspectRatio: metaSettings.aspectRatio ?? null,
|
|
2603
|
+
defaultPrompts: metaSettings.defaultPrompts || [],
|
|
2604
|
+
}));
|
|
2605
|
+
const fromName = item.name;
|
|
2606
|
+
if (typeof showToast === 'function') {
|
|
2607
|
+
showToast(`📋 Настройки сцены «${fromName}» скопированы`, 'info');
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
async function pasteBoardSettings(kind, item) {
|
|
2611
|
+
const cb = state.clipboardSceneSettings;
|
|
2612
|
+
if (!cb) { alert('Сначала скопируй настройки другой сцены через ПКМ'); return; }
|
|
2613
|
+
const isActive = state.currentBoard?.kind === kind && state.currentBoard.name === item.name;
|
|
2614
|
+
if (isActive) {
|
|
2615
|
+
if (!state.currentBoard.metadata.settings) state.currentBoard.metadata.settings = {};
|
|
2616
|
+
const s = state.currentBoard.metadata.settings;
|
|
2617
|
+
if (cb.aspectRatio) s.aspectRatio = cb.aspectRatio;
|
|
2618
|
+
if (cb.defaultPrompts && cb.defaultPrompts.length) {
|
|
2619
|
+
// Глубокая копия + новые id чтобы не было коллизий id'ов промптов.
|
|
2620
|
+
s.defaultPrompts = cb.defaultPrompts.map(p => ({ ...p, id: crypto.randomUUID() }));
|
|
2621
|
+
} else {
|
|
2622
|
+
delete s.defaultPrompts;
|
|
2623
|
+
}
|
|
2624
|
+
scheduleSave();
|
|
2625
|
+
if (typeof updateTimelineAspectLabel === 'function') updateTimelineAspectLabel();
|
|
2626
|
+
} else {
|
|
2627
|
+
const meta = await loadBoardMetadata(item.handle);
|
|
2628
|
+
meta.settings = meta.settings || {};
|
|
2629
|
+
if (cb.aspectRatio) meta.settings.aspectRatio = cb.aspectRatio;
|
|
2630
|
+
if (cb.defaultPrompts && cb.defaultPrompts.length) {
|
|
2631
|
+
meta.settings.defaultPrompts = cb.defaultPrompts.map(p => ({ ...p, id: crypto.randomUUID() }));
|
|
2632
|
+
} else {
|
|
2633
|
+
delete meta.settings.defaultPrompts;
|
|
2634
|
+
}
|
|
2635
|
+
await saveBoardMetadata(item.handle, meta);
|
|
2636
|
+
}
|
|
2637
|
+
if (typeof showToast === 'function') {
|
|
2638
|
+
showToast(`📥 Настройки вставлены в «${item.name}»`, 'ok');
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2579
2642
|
// Open «Дефолтные промпты сцены» modal — multi-prompt list, each with
|
|
2580
2643
|
// kind-tags (image/video/audio/text) и default-enabled-чекбоксом.
|
|
2581
2644
|
// Сохраняется в scene.json → settings.defaultPrompts как массив.
|
|
@@ -2668,10 +2731,25 @@ async function openDefaultPromptsDialog(kind, item) {
|
|
|
2668
2731
|
metaSettings = meta.settings || {};
|
|
2669
2732
|
}
|
|
2670
2733
|
const prompts = (metaSettings.defaultPrompts || []);
|
|
2734
|
+
const currentAspect = metaSettings.aspectRatio || '9:16';
|
|
2671
2735
|
const titleEl = document.getElementById('defaultPromptsTitle');
|
|
2672
2736
|
if (titleEl)
|
|
2673
|
-
titleEl.textContent =
|
|
2674
|
-
//
|
|
2737
|
+
titleEl.textContent = `Настройки сцены «${item.name}»`;
|
|
2738
|
+
// Подсветка текущего aspect ratio.
|
|
2739
|
+
document.querySelectorAll('#bsAspectCtl [data-bs-asp]').forEach(b => {
|
|
2740
|
+
b.classList.toggle('active', b.dataset.bsAsp === currentAspect);
|
|
2741
|
+
});
|
|
2742
|
+
// Wire toggle (один раз достаточно, но click-handlers идемпотентны).
|
|
2743
|
+
document.querySelectorAll('#bsAspectCtl [data-bs-asp]').forEach(b => {
|
|
2744
|
+
if (b.__bsAspWired) return;
|
|
2745
|
+
b.__bsAspWired = true;
|
|
2746
|
+
b.addEventListener('click', () => {
|
|
2747
|
+
document.querySelectorAll('#bsAspectCtl [data-bs-asp]')
|
|
2748
|
+
.forEach(x => x.classList.remove('active'));
|
|
2749
|
+
b.classList.add('active');
|
|
2750
|
+
});
|
|
2751
|
+
});
|
|
2752
|
+
// Рендерим существующие default-prompts.
|
|
2675
2753
|
const list = document.getElementById('dpList');
|
|
2676
2754
|
list.innerHTML = '';
|
|
2677
2755
|
for (const p of prompts)
|
|
@@ -2701,6 +2779,9 @@ async function openDefaultPromptsDialog(kind, item) {
|
|
|
2701
2779
|
};
|
|
2702
2780
|
const onSave = async () => {
|
|
2703
2781
|
const next = _dpReadList();
|
|
2782
|
+
// Aspect ratio из активной кнопки .seg.
|
|
2783
|
+
const aspBtn = document.querySelector('#bsAspectCtl [data-bs-asp].active');
|
|
2784
|
+
const newAspect = aspBtn ? aspBtn.dataset.bsAsp : null;
|
|
2704
2785
|
if (isActive) {
|
|
2705
2786
|
if (!state.currentBoard.metadata.settings)
|
|
2706
2787
|
state.currentBoard.metadata.settings = {};
|
|
@@ -2708,7 +2789,9 @@ async function openDefaultPromptsDialog(kind, item) {
|
|
|
2708
2789
|
state.currentBoard.metadata.settings.defaultPrompts = next;
|
|
2709
2790
|
else
|
|
2710
2791
|
delete state.currentBoard.metadata.settings.defaultPrompts;
|
|
2792
|
+
if (newAspect) state.currentBoard.metadata.settings.aspectRatio = newAspect;
|
|
2711
2793
|
scheduleSave();
|
|
2794
|
+
if (typeof updateTimelineAspectLabel === 'function') updateTimelineAspectLabel();
|
|
2712
2795
|
}
|
|
2713
2796
|
else {
|
|
2714
2797
|
const meta = await loadBoardMetadata(item.handle);
|
|
@@ -2717,6 +2800,7 @@ async function openDefaultPromptsDialog(kind, item) {
|
|
|
2717
2800
|
meta.settings.defaultPrompts = next;
|
|
2718
2801
|
else
|
|
2719
2802
|
delete meta.settings.defaultPrompts;
|
|
2803
|
+
if (newAspect) meta.settings.aspectRatio = newAspect;
|
|
2720
2804
|
await saveBoardMetadata(item.handle, meta);
|
|
2721
2805
|
}
|
|
2722
2806
|
close();
|
package/renderer/notifyPanel.js
CHANGED
|
@@ -184,7 +184,15 @@
|
|
|
184
184
|
list.innerHTML = '<div style="padding:24px; text-align:center; color:#555; font-size:12px;">Нет событий</div>';
|
|
185
185
|
return;
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
// В auto-режиме (panel всплыла сама после нового события) показываем
|
|
188
|
+
// ТОЛЬКО 3 последних события — иначе панель раскрывается на пол-экрана
|
|
189
|
+
// и мешает основному UI. Юзер: «всплывающее окно когда что-то готово —
|
|
190
|
+
// показывай 3 последних (сейчас слишком высокое)».
|
|
191
|
+
// В manual-режиме (юзер сам кликнул на 🔔) — полный список.
|
|
192
|
+
const limit = (openMode === 'auto') ? 3 : events.length;
|
|
193
|
+
const start = Math.max(0, events.length - limit);
|
|
194
|
+
const hidden = events.length - (events.length - start); // = events.length - count_shown
|
|
195
|
+
for (let i = events.length - 1; i >= start; i--) {
|
|
188
196
|
const e = events[i];
|
|
189
197
|
const row = document.createElement('div');
|
|
190
198
|
const colors = {
|
|
@@ -238,6 +246,18 @@
|
|
|
238
246
|
}
|
|
239
247
|
list.appendChild(row);
|
|
240
248
|
}
|
|
249
|
+
// Подсказка «ещё N» — в auto-режиме если есть скрытые события.
|
|
250
|
+
// Клик открывает панель в manual-режиме (= полный список + не закроется
|
|
251
|
+
// авто-таймером).
|
|
252
|
+
if (openMode === 'auto' && start > 0) {
|
|
253
|
+
const more = document.createElement('div');
|
|
254
|
+
more.style.cssText = 'padding:6px 10px; text-align:center; color:#888; font-size:11px; cursor:pointer; border-top:1px dashed #2a2a2a; margin-top:4px;';
|
|
255
|
+
more.textContent = `+ ещё ${start} событий — открыть всё`;
|
|
256
|
+
more.addEventListener('mouseenter', () => more.style.color = '#bbb');
|
|
257
|
+
more.addEventListener('mouseleave', () => more.style.color = '#888');
|
|
258
|
+
more.addEventListener('click', () => setOpen(true, 'manual'));
|
|
259
|
+
list.appendChild(more);
|
|
260
|
+
}
|
|
241
261
|
}
|
|
242
262
|
|
|
243
263
|
// Public API.
|