kingkont 0.7.10 → 0.7.12
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/bin/kingkont.js +16 -1
- package/index.html +47 -5
- package/package.json +1 -1
- package/scripts/patch-electron-name.js +79 -89
package/bin/kingkont.js
CHANGED
|
@@ -79,8 +79,23 @@ if (args[0] === 'serve') {
|
|
|
79
79
|
} else {
|
|
80
80
|
// Electron-приложение.
|
|
81
81
|
applySettingsToEnv();
|
|
82
|
+
// Self-heal: если postinstall не отработал (npm 9+ иногда тихо пропускает
|
|
83
|
+
// scripts при глобал-install под некоторыми node-prefix'ами), Electron.app
|
|
84
|
+
// в node_modules останется не переименованным → в menubar macOS «Electron»
|
|
85
|
+
// вместо «KingKont». Запустим патч-скрипт прямо сейчас, idempotent — если
|
|
86
|
+
// уже переименовано, выйдет no-op. Ошибку проглатываем — это cosmetic.
|
|
87
|
+
if (process.platform === 'darwin') {
|
|
88
|
+
try {
|
|
89
|
+
const patch = require(path.join(root, 'scripts', 'patch-electron-name.js'));
|
|
90
|
+
patch();
|
|
91
|
+
} catch (e) { console.warn('[kingkont] electron-name patch failed:', e.message); }
|
|
92
|
+
}
|
|
82
93
|
const electronPath = (() => {
|
|
83
|
-
try {
|
|
94
|
+
try {
|
|
95
|
+
// Сбрасываем кэш — postinstall мог только что переписать path.txt.
|
|
96
|
+
delete require.cache[require.resolve('electron')];
|
|
97
|
+
return require('electron');
|
|
98
|
+
}
|
|
84
99
|
catch { return null; }
|
|
85
100
|
})();
|
|
86
101
|
if (!electronPath) {
|
package/index.html
CHANGED
|
@@ -150,6 +150,23 @@
|
|
|
150
150
|
width: 240px; flex-shrink: 0;
|
|
151
151
|
scroll-snap-align: start;
|
|
152
152
|
}
|
|
153
|
+
/* Карточка «Открыть проект» — стилизована под обычную recent-карточку,
|
|
154
|
+
но контент не превью, а большая иконка + надпись. */
|
|
155
|
+
.welcome-card.open-card {
|
|
156
|
+
background: linear-gradient(135deg, #2a3e5c, #344a6e);
|
|
157
|
+
border-color: #4a6a9a;
|
|
158
|
+
}
|
|
159
|
+
.welcome-card.open-card:hover {
|
|
160
|
+
border-color: #6a8aba;
|
|
161
|
+
background: linear-gradient(135deg, #344a6e, #4a6a9a);
|
|
162
|
+
}
|
|
163
|
+
.welcome-card.open-card .welcome-card-thumb {
|
|
164
|
+
background: transparent; color: #c4d4ec; font-size: 56px; line-height: 1;
|
|
165
|
+
}
|
|
166
|
+
.welcome-card.open-card .welcome-card-name {
|
|
167
|
+
color: #e0e8f4; font-weight: 600;
|
|
168
|
+
}
|
|
169
|
+
.welcome-card.open-card .welcome-card-ts { color: #aac0d8; }
|
|
153
170
|
.welcome-card:hover { border-color: #4a6a9a; transform: translateY(-2px); }
|
|
154
171
|
.welcome-card-thumb {
|
|
155
172
|
width: 100%; aspect-ratio: 16 / 9; background: #1a1a1a;
|
|
@@ -1017,12 +1034,13 @@
|
|
|
1017
1034
|
<img class="welcome-logo" src="assets/logo-square.svg" alt="" draggable="false" id="welcomeLogo" title="Дабл-клик — настройки" style="cursor:pointer;">
|
|
1018
1035
|
<h1 class="welcome-title">KingKont</h1>
|
|
1019
1036
|
<div class="welcome-sub">Видео-редактор</div>
|
|
1020
|
-
<button id="welcomeOpen" class="welcome-open primary">Открыть проект</button>
|
|
1021
1037
|
</div>
|
|
1022
|
-
<div class="welcome-recent" id="welcomeRecent"
|
|
1023
|
-
<div class="welcome-recent-title"
|
|
1038
|
+
<div class="welcome-recent" id="welcomeRecent">
|
|
1039
|
+
<div class="welcome-recent-title" id="welcomeRecentTitle">Открыть проект</div>
|
|
1024
1040
|
<div class="welcome-recent-grid" id="welcomeRecentGrid"></div>
|
|
1025
1041
|
</div>
|
|
1042
|
+
<!-- Скрытая кнопка-shim — на неё дёргают .click() из app menu и dropzone'ов. -->
|
|
1043
|
+
<button id="welcomeOpen" style="display:none;"></button>
|
|
1026
1044
|
</div>
|
|
1027
1045
|
</div>
|
|
1028
1046
|
|
|
@@ -2286,11 +2304,35 @@ function fmtRelativeTime(ts) {
|
|
|
2286
2304
|
async function renderWelcomeRecents() {
|
|
2287
2305
|
const grid = $('welcomeRecentGrid');
|
|
2288
2306
|
const wrap = $('welcomeRecent');
|
|
2307
|
+
const titleEl = $('welcomeRecentTitle');
|
|
2289
2308
|
if (!grid || !wrap) return;
|
|
2290
2309
|
grid.innerHTML = '';
|
|
2310
|
+
wrap.style.display = '';
|
|
2291
2311
|
const list = await getRecents();
|
|
2292
|
-
|
|
2293
|
-
|
|
2312
|
+
|
|
2313
|
+
// Первой картой — «Открыть проект». Кликается → дёргает скрытый
|
|
2314
|
+
// #pickRoot button (тот же, что использует app menu).
|
|
2315
|
+
const openCard = document.createElement('div');
|
|
2316
|
+
openCard.className = 'welcome-card open-card';
|
|
2317
|
+
const openThumb = document.createElement('div');
|
|
2318
|
+
openThumb.className = 'welcome-card-thumb';
|
|
2319
|
+
openThumb.textContent = '+';
|
|
2320
|
+
const openMeta = document.createElement('div');
|
|
2321
|
+
openMeta.className = 'welcome-card-meta';
|
|
2322
|
+
const openName = document.createElement('div');
|
|
2323
|
+
openName.className = 'welcome-card-name';
|
|
2324
|
+
openName.textContent = 'Открыть проект';
|
|
2325
|
+
const openSub = document.createElement('div');
|
|
2326
|
+
openSub.className = 'welcome-card-ts';
|
|
2327
|
+
openSub.textContent = 'выбрать папку…';
|
|
2328
|
+
openMeta.append(openName, openSub);
|
|
2329
|
+
openCard.append(openThumb, openMeta);
|
|
2330
|
+
openCard.addEventListener('click', () => $('pickRoot').click());
|
|
2331
|
+
grid.appendChild(openCard);
|
|
2332
|
+
|
|
2333
|
+
// Title меняем в зависимости от наличия recents.
|
|
2334
|
+
if (titleEl) titleEl.textContent = list.length ? 'Открыть проект · недавние' : 'Открыть проект';
|
|
2335
|
+
|
|
2294
2336
|
for (const r of list) {
|
|
2295
2337
|
const card = document.createElement('div');
|
|
2296
2338
|
card.className = 'welcome-card';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.12",
|
|
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": {
|
|
@@ -1,108 +1,92 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Переименовывает dev-Electron бандл в «KingKont» — в menubar macOS,
|
|
3
|
-
// Activity Monitor, Dock-tooltip и пр. Запускается через postinstall
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// Activity Monitor, Dock-tooltip и пр. Запускается через postinstall
|
|
4
|
+
// или (как self-heal) из bin/kingkont.js при каждом старте.
|
|
5
|
+
// Идемпотентно. Молча выходит если что-то не так — не критическая часть.
|
|
6
6
|
'use strict';
|
|
7
7
|
const fs = require('node:fs');
|
|
8
8
|
const path = require('node:path');
|
|
9
9
|
const { execFileSync } = require('node:child_process');
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
function patchElectronName() {
|
|
12
|
+
if (process.platform !== 'darwin') return false;
|
|
12
13
|
|
|
13
|
-
let electronExe;
|
|
14
|
-
try { electronExe = require('electron'); }
|
|
15
|
-
catch (e) {
|
|
16
|
-
console.warn('[kingkont postinstall] electron not found, skip rename:', e.message);
|
|
17
|
-
process.exit(0);
|
|
18
|
-
}
|
|
19
|
-
// require('electron') возвращает путь к бинарю. На macOS это:
|
|
20
|
-
// node_modules/electron/dist/Electron.app/Contents/MacOS/Electron
|
|
21
|
-
// Если уже переименовано — KingKont.app/Contents/MacOS/KingKont
|
|
22
|
-
const macOsDir = path.dirname(electronExe); // .../MacOS
|
|
23
|
-
const contentsDir = path.dirname(macOsDir); // .../Contents
|
|
24
|
-
const appBundle = path.dirname(contentsDir); // .../Electron.app или KingKont.app
|
|
25
|
-
const dist = path.dirname(appBundle); // .../dist
|
|
26
|
-
const electronPkg = path.dirname(dist); // .../electron
|
|
27
|
-
|
|
28
|
-
const oldApp = path.join(dist, 'Electron.app');
|
|
29
|
-
const newApp = path.join(dist, 'KingKont.app');
|
|
30
|
-
|
|
31
|
-
// Уже переименовано?
|
|
32
|
-
if (fs.existsSync(newApp) && !fs.existsSync(oldApp)) {
|
|
33
|
-
// Убедимся что иконка из нашего пакета актуальна (на случай обновления).
|
|
34
|
-
ensureIcon(newApp);
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
if (!fs.existsSync(oldApp)) {
|
|
38
|
-
console.warn('[kingkont postinstall] Electron.app not found at', oldApp);
|
|
39
|
-
process.exit(0);
|
|
40
|
-
}
|
|
14
|
+
let electronExe;
|
|
15
|
+
try { electronExe = require('electron'); }
|
|
16
|
+
catch (e) { return false; }
|
|
41
17
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// 2) Helpers
|
|
50
|
-
const fwDir = path.join(newApp, 'Contents', 'Frameworks');
|
|
51
|
-
const helpers = [
|
|
52
|
-
['Electron Helper.app', 'KingKont Helper.app'],
|
|
53
|
-
['Electron Helper (GPU).app', 'KingKont Helper (GPU).app'],
|
|
54
|
-
['Electron Helper (Plugin).app', 'KingKont Helper (Plugin).app'],
|
|
55
|
-
['Electron Helper (Renderer).app','KingKont Helper (Renderer).app'],
|
|
56
|
-
];
|
|
57
|
-
for (const [oldH, newH] of helpers) {
|
|
58
|
-
const o = path.join(fwDir, oldH);
|
|
59
|
-
const n = path.join(fwDir, newH);
|
|
60
|
-
if (!fs.existsSync(o)) continue;
|
|
61
|
-
fs.renameSync(o, n);
|
|
62
|
-
const oldBin = oldH.replace(/\.app$/, '');
|
|
63
|
-
const newBin = newH.replace(/\.app$/, '');
|
|
64
|
-
fs.renameSync(path.join(n, 'Contents', 'MacOS', oldBin),
|
|
65
|
-
path.join(n, 'Contents', 'MacOS', newBin));
|
|
66
|
-
patchPlist(path.join(n, 'Contents', 'Info.plist'), {
|
|
67
|
-
CFBundleExecutable: newBin,
|
|
68
|
-
CFBundleName: newBin,
|
|
69
|
-
CFBundleDisplayName: newBin,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
18
|
+
// require('electron') возвращает путь к бинарю.
|
|
19
|
+
const macOsDir = path.dirname(electronExe);
|
|
20
|
+
const contentsDir = path.dirname(macOsDir);
|
|
21
|
+
const appBundle = path.dirname(contentsDir);
|
|
22
|
+
const dist = path.dirname(appBundle);
|
|
23
|
+
const electronPkg = path.dirname(dist);
|
|
72
24
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
CFBundleExecutable: 'KingKont',
|
|
76
|
-
CFBundleName: 'KingKont',
|
|
77
|
-
CFBundleDisplayName: 'KingKont',
|
|
78
|
-
});
|
|
25
|
+
const oldApp = path.join(dist, 'Electron.app');
|
|
26
|
+
const newApp = path.join(dist, 'KingKont.app');
|
|
79
27
|
|
|
80
|
-
//
|
|
81
|
-
fs.
|
|
82
|
-
|
|
28
|
+
// Уже переименовано?
|
|
29
|
+
if (fs.existsSync(newApp) && !fs.existsSync(oldApp)) {
|
|
30
|
+
ensureIcon(newApp);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!fs.existsSync(oldApp)) return false;
|
|
34
|
+
|
|
35
|
+
console.log('[kingkont] Electron → KingKont…');
|
|
36
|
+
|
|
37
|
+
fs.renameSync(oldApp, newApp);
|
|
38
|
+
fs.renameSync(path.join(newApp, 'Contents', 'MacOS', 'Electron'),
|
|
39
|
+
path.join(newApp, 'Contents', 'MacOS', 'KingKont'));
|
|
40
|
+
|
|
41
|
+
const fwDir = path.join(newApp, 'Contents', 'Frameworks');
|
|
42
|
+
const helpers = [
|
|
43
|
+
['Electron Helper.app', 'KingKont Helper.app'],
|
|
44
|
+
['Electron Helper (GPU).app', 'KingKont Helper (GPU).app'],
|
|
45
|
+
['Electron Helper (Plugin).app', 'KingKont Helper (Plugin).app'],
|
|
46
|
+
['Electron Helper (Renderer).app','KingKont Helper (Renderer).app'],
|
|
47
|
+
];
|
|
48
|
+
for (const [oldH, newH] of helpers) {
|
|
49
|
+
const o = path.join(fwDir, oldH);
|
|
50
|
+
const n = path.join(fwDir, newH);
|
|
51
|
+
if (!fs.existsSync(o)) continue;
|
|
52
|
+
fs.renameSync(o, n);
|
|
53
|
+
const oldBin = oldH.replace(/\.app$/, '');
|
|
54
|
+
const newBin = newH.replace(/\.app$/, '');
|
|
55
|
+
fs.renameSync(path.join(n, 'Contents', 'MacOS', oldBin),
|
|
56
|
+
path.join(n, 'Contents', 'MacOS', newBin));
|
|
57
|
+
patchPlist(path.join(n, 'Contents', 'Info.plist'), {
|
|
58
|
+
CFBundleExecutable: newBin,
|
|
59
|
+
CFBundleName: newBin,
|
|
60
|
+
CFBundleDisplayName: newBin,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
83
63
|
|
|
84
|
-
|
|
85
|
-
|
|
64
|
+
patchPlist(path.join(newApp, 'Contents', 'Info.plist'), {
|
|
65
|
+
CFBundleExecutable: 'KingKont',
|
|
66
|
+
CFBundleName: 'KingKont',
|
|
67
|
+
CFBundleDisplayName: 'KingKont',
|
|
68
|
+
});
|
|
86
69
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
execFileSync('codesign', ['--force', '--deep', '--sign', '-', newApp], { stdio: 'ignore' });
|
|
90
|
-
} catch {}
|
|
70
|
+
fs.writeFileSync(path.join(electronPkg, 'path.txt'),
|
|
71
|
+
'KingKont.app/Contents/MacOS/KingKont');
|
|
91
72
|
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
execFileSync('/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister',
|
|
95
|
-
['-f', newApp], { stdio: 'ignore' });
|
|
96
|
-
} catch {}
|
|
73
|
+
ensureIcon(newApp);
|
|
97
74
|
|
|
98
|
-
|
|
75
|
+
// Ad-hoc resign — без неё macOS Sequoia может убить процесс при старте.
|
|
76
|
+
try { execFileSync('codesign', ['--force', '--deep', '--sign', '-', newApp], { stdio: 'ignore' }); } catch {}
|
|
77
|
+
// Refresh LaunchServices.
|
|
78
|
+
try {
|
|
79
|
+
execFileSync('/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister',
|
|
80
|
+
['-f', newApp], { stdio: 'ignore' });
|
|
81
|
+
} catch {}
|
|
99
82
|
|
|
100
|
-
|
|
83
|
+
console.log('[kingkont] ✓ KingKont готов');
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
101
86
|
|
|
102
87
|
function patchPlist(plistPath, fields) {
|
|
103
88
|
if (!fs.existsSync(plistPath)) return;
|
|
104
89
|
for (const [k, v] of Object.entries(fields)) {
|
|
105
|
-
// Сначала Set; если ключа нет — Add.
|
|
106
90
|
try {
|
|
107
91
|
execFileSync('/usr/libexec/PlistBuddy', ['-c', `Set :${k} ${v}`, plistPath], { stdio: 'ignore' });
|
|
108
92
|
} catch {
|
|
@@ -114,11 +98,17 @@ function patchPlist(plistPath, fields) {
|
|
|
114
98
|
}
|
|
115
99
|
|
|
116
100
|
function ensureIcon(bundle) {
|
|
117
|
-
// Этот скрипт лежит в <pkg>/scripts/, иконка в <pkg>/assets/logo.icns.
|
|
118
101
|
const src = path.join(__dirname, '..', 'assets', 'logo.icns');
|
|
119
102
|
const dst = path.join(bundle, 'Contents', 'Resources', 'electron.icns');
|
|
120
103
|
if (!fs.existsSync(src)) return;
|
|
121
|
-
try {
|
|
122
|
-
|
|
123
|
-
|
|
104
|
+
try { fs.copyFileSync(src, dst); } catch {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = patchElectronName;
|
|
108
|
+
|
|
109
|
+
// Если запущен как entry-point (postinstall) — выполняем сразу.
|
|
110
|
+
if (require.main === module) {
|
|
111
|
+
try { patchElectronName(); } catch (e) {
|
|
112
|
+
console.warn('[kingkont postinstall] failed:', e.message);
|
|
113
|
+
}
|
|
124
114
|
}
|