u2a 3.5.1 → 3.5.3
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/.github/workflows/npm-publish.yml +22 -0
- package/package.json +1 -2
- package/src/commands/configure.js +154 -124
- package/src/utils/appGenerator.js +349 -349
- package/src/utils/builder.js +125 -125
- package/src/utils/logger.js +5 -1
- package/src/utils/noroot.js +41 -41
- package/src/utils/osIntegration.js +187 -187
- package/src/utils/postinstall.js +119 -119
- package/src/utils/sanitize.js +20 -20
- package/src/utils/securexec.js +12 -12
- package/src/utils/settings.js +112 -110
- package/src/utils/versionCheck.js +149 -148
|
@@ -1,350 +1,350 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const Logger = require('./logger');
|
|
4
|
-
|
|
5
|
-
const logger = new Logger('appGenerator');
|
|
6
|
-
|
|
7
|
-
function generateMainJs(appName, url, iconPath, options = {}) {
|
|
8
|
-
const width = options.width || 1200;
|
|
9
|
-
const height = options.height || 800;
|
|
10
|
-
|
|
11
|
-
return `
|
|
12
|
-
const { app, BrowserWindow, Menu, shell, nativeTheme } = require('electron');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
const fs = require('fs');
|
|
15
|
-
|
|
16
|
-
const APP_NAME = "${appName}";
|
|
17
|
-
const APP_URL = "${url}";
|
|
18
|
-
const APP_ICON_PATH = "${iconPath.replace(/\\/g, '\\\\')}";
|
|
19
|
-
const WINDOW_WIDTH = ${width};
|
|
20
|
-
const WINDOW_HEIGHT = ${height};
|
|
21
|
-
|
|
22
|
-
let mainWindow;
|
|
23
|
-
let splashWindow;
|
|
24
|
-
|
|
25
|
-
function logAppInfo() {
|
|
26
|
-
const packageJsonPath = path.join(__dirname, 'package.json');
|
|
27
|
-
let packageInfo = {};
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
31
|
-
packageInfo = JSON.parse(packageJsonContent);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error('Error reading package.json:', error.message);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log('\\n--------------------------------');
|
|
37
|
-
console.log(' APPLICATION INFORMATION');
|
|
38
|
-
console.log('--------------------------------');
|
|
39
|
-
console.log(\`Application: \${APP_NAME}\`);
|
|
40
|
-
console.log(\`URL: \${APP_URL}\`);
|
|
41
|
-
console.log(\`Started at: \${new Date().toLocaleString()}\`);
|
|
42
|
-
console.log(\`App directory: \${__dirname}\`);
|
|
43
|
-
console.log(\`Icon path: \${APP_ICON_PATH}\`);
|
|
44
|
-
|
|
45
|
-
console.log('\\n PACKAGE INFO:');
|
|
46
|
-
console.log(\` - Name: \${packageInfo.name || 'N/A'}\`);
|
|
47
|
-
console.log(\` - Version: \${packageInfo.version || 'N/A'}\`);
|
|
48
|
-
console.log(\` - Description: \${packageInfo.description || 'N/A'}\`);
|
|
49
|
-
console.log(\` - Electron version: \${packageInfo.dependencies?.electron || 'N/A'}\`);
|
|
50
|
-
|
|
51
|
-
if (packageInfo.build) {
|
|
52
|
-
console.log('\\n BUILD CONFIG:');
|
|
53
|
-
console.log(\` - App ID: \${packageInfo.build.appId || 'N/A'}\`);
|
|
54
|
-
console.log(\` - Product Name: \${packageInfo.build.productName || 'N/A'}\`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log('--------------------------------\\n');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function createSplashScreen() {
|
|
61
|
-
splashWindow = new BrowserWindow({
|
|
62
|
-
width: 200,
|
|
63
|
-
height: 40,
|
|
64
|
-
transparent: true,
|
|
65
|
-
frame: false,
|
|
66
|
-
alwaysOnTop: true,
|
|
67
|
-
skipTaskbar: true,
|
|
68
|
-
resizable: false,
|
|
69
|
-
icon: APP_ICON_PATH,
|
|
70
|
-
webPreferences: {
|
|
71
|
-
nodeIntegration: false,
|
|
72
|
-
contextIsolation: true
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const isDarkMode = nativeTheme.shouldUseDarkColors;
|
|
77
|
-
const bgColor = isDarkMode ? '#333333' : '#f5f5f5';
|
|
78
|
-
const loaderBgColor = isDarkMode ? '#555555' : '#e0e0e0';
|
|
79
|
-
const loaderColor = isDarkMode ? '#ffffff' : '#2563eb';
|
|
80
|
-
const shadowColor = isDarkMode ? 'rgba(0, 0, 0, 0.5)' : 'rgba(0, 0, 0, 0.2)';
|
|
81
|
-
|
|
82
|
-
const splashHtml = \`
|
|
83
|
-
<!DOCTYPE html>
|
|
84
|
-
<html>
|
|
85
|
-
<head>
|
|
86
|
-
<meta charset="UTF-8">
|
|
87
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'none';">
|
|
88
|
-
<title>Loading</title>
|
|
89
|
-
<style>
|
|
90
|
-
html, body {
|
|
91
|
-
margin: 0;
|
|
92
|
-
padding: 0;
|
|
93
|
-
width: 100%;
|
|
94
|
-
height: 100%;
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
background-color: transparent;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.container {
|
|
100
|
-
width: 100%;
|
|
101
|
-
height: 100%;
|
|
102
|
-
display: flex;
|
|
103
|
-
justify-content: center;
|
|
104
|
-
align-items: center;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.loader-container {
|
|
108
|
-
width: 180px;
|
|
109
|
-
height: 12px;
|
|
110
|
-
background-color: \${bgColor};
|
|
111
|
-
border-radius: 6px;
|
|
112
|
-
overflow: hidden;
|
|
113
|
-
box-shadow: 0 2px 8px \${shadowColor};
|
|
114
|
-
padding: 3px;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.loader-bg {
|
|
118
|
-
width: 100%;
|
|
119
|
-
height: 100%;
|
|
120
|
-
background-color: \${loaderBgColor};
|
|
121
|
-
border-radius: 4px;
|
|
122
|
-
overflow: hidden;
|
|
123
|
-
position: relative;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.loader {
|
|
127
|
-
position: absolute;
|
|
128
|
-
top: 0;
|
|
129
|
-
left: 0;
|
|
130
|
-
height: 100%;
|
|
131
|
-
width: 30%;
|
|
132
|
-
background-color: \${loaderColor};
|
|
133
|
-
border-radius: 4px;
|
|
134
|
-
animation: loading 1.5s infinite ease-in-out;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
@keyframes loading {
|
|
138
|
-
0% {
|
|
139
|
-
left: -30%;
|
|
140
|
-
}
|
|
141
|
-
100% {
|
|
142
|
-
left: 100%;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
</style>
|
|
146
|
-
</head>
|
|
147
|
-
<body>
|
|
148
|
-
<div class="container">
|
|
149
|
-
<div class="loader-container">
|
|
150
|
-
<div class="loader-bg">
|
|
151
|
-
<div class="loader"></div>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
</body>
|
|
156
|
-
</html>
|
|
157
|
-
\`;
|
|
158
|
-
|
|
159
|
-
const splashPath = path.join(app.getPath('temp'), \`\${APP_NAME}-splash.html\`);
|
|
160
|
-
fs.writeFileSync(splashPath, splashHtml);
|
|
161
|
-
|
|
162
|
-
splashWindow.loadFile(splashPath);
|
|
163
|
-
|
|
164
|
-
const { screen } = require('electron');
|
|
165
|
-
const primaryDisplay = screen.getPrimaryDisplay();
|
|
166
|
-
const { width, height } = primaryDisplay.workAreaSize;
|
|
167
|
-
|
|
168
|
-
splashWindow.setPosition(
|
|
169
|
-
Math.floor(width / 2 - 100),
|
|
170
|
-
Math.floor(height / 2 - 20)
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function createWindow() {
|
|
175
|
-
logAppInfo();
|
|
176
|
-
|
|
177
|
-
app.setAppUserModelId(APP_NAME);
|
|
178
|
-
|
|
179
|
-
mainWindow = new BrowserWindow({
|
|
180
|
-
width: WINDOW_WIDTH,
|
|
181
|
-
height: WINDOW_HEIGHT,
|
|
182
|
-
title: APP_NAME,
|
|
183
|
-
icon: APP_ICON_PATH,
|
|
184
|
-
show: false,
|
|
185
|
-
webPreferences: {
|
|
186
|
-
nodeIntegration: false,
|
|
187
|
-
contextIsolation: true
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
mainWindow.webContents.on('did-finish-load', () => {
|
|
192
|
-
setTimeout(() => {
|
|
193
|
-
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
194
|
-
splashWindow.close();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (!mainWindow.isVisible()) {
|
|
198
|
-
mainWindow.show();
|
|
199
|
-
mainWindow.focus();
|
|
200
|
-
}
|
|
201
|
-
}, 500);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
mainWindow.loadURL(APP_URL);
|
|
205
|
-
|
|
206
|
-
mainWindow.webContents.on('context-menu', (e, params) => {
|
|
207
|
-
e.preventDefault();
|
|
208
|
-
mainWindow.webContents.executeJavaScript(\`
|
|
209
|
-
window.addEventListener('contextmenu', (e) => {
|
|
210
|
-
e.stopPropagation();
|
|
211
|
-
}, true);
|
|
212
|
-
\`);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
mainWindow.webContents.on('new-window', (event, url) => {
|
|
216
|
-
event.preventDefault();
|
|
217
|
-
shell.openExternal(url);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const template = [];
|
|
221
|
-
|
|
222
|
-
const menu = Menu.buildFromTemplate(template);
|
|
223
|
-
Menu.setApplicationMenu(menu);
|
|
224
|
-
|
|
225
|
-
setTimeout(() => {
|
|
226
|
-
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
227
|
-
splashWindow.close();
|
|
228
|
-
if (!mainWindow.isVisible()) {
|
|
229
|
-
mainWindow.show();
|
|
230
|
-
mainWindow.focus();
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}, 10000);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (process.platform === 'win32') {
|
|
237
|
-
app.setAppUserModelId(app.name);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
app.whenReady().then(() => {
|
|
241
|
-
createSplashScreen();
|
|
242
|
-
createWindow();
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
app.on('window-all-closed', () => {
|
|
246
|
-
if (process.platform !== 'darwin') {
|
|
247
|
-
app.quit();
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
app.on('activate', () => {
|
|
252
|
-
if (BrowserWindow.getAllWindows().length === 0) {
|
|
253
|
-
createWindow();
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
`;
|
|
257
|
-
} // note for one day: put this in a different file
|
|
258
|
-
|
|
259
|
-
async function createPackageJson(appName, iconPath, isExecutable = false, createSetup = false) {
|
|
260
|
-
const u2aPackagePath = path.resolve(__dirname, '../../package.json');
|
|
261
|
-
|
|
262
|
-
let u2aVersion = '1.0.0';
|
|
263
|
-
try {
|
|
264
|
-
const u2aPackageContent = fs.readFileSync(u2aPackagePath, 'utf8');
|
|
265
|
-
const u2aPackage = JSON.parse(u2aPackageContent);
|
|
266
|
-
u2aVersion = u2aPackage.version || u2aVersion;
|
|
267
|
-
} catch (error) {
|
|
268
|
-
logger.error('Error while fetching u2a package.json', error);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (createSetup) {
|
|
272
|
-
const { processFavicon } = require('./favicon');
|
|
273
|
-
iconPath = await processFavicon(iconPath);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const packageJson = {
|
|
277
|
-
name: `u2a-${appName.replace(/\s+/g, '-')}`,
|
|
278
|
-
version: u2aVersion,
|
|
279
|
-
description: `Web app for ${appName}`,
|
|
280
|
-
main: 'main.js',
|
|
281
|
-
author: `${appName}`,
|
|
282
|
-
scripts: {
|
|
283
|
-
start: 'electron .'
|
|
284
|
-
},
|
|
285
|
-
dependencies: {
|
|
286
|
-
electron: '^22.0.0'
|
|
287
|
-
},
|
|
288
|
-
build: {
|
|
289
|
-
appId: `com.u2a.${appName.replace(/\s+/g, '-')}`,
|
|
290
|
-
productName: appName,
|
|
291
|
-
icon: iconPath
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
if (isExecutable) {
|
|
296
|
-
packageJson.devDependencies = {
|
|
297
|
-
"electron-packager": "^17.1.1",
|
|
298
|
-
"electron-builder": "^24.6.3",
|
|
299
|
-
"electron": "^22.0.0"
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
packageJson.dependencies = {};
|
|
303
|
-
|
|
304
|
-
packageJson.scripts.package = "electron-packager . --overwrite --asar";
|
|
305
|
-
packageJson.scripts.setup = "electron-builder";
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (isExecutable && createSetup) {
|
|
309
|
-
packageJson.build = {
|
|
310
|
-
...packageJson.build,
|
|
311
|
-
appId: `com.u2a.${appName.replace(/\s+/g, '-')}`,
|
|
312
|
-
productName: appName,
|
|
313
|
-
directories: {
|
|
314
|
-
output: "installer"
|
|
315
|
-
},
|
|
316
|
-
files: [
|
|
317
|
-
"**/*",
|
|
318
|
-
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}",
|
|
319
|
-
"!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
|
|
320
|
-
"!**/node_modules/*.d.ts",
|
|
321
|
-
"!**/node_modules/.bin",
|
|
322
|
-
"!**/.{idea,git,cache,build,dist}",
|
|
323
|
-
"!dist/**/*",
|
|
324
|
-
"!installer/**/*"
|
|
325
|
-
],
|
|
326
|
-
win: {
|
|
327
|
-
target: "nsis",
|
|
328
|
-
icon: iconPath
|
|
329
|
-
},
|
|
330
|
-
mac: {
|
|
331
|
-
target: "dmg"
|
|
332
|
-
},
|
|
333
|
-
linux: {
|
|
334
|
-
target: "AppImage",
|
|
335
|
-
icon: iconPath
|
|
336
|
-
},
|
|
337
|
-
nsis: {
|
|
338
|
-
oneClick: false,
|
|
339
|
-
allowToChangeInstallationDirectory: true
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return packageJson;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
module.exports = {
|
|
348
|
-
generateMainJs,
|
|
349
|
-
createPackageJson
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const Logger = require('./logger');
|
|
4
|
+
|
|
5
|
+
const logger = new Logger('appGenerator');
|
|
6
|
+
|
|
7
|
+
function generateMainJs(appName, url, iconPath, options = {}) {
|
|
8
|
+
const width = options.width || 1200;
|
|
9
|
+
const height = options.height || 800;
|
|
10
|
+
|
|
11
|
+
return `
|
|
12
|
+
const { app, BrowserWindow, Menu, shell, nativeTheme } = require('electron');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
|
|
16
|
+
const APP_NAME = "${appName}";
|
|
17
|
+
const APP_URL = "${url}";
|
|
18
|
+
const APP_ICON_PATH = "${iconPath.replace(/\\/g, '\\\\')}";
|
|
19
|
+
const WINDOW_WIDTH = ${width};
|
|
20
|
+
const WINDOW_HEIGHT = ${height};
|
|
21
|
+
|
|
22
|
+
let mainWindow;
|
|
23
|
+
let splashWindow;
|
|
24
|
+
|
|
25
|
+
function logAppInfo() {
|
|
26
|
+
const packageJsonPath = path.join(__dirname, 'package.json');
|
|
27
|
+
let packageInfo = {};
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
31
|
+
packageInfo = JSON.parse(packageJsonContent);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error('Error reading package.json:', error.message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('\\n--------------------------------');
|
|
37
|
+
console.log(' APPLICATION INFORMATION');
|
|
38
|
+
console.log('--------------------------------');
|
|
39
|
+
console.log(\`Application: \${APP_NAME}\`);
|
|
40
|
+
console.log(\`URL: \${APP_URL}\`);
|
|
41
|
+
console.log(\`Started at: \${new Date().toLocaleString()}\`);
|
|
42
|
+
console.log(\`App directory: \${__dirname}\`);
|
|
43
|
+
console.log(\`Icon path: \${APP_ICON_PATH}\`);
|
|
44
|
+
|
|
45
|
+
console.log('\\n PACKAGE INFO:');
|
|
46
|
+
console.log(\` - Name: \${packageInfo.name || 'N/A'}\`);
|
|
47
|
+
console.log(\` - Version: \${packageInfo.version || 'N/A'}\`);
|
|
48
|
+
console.log(\` - Description: \${packageInfo.description || 'N/A'}\`);
|
|
49
|
+
console.log(\` - Electron version: \${packageInfo.dependencies?.electron || 'N/A'}\`);
|
|
50
|
+
|
|
51
|
+
if (packageInfo.build) {
|
|
52
|
+
console.log('\\n BUILD CONFIG:');
|
|
53
|
+
console.log(\` - App ID: \${packageInfo.build.appId || 'N/A'}\`);
|
|
54
|
+
console.log(\` - Product Name: \${packageInfo.build.productName || 'N/A'}\`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('--------------------------------\\n');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function createSplashScreen() {
|
|
61
|
+
splashWindow = new BrowserWindow({
|
|
62
|
+
width: 200,
|
|
63
|
+
height: 40,
|
|
64
|
+
transparent: true,
|
|
65
|
+
frame: false,
|
|
66
|
+
alwaysOnTop: true,
|
|
67
|
+
skipTaskbar: true,
|
|
68
|
+
resizable: false,
|
|
69
|
+
icon: APP_ICON_PATH,
|
|
70
|
+
webPreferences: {
|
|
71
|
+
nodeIntegration: false,
|
|
72
|
+
contextIsolation: true
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const isDarkMode = nativeTheme.shouldUseDarkColors;
|
|
77
|
+
const bgColor = isDarkMode ? '#333333' : '#f5f5f5';
|
|
78
|
+
const loaderBgColor = isDarkMode ? '#555555' : '#e0e0e0';
|
|
79
|
+
const loaderColor = isDarkMode ? '#ffffff' : '#2563eb';
|
|
80
|
+
const shadowColor = isDarkMode ? 'rgba(0, 0, 0, 0.5)' : 'rgba(0, 0, 0, 0.2)';
|
|
81
|
+
|
|
82
|
+
const splashHtml = \`
|
|
83
|
+
<!DOCTYPE html>
|
|
84
|
+
<html>
|
|
85
|
+
<head>
|
|
86
|
+
<meta charset="UTF-8">
|
|
87
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'none';">
|
|
88
|
+
<title>Loading</title>
|
|
89
|
+
<style>
|
|
90
|
+
html, body {
|
|
91
|
+
margin: 0;
|
|
92
|
+
padding: 0;
|
|
93
|
+
width: 100%;
|
|
94
|
+
height: 100%;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
background-color: transparent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.container {
|
|
100
|
+
width: 100%;
|
|
101
|
+
height: 100%;
|
|
102
|
+
display: flex;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.loader-container {
|
|
108
|
+
width: 180px;
|
|
109
|
+
height: 12px;
|
|
110
|
+
background-color: \${bgColor};
|
|
111
|
+
border-radius: 6px;
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
box-shadow: 0 2px 8px \${shadowColor};
|
|
114
|
+
padding: 3px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.loader-bg {
|
|
118
|
+
width: 100%;
|
|
119
|
+
height: 100%;
|
|
120
|
+
background-color: \${loaderBgColor};
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
position: relative;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.loader {
|
|
127
|
+
position: absolute;
|
|
128
|
+
top: 0;
|
|
129
|
+
left: 0;
|
|
130
|
+
height: 100%;
|
|
131
|
+
width: 30%;
|
|
132
|
+
background-color: \${loaderColor};
|
|
133
|
+
border-radius: 4px;
|
|
134
|
+
animation: loading 1.5s infinite ease-in-out;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@keyframes loading {
|
|
138
|
+
0% {
|
|
139
|
+
left: -30%;
|
|
140
|
+
}
|
|
141
|
+
100% {
|
|
142
|
+
left: 100%;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
146
|
+
</head>
|
|
147
|
+
<body>
|
|
148
|
+
<div class="container">
|
|
149
|
+
<div class="loader-container">
|
|
150
|
+
<div class="loader-bg">
|
|
151
|
+
<div class="loader"></div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</body>
|
|
156
|
+
</html>
|
|
157
|
+
\`;
|
|
158
|
+
|
|
159
|
+
const splashPath = path.join(app.getPath('temp'), \`\${APP_NAME}-splash.html\`);
|
|
160
|
+
fs.writeFileSync(splashPath, splashHtml);
|
|
161
|
+
|
|
162
|
+
splashWindow.loadFile(splashPath);
|
|
163
|
+
|
|
164
|
+
const { screen } = require('electron');
|
|
165
|
+
const primaryDisplay = screen.getPrimaryDisplay();
|
|
166
|
+
const { width, height } = primaryDisplay.workAreaSize;
|
|
167
|
+
|
|
168
|
+
splashWindow.setPosition(
|
|
169
|
+
Math.floor(width / 2 - 100),
|
|
170
|
+
Math.floor(height / 2 - 20)
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function createWindow() {
|
|
175
|
+
logAppInfo();
|
|
176
|
+
|
|
177
|
+
app.setAppUserModelId(APP_NAME);
|
|
178
|
+
|
|
179
|
+
mainWindow = new BrowserWindow({
|
|
180
|
+
width: WINDOW_WIDTH,
|
|
181
|
+
height: WINDOW_HEIGHT,
|
|
182
|
+
title: APP_NAME,
|
|
183
|
+
icon: APP_ICON_PATH,
|
|
184
|
+
show: false,
|
|
185
|
+
webPreferences: {
|
|
186
|
+
nodeIntegration: false,
|
|
187
|
+
contextIsolation: true
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
mainWindow.webContents.on('did-finish-load', () => {
|
|
192
|
+
setTimeout(() => {
|
|
193
|
+
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
194
|
+
splashWindow.close();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!mainWindow.isVisible()) {
|
|
198
|
+
mainWindow.show();
|
|
199
|
+
mainWindow.focus();
|
|
200
|
+
}
|
|
201
|
+
}, 500);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
mainWindow.loadURL(APP_URL);
|
|
205
|
+
|
|
206
|
+
mainWindow.webContents.on('context-menu', (e, params) => {
|
|
207
|
+
e.preventDefault();
|
|
208
|
+
mainWindow.webContents.executeJavaScript(\`
|
|
209
|
+
window.addEventListener('contextmenu', (e) => {
|
|
210
|
+
e.stopPropagation();
|
|
211
|
+
}, true);
|
|
212
|
+
\`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
mainWindow.webContents.on('new-window', (event, url) => {
|
|
216
|
+
event.preventDefault();
|
|
217
|
+
shell.openExternal(url);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const template = [];
|
|
221
|
+
|
|
222
|
+
const menu = Menu.buildFromTemplate(template);
|
|
223
|
+
Menu.setApplicationMenu(menu);
|
|
224
|
+
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
227
|
+
splashWindow.close();
|
|
228
|
+
if (!mainWindow.isVisible()) {
|
|
229
|
+
mainWindow.show();
|
|
230
|
+
mainWindow.focus();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}, 10000);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (process.platform === 'win32') {
|
|
237
|
+
app.setAppUserModelId(app.name);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
app.whenReady().then(() => {
|
|
241
|
+
createSplashScreen();
|
|
242
|
+
createWindow();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
app.on('window-all-closed', () => {
|
|
246
|
+
if (process.platform !== 'darwin') {
|
|
247
|
+
app.quit();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
app.on('activate', () => {
|
|
252
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
253
|
+
createWindow();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
`;
|
|
257
|
+
} // note for one day: put this in a different file
|
|
258
|
+
|
|
259
|
+
async function createPackageJson(appName, iconPath, isExecutable = false, createSetup = false) {
|
|
260
|
+
const u2aPackagePath = path.resolve(__dirname, '../../package.json');
|
|
261
|
+
|
|
262
|
+
let u2aVersion = '1.0.0';
|
|
263
|
+
try {
|
|
264
|
+
const u2aPackageContent = fs.readFileSync(u2aPackagePath, 'utf8');
|
|
265
|
+
const u2aPackage = JSON.parse(u2aPackageContent);
|
|
266
|
+
u2aVersion = u2aPackage.version || u2aVersion;
|
|
267
|
+
} catch (error) {
|
|
268
|
+
logger.error('Error while fetching u2a package.json', error);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (createSetup) {
|
|
272
|
+
const { processFavicon } = require('./favicon');
|
|
273
|
+
iconPath = await processFavicon(iconPath);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const packageJson = {
|
|
277
|
+
name: `u2a-${appName.replace(/\s+/g, '-')}`,
|
|
278
|
+
version: u2aVersion,
|
|
279
|
+
description: `Web app for ${appName}`,
|
|
280
|
+
main: 'main.js',
|
|
281
|
+
author: `${appName}`,
|
|
282
|
+
scripts: {
|
|
283
|
+
start: 'electron .'
|
|
284
|
+
},
|
|
285
|
+
dependencies: {
|
|
286
|
+
electron: '^22.0.0'
|
|
287
|
+
},
|
|
288
|
+
build: {
|
|
289
|
+
appId: `com.u2a.${appName.replace(/\s+/g, '-')}`,
|
|
290
|
+
productName: appName,
|
|
291
|
+
icon: iconPath
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
if (isExecutable) {
|
|
296
|
+
packageJson.devDependencies = {
|
|
297
|
+
"electron-packager": "^17.1.1",
|
|
298
|
+
"electron-builder": "^24.6.3",
|
|
299
|
+
"electron": "^22.0.0"
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
packageJson.dependencies = {};
|
|
303
|
+
|
|
304
|
+
packageJson.scripts.package = "electron-packager . --overwrite --asar";
|
|
305
|
+
packageJson.scripts.setup = "electron-builder";
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (isExecutable && createSetup) {
|
|
309
|
+
packageJson.build = {
|
|
310
|
+
...packageJson.build,
|
|
311
|
+
appId: `com.u2a.${appName.replace(/\s+/g, '-')}`,
|
|
312
|
+
productName: appName,
|
|
313
|
+
directories: {
|
|
314
|
+
output: "installer"
|
|
315
|
+
},
|
|
316
|
+
files: [
|
|
317
|
+
"**/*",
|
|
318
|
+
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}",
|
|
319
|
+
"!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
|
|
320
|
+
"!**/node_modules/*.d.ts",
|
|
321
|
+
"!**/node_modules/.bin",
|
|
322
|
+
"!**/.{idea,git,cache,build,dist}",
|
|
323
|
+
"!dist/**/*",
|
|
324
|
+
"!installer/**/*"
|
|
325
|
+
],
|
|
326
|
+
win: {
|
|
327
|
+
target: "nsis",
|
|
328
|
+
icon: iconPath
|
|
329
|
+
},
|
|
330
|
+
mac: {
|
|
331
|
+
target: "dmg"
|
|
332
|
+
},
|
|
333
|
+
linux: {
|
|
334
|
+
target: "AppImage",
|
|
335
|
+
icon: iconPath
|
|
336
|
+
},
|
|
337
|
+
nsis: {
|
|
338
|
+
oneClick: false,
|
|
339
|
+
allowToChangeInstallationDirectory: true
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return packageJson;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
module.exports = {
|
|
348
|
+
generateMainJs,
|
|
349
|
+
createPackageJson
|
|
350
350
|
};
|