kreftjs 0.0.6-beta → 0.0.9-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 +5 -31
- package/bin/artisan-more.js +2 -0
- package/bin/artisan.js +51 -49
- package/bin/backend/config.js +2 -2
- package/bin/backend/http.js +5 -5
- package/bin/backend/index.js +2 -2
- package/bin/backend/mcp.js +3 -5
- package/bin/backend/migrator.js +1 -3
- package/bin/backend/query.js +1 -1
- package/bin/backend/queue.js +8 -9
- package/bin/backend/redis.js +1 -1
- package/bin/backend/typescript.js +1 -1
- package/bin/build.js +23 -19
- package/bin/db-api.js +2 -2
- package/bin/db.js +4 -4
- package/bin/deps.js +1 -1
- package/bin/electron.js +3 -5
- package/bin/kreftjs-config.js +1 -6
- package/bin/kreftjs.js +34 -35
- package/bin/layout.js +1 -1
- package/bin/no-auth.js +21 -19
- package/bin/prerender.js +1 -1
- package/bin/ssr.js +3 -3
- package/bin/update.js +10 -10
- package/docs/{Docs.kreftjs → Docs.kreft} +1 -1
- package/docs/README.md +90 -102
- package/editors/vscode/README.md +3 -3
- package/editors/vscode/package.json +3 -4
- package/editors/vscode/snippets/kreftjs.json +2 -2
- package/kreftjs.d.ts +15 -27
- package/kreftjs.js +69 -79
- package/package.json +4 -4
- package/templates/app/README.md +11 -11
- package/templates/app/_env.example +4 -2
- package/templates/app/_vscode/settings.json +3 -2
- package/templates/app/backend/app/Http/Controllers/Admin/DashboardController.js +2 -2
- package/templates/app/backend/app/Http/Controllers/Admin/UserController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/ApiTokenController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/AuthenticatedSessionController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/ConfirmablePasswordController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/EmailVerificationController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/NewPasswordController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/PasswordResetLinkController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/RegisteredUserController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/SessionController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/TwoFactorController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/ProfileController.js +1 -1
- package/templates/app/backend/app/Http/Middleware/RequirePassword.js +1 -1
- package/templates/app/frontend/{App.kreftjs → App.kreft} +1 -1
- package/templates/app/frontend/components/profile/{ApiTokens.kreftjs → ApiTokens.kreft} +1 -1
- package/templates/app/frontend/components/profile/{Sessions.kreftjs → Sessions.kreft} +1 -1
- package/templates/app/frontend/components/profile/{TwoFactor.kreftjs → TwoFactor.kreft} +1 -1
- package/templates/app/frontend/errors/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +6 -4
- package/templates/app/frontend/index.html +8 -8
- package/templates/app/frontend/kreftjs.d.ts +15 -27
- package/templates/app/frontend/kreftjs.js +69 -79
- package/templates/app/frontend/layouts/{app.kreftjs → app.kreft} +7 -1
- package/templates/app/frontend/layouts/{docs.kreftjs → docs.kreft} +1 -1
- package/templates/app/frontend/pages/{Dashboard.kreftjs → Dashboard.kreft} +4 -2
- package/templates/app/frontend/pages/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +2 -2
- package/templates/app/frontend/pages/{Home.kreftjs → Home.kreft} +10 -9
- package/templates/app/frontend/pages/{Profile.kreftjs → Profile.kreft} +3 -3
- package/templates/app/frontend/routes/web.kreft +34 -0
- package/templates/app/frontend/tests/components/{Counter.kreftjs → Counter.kreft} +1 -1
- package/templates/app/frontend/tests/pages/About.kreft +12 -0
- package/templates/app/frontend/tests/pages/{Test.kreftjs → Test.kreft} +1 -1
- package/templates/errors/{401.kreftjs → 401.kreft} +2 -2
- package/templates/errors/{402.kreftjs → 402.kreft} +2 -2
- package/templates/errors/{403.kreftjs → 403.kreft} +2 -2
- package/templates/errors/{404.kreftjs → 404.kreft} +2 -2
- package/templates/errors/{419.kreftjs → 419.kreft} +2 -2
- package/templates/errors/{429.kreftjs → 429.kreft} +2 -2
- package/templates/errors/{500.kreftjs → 500.kreft} +2 -2
- package/templates/errors/{503.kreftjs → 503.kreft} +2 -2
- package/templates/errors/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +17 -14
- package/templates/errors/{error.kreftjs → error.kreft} +2 -2
- package/templates/errors/{minimal.kreftjs → minimal.kreft} +1 -1
- package/tools/dev-client.js +2 -2
- package/tools/vite-plugin-kreftjs.d.ts +3 -5
- package/tools/vite-plugin-kreftjs.js +12 -14
- package/templates/app/frontend/routes/web.kreftjs +0 -34
- package/templates/app/frontend/tests/pages/About.kreftjs +0 -12
- /package/templates/app/frontend/components/{Field.kreftjs → Field.kreft} +0 -0
- /package/templates/app/frontend/components/{StatCard.kreftjs → StatCard.kreft} +0 -0
- /package/templates/app/frontend/layouts/{guest.kreftjs → guest.kreft} +0 -0
- /package/templates/app/frontend/pages/{Users.kreftjs → Users.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{ConfirmPassword.kreftjs → ConfirmPassword.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{ForgotPassword.kreftjs → ForgotPassword.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{Login.kreftjs → Login.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{Register.kreftjs → Register.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{ResetPassword.kreftjs → ResetPassword.kreft} +0 -0
- /package/templates/app/frontend/pages/auth/{VerifyEmail.kreftjs → VerifyEmail.kreft} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
3
|
-
* The .
|
|
2
|
+
* Kreft v0.0.9-beta — reactive by nature
|
|
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.
|
|
6
6
|
* One file, no build step, no virtual DOM. MIT License.
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
};
|
|
30
30
|
const text = () => document.createTextNode('');
|
|
31
31
|
// `kreft dev` turns this on: live components are tracked for hot reload and the DevTools panel
|
|
32
|
-
const devMode = () => !!
|
|
32
|
+
const devMode = () => !!global.__KREFT_DEV__;
|
|
33
33
|
const liveInstances = new Set();
|
|
34
34
|
const BAD_PATH_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
35
35
|
const getPath = (obj, path) => String(path).split('.').reduce((o, k) => (o == null || BAD_PATH_KEYS.has(k) ? undefined : o[k]), obj);
|
|
@@ -651,8 +651,8 @@
|
|
|
651
651
|
return replacePlaceholders(chosen, fullReplace);
|
|
652
652
|
}
|
|
653
653
|
|
|
654
|
-
if (typeof window !== 'undefined' && (window.__KREFT_LANG__
|
|
655
|
-
addTranslations(window.__KREFT_LANG__
|
|
654
|
+
if (typeof window !== 'undefined' && (window.__KREFT_LANG__)) {
|
|
655
|
+
addTranslations(window.__KREFT_LANG__);
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
function formatNumber(n, options, locale = currentLocaleRef.value) {
|
|
@@ -1898,9 +1898,9 @@
|
|
|
1898
1898
|
|
|
1899
1899
|
/* ---------- <kreft-view>: the page for the current route (nested views show child routes) ----------
|
|
1900
1900
|
* Layouts: the page is shown inside a layout component, in its <slot>.
|
|
1901
|
-
* Kreftjs.router({ layout: 'app', routes }) every page uses layouts/app.
|
|
1902
|
-
* { path: '/admin', component: …, layout: 'admin' } this route (and its children) use layouts/admin.
|
|
1903
|
-
* layout admin in a page's .
|
|
1901
|
+
* Kreftjs.router({ layout: 'app', routes }) every page uses layouts/app.kreft
|
|
1902
|
+
* { path: '/admin', component: …, layout: 'admin' } this route (and its children) use layouts/admin.kreft
|
|
1903
|
+
* layout admin in a page's .kreft file: this page uses it
|
|
1904
1904
|
* layout none / layout: false no layout
|
|
1905
1905
|
* Moving between pages with the same layout keeps the layout on the page (its state stays).
|
|
1906
1906
|
* ------------------------------------------------------------------------------------------- */
|
|
@@ -1953,7 +1953,7 @@
|
|
|
1953
1953
|
const p = loadDef(def).then(() => { loaded.value++; }, (e) => {
|
|
1954
1954
|
def.__failed = true;
|
|
1955
1955
|
def.__failedError = e;
|
|
1956
|
-
if (router.__errors) { console.error('[Kreft error] the page could not be loaded:', e); return router.abort(500, e && e.message); } // errors/500.
|
|
1956
|
+
if (router.__errors) { console.error('[Kreft error] the page could not be loaded:', e); return router.abort(500, e && e.message); } // errors/500.kreft
|
|
1957
1957
|
loaded.value++; // the page reports its own error
|
|
1958
1958
|
});
|
|
1959
1959
|
if (first) waitFor(p);
|
|
@@ -2028,7 +2028,7 @@
|
|
|
2028
2028
|
|
|
2029
2029
|
/* ---------- <kreft-wait>: show something else until everything inside has loaded ----------
|
|
2030
2030
|
* <kreft-wait>
|
|
2031
|
-
* <UserList /> (its .
|
|
2031
|
+
* <UserList /> (its .kreft file, `load` data, async `on start`)
|
|
2032
2032
|
* <p k-waiting>Loading…</p>
|
|
2033
2033
|
* <p k-failed="error">Could not load: {error.message}</p>
|
|
2034
2034
|
* </kreft-wait>
|
|
@@ -2234,20 +2234,7 @@
|
|
|
2234
2234
|
if (open.length) throw new SyntaxError('A {for} block is missing its {/for}');
|
|
2235
2235
|
return out;
|
|
2236
2236
|
}
|
|
2237
|
-
|
|
2238
|
-
// It runs on the finished markup, so the browser, `kreft build` and the Vite plugin all see the same names.
|
|
2239
|
-
const LEGACY_TAGS = /^som-(?=(?:wait|view|component|yield|section|portal|link)$)/i;
|
|
2240
|
-
const TAG_SCAN = /<(\/?)([A-Za-z][\w:.-]*)((?:\s+[^\s"'<>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]+))?)*)(\s*\/?>)/g;
|
|
2241
|
-
const ATTR_SCAN = /(\s+)([^\s"'<>\/=]+)(\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
2242
|
-
function legacyMarkup(html) {
|
|
2243
|
-
if (!/s-[a-z]|<\/?som-/i.test(html)) return html;
|
|
2244
|
-
return html.replace(TAG_SCAN, (m, slash, name, attrs, end) => {
|
|
2245
|
-
const tag = LEGACY_TAGS.test(name) ? 'kreft-' + name.slice(4) : name;
|
|
2246
|
-
const out = attrs ? attrs.replace(ATTR_SCAN, (a, sp, an, val) => (/^s-[a-z]/i.test(an) ? sp + 'k-' + an.slice(2) + (val || '') : a)) : attrs;
|
|
2247
|
-
return tag === name && out === attrs ? m : '<' + slash + tag + out + end;
|
|
2248
|
-
});
|
|
2249
|
-
}
|
|
2250
|
-
const prepareTemplate = (src) => legacyMarkup(quoteBraceAttrs(expandBlocks(expandSelfClosing(src))));
|
|
2237
|
+
const prepareTemplate = (src) => quoteBraceAttrs(expandBlocks(expandSelfClosing(src)));
|
|
2251
2238
|
function getTemplate(def) {
|
|
2252
2239
|
if (def.__tpl) return def.__tpl;
|
|
2253
2240
|
let src = def.template;
|
|
@@ -2380,7 +2367,7 @@
|
|
|
2380
2367
|
}
|
|
2381
2368
|
|
|
2382
2369
|
function mountComponent(el, def, parentScope, parentInst, options = {}) {
|
|
2383
|
-
if (typeof def === 'string') def = kreftComponent(def); // 'components/Card.
|
|
2370
|
+
if (typeof def === 'string') def = kreftComponent(def); // 'components/Card.kreft'
|
|
2384
2371
|
if (def.__loader && def.__resolved) def = def.__resolved;
|
|
2385
2372
|
if (isFunction(def)) def = { init: def };
|
|
2386
2373
|
if (def.__loader || (def.templateUrl && !def.__tpl)) {
|
|
@@ -2574,11 +2561,16 @@
|
|
|
2574
2561
|
if (refName && parentInst) setRef(parentInst, refName, inst.exposed ? reactive(inst.exposed) : inst.ctx);
|
|
2575
2562
|
const mountedJob = () => {
|
|
2576
2563
|
inst.isMounted = true;
|
|
2577
|
-
// run inside the component's scope, so watchers and bus listeners made here are removed with it
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2564
|
+
// run inside the component's scope, so watchers and bus listeners made here are removed with it.
|
|
2565
|
+
// The instance is current too, so `on ready { onDestroy(() => …) }` registers its cleanup on this component
|
|
2566
|
+
const prevInstance = currentInstance;
|
|
2567
|
+
currentInstance = inst;
|
|
2568
|
+
try {
|
|
2569
|
+
inst.scope.run(() => {
|
|
2570
|
+
inst.hooks.ready.forEach((h) => safeCall(h, inst.ctx));
|
|
2571
|
+
if (inst.keep) inst.hooks.show.forEach((h) => safeCall(h, inst.ctx)); // a kept one is shown the first time too
|
|
2572
|
+
});
|
|
2573
|
+
} finally { currentInstance = prevInstance; }
|
|
2582
2574
|
};
|
|
2583
2575
|
if (setupDone.length) {
|
|
2584
2576
|
const waitCtx = currentWait, keepCtx = currentKeep;
|
|
@@ -2743,7 +2735,7 @@
|
|
|
2743
2735
|
if (!container) return warn(`Failed to mount app: "${target}" not found.`);
|
|
2744
2736
|
if (rootInst) return warn('App has already been mounted.');
|
|
2745
2737
|
// copy with descriptors so getters stay getters (computed)
|
|
2746
|
-
let def = rootComponent; // a .
|
|
2738
|
+
let def = rootComponent; // a .kreft path like 'App.kreft', or an object
|
|
2747
2739
|
let source = container.innerHTML;
|
|
2748
2740
|
if (container.hasAttribute('data-kreft-ssg')) { // a page made by `kreft build --prerender`: its first view came ready
|
|
2749
2741
|
const t = document.querySelector('template[data-kreft-ssg-source]');
|
|
@@ -2846,14 +2838,13 @@
|
|
|
2846
2838
|
|
|
2847
2839
|
/* ================================================================
|
|
2848
2840
|
* Saved data — kept in localStorage, so it survives a page reload
|
|
2849
|
-
* .
|
|
2841
|
+
* .kreft: saved todos = [] (key: "<Component>.todos")
|
|
2850
2842
|
* saved theme = 'dark' as 'settings.theme'
|
|
2851
2843
|
* JS: const theme = Kreftjs.saved('theme', 'dark') → a signal
|
|
2852
2844
|
* Kreftjs.storage.get / set / remove / clear
|
|
2853
|
-
* Values are stored as JSON under "
|
|
2845
|
+
* Values are stored as JSON under "kreft:<key>". Changes in another tab show up here too.
|
|
2854
2846
|
* ================================================================ */
|
|
2855
|
-
|
|
2856
|
-
const STORAGE_PREFIX = 'som:';
|
|
2847
|
+
const STORAGE_PREFIX = 'kreft:';
|
|
2857
2848
|
const ls = () => { try { return typeof localStorage !== 'undefined' ? localStorage : null; } catch (_) { return null; } };
|
|
2858
2849
|
const storage = {
|
|
2859
2850
|
has(key) { const s = ls(); try { return !!s && s.getItem(STORAGE_PREFIX + key) !== null; } catch (_) { return false; } },
|
|
@@ -3048,7 +3039,7 @@
|
|
|
3048
3039
|
|
|
3049
3040
|
/* ================================================================
|
|
3050
3041
|
* load — data from an async function, with loading and error built in
|
|
3051
|
-
* .
|
|
3042
|
+
* .kreft: load users = api.get('/api/users')
|
|
3052
3043
|
* JS: const users = Kreftjs.resource(() => Kreftjs.api.get('/api/users'))
|
|
3053
3044
|
* → users.data · users.loading · users.error · users.loaded · users.reload()
|
|
3054
3045
|
* It loads again by itself when a value it reads changes: load user = api.get('/api/users/' + id)
|
|
@@ -3158,7 +3149,7 @@
|
|
|
3158
3149
|
}
|
|
3159
3150
|
|
|
3160
3151
|
/* ================================================================
|
|
3161
|
-
* The .
|
|
3152
|
+
* The .kreft language
|
|
3162
3153
|
*
|
|
3163
3154
|
* prop start = 0
|
|
3164
3155
|
* state count = start
|
|
@@ -3174,20 +3165,20 @@
|
|
|
3174
3165
|
*
|
|
3175
3166
|
* <style scoped> button { color: red } </style>
|
|
3176
3167
|
*
|
|
3177
|
-
* Load with app.component('Counter', 'components/Counter.
|
|
3178
|
-
* a route { path: '/', component: 'pages/Home.
|
|
3168
|
+
* Load with app.component('Counter', 'components/Counter.kreft'),
|
|
3169
|
+
* a route { path: '/', component: 'pages/Home.kreft' } or Kreftjs.load(url).
|
|
3179
3170
|
* ================================================================ */
|
|
3180
|
-
// Component files are `.
|
|
3181
|
-
//
|
|
3182
|
-
const EXT = '.
|
|
3183
|
-
const LEGACY_EXTS = ['.
|
|
3184
|
-
const EXT_RE = /\.(?:kreftjs|kreft
|
|
3185
|
-
const COMPONENT_RE = /\.(?:kreftjs|kreft
|
|
3171
|
+
// Component files are `.kreft`. Projects from the 0.0.x betas have `.kreftjs` files:
|
|
3172
|
+
// both are accepted, and a name that is not found with one extension is tried with the other.
|
|
3173
|
+
const EXT = '.kreft';
|
|
3174
|
+
const LEGACY_EXTS = ['.kreftjs'];
|
|
3175
|
+
const EXT_RE = /\.(?:kreftjs|kreft)$/i;
|
|
3176
|
+
const COMPONENT_RE = /\.(?:kreftjs|kreft)(?:[?#].*)?$/i;
|
|
3186
3177
|
const isComponent = (s) => COMPONENT_RE.test(s);
|
|
3187
3178
|
const isKreftUrl = isComponent;
|
|
3188
3179
|
// the same address under the other extensions
|
|
3189
3180
|
const altExts = (url) => {
|
|
3190
|
-
const m = /^(.*?)(\.(?:kreftjs|kreft
|
|
3181
|
+
const m = /^(.*?)(\.(?:kreftjs|kreft))([?#].*)?$/i.exec(url);
|
|
3191
3182
|
return m ? [EXT, ...LEGACY_EXTS].filter((e) => e !== m[2].toLowerCase()).map((e) => m[1] + e + (m[3] || '')) : [];
|
|
3192
3183
|
};
|
|
3193
3184
|
// fetch() the file, or the first of its other-extension names that exists; also tells which address answered
|
|
@@ -3228,7 +3219,7 @@
|
|
|
3228
3219
|
const hashString = (s) => { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };
|
|
3229
3220
|
|
|
3230
3221
|
/* ---------- a small scanner that understands strings, comments and brackets ---------- */
|
|
3231
|
-
// the .
|
|
3222
|
+
// the .kreft script part may hold regular expressions like /["']/g; views never do ({/for} must stay a block)
|
|
3232
3223
|
let scanScript = false;
|
|
3233
3224
|
const REGEX_BEFORE = /(?:^|[(,=:[!&|?{};+\-*%<>~^]|\b(?:return|typeof|instanceof|in|of|new|delete|void|throw|case|do|else|yield|await))\s*$/;
|
|
3234
3225
|
function skipLiteral(src, i) {
|
|
@@ -3634,7 +3625,7 @@
|
|
|
3634
3625
|
}
|
|
3635
3626
|
}
|
|
3636
3627
|
|
|
3637
|
-
/* ---------- the compiler: .
|
|
3628
|
+
/* ---------- the compiler: .kreft source → component definition ---------- */
|
|
3638
3629
|
function parseKreftScript(src, url) {
|
|
3639
3630
|
scanScript = true;
|
|
3640
3631
|
try { return parseKreftScriptInner(src, url); } finally { scanScript = false; }
|
|
@@ -3677,7 +3668,7 @@
|
|
|
3677
3668
|
if (m && (m[1] === 'watch' || m[1] === 'when') && /^\w+\s*\(/.test(src.slice(i))) m = null;
|
|
3678
3669
|
if (m && m[1] === 'interface' && !/^interface\s+[A-Za-z_$][\w$]*/.test(src.slice(i, i + 120))) m = null;
|
|
3679
3670
|
if (m && m[1] === 'type' && !/^type\s+[A-Za-z_$][\w$]*(?:\s*<[^>]*>)?\s*=(?!=)/.test(src.slice(i, i + 160))) m = null;
|
|
3680
|
-
// `layout admin` / `layout 'layouts/admin.
|
|
3671
|
+
// `layout admin` / `layout 'layouts/admin.kreft'` / `layout none`: only like that, so `layout = …` stays code
|
|
3681
3672
|
const lm = m && m[1] === 'layout' && src.slice(i).match(/^layout[ \t]+(?:(['"])([^'"\n]+)\1|([\w./-]+))[ \t]*;?[ \t]*(?=\n|$|\/\/)/);
|
|
3682
3673
|
if (m && m[1] === 'layout' && !lm) m = null;
|
|
3683
3674
|
if (lm) { layout = lm[2] || lm[3]; if (layout === 'none' || layout === 'false') layout = false; i += lm[0].length; continue; }
|
|
@@ -3844,7 +3835,7 @@
|
|
|
3844
3835
|
return { code: out.join('\n'), imports, props, events, layout };
|
|
3845
3836
|
}
|
|
3846
3837
|
|
|
3847
|
-
// a CSS file imported by a .
|
|
3838
|
+
// a CSS file imported by a .kreft file: one <link> for the whole page, before the components' own styles
|
|
3848
3839
|
function addStylesheet(href) {
|
|
3849
3840
|
if (typeof document === 'undefined') return;
|
|
3850
3841
|
const full = new URL(href, document.baseURI).href;
|
|
@@ -3857,14 +3848,14 @@
|
|
|
3857
3848
|
document.head.insertBefore(link, first);
|
|
3858
3849
|
}
|
|
3859
3850
|
|
|
3860
|
-
// load `import` lines once per file; .
|
|
3851
|
+
// load `import` lines once per file; .kreft imports become local components
|
|
3861
3852
|
async function resolveImports(list, url) {
|
|
3862
3853
|
const values = {}, components = {};
|
|
3863
3854
|
for (const stmt of list) {
|
|
3864
3855
|
const m = stmt.match(/^import\s+(?:([\s\S]+?)\s+from\s+)?(['"])(.+?)\2/);
|
|
3865
3856
|
if (!m) { warn(`Can't read import: ${stmt}`); continue; }
|
|
3866
3857
|
const [, what, , spec] = m;
|
|
3867
|
-
if (/^(?:kreftjs|kreft
|
|
3858
|
+
if (/^(?:kreftjs|kreft)(\.js)?$/.test(spec)) continue; // Kreft's own functions are always available
|
|
3868
3859
|
const abs = /^\.{0,2}\//.test(spec) ? new URL(spec, url).href : spec;
|
|
3869
3860
|
if (isKreftUrl(spec)) {
|
|
3870
3861
|
if (what && IDENT.test(what.trim())) components[what.trim()] = kreftComponent(abs);
|
|
@@ -4072,15 +4063,15 @@
|
|
|
4072
4063
|
return st;
|
|
4073
4064
|
}
|
|
4074
4065
|
|
|
4075
|
-
// Pure text work, shared by the browser and `kreft build`: .
|
|
4076
|
-
function splitKreft(source, url = 'inline.
|
|
4066
|
+
// Pure text work, shared by the browser and `kreft build`: .kreft source → its parts
|
|
4067
|
+
function splitKreft(source, url = 'inline.kreft') {
|
|
4077
4068
|
const name = (url.split('/').pop() || '').replace(/[?#].*$/, '').replace(EXT_RE, '');
|
|
4078
4069
|
source = source.replace(/\r\n?/g, '\n');
|
|
4079
4070
|
// Safe linear extraction of <view> ... </view> to prevent ReDoS catastrophic backtracking
|
|
4080
4071
|
const viewOpenIdx = source.search(/<view(\s[^>]*)?>/i);
|
|
4081
4072
|
const viewCloseIdx = source.toLowerCase().lastIndexOf('</view>');
|
|
4082
4073
|
if (viewOpenIdx === -1 || viewCloseIdx === -1 || viewCloseIdx <= viewOpenIdx) {
|
|
4083
|
-
throw new SyntaxError(`${name}.
|
|
4074
|
+
throw new SyntaxError(`${name}.kreft has no <view> … </view>`);
|
|
4084
4075
|
}
|
|
4085
4076
|
const viewOpenTagMatch = source.slice(viewOpenIdx).match(/^<view(\s[^>]*)?>/i);
|
|
4086
4077
|
const viewContentStart = viewOpenIdx + viewOpenTagMatch[0].length;
|
|
@@ -4120,12 +4111,12 @@
|
|
|
4120
4111
|
return def;
|
|
4121
4112
|
}
|
|
4122
4113
|
|
|
4123
|
-
async function compileKreft(source, url = 'inline.
|
|
4114
|
+
async function compileKreft(source, url = 'inline.kreft') {
|
|
4124
4115
|
const sp = splitKreft(source, url);
|
|
4125
4116
|
const { values, components } = await resolveImports(sp.imports, url);
|
|
4126
4117
|
let run;
|
|
4127
4118
|
try { run = new Function('$scope', '$h', `with ($scope) {\n${sp.code}\n}`); }
|
|
4128
|
-
catch (e) { throw new SyntaxError(`${sp.name}.
|
|
4119
|
+
catch (e) { throw new SyntaxError(`${sp.name}.kreft: ${e.message}`); }
|
|
4129
4120
|
|
|
4130
4121
|
const props = {};
|
|
4131
4122
|
for (const p in sp.props) {
|
|
@@ -4270,20 +4261,20 @@
|
|
|
4270
4261
|
|
|
4271
4262
|
// mode 'history' (default): clean URLs like /users/5 — the server must send index.html for every path.
|
|
4272
4263
|
// mode 'hash': URLs like #/users/5 — works with any server, even file://.
|
|
4273
|
-
// Error pages: errors/404.
|
|
4264
|
+
// Error pages: errors/404.kreft, errors/403.kreft, errors/500.kreft …
|
|
4274
4265
|
// (Kreftjs.router({ errors: 'errors' }) turns them on; `kreft make:errors` writes them into a project)
|
|
4275
4266
|
const ERROR_PAGES = [401, 402, 403, 404, 419, 429, 500, 503];
|
|
4276
4267
|
const ERROR_TITLES = { 400: 'Bad Request', 401: 'Unauthorized', 402: 'Payment Required', 403: 'Forbidden', 404: 'Not Found', 405: 'Method Not Allowed', 409: 'Conflict', 410: 'Gone', 419: 'Page Expired', 422: 'Unprocessable Content', 429: 'Too Many Requests', 500: 'Server Error', 502: 'Bad Gateway', 503: 'Service Unavailable', 504: 'Gateway Timeout' };
|
|
4277
4268
|
let activeRouter = null;
|
|
4278
4269
|
|
|
4279
|
-
/* ---------- route files: routes/web.
|
|
4280
|
-
* Route.view('/', 'pages/Home.
|
|
4281
|
-
* Route.view('/users/:id', 'pages/User.
|
|
4282
|
-
* Route.middleware('auth').group(() => { Route.view('/dashboard', 'pages/Dashboard.
|
|
4283
|
-
* Route.layout('guest').middleware('guest').group(() => { Route.view('/login', 'pages/auth/Login.
|
|
4270
|
+
/* ---------- route files: routes/web.kreft ----------
|
|
4271
|
+
* Route.view('/', 'pages/Home.kreft').name('home').title('Home')
|
|
4272
|
+
* Route.view('/users/:id', 'pages/User.kreft') // :id reaches the page as a prop
|
|
4273
|
+
* Route.middleware('auth').group(() => { Route.view('/dashboard', 'pages/Dashboard.kreft') })
|
|
4274
|
+
* Route.layout('guest').middleware('guest').group(() => { Route.view('/login', 'pages/auth/Login.kreft') })
|
|
4284
4275
|
* Route.prefix('/admin').name('admin.').group(() => { … })
|
|
4285
4276
|
* Route.redirect('/home', '/')
|
|
4286
|
-
* Route.view('/settings', 'pages/Settings.
|
|
4277
|
+
* Route.view('/settings', 'pages/Settings.kreft').children(() => { Route.view('profile', 'pages/settings/Profile.kreft') })
|
|
4287
4278
|
*/
|
|
4288
4279
|
const routeFiles = new Map(); // absolute URL → function (Route) { … } (kreft build puts them in app.js)
|
|
4289
4280
|
function defineRoutes(path, fn) { routeFiles.set(new URL(path, document.baseURI).href, fn); }
|
|
@@ -4397,7 +4388,7 @@
|
|
|
4397
4388
|
}
|
|
4398
4389
|
|
|
4399
4390
|
function createRouter({ routes = [], mode = 'history', base, scrollToTop = true, layout = null, layouts = null, errors = null, middleware = {} } = {}) {
|
|
4400
|
-
// routes: 'routes/web.
|
|
4391
|
+
// routes: 'routes/web.kreft', or ['routes/web.kreft', 'routes/admin.kreft'], or the route objects themselves
|
|
4401
4392
|
const files = [].concat(routes).filter((r) => typeof r === 'string');
|
|
4402
4393
|
const inline = [].concat(routes).filter((r) => r && typeof r === 'object');
|
|
4403
4394
|
const middlewares = { ...middleware };
|
|
@@ -4539,7 +4530,7 @@
|
|
|
4539
4530
|
if (!fromBrowser) setURL(target.fullPath, replace);
|
|
4540
4531
|
Object.assign(route, target, { error: null });
|
|
4541
4532
|
const rec = target.matched;
|
|
4542
|
-
if (!rec && errorsDir) { // no route for this address: errors/404.
|
|
4533
|
+
if (!rec && errorsDir) { // no route for this address: errors/404.kreft
|
|
4543
4534
|
showError(404, '');
|
|
4544
4535
|
afterHooks.forEach((h) => { try { h(route, from); } catch (e) { console.error(e); } });
|
|
4545
4536
|
return readyResolve();
|
|
@@ -4563,10 +4554,10 @@
|
|
|
4563
4554
|
readyResolve();
|
|
4564
4555
|
}
|
|
4565
4556
|
|
|
4566
|
-
// shows errors/<status>.
|
|
4557
|
+
// shows errors/<status>.kreft in place of the page; the address stays as it is
|
|
4567
4558
|
function showError(status, message) {
|
|
4568
4559
|
status = Number(status) || 500;
|
|
4569
|
-
const file = ERROR_PAGES.includes(status) ? status : 'error'; // errors/error.
|
|
4560
|
+
const file = ERROR_PAGES.includes(status) ? status : 'error'; // errors/error.kreft for any other status
|
|
4570
4561
|
const component = kreftComponent(`${errorsDir}/${file}${EXT}`);
|
|
4571
4562
|
route.error = { status, message: message || '' };
|
|
4572
4563
|
levels.value = [{ component, isError: true, props: { status, message: message || '', title: ERROR_TITLES[status] || 'Error' } }];
|
|
@@ -4635,7 +4626,7 @@
|
|
|
4635
4626
|
};
|
|
4636
4627
|
return router;
|
|
4637
4628
|
}
|
|
4638
|
-
// abort(404) in any .
|
|
4629
|
+
// abort(404) in any .kreft file or in JavaScript
|
|
4639
4630
|
const abortPage = (status, message) => { if (activeRouter) activeRouter.abort(status, message); else warn('abort() needs a router.'); };
|
|
4640
4631
|
const currentRouter = () => receive(ROUTER_KEY, null);
|
|
4641
4632
|
const currentRoute = () => { const r = receive(ROUTER_KEY, null); return r && r.route; };
|
|
@@ -4959,7 +4950,7 @@
|
|
|
4959
4950
|
Object.keys(kept).forEach((k) => { if (hasOwn(raw, k) && keepable(raw[k])) s[k] = kept[k]; });
|
|
4960
4951
|
});
|
|
4961
4952
|
}
|
|
4962
|
-
// a .
|
|
4953
|
+
// a .kreft file changed: compile it again and swap every live copy (false = reload the page instead)
|
|
4963
4954
|
async function hotUpdate(url, source) {
|
|
4964
4955
|
const abs = new URL(url, document.baseURI).href;
|
|
4965
4956
|
const entry = kreftCache.get(abs);
|
|
@@ -5032,29 +5023,29 @@
|
|
|
5032
5023
|
stores, storeLog, busLog,
|
|
5033
5024
|
};
|
|
5034
5025
|
|
|
5035
|
-
const VERSION = '0.0.
|
|
5026
|
+
const VERSION = '0.0.9-beta';
|
|
5036
5027
|
const Kreftjs = {
|
|
5037
5028
|
version: VERSION,
|
|
5038
5029
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
|
5039
|
-
get env() { return Object.freeze({ ...((typeof window !== 'undefined' &&
|
|
5030
|
+
get env() { return Object.freeze({ ...((typeof window !== 'undefined' && window.__KREFT_ENV__) || {}) }); },
|
|
5040
5031
|
get isVite() {
|
|
5041
|
-
return Boolean(typeof window !== 'undefined' &&
|
|
5032
|
+
return Boolean(typeof window !== 'undefined' && window.__KREFT_VITE__);
|
|
5042
5033
|
},
|
|
5043
5034
|
get isElectron() {
|
|
5044
5035
|
return Boolean(
|
|
5045
5036
|
typeof window !== 'undefined' && (
|
|
5046
|
-
window.kreftDesktop ||
|
|
5037
|
+
window.kreftDesktop ||
|
|
5047
5038
|
(window.process && window.process.type === 'renderer') ||
|
|
5048
5039
|
(typeof navigator !== 'undefined' && /electron/i.test(navigator.userAgent))
|
|
5049
5040
|
)
|
|
5050
5041
|
);
|
|
5051
5042
|
},
|
|
5052
5043
|
get desktop() {
|
|
5053
|
-
return (typeof window !== 'undefined' &&
|
|
5044
|
+
return (typeof window !== 'undefined' && window.kreftDesktop) || null;
|
|
5054
5045
|
},
|
|
5055
5046
|
abort: abortPage,
|
|
5056
5047
|
// apps & components
|
|
5057
|
-
app: createApp, lazy, load, compile: compileKreft,
|
|
5048
|
+
app: createApp, lazy, load, compile: compileKreft, render,
|
|
5058
5049
|
// used by `kreft build`, Vite plugin and the app.js it writes
|
|
5059
5050
|
__makeDef: makeKreftDef,
|
|
5060
5051
|
__registerDef: registerDef,
|
|
@@ -5063,7 +5054,7 @@
|
|
|
5063
5054
|
__routes: defineRoutes,
|
|
5064
5055
|
__fileHeaders: (url) => fileHeaders(new URL(url, document.baseURI).href),
|
|
5065
5056
|
__npmBase: '/__kreft/npm/', // where kreft dev serves files from node_modules (CSS imports)
|
|
5066
|
-
__import: (url) => import(url), // how built apps load the .js modules a .
|
|
5057
|
+
__import: (url) => import(url), // how built apps load the .js modules a .kreft file imports
|
|
5067
5058
|
__precompiled: precompiled,
|
|
5068
5059
|
__hot: hotUpdate,
|
|
5069
5060
|
__devtools: devtools,
|
|
@@ -5098,11 +5089,10 @@
|
|
|
5098
5089
|
|
|
5099
5090
|
// the text-only helpers the build tool reuses, so built code matches the browser exactly
|
|
5100
5091
|
Object.defineProperty(Kreftjs, '__internal', {
|
|
5101
|
-
value: { expandBlocks, prepareTemplate,
|
|
5092
|
+
value: { expandBlocks, prepareTemplate, splitKreft, splitInterp, exactBrace, stripBrace, interpToExpr, quoteBraceAttrs, expandSelfClosing, scopeCss, hashString, propType, simplePathRE, fnExpRE, forAliasRE, makeKreftDef, compileFn, evaluate, stripTypeScript, stripTsParams },
|
|
5102
5093
|
});
|
|
5103
5094
|
|
|
5104
5095
|
if (typeof module !== 'undefined' && module.exports) module.exports = Kreftjs;
|
|
5105
5096
|
global.Kreftjs = Kreftjs;
|
|
5106
5097
|
global.Kreft = Kreftjs; // the shorter name, kept as an alias
|
|
5107
|
-
global.Som = Kreftjs; // Som.js name, kept so older code keeps working (deprecated: use Kreftjs)
|
|
5108
5098
|
})(typeof window !== 'undefined' ? window : globalThis);
|
|
@@ -11,6 +11,7 @@ state remainingMinutes = 5
|
|
|
11
11
|
state inactivityTimer = null
|
|
12
12
|
|
|
13
13
|
// SVG vector icon paths (24x24)
|
|
14
|
+
state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$/, '') // where "Documentation" links go: PUBLIC_DOCS_URL in .env
|
|
14
15
|
state icons = {
|
|
15
16
|
dashboard: 'M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z',
|
|
16
17
|
users: 'M16 19v-1a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v1M9.5 10a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7M21 19v-1a4 4 0 0 0-3-3.87M15.5 3.13a3.5 3.5 0 0 1 0 6.75',
|
|
@@ -33,7 +34,7 @@ state navGroups = [
|
|
|
33
34
|
{ label: 'Platform', links: [
|
|
34
35
|
{ to: 'welcome', label: 'Showcase', icon: 'showcase' },
|
|
35
36
|
{ to: 'error-monitor', label: 'Error Monitor', icon: 'panel' },
|
|
36
|
-
{
|
|
37
|
+
{ docs: '/docs', label: 'Documentation', icon: 'docs' },
|
|
37
38
|
{ to: 'tests.index', label: 'Test Suite', icon: 'tests' },
|
|
38
39
|
] },
|
|
39
40
|
]
|
|
@@ -130,7 +131,12 @@ action extendSession() {
|
|
|
130
131
|
<ul class="nav-list">
|
|
131
132
|
{for link in group.links}
|
|
132
133
|
<li>
|
|
134
|
+
<a k-if="link.docs" href={docs + link.docs} target="_blank" rel="noopener" title={collapsed ? link.label : null} class="nav-item">
|
|
135
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" class="nav-icon"><path d={icons[link.icon] || icons.panel}></path></svg>
|
|
136
|
+
<span class="nav-label">{link.label}</span>
|
|
137
|
+
</a>
|
|
133
138
|
<kreft-link
|
|
139
|
+
k-else
|
|
134
140
|
to={link.to}
|
|
135
141
|
exact-class={link.exact ? 'active-link' : 'kreft-link-exact'}
|
|
136
142
|
active-class={link.exact ? 'kreft-link-active' : 'active-link'}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- The layout of the documentation page (/docs): a slim top bar and the page, without the dashboard sidebar.
|
|
2
|
-
The route asks for it with .layout('docs') in routes/web.
|
|
2
|
+
The route asks for it with .layout('docs') in routes/web.kreft. The documentation viewer (docs/Docs.kreft)
|
|
3
3
|
assumes a bar this tall (60px) above it. -->
|
|
4
4
|
<view>
|
|
5
5
|
<header>
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
load stats = api.get('/api/admin/stats')
|
|
6
6
|
load board = api.get('/api/dashboard')
|
|
7
7
|
|
|
8
|
+
state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$/, '') // where "Documentation" links go: PUBLIC_DOCS_URL in .env
|
|
9
|
+
|
|
8
10
|
<view>
|
|
9
11
|
<div class="dashboard-page">
|
|
10
12
|
<div class="dashboard-header">
|
|
@@ -110,7 +112,7 @@ load board = api.get('/api/dashboard')
|
|
|
110
112
|
<div class="info-list">
|
|
111
113
|
<div class="info-item">
|
|
112
114
|
<span class="info-label">Framework Engine</span>
|
|
113
|
-
<span class="info-value">Kreft {Kreftjs.version || '0.0.
|
|
115
|
+
<span class="info-value">Kreft {Kreftjs.version || '0.0.9-beta'}</span>
|
|
114
116
|
</div>
|
|
115
117
|
<div class="info-item">
|
|
116
118
|
<span class="info-label">Active Database</span>
|
|
@@ -128,7 +130,7 @@ load board = api.get('/api/dashboard')
|
|
|
128
130
|
|
|
129
131
|
<div class="quick-nav-group">
|
|
130
132
|
<kreft-link to="/profile" class="btn secondary sm w-full">Edit Profile Settings</kreft-link>
|
|
131
|
-
<
|
|
133
|
+
<a href={docs + '/docs'} class="btn ghost sm w-full" target="_blank" rel="noopener">API Documentation</a>
|
|
132
134
|
<kreft-link to="/welcome" class="btn ghost sm w-full">Landing Page Showcase</kreft-link>
|
|
133
135
|
</div>
|
|
134
136
|
</section>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
ErrorMonitor Page — Interactive Kreft Diagnostic Inspector Showcase
|
|
3
|
-
Uses Kreft's own minimalist geometric UI and authentic JavaScript/.
|
|
3
|
+
Uses Kreft's own minimalist geometric UI and authentic JavaScript/.kreft stack traces.
|
|
4
4
|
-->
|
|
5
|
-
import ErrorMonitor from '../errors/ErrorMonitor.
|
|
5
|
+
import ErrorMonitor from '../errors/ErrorMonitor.kreft'
|
|
6
6
|
|
|
7
7
|
state scenario = 'method'
|
|
8
8
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<!-- The welcome page: what Kreft is, shown with a component that runs right here.
|
|
2
|
-
routes/web.
|
|
2
|
+
routes/web.kreft gives it no layout, so the bar and the footer are part of this page. -->
|
|
3
3
|
|
|
4
4
|
state name = 'Enterprise User'
|
|
5
5
|
state count = 0
|
|
6
6
|
state copied = false
|
|
7
7
|
derive double = count * 2
|
|
8
8
|
|
|
9
|
+
state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$/, '') // where "Documentation" links go: PUBLIC_DOCS_URL in .env
|
|
9
10
|
state words = [
|
|
10
11
|
{ word: 'state', says: 'a value that can change', to: '/docs#components-and-the-kreftjs-file' },
|
|
11
12
|
{ word: 'saved', says: 'a value kept after a reload', to: '/docs#saving-data-in-the-browser' },
|
|
@@ -49,7 +50,7 @@ action copy() {
|
|
|
49
50
|
<header class="site-bar">
|
|
50
51
|
<kreft-link to="/" class="site-brand"><span class="site-mark" aria-hidden="true"></span>{env.PUBLIC_APP_NAME || 'Kreft'}</kreft-link>
|
|
51
52
|
<nav class="site-nav">
|
|
52
|
-
<
|
|
53
|
+
<a href={docs + '/docs'} target="_blank" rel="noopener">Documentation</a>
|
|
53
54
|
<kreft-link k-if="$store.auth.user" to="/dashboard">Dashboard</kreft-link>
|
|
54
55
|
<kreft-link k-if="!$store.auth.user" to="/login">Log in</kreft-link>
|
|
55
56
|
<kreft-link k-if="!$store.auth.user" to="/register" class="site-cta">Sign up</kreft-link>
|
|
@@ -77,10 +78,10 @@ action copy() {
|
|
|
77
78
|
|
|
78
79
|
<!-- CTA Buttons -->
|
|
79
80
|
<div class="cta-actions">
|
|
80
|
-
<
|
|
81
|
+
<a href={docs + '/docs'} class="pill-btn primary" target="_blank" rel="noopener">Read the docs</a>
|
|
81
82
|
<kreft-link k-if="$store.auth.user" to="/dashboard" class="pill-btn ghost">Open dashboard</kreft-link>
|
|
82
83
|
<kreft-link k-if="!$store.auth.user" to="/register" class="pill-btn ghost">Sign up</kreft-link>
|
|
83
|
-
<
|
|
84
|
+
<a href={docs + '/docs#your-first-app'} class="pill-btn ghost" target="_blank" rel="noopener">Quick start</a>
|
|
84
85
|
</div>
|
|
85
86
|
|
|
86
87
|
<!-- Badges Row -->
|
|
@@ -102,7 +103,7 @@ action copy() {
|
|
|
102
103
|
<span class="mac-dot yellow"></span>
|
|
103
104
|
<span class="mac-dot green"></span>
|
|
104
105
|
</div>
|
|
105
|
-
<span class="tab-title">Hello.ts.
|
|
106
|
+
<span class="tab-title">Hello.ts.kreft</span>
|
|
106
107
|
<div class="terminal-bar-end"></div>
|
|
107
108
|
</div>
|
|
108
109
|
|
|
@@ -177,7 +178,7 @@ action copy() {
|
|
|
177
178
|
<h2>The whole language fits on one screen</h2>
|
|
178
179
|
<dl>
|
|
179
180
|
{for w in words key w.word}
|
|
180
|
-
<div><dt><
|
|
181
|
+
<div><dt><a href={docs + w.to} target="_blank" rel="noopener">{w.word}</a></dt><dd>{w.says}</dd></div>
|
|
181
182
|
{/for}
|
|
182
183
|
</dl>
|
|
183
184
|
</section>
|
|
@@ -186,7 +187,7 @@ action copy() {
|
|
|
186
187
|
<h2>Also in the box</h2>
|
|
187
188
|
<ul>
|
|
188
189
|
{for p in parts key p.title}
|
|
189
|
-
<li><
|
|
190
|
+
<li><a href={docs + p.to} target="_blank" rel="noopener"><strong>{p.title}</strong><span>{p.text}</span></a></li>
|
|
190
191
|
{/for}
|
|
191
192
|
</ul>
|
|
192
193
|
</section>
|
|
@@ -197,12 +198,12 @@ action copy() {
|
|
|
197
198
|
<code>kreft new my-app --db sqlite</code>
|
|
198
199
|
<button class="sm" @click={copy} aria-label="Copy the command">{copied ? 'Copied' : 'Copy'}</button>
|
|
199
200
|
</div>
|
|
200
|
-
<p>Then <code>cd my-app</code> and <code>npm run dev</code>. Coming from Vue? The <
|
|
201
|
+
<p>Then <code>cd my-app</code> and <code>npm run dev</code>. Coming from Vue? The <a href={docs + '/docs'} target="_blank" rel="noopener">docs</a> have a table with the Kreft name for every Vue feature.</p>
|
|
201
202
|
</section>
|
|
202
203
|
|
|
203
204
|
<footer class="site-foot">
|
|
204
205
|
<span>Kreft {Kreftjs.version}</span>
|
|
205
|
-
<
|
|
206
|
+
<a href={docs + '/docs'} target="_blank" rel="noopener">Docs</a>
|
|
206
207
|
<kreft-link to="/error-monitor">Error monitor</kreft-link>
|
|
207
208
|
</footer>
|
|
208
209
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<!-- /profile: name, email, password, two-factor, devices, API tokens, or delete the account
|
|
2
2
|
(app/Http/Controllers/ProfileController.js and Auth/…) -->
|
|
3
|
-
import TwoFactor from '../components/profile/TwoFactor.
|
|
4
|
-
import Sessions from '../components/profile/Sessions.
|
|
5
|
-
import ApiTokens from '../components/profile/ApiTokens.
|
|
3
|
+
import TwoFactor from '../components/profile/TwoFactor.kreft'
|
|
4
|
+
import Sessions from '../components/profile/Sessions.kreft'
|
|
5
|
+
import ApiTokens from '../components/profile/ApiTokens.kreft'
|
|
6
6
|
state info = form(
|
|
7
7
|
{ name: $store.auth.user ? $store.auth.user.name : '', email: $store.auth.user ? $store.auth.user.email : '' },
|
|
8
8
|
{ name: 'required|max:255', email: 'required|email|max:255' },
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Application Web Routes.
|
|
2
|
+
// Developers can attach custom auth guards directly: .middleware('auth', 'admin') or custom guards.
|
|
3
|
+
|
|
4
|
+
// Public Welcome & Showcase Page (shows first with links to Sign Up, Log In, Docs)
|
|
5
|
+
Route.view('/', 'pages/Home.kreft').layout('none').name('home').title('Welcome')
|
|
6
|
+
Route.view('/welcome', 'pages/Home.kreft').layout('none').name('welcome').title('Welcome')
|
|
7
|
+
|
|
8
|
+
// Protected Dashboard & management pages (requires signed-in user)
|
|
9
|
+
Route.middleware('auth').group(() => {
|
|
10
|
+
Route.view('/dashboard', 'pages/Dashboard.kreft').name('dashboard').title('Dashboard')
|
|
11
|
+
Route.view('/users', 'pages/Users.kreft').name('users').title('Users')
|
|
12
|
+
Route.view('/profile', 'pages/Profile.kreft').name('profile').title('Profile')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// Authentication routes (pages/auth/), wrapped in guest layout
|
|
16
|
+
Route.layout('guest').group(() => {
|
|
17
|
+
Route.middleware('guest').group(() => {
|
|
18
|
+
Route.view('/login', 'pages/auth/Login.kreft').name('login').title('Log In')
|
|
19
|
+
Route.view('/register', 'pages/auth/Register.kreft').name('register').title('Register')
|
|
20
|
+
Route.view('/forgot-password', 'pages/auth/ForgotPassword.kreft').name('password.request').title('Forgot Password')
|
|
21
|
+
})
|
|
22
|
+
Route.view('/reset-password/:token', 'pages/auth/ResetPassword.kreft').name('password.reset').title('Reset Password')
|
|
23
|
+
Route.view('/verify-email/:id?/:hash?', 'pages/auth/VerifyEmail.kreft').name('verification.notice').title('Verify Email')
|
|
24
|
+
Route.view('/confirm-password', 'pages/auth/ConfirmPassword.kreft').name('password.confirm').title('Confirm Password').middleware('auth')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// Documentation (docs/) and test suite (tests/)
|
|
28
|
+
Route.view('/docs', 'docs/Docs.kreft').name('docs').title('Documentation').layout('docs') // its own slim bar, not the dashboard sidebar
|
|
29
|
+
Route.view('/error-monitor', 'pages/ErrorMonitor.kreft').name('error-monitor').title('Error Monitor')
|
|
30
|
+
Route.prefix('/tests').name('tests.').group(() => {
|
|
31
|
+
Route.view('/', 'tests/pages/Test.kreft').name('index').title('Test Suite')
|
|
32
|
+
Route.view('/about', 'tests/pages/About.kreft').name('about').title('About · Tests')
|
|
33
|
+
})
|
|
34
|
+
|