kingkont 0.7.54 → 0.7.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 +1 -1
- package/renderer/board.js +58 -21
- package/renderer/generate.js +17 -0
- package/renderer/settings.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.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
|
@@ -704,32 +704,23 @@ async function promptBoardAspectRatio(kind, item) {
|
|
|
704
704
|
const current = isActive
|
|
705
705
|
? (state.currentBoard.metadata.settings?.aspectRatio || '9:16')
|
|
706
706
|
: (await loadBoardMetadata(item.handle)).settings?.aspectRatio || '9:16';
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
`Применяется когда нода или gen-модалка не указывают своё.\n\n` +
|
|
711
|
-
`Доступные значения: ${choices}\n` +
|
|
712
|
-
`Текущее: ${current}`,
|
|
707
|
+
const chosen = await askChoice(
|
|
708
|
+
`Соотношение сторон для «${item.name}» (image/video). Текущее: ${current}`,
|
|
709
|
+
ASPECT_OPTIONS,
|
|
713
710
|
current,
|
|
714
711
|
);
|
|
715
|
-
if (
|
|
716
|
-
const trimmed = ans.trim();
|
|
717
|
-
if (!trimmed) return;
|
|
718
|
-
if (!ASPECT_OPTIONS.includes(trimmed)) {
|
|
719
|
-
alert('Неподдерживаемое значение. Доступны: ' + choices);
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
712
|
+
if (chosen == null || chosen === current) return;
|
|
722
713
|
if (isActive) {
|
|
723
714
|
if (!state.currentBoard.metadata.settings) state.currentBoard.metadata.settings = {};
|
|
724
|
-
state.currentBoard.metadata.settings.aspectRatio =
|
|
715
|
+
state.currentBoard.metadata.settings.aspectRatio = chosen;
|
|
725
716
|
scheduleSave();
|
|
726
717
|
} else {
|
|
727
718
|
// Доска не активна — пишем напрямую.
|
|
728
719
|
const meta = await loadBoardMetadata(item.handle);
|
|
729
|
-
meta.settings = { ...(meta.settings || {}), aspectRatio:
|
|
720
|
+
meta.settings = { ...(meta.settings || {}), aspectRatio: chosen };
|
|
730
721
|
await saveBoardMetadata(item.handle, meta);
|
|
731
722
|
}
|
|
732
|
-
console.log(`[board] ${kind}/${item.name} aspectRatio → ${
|
|
723
|
+
console.log(`[board] ${kind}/${item.name} aspectRatio → ${chosen}`);
|
|
733
724
|
}
|
|
734
725
|
|
|
735
726
|
// Переименовать board (папку): создать новую папку с тем же именем, перенести
|
|
@@ -913,7 +904,7 @@ async function undoBoardDelete() {
|
|
|
913
904
|
|
|
914
905
|
// Собственный prompt — нативный prompt() в Electron подавлен (deprecated в Chromium).
|
|
915
906
|
// Возвращает строку или null. Esc/Cancel = null. Enter = подтвердить.
|
|
916
|
-
function askName(title, placeholder = '', initialValue = '') {
|
|
907
|
+
function askName(title, placeholder = '', initialValue = '', opts = {}) {
|
|
917
908
|
return new Promise(resolve => {
|
|
918
909
|
const overlay = document.createElement('div');
|
|
919
910
|
overlay.className = 'modal';
|
|
@@ -933,9 +924,9 @@ function askName(title, placeholder = '', initialValue = '') {
|
|
|
933
924
|
const cancel = document.createElement('button');
|
|
934
925
|
cancel.textContent = 'Отмена';
|
|
935
926
|
const ok = document.createElement('button');
|
|
936
|
-
//
|
|
937
|
-
//
|
|
938
|
-
ok.textContent = initialValue ? 'Сохранить' : 'Создать';
|
|
927
|
+
// Приоритет: явный opts.okText > '«Сохранить» если редактирование (есть
|
|
928
|
+
// initialValue)' > '«Создать» если создание нового объекта'.
|
|
929
|
+
ok.textContent = opts.okText || (initialValue ? 'Сохранить' : 'Создать');
|
|
939
930
|
ok.className = 'primary';
|
|
940
931
|
row.append(cancel, ok);
|
|
941
932
|
box.append(h, inp, row); overlay.append(box);
|
|
@@ -952,6 +943,49 @@ function askName(title, placeholder = '', initialValue = '') {
|
|
|
952
943
|
});
|
|
953
944
|
}
|
|
954
945
|
|
|
946
|
+
// Похож на askName, но вместо input — список кнопок-опций.
|
|
947
|
+
// Возвращает выбранную строку или null если юзер закрыл.
|
|
948
|
+
// window.prompt() в Electron renderer молча возвращает null — поэтому
|
|
949
|
+
// нельзя использовать его для select-подобных диалогов.
|
|
950
|
+
function askChoice(title, options, currentValue) {
|
|
951
|
+
return new Promise(resolve => {
|
|
952
|
+
const overlay = document.createElement('div');
|
|
953
|
+
overlay.className = 'modal';
|
|
954
|
+
overlay.style.cssText = 'position:fixed; inset:0; background:rgba(0,0,0,0.55); display:flex; align-items:center; justify-content:center; z-index:9999;';
|
|
955
|
+
const box = document.createElement('div');
|
|
956
|
+
box.style.cssText = 'background:#222; border:1px solid #444; border-radius:8px; padding:18px 20px; min-width:360px; box-shadow:0 8px 32px rgba(0,0,0,0.6);';
|
|
957
|
+
const h = document.createElement('h3');
|
|
958
|
+
h.textContent = title;
|
|
959
|
+
h.style.cssText = 'margin:0 0 12px; font-size:14px; color:#e0e0e0;';
|
|
960
|
+
box.append(h);
|
|
961
|
+
const grid = document.createElement('div');
|
|
962
|
+
grid.style.cssText = 'display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px;';
|
|
963
|
+
const close = (val) => { overlay.remove(); resolve(val); };
|
|
964
|
+
for (const opt of options) {
|
|
965
|
+
const b = document.createElement('button');
|
|
966
|
+
b.textContent = opt;
|
|
967
|
+
b.style.cssText = 'padding:6px 12px; background:#1a1a1a; color:#e0e0e0; border:1px solid #444; border-radius:4px; font-size:13px; cursor:pointer;' +
|
|
968
|
+
(opt === currentValue ? 'border-color:#7c3aed; background:#2a1a3a;' : '');
|
|
969
|
+
b.addEventListener('click', () => close(opt));
|
|
970
|
+
grid.append(b);
|
|
971
|
+
}
|
|
972
|
+
box.append(grid);
|
|
973
|
+
const row = document.createElement('div');
|
|
974
|
+
row.style.cssText = 'display:flex; gap:8px; justify-content:flex-end;';
|
|
975
|
+
const cancel = document.createElement('button');
|
|
976
|
+
cancel.textContent = 'Отмена';
|
|
977
|
+
cancel.addEventListener('click', () => close(null));
|
|
978
|
+
row.append(cancel);
|
|
979
|
+
box.append(row);
|
|
980
|
+
overlay.append(box);
|
|
981
|
+
document.body.append(overlay);
|
|
982
|
+
overlay.addEventListener('mousedown', e => { if (e.target === overlay) close(null); });
|
|
983
|
+
document.addEventListener('keydown', function onEsc(e) {
|
|
984
|
+
if (e.key === 'Escape') { document.removeEventListener('keydown', onEsc); close(null); }
|
|
985
|
+
});
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
|
|
955
989
|
// Лог-буфер: всё что пишем сюда — попадает в console и в window.veLog.
|
|
956
990
|
// Достать из DevTools одной строкой:
|
|
957
991
|
// copy(JSON.stringify(window.veLog, null, 2)) // в буфер
|
|
@@ -1433,7 +1467,10 @@ async function createNodeEl(node) {
|
|
|
1433
1467
|
// =================== Контекстное меню ноды (ПКМ) ===================
|
|
1434
1468
|
async function renameNode(node) {
|
|
1435
1469
|
const current = node.name || '';
|
|
1436
|
-
|
|
1470
|
+
// okText='Сохранить' независимо от того, было имя или нет — мы НЕ создаём
|
|
1471
|
+
// ноду, а присваиваем/меняем имя существующей. Без явного okText askName
|
|
1472
|
+
// показал бы «Создать» для безымянной ноды (initialValue=='').
|
|
1473
|
+
const newName = await askName('Имя ноды (для @-ссылок):', '', current, { okText: 'Сохранить' });
|
|
1437
1474
|
if (newName == null) return;
|
|
1438
1475
|
const trimmed = newName.trim();
|
|
1439
1476
|
// Текст-нода: переименовать соответствующий .md файл
|
package/renderer/generate.js
CHANGED
|
@@ -330,6 +330,16 @@ async function openGenModal(kind) {
|
|
|
330
330
|
if (kind === 'audio') { loadVoices(); }
|
|
331
331
|
closeMentionPopup();
|
|
332
332
|
syncSourceRefRow();
|
|
333
|
+
// Если открываем image-генерацию и есть исходная картинка-референс —
|
|
334
|
+
// дефолт «↺ Как у исходной» (юзер обычно хочет такой же формат как у
|
|
335
|
+
// источника). Если потом юзер выберет другой aspect — это его выбор,
|
|
336
|
+
// и при следующем открытии modal'а с source мы снова поставим source
|
|
337
|
+
// (это per-open default, не sticky).
|
|
338
|
+
if (kind === 'image'
|
|
339
|
+
&& state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
|
|
340
|
+
state.imageAspect = 'source';
|
|
341
|
+
syncImageAspectActive();
|
|
342
|
+
}
|
|
333
343
|
$('genModal').classList.remove('hidden');
|
|
334
344
|
setTimeout(() => $('genPrompt').focus(), 50);
|
|
335
345
|
}
|
|
@@ -736,6 +746,13 @@ document.querySelectorAll('#genModal [data-kind]').forEach(b => {
|
|
|
736
746
|
$('genPrompt').setAttribute('placeholder', ph);
|
|
737
747
|
syncSourceRefRow();
|
|
738
748
|
syncCharLocRows();
|
|
749
|
+
// То же auto-default «↺ Как у исходной» при переключении на image-kind
|
|
750
|
+
// (см. комментарий в openGenModal).
|
|
751
|
+
if (state.genKind === 'image'
|
|
752
|
+
&& state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
|
|
753
|
+
state.imageAspect = 'source';
|
|
754
|
+
syncImageAspectActive();
|
|
755
|
+
}
|
|
739
756
|
});
|
|
740
757
|
});
|
|
741
758
|
|
package/renderer/settings.js
CHANGED
|
@@ -532,6 +532,10 @@ function attachResize(el, node, handle) {
|
|
|
532
532
|
node.height = h;
|
|
533
533
|
el.style.width = w + 'px';
|
|
534
534
|
el.style.height = h + 'px';
|
|
535
|
+
// Перерисовываем коннекторы — anchor-points (правая середина для
|
|
536
|
+
// out, левая для in) считаются от node.x/y/width/height, поэтому при
|
|
537
|
+
// resize bezier должен следовать за новым размером.
|
|
538
|
+
renderConnections();
|
|
535
539
|
};
|
|
536
540
|
const onUp = () => {
|
|
537
541
|
document.removeEventListener('mousemove', onMove);
|