kreftjs 0.0.14-beta → 0.0.16-beta
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/README.md +2 -0
- package/assets/logo.png +0 -0
- package/bin/db.js +15 -3
- package/bin/electron.js +62 -18
- package/bin/no-auth.js +2 -2
- package/docs/README.md +41 -9
- package/editors/vscode/.vscodeignore +4 -0
- package/editors/vscode/CHANGELOG.md +6 -0
- package/editors/vscode/LICENSE +95 -0
- package/editors/vscode/README.md +17 -4
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/package.json +24 -1
- package/kreftjs.d.ts +1 -1
- package/kreftjs.js +2 -2
- package/package.json +3 -2
- package/templates/app/frontend/errors/ErrorMonitor.kreft +2 -2
- package/templates/app/frontend/index.html +1 -0
- package/templates/app/frontend/kreftjs.d.ts +1 -1
- package/templates/app/frontend/kreftjs.js +2 -2
- package/templates/app/frontend/layouts/docs.kreft +2 -2
- package/templates/app/frontend/layouts/guest.kreft +2 -2
- package/templates/app/frontend/logo-mark.svg +22 -0
- package/templates/app/frontend/pages/Dashboard.kreft +1 -1
- package/templates/app/frontend/pages/Home.kreft +2 -2
- package/templates/errors/ErrorMonitor.kreft +1 -1
package/README.md
CHANGED
package/assets/logo.png
ADDED
|
Binary file
|
package/bin/db.js
CHANGED
|
@@ -41,11 +41,23 @@ const TEXT = /char|text|clob|string|uuid|enum|json/i;
|
|
|
41
41
|
const dateOut = (d) => d.toISOString().slice(0, 19).replace('T', ' ');
|
|
42
42
|
const BOOL = /^bool/i;
|
|
43
43
|
|
|
44
|
+
// a missing table nearly always means a migration has not been run yet, so say so
|
|
45
|
+
const MISSING_TABLE = /no such table|doesn't exist|does not exist|ER_NO_SUCH_TABLE/i;
|
|
46
|
+
function hintMissingTable(e) {
|
|
47
|
+
if (e && typeof e.message === 'string' && MISSING_TABLE.test(e.message) && /table|relation/i.test(e.message) && !e.message.includes('kreft migrate')) {
|
|
48
|
+
e.message += '\n Hint: the table is missing. Run `kreft migrate` to create it.';
|
|
49
|
+
}
|
|
50
|
+
return e;
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
async function connect(url, { root } = {}) {
|
|
45
54
|
const cfg = parseUrl(url);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
const db = cfg.kind === 'sqlite' ? await sqlite(cfg, root) : cfg.kind === 'mysql' ? await mysql(cfg, root) : await postgres(cfg, root);
|
|
56
|
+
for (const m of ['query', 'run']) {
|
|
57
|
+
const fn = db[m];
|
|
58
|
+
if (typeof fn === 'function') db[m] = async (...a) => { try { return await fn.apply(db, a); } catch (e) { throw hintMissingTable(e); } };
|
|
59
|
+
}
|
|
60
|
+
return db;
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
/* ---------------------------------------------------------------- SQLite (node:sqlite) */
|
package/bin/electron.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Commands:
|
|
5
5
|
* kreft electron:init Add Electron files to an existing project (alias: kreft make:electron)
|
|
6
|
-
* kreft electron:dev Run the app in an Electron desktop window
|
|
6
|
+
* kreft electron:dev Run the app in an Electron desktop window only (hidden server, no browser, no URL)
|
|
7
7
|
* kreft electron:build Build static bundle (kreft build) and package desktop installer (electron-builder)
|
|
8
8
|
*
|
|
9
9
|
* CLI flag:
|
|
@@ -19,10 +19,11 @@ function getProjectRoot(start = process.cwd()) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const TEMPLATES = {
|
|
22
|
-
main: () => `const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron');
|
|
22
|
+
main: () => `const { app, BrowserWindow, Menu, ipcMain, dialog, shell } = require('electron');
|
|
23
23
|
const path = require('path');
|
|
24
24
|
const http = require('http');
|
|
25
25
|
|
|
26
|
+
// Dev: the app's own server runs hidden on a private port of this computer, only this window uses it.
|
|
26
27
|
const isDev = !app.isPackaged || process.env.NODE_ENV === 'development';
|
|
27
28
|
const DEV_PORT = process.env.PORT || 8000;
|
|
28
29
|
const DEV_URL = \`http://localhost:\${DEV_PORT}\`;
|
|
@@ -47,6 +48,25 @@ function getDevToolsConfig() {
|
|
|
47
48
|
return { show: true, mode };
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
// Window menu (File, Edit, View…):
|
|
52
|
+
// ELECTRON_MENU=show (default) menu bar visible
|
|
53
|
+
// ELECTRON_MENU=auto hidden, press Alt to show it (Windows / Linux)
|
|
54
|
+
// ELECTRON_MENU=hide no menu at all
|
|
55
|
+
// Change it while running from the page: window.kreftDesktop.setMenu('show' | 'auto' | 'hide')
|
|
56
|
+
let menuMode = String(process.env.ELECTRON_MENU || 'show').toLowerCase();
|
|
57
|
+
const defaultMenu = Menu.getApplicationMenu();
|
|
58
|
+
function applyMenu(mode) {
|
|
59
|
+
menuMode = ['show', 'auto', 'hide'].includes(mode) ? mode : 'show';
|
|
60
|
+
Menu.setApplicationMenu(menuMode === 'hide' ? null : (Menu.getApplicationMenu() || defaultMenu));
|
|
61
|
+
if (mainWindow && process.platform !== 'darwin') {
|
|
62
|
+
mainWindow.setAutoHideMenuBar(menuMode === 'auto');
|
|
63
|
+
mainWindow.setMenuBarVisibility(menuMode === 'show');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// App icon: build/icon.png (512x512 or bigger). electron-builder makes .icns / .ico from it.
|
|
68
|
+
const ICON = path.join(__dirname, '..', 'build', 'icon.png');
|
|
69
|
+
|
|
50
70
|
let mainWindow = null;
|
|
51
71
|
|
|
52
72
|
function waitForServer(url, timeout = 15000) {
|
|
@@ -76,6 +96,8 @@ async function createWindow() {
|
|
|
76
96
|
frame: true,
|
|
77
97
|
backgroundColor: '#ffffff',
|
|
78
98
|
show: false,
|
|
99
|
+
icon: require('fs').existsSync(ICON) ? ICON : undefined,
|
|
100
|
+
autoHideMenuBar: menuMode === 'auto',
|
|
79
101
|
webPreferences: {
|
|
80
102
|
preload: path.join(__dirname, 'preload.js'),
|
|
81
103
|
contextIsolation: true,
|
|
@@ -86,6 +108,7 @@ async function createWindow() {
|
|
|
86
108
|
});
|
|
87
109
|
|
|
88
110
|
mainWindow.once('ready-to-show', () => {
|
|
111
|
+
applyMenu(menuMode);
|
|
89
112
|
mainWindow.show();
|
|
90
113
|
});
|
|
91
114
|
|
|
@@ -122,12 +145,8 @@ async function createWindow() {
|
|
|
122
145
|
const devTools = getDevToolsConfig();
|
|
123
146
|
|
|
124
147
|
if (isDev) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
await mainWindow.loadURL(DEV_URL);
|
|
128
|
-
} else {
|
|
129
|
-
await mainWindow.loadURL(DEV_URL); // attempt anyway
|
|
130
|
-
}
|
|
148
|
+
await waitForServer(DEV_URL);
|
|
149
|
+
await mainWindow.loadURL(DEV_URL);
|
|
131
150
|
if (devTools.show) {
|
|
132
151
|
mainWindow.webContents.openDevTools({ mode: devTools.mode });
|
|
133
152
|
}
|
|
@@ -174,6 +193,11 @@ ipcMain.handle('kreft:close', () => {
|
|
|
174
193
|
if (mainWindow) mainWindow.close();
|
|
175
194
|
});
|
|
176
195
|
|
|
196
|
+
ipcMain.handle('kreft:menu', (_, mode) => {
|
|
197
|
+
if (mode !== undefined) applyMenu(String(mode));
|
|
198
|
+
return menuMode;
|
|
199
|
+
});
|
|
200
|
+
|
|
177
201
|
ipcMain.handle('kreft:devtools:open', (_, mode) => {
|
|
178
202
|
if (mainWindow) mainWindow.webContents.openDevTools({ mode: mode || 'right' });
|
|
179
203
|
});
|
|
@@ -232,6 +256,8 @@ const desktop = {
|
|
|
232
256
|
minimize: () => ipcRenderer.invoke('kreft:minimize'),
|
|
233
257
|
maximize: () => ipcRenderer.invoke('kreft:maximize'),
|
|
234
258
|
close: () => ipcRenderer.invoke('kreft:close'),
|
|
259
|
+
getMenu: () => ipcRenderer.invoke('kreft:menu'),
|
|
260
|
+
setMenu: (mode) => ipcRenderer.invoke('kreft:menu', mode),
|
|
235
261
|
openDevTools: (mode) => ipcRenderer.invoke('kreft:devtools:open', mode),
|
|
236
262
|
closeDevTools: () => ipcRenderer.invoke('kreft:devtools:close'),
|
|
237
263
|
toggleDevTools: () => ipcRenderer.invoke('kreft:devtools:toggle'),
|
|
@@ -287,6 +313,10 @@ function init(args = []) {
|
|
|
287
313
|
pkg.scripts['electron'] = 'kreft electron';
|
|
288
314
|
pkg.scripts['electron:dev'] = 'kreft electron:dev';
|
|
289
315
|
pkg.scripts['electron:build'] = 'kreft electron:build';
|
|
316
|
+
pkg.scripts['electron:build:mac'] = 'kreft electron:build --mac';
|
|
317
|
+
pkg.scripts['electron:build:win'] = 'kreft electron:build --win';
|
|
318
|
+
pkg.scripts['electron:build:linux'] = 'kreft electron:build --linux';
|
|
319
|
+
pkg.scripts['electron:build:all'] = 'kreft electron:build --mac --win --linux';
|
|
290
320
|
|
|
291
321
|
pkg.devDependencies = pkg.devDependencies || {};
|
|
292
322
|
if (!pkg.devDependencies['electron']) pkg.devDependencies['electron'] = '^34.2.0';
|
|
@@ -295,13 +325,26 @@ function init(args = []) {
|
|
|
295
325
|
pkg.build = pkg.build || {
|
|
296
326
|
appId: `com.kreftjs.${(pkg.name || 'app').toLowerCase().replace(/[^a-z0-9]/g, '')}`,
|
|
297
327
|
productName: pkg.name ? pkg.name.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) : 'Kreft Desktop',
|
|
298
|
-
directories: { output: 'dist-electron' },
|
|
299
|
-
files: ['dist/**/*', 'electron/**/*', 'package.json'],
|
|
300
|
-
mac: { target: ['dmg', 'zip'], category: 'public.app-category.developer-tools' },
|
|
301
|
-
win: { target: ['nsis', 'portable'] },
|
|
302
|
-
|
|
328
|
+
directories: { output: 'dist-electron', buildResources: 'build' },
|
|
329
|
+
files: ['dist/**/*', 'electron/**/*', 'build/icon.png', 'package.json'],
|
|
330
|
+
mac: { target: ['dmg', 'zip'], category: 'public.app-category.developer-tools', icon: 'build/icon.png' },
|
|
331
|
+
win: { target: ['nsis', 'portable'], icon: 'build/icon.png' },
|
|
332
|
+
nsis: { oneClick: false, allowToChangeInstallationDirectory: true },
|
|
333
|
+
linux: { target: ['AppImage', 'deb', 'rpm'], category: 'Utility', icon: 'build/icon.png' },
|
|
303
334
|
};
|
|
304
335
|
|
|
336
|
+
// The app icon: replace build/icon.png with your own (square PNG, 512x512 or bigger)
|
|
337
|
+
const iconFile = path.join(root, 'build', 'icon.png');
|
|
338
|
+
let wroteIcon = false;
|
|
339
|
+
if (!fs.existsSync(iconFile)) {
|
|
340
|
+
const logo = path.join(__dirname, '..', 'assets', 'logo-mark.png');
|
|
341
|
+
if (fs.existsSync(logo)) {
|
|
342
|
+
fs.mkdirSync(path.dirname(iconFile), { recursive: true });
|
|
343
|
+
fs.copyFileSync(logo, iconFile);
|
|
344
|
+
wroteIcon = true;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
305
348
|
fs.writeFileSync(pkgFile, JSON.stringify(pkg, null, 2) + '\n');
|
|
306
349
|
|
|
307
350
|
const droppedFonts = dropWebFonts(root);
|
|
@@ -309,7 +352,8 @@ function init(args = []) {
|
|
|
309
352
|
console.log(`
|
|
310
353
|
Electron configured for Kreft:
|
|
311
354
|
CREATED electron/main.js
|
|
312
|
-
CREATED electron/preload.js
|
|
355
|
+
CREATED electron/preload.js${wroteIcon ? `
|
|
356
|
+
CREATED build/icon.png (the app icon: replace it with your own, square PNG 512x512 or bigger)` : ''}
|
|
313
357
|
UPDATED package.json (scripts: electron, electron:dev, electron:build)${droppedFonts ? `
|
|
314
358
|
UPDATED ${droppedFonts} (removed the Google Fonts links: a desktop app should start without the network; the system fonts are used)` : ''}
|
|
315
359
|
|
|
@@ -398,12 +442,12 @@ function startDev(args, port) {
|
|
|
398
442
|
if (!serverArgs.some((a) => a === '--port' || a === '-p')) serverArgs.push('--port', String(port));
|
|
399
443
|
|
|
400
444
|
// 1. Start dev server child process
|
|
401
|
-
console.log(
|
|
445
|
+
console.log(' Starting the Kreft desktop window…');
|
|
402
446
|
const kreftCli = path.join(__dirname, 'kreftjs.js');
|
|
403
447
|
const server = spawn(process.execPath, [kreftCli, 'dev', ...serverArgs], {
|
|
404
448
|
cwd: root,
|
|
405
|
-
stdio: 'inherit',
|
|
406
|
-
env: { ...process.env, PORT: String(port), KREFT_ELECTRON: 'true' },
|
|
449
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
450
|
+
env: { ...process.env, PORT: String(port), KREFT_ELECTRON: 'true', BROWSER: 'none' },
|
|
407
451
|
});
|
|
408
452
|
|
|
409
453
|
// 2. Launch Electron after small pause
|
|
@@ -466,7 +510,7 @@ function build(args = []) {
|
|
|
466
510
|
// 1. Build Kreft frontend for desktop with relative base
|
|
467
511
|
console.log('\n Step 1: Building Kreft static bundle with relative base (./)…');
|
|
468
512
|
const kreftCli = path.join(__dirname, 'kreftjs.js');
|
|
469
|
-
const buildProc = spawn(process.execPath, [kreftCli, 'build', '--base', './', ...args], {
|
|
513
|
+
const buildProc = spawn(process.execPath, [kreftCli, 'build', '--base', './', ...args.filter((a) => !/^--(mac|win|linux|dir|x64|arm64|ia32|armv7l|universal|publish.*)$/.test(a))], {
|
|
470
514
|
cwd: root,
|
|
471
515
|
stdio: 'inherit',
|
|
472
516
|
});
|
package/bin/no-auth.js
CHANGED
|
@@ -79,7 +79,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\\/+
|
|
|
79
79
|
|
|
80
80
|
<view>
|
|
81
81
|
<header>
|
|
82
|
-
<kreft-link to="/" class="brand"><
|
|
82
|
+
<kreft-link to="/" class="brand"><img class="mark" src="logo-mark.svg" alt="" width="22" height="22">{env.PUBLIC_APP_NAME || 'My app'}</kreft-link>
|
|
83
83
|
<nav>
|
|
84
84
|
<kreft-link to="/" exact-class="here">Home</kreft-link>${todos ? `
|
|
85
85
|
<kreft-link to="/todos" exact-class="here">Todos</kreft-link>` : ''}
|
|
@@ -99,7 +99,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\\/+
|
|
|
99
99
|
<style scoped>
|
|
100
100
|
header { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; gap: 14px; height: 60px; padding: 0 var(--container-pad, 28px); background: var(--background); border-bottom: 1px solid var(--border); box-sizing: border-box; }
|
|
101
101
|
.brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; letter-spacing: -0.02em; color: var(--foreground); text-decoration: none; }
|
|
102
|
-
.mark { width:
|
|
102
|
+
.mark { width: 22px; height: 22px; }
|
|
103
103
|
nav { display: flex; align-items: center; gap: 4px; margin-inline-start: auto; }
|
|
104
104
|
nav a { padding: 6px 10px; font-size: 14px; color: var(--muted); text-decoration: none; border-radius: var(--radius); }
|
|
105
105
|
nav a:hover, nav a.here { color: var(--foreground); background: var(--accent); }
|
package/docs/README.md
CHANGED
|
@@ -82,7 +82,7 @@ npx kreftjs dev
|
|
|
82
82
|
### Check that it works
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
kreft --version # for example 0.0.
|
|
85
|
+
kreft --version # for example 0.0.16-beta
|
|
86
86
|
kreft about # Kreft and Node.js versions, this project's settings and drivers
|
|
87
87
|
kreft list # every command your version has
|
|
88
88
|
```
|
|
@@ -1891,7 +1891,7 @@ Kreft can package your app as a desktop application for Windows, macOS and Linux
|
|
|
1891
1891
|
```bash
|
|
1892
1892
|
kreft new my-app --electron # a new app with desktop support
|
|
1893
1893
|
cd my-app && npm install
|
|
1894
|
-
kreft electron:dev #
|
|
1894
|
+
kreft electron:dev # a desktop window only (the server is hidden), with hot reload
|
|
1895
1895
|
kreft electron:build # an installer in dist-electron/
|
|
1896
1896
|
```
|
|
1897
1897
|
|
|
@@ -1906,8 +1906,8 @@ npm install # installs electron and electron-builder
|
|
|
1906
1906
|
|
|
1907
1907
|
| Command | What it does |
|
|
1908
1908
|
|---|---|
|
|
1909
|
-
| `kreft electron:init` | Writes `electron/main.js
|
|
1910
|
-
| `kreft electron:dev` |
|
|
1909
|
+
| `kreft electron:init` | Writes `electron/main.js`, `electron/preload.js` and the app icon `build/icon.png`, and adds the scripts (including `electron:build:mac`, `:win`, `:linux` and `:all`), the `electron` and `electron-builder` dev dependencies and a `build` block to `package.json`. Files that already exist are never overwritten. It also removes the Google Fonts links from `index.html`, so the app starts without a network. |
|
|
1910
|
+
| `kreft electron:dev` | Opens the app in a desktop window only: no browser opens and no URL is printed. The dev server runs hidden on a private port of your computer that only the window uses (hot reload works). Closing the window stops the server. Flags after the command go to the dev server. |
|
|
1911
1911
|
| `kreft electron:build` | Runs `kreft build --base ./`, then `electron-builder`. |
|
|
1912
1912
|
|
|
1913
1913
|
`kreft electron` is the same as `kreft electron:dev`. If the `electron/` folder is missing, both commands create it first.
|
|
@@ -1994,17 +1994,49 @@ ELECTRON_DEVTOOLS=bottom kreft electron:dev
|
|
|
1994
1994
|
|
|
1995
1995
|
In development, F12 or Ctrl+Shift+I toggles them.
|
|
1996
1996
|
|
|
1997
|
+
### The window menu
|
|
1998
|
+
|
|
1999
|
+
Set the menu bar when you start the app:
|
|
2000
|
+
|
|
2001
|
+
```bash
|
|
2002
|
+
ELECTRON_MENU=show kreft electron # default: the menu bar is visible
|
|
2003
|
+
ELECTRON_MENU=auto kreft electron # hidden, press Alt to show it (Windows and Linux)
|
|
2004
|
+
ELECTRON_MENU=hide kreft electron # no menu at all
|
|
2005
|
+
```
|
|
2006
|
+
|
|
2007
|
+
Or change it while the app runs, from a page:
|
|
2008
|
+
|
|
2009
|
+
```js
|
|
2010
|
+
window.kreftDesktop.setMenu('hide') // 'show' | 'auto' | 'hide'
|
|
2011
|
+
window.kreftDesktop.getMenu() // the current mode
|
|
2012
|
+
```
|
|
2013
|
+
|
|
2014
|
+
On macOS the menu lives in the top bar of the screen, so `show` and `auto` look the same. For your own menu (File, Edit…), call `Menu.buildFromTemplate([...])` and `Menu.setApplicationMenu(...)` in `electron/main.js`.
|
|
2015
|
+
|
|
2016
|
+
### The app icon
|
|
2017
|
+
|
|
2018
|
+
`kreft electron:init` copies the Kreft logo to `build/icon.png`. Replace it with your own square PNG, 512×512 or bigger. The window uses it, and electron-builder makes the `.icns` (macOS) and `.ico` (Windows) files from it. Set the app name with `build.productName` and `build.appId` in `package.json`, and add `description` and `author` there too (electron-builder warns without them).
|
|
2019
|
+
|
|
1997
2020
|
### Packaging and installers
|
|
1998
2021
|
|
|
1999
|
-
|
|
2022
|
+
```bash
|
|
2023
|
+
npm run electron:build:mac # .dmg and .zip
|
|
2024
|
+
npm run electron:build:win # NSIS installer and portable .exe
|
|
2025
|
+
npm run electron:build:linux # AppImage, .deb and .rpm
|
|
2026
|
+
npm run electron:build:all # all three
|
|
2027
|
+
```
|
|
2028
|
+
|
|
2029
|
+
`electron:build` writes to `dist-electron/`. Flags go to electron-builder, for example `kreft electron:build --mac --arm64`. The defaults in the `build` block of `package.json` are:
|
|
2000
2030
|
|
|
2001
2031
|
| System | Targets |
|
|
2002
2032
|
|---|---|
|
|
2003
|
-
| Windows | `nsis` installer, `portable` |
|
|
2033
|
+
| Windows | `nsis` installer (choose the folder), `portable` |
|
|
2004
2034
|
| macOS | `dmg`, `zip` |
|
|
2005
|
-
| Linux | `AppImage`, `deb` |
|
|
2035
|
+
| Linux | `AppImage`, `deb`, `rpm` |
|
|
2036
|
+
|
|
2037
|
+
Edit `appId`, `productName` and the targets there. Build for each system on that system: a macOS installer needs a Mac (Windows installers from a Mac need Wine; `.rpm` needs `rpm` installed). Code signing and notarisation (macOS) or a signing certificate (Windows) are set up through electron-builder (electron.build/code-signing) and are needed before you give the app to other people; unsigned macOS apps show a Gatekeeper warning.
|
|
2006
2038
|
|
|
2007
|
-
|
|
2039
|
+
The packaged app loads the built `dist/index.html` and does not start a backend. A frontend-only app works as is; a full-stack app (login, database) does not work once installed.
|
|
2008
2040
|
|
|
2009
2041
|
### Security
|
|
2010
2042
|
|
|
@@ -2026,7 +2058,7 @@ Do not turn these off to make something work. Add a bridge function instead.
|
|
|
2026
2058
|
| A white window in the packaged app | Run `electron:build` again; the build must use `--base ./`. Check that `dist/index.html` exists. |
|
|
2027
2059
|
| API calls fail in the packaged app | The backend is not bundled. Set an absolute `base` for the API client (see above). |
|
|
2028
2060
|
| The window opens before the server is ready | It waits up to 15 seconds. Check the terminal for a dev server error. |
|
|
2029
|
-
| Port 8000 is taken |
|
|
2061
|
+
| Port 8000 is taken | Nothing to do: the hidden server picks the next free port. |
|
|
2030
2062
|
|
|
2031
2063
|
## Packages
|
|
2032
2064
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.3.0
|
|
4
|
+
- Syntax colors for `.kreft` (and legacy `.kreftjs`) files, including embedded HTML, CSS and JavaScript.
|
|
5
|
+
- Bracket matching, auto-closing pairs, comments (Ctrl+/) and folding for `<view>` and `<style>`.
|
|
6
|
+
- Document formatter and snippets (`kreftjs`, `state`, `action`, `for`, `kreft-wait`, ...).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Copyright 2026 Maxamuud Xuseen
|
|
2
|
+
|
|
3
|
+
Elastic License 2.0
|
|
4
|
+
|
|
5
|
+
URL: https://www.elastic.co/licensing/elastic-license
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
14
|
+
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
15
|
+
available, and prepare derivative works of the software, in each case subject to
|
|
16
|
+
the limitations and conditions below.
|
|
17
|
+
|
|
18
|
+
## Limitations
|
|
19
|
+
|
|
20
|
+
You may not provide the software to third parties as a hosted or managed
|
|
21
|
+
service, where the service provides users with access to any substantial set of
|
|
22
|
+
the features or functionality of the software.
|
|
23
|
+
|
|
24
|
+
You may not move, change, disable, or circumvent the license key functionality
|
|
25
|
+
in the software, and you may not remove or obscure any functionality in the
|
|
26
|
+
software that is protected by the license key.
|
|
27
|
+
|
|
28
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|
29
|
+
of the licensor in the software. Any use of the licensor’s trademarks is subject
|
|
30
|
+
to applicable law.
|
|
31
|
+
|
|
32
|
+
## Patents
|
|
33
|
+
|
|
34
|
+
The licensor grants you a license, under any patent claims the licensor can
|
|
35
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
36
|
+
sale, import and have imported the software, in each case subject to the
|
|
37
|
+
limitations and conditions in this license. This license does not cover any
|
|
38
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
39
|
+
the software. If you or your company make any written claim that the software
|
|
40
|
+
infringes or contributes to infringement of any patent, your patent license for
|
|
41
|
+
the software granted under these terms ends immediately. If your company makes
|
|
42
|
+
such a claim, your patent license ends immediately for work on behalf of your
|
|
43
|
+
company.
|
|
44
|
+
|
|
45
|
+
## Notices
|
|
46
|
+
|
|
47
|
+
You must ensure that anyone who gets a copy of any part of the software from you
|
|
48
|
+
also gets a copy of these terms.
|
|
49
|
+
|
|
50
|
+
If you modify the software, you must include in any modified copies of the
|
|
51
|
+
software prominent notices stating that you have modified the software.
|
|
52
|
+
|
|
53
|
+
## No Other Rights
|
|
54
|
+
|
|
55
|
+
These terms do not imply any licenses other than those expressly granted in
|
|
56
|
+
these terms.
|
|
57
|
+
|
|
58
|
+
## Termination
|
|
59
|
+
|
|
60
|
+
If you use the software in violation of these terms, such use is not licensed,
|
|
61
|
+
and your licenses will automatically terminate. If the licensor provides you
|
|
62
|
+
with a notice of your violation, and you cease all violation of this license no
|
|
63
|
+
later than 30 days after you receive that notice, your licenses will be
|
|
64
|
+
reinstated retroactively. However, if you violate these terms after such
|
|
65
|
+
reinstatement, any additional violation of these terms will cause your licenses
|
|
66
|
+
to terminate automatically and permanently.
|
|
67
|
+
|
|
68
|
+
## No Liability
|
|
69
|
+
|
|
70
|
+
*As far as the law allows, the software comes as is, without any warranty or
|
|
71
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
72
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
73
|
+
legal claim.*
|
|
74
|
+
|
|
75
|
+
## Definitions
|
|
76
|
+
|
|
77
|
+
The **licensor** is the entity offering these terms, and the **software** is the
|
|
78
|
+
software the licensor makes available under these terms, including any portion
|
|
79
|
+
of it.
|
|
80
|
+
|
|
81
|
+
**you** refers to the individual or entity agreeing to these terms.
|
|
82
|
+
|
|
83
|
+
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
84
|
+
organization that you work for, plus all organizations that have control over,
|
|
85
|
+
are under the control of, or are under common control with that
|
|
86
|
+
organization. **control** means ownership of substantially all the assets of an
|
|
87
|
+
entity, or the power to direct its management and policies by vote, contract, or
|
|
88
|
+
otherwise. Control can be direct or indirect.
|
|
89
|
+
|
|
90
|
+
**your licenses** are all the licenses granted to you for the software under
|
|
91
|
+
these terms.
|
|
92
|
+
|
|
93
|
+
**use** means anything you do with the software requiring one of your licenses.
|
|
94
|
+
|
|
95
|
+
**trademark** means trademarks, service marks, and similar rights.
|
package/editors/vscode/README.md
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# Kreft for VS Code
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Language support for [Kreft](https://github.com/gadhyare/somjs) `.kreft` component files.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Syntax colors** for `<view>`, `<style>` and `<script>` blocks, with HTML, CSS and JavaScript embedded.
|
|
8
|
+
- **Formatting**: format a `.kreft` file with *Format Document* (Shift+Alt+F).
|
|
9
|
+
- **Snippets**: type `kreftjs` in an empty `.kreft` file for a starter component, or `state`, `action`, `for`, `kreft-wait` and more.
|
|
10
|
+
- **Editing helpers**: bracket matching, auto-closing pairs, line comments (Ctrl+/) and folding for `<view>` / `<style>`.
|
|
11
|
+
|
|
12
|
+
Files with the older `.kreftjs` extension get the same support.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Search for **Kreft** in the Extensions view, or from a Kreft project run:
|
|
6
17
|
|
|
7
18
|
```bash
|
|
8
19
|
kreftjs vscode
|
|
9
20
|
```
|
|
10
21
|
|
|
11
|
-
Then restart VS Code.
|
|
22
|
+
Then restart VS Code.
|
|
23
|
+
|
|
24
|
+
## License
|
|
12
25
|
|
|
13
|
-
|
|
26
|
+
Elastic License 2.0. See [LICENSE](LICENSE).
|
|
Binary file
|
|
@@ -4,7 +4,30 @@
|
|
|
4
4
|
"description": "Colors, brackets, formatting and snippets for Kreft .kreft component files (and .kreftjs files from the 0.0.x betas).",
|
|
5
5
|
"version": "2.3.0",
|
|
6
6
|
"publisher": "kreft",
|
|
7
|
-
"
|
|
7
|
+
"icon": "icon.png",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/gadhyare/somjs.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/gadhyare/somjs#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/gadhyare/somjs/issues"
|
|
15
|
+
},
|
|
16
|
+
"galleryBanner": {
|
|
17
|
+
"color": "#1e1b4b",
|
|
18
|
+
"theme": "dark"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"kreft",
|
|
22
|
+
"kreftjs",
|
|
23
|
+
".kreft",
|
|
24
|
+
"syntax highlighting",
|
|
25
|
+
"snippets",
|
|
26
|
+
"formatter",
|
|
27
|
+
"framework",
|
|
28
|
+
"laravel"
|
|
29
|
+
],
|
|
30
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
8
31
|
"engines": {
|
|
9
32
|
"vscode": "^1.60.0"
|
|
10
33
|
},
|
package/kreftjs.d.ts
CHANGED
package/kreftjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.16-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -5036,7 +5036,7 @@
|
|
|
5036
5036
|
stores, storeLog, busLog,
|
|
5037
5037
|
};
|
|
5038
5038
|
|
|
5039
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.16-beta';
|
|
5040
5040
|
const Kreftjs = {
|
|
5041
5041
|
version: VERSION,
|
|
5042
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kreftjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16-beta",
|
|
4
4
|
"description": "A tiny reactive framework with its own component language (.kreft files): router with nested routes, stores, saved data, animations, an API client, hot reload, DevTools and a template engine.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"main": "kreftjs.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"start": "node bin/kreftjs.js dev --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
15
15
|
"build": "node bin/kreftjs.js build demo --out dist/demo --include docs",
|
|
16
16
|
"preview": "node bin/kreftjs.js dev dist --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
17
|
-
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js test/cookie-secure.test.js test/password-rule.test.js test/headline.test.js",
|
|
17
|
+
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js test/cookie-secure.test.js test/password-rule.test.js test/headline.test.js test/menu.test.js",
|
|
18
18
|
"electron": "kreftjs electron",
|
|
19
19
|
"electron:dev": "kreftjs electron:dev",
|
|
20
20
|
"electron:build": "kreftjs electron:build"
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"editors/",
|
|
30
30
|
"templates/",
|
|
31
31
|
"docs/",
|
|
32
|
+
"assets/logo.png",
|
|
32
33
|
"README.md"
|
|
33
34
|
],
|
|
34
35
|
"keywords": [
|
|
@@ -92,7 +92,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
92
92
|
<div class="badges">
|
|
93
93
|
<span class="badge danger-badge">HTTP {status}</span>
|
|
94
94
|
<span class="badge solid">{currentTitle}</span>
|
|
95
|
-
<span class="badge">Kreft {Kreftjs.version || '0.0.
|
|
95
|
+
<span class="badge">Kreft {Kreftjs.version || '0.0.16-beta'}</span>
|
|
96
96
|
</div>
|
|
97
97
|
<div class="actions">
|
|
98
98
|
<button class="sm" @click={copyReport}>{copied ? 'Copied Markdown' : 'Copy Report'}</button>
|
|
@@ -189,7 +189,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
189
189
|
<h3>Kreft Runtime</h3>
|
|
190
190
|
<table>
|
|
191
191
|
<tbody>
|
|
192
|
-
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.
|
|
192
|
+
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.16-beta'}</code></td></tr>
|
|
193
193
|
<tr><th>Sanitizer</th><td><code>Active (cleanHtml / SafeHtml)</code></td></tr>
|
|
194
194
|
<tr><th>Environment</th><td><code>development (APP_DEBUG=true)</code></td></tr>
|
|
195
195
|
</tbody>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<!-- where the app lives: routes and .kreft paths start here -->
|
|
7
7
|
<base href="/">
|
|
8
8
|
<title>My Kreft app</title>
|
|
9
|
+
<link rel="icon" type="image/svg+xml" href="logo-mark.svg">
|
|
9
10
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
11
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
12
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600;700&display=swap">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.16-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -5036,7 +5036,7 @@
|
|
|
5036
5036
|
stores, storeLog, busLog,
|
|
5037
5037
|
};
|
|
5038
5038
|
|
|
5039
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.16-beta';
|
|
5040
5040
|
const Kreftjs = {
|
|
5041
5041
|
version: VERSION,
|
|
5042
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
assumes a bar this tall (60px) above it. -->
|
|
4
4
|
<view>
|
|
5
5
|
<header>
|
|
6
|
-
<kreft-link to="/" class="brand"><
|
|
6
|
+
<kreft-link to="/" class="brand"><img class="mark" src="logo-mark.svg" alt="" width="22" height="22">{env.PUBLIC_APP_NAME || 'My app'}</kreft-link>
|
|
7
7
|
<span class="label">Documentation</span>
|
|
8
8
|
<nav>
|
|
9
9
|
<kreft-link to={$store.auth.user ? '/dashboard' : '/'} class="back">← {$store.auth.user ? 'Back to the app' : 'Home'}</kreft-link>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<style scoped>
|
|
22
22
|
header { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; gap: 14px; height: 60px; padding: 0 var(--container-pad, 28px); background: var(--background); border-bottom: 1px solid var(--border); box-sizing: border-box; }
|
|
23
23
|
.brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; letter-spacing: -0.02em; color: var(--foreground); text-decoration: none; }
|
|
24
|
-
.mark { width:
|
|
24
|
+
.mark { width: 22px; height: 22px; }
|
|
25
25
|
.label { padding-inline-start: 14px; border-inline-start: 1px solid var(--border); font-size: 14px; color: var(--muted); }
|
|
26
26
|
nav { display: flex; align-items: center; gap: 10px; margin-inline-start: auto; }
|
|
27
27
|
.back { padding: 6px 10px; font-size: 14px; color: var(--muted); text-decoration: none; border-radius: var(--radius); }
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
The routes in index.html ask for it with layout: 'guest'. -->
|
|
3
3
|
<view>
|
|
4
4
|
<main>
|
|
5
|
-
<kreft-link to="/" class="brand"><
|
|
5
|
+
<kreft-link to="/" class="brand"><img class="mark" src="logo-mark.svg" alt="" width="22" height="22">{env.PUBLIC_APP_NAME || 'My app'}</kreft-link>
|
|
6
6
|
<div class="box">
|
|
7
7
|
<slot></slot>
|
|
8
8
|
</div>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<style scoped>
|
|
13
13
|
main { min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: 72px 16px 48px; background: var(--accent); }
|
|
14
14
|
.brand { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 24px; font-weight: 700; font-size: 16px; letter-spacing: -0.02em; color: var(--foreground); text-decoration: none; }
|
|
15
|
-
.mark { width:
|
|
15
|
+
.mark { width: 22px; height: 22px; }
|
|
16
16
|
.box { width: 100%; max-width: 400px; background: var(--card); border: 1px solid var(--border); padding: 32px; }
|
|
17
17
|
@media (max-width: 480px) { main { padding-top: 40px; } .box { padding: 24px 20px; } }
|
|
18
18
|
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="640" height="640" role="img" aria-label="Kreft">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="kreft-o" gradientUnits="userSpaceOnUse" x1="510" y1="617" x2="1005" y2="192">
|
|
4
|
+
<stop offset="0" stop-color="#fb5f02"/>
|
|
5
|
+
<stop offset="1" stop-color="#ffac00"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="kreft-s" gradientUnits="userSpaceOnUse" x1="700" y1="500" x2="830" y2="520">
|
|
8
|
+
<stop offset="0" stop-color="#c42b00"/>
|
|
9
|
+
<stop offset="1" stop-color="#c42b00" stop-opacity="0"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
<rect width="640" height="640" rx="140" fill="#fff"/>
|
|
13
|
+
<g transform="translate(320 320) scale(0.86) translate(-751.5 -403)">
|
|
14
|
+
<!-- the stem -->
|
|
15
|
+
<path d="M498 300 Q498 280 515 268 L620 190 Q632 186 636 198 L636 375 L525 480 Q510 495 508 512 L508 612 Q508 618 500 618 L498 606 Z" fill="#2b2b2b"/>
|
|
16
|
+
<!-- the lower arm -->
|
|
17
|
+
<path d="M790 410 L998 608 Q1002 614 994 617 L800 617 Q790 617 780 608 L685 515 Z" fill="url(#kreft-o)"/>
|
|
18
|
+
<path d="M685 515 L790 410 L860 478 L770 548 Z" fill="url(#kreft-s)"/>
|
|
19
|
+
<!-- the big diagonal band -->
|
|
20
|
+
<path d="M808 203 Q820 192 838 192 L996 192 Q1008 193 1003 204 L685 515 L592 607 Q584 617 570 617 L512 617 Q508 617 508 610 L508 512 Q510 495 525 480 Z" fill="url(#kreft-o)"/>
|
|
21
|
+
</g>
|
|
22
|
+
</svg>
|
|
@@ -112,7 +112,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
112
112
|
<div class="info-list">
|
|
113
113
|
<div class="info-item">
|
|
114
114
|
<span class="info-label">Framework Engine</span>
|
|
115
|
-
<span class="info-value">Kreft {Kreftjs.version || '0.0.
|
|
115
|
+
<span class="info-value">Kreft {Kreftjs.version || '0.0.16-beta'}</span>
|
|
116
116
|
</div>
|
|
117
117
|
<div class="info-item">
|
|
118
118
|
<span class="info-label">Active Database</span>
|
|
@@ -64,7 +64,7 @@ action copy() {
|
|
|
64
64
|
|
|
65
65
|
<!-- Top bar -->
|
|
66
66
|
<header class="site-bar">
|
|
67
|
-
<kreft-link to="/" class="site-brand"><
|
|
67
|
+
<kreft-link to="/" class="site-brand"><img class="site-mark" src="logo-mark.svg" alt="" width="22" height="22">{env.PUBLIC_APP_NAME || 'Kreft'}</kreft-link>
|
|
68
68
|
<nav class="site-nav">
|
|
69
69
|
<a href={docs + '/docs'} target="_blank" rel="noopener">Documentation</a>
|
|
70
70
|
<kreft-link k-if="$store.auth.user" to="/dashboard">Dashboard</kreft-link>
|
|
@@ -242,7 +242,7 @@ action copy() {
|
|
|
242
242
|
/* Top bar and footer (this page has no layout) */
|
|
243
243
|
.site-bar { position: relative; z-index: 2; display: flex; align-items: center; gap: 14px; height: 64px; }
|
|
244
244
|
.site-brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; letter-spacing: -0.02em; color: var(--foreground); text-decoration: none; }
|
|
245
|
-
.site-mark { width:
|
|
245
|
+
.site-mark { width: 22px; height: 22px; }
|
|
246
246
|
.site-nav { display: flex; align-items: center; gap: 6px; margin-inline-start: auto; }
|
|
247
247
|
.site-nav a { padding: 6px 12px; font-size: 14px; color: var(--muted); text-decoration: none; border-radius: var(--radius); }
|
|
248
248
|
.site-nav a:hover { color: var(--foreground); background: var(--accent); }
|
|
@@ -118,7 +118,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
118
118
|
<div class="hero-badges">
|
|
119
119
|
<span class="badge-exception">{currentTitle}</span>
|
|
120
120
|
<span class="badge-env">Node.js {typeof process !== 'undefined' ? process.version : 'v22.0.0'}</span>
|
|
121
|
-
<span class="badge-env">Kreft v0.0.
|
|
121
|
+
<span class="badge-env">Kreft v0.0.16-beta</span>
|
|
122
122
|
</div>
|
|
123
123
|
<h1 class="hero-error-message">{currentMessage}</h1>
|
|
124
124
|
</div>
|