kreftjs 0.0.23-beta.0 → 0.0.23-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/home-variants.js +278 -0
- package/bin/kreftjs.js +3 -0
- package/bin/mobile.js +1 -0
- package/docs/README.md +13 -0
- package/kreftjs.js +2 -2
- package/package.json +2 -2
- package/templates/app/frontend/kreftjs.js +2 -2
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Home pages made for apps, not for the web:
|
|
3
|
+
*
|
|
4
|
+
* kreft new my-app --mobile the home page is a phone screen: top bar, cards, big touch targets, bottom tab bar
|
|
5
|
+
* kreft new my-app --electron the home page is a desktop workspace: sidebar, toolbar, cards, shortcuts
|
|
6
|
+
* kreft make:home --mobile | --desktop (re)write them in an existing project (replaces pages/Home.kreft)
|
|
7
|
+
*
|
|
8
|
+
* Both together: pages/Home.kreft shows the desktop one inside the Electron window and the phone one everywhere else.
|
|
9
|
+
* Add ?platform=mobile or ?platform=desktop to the address to preview either in a normal browser.
|
|
10
|
+
*
|
|
11
|
+
* The generated files are plain .kreft files in the project: change them freely.
|
|
12
|
+
*/
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
// what the project has: no-auth projects have no dashboard, users or profile pages
|
|
17
|
+
function features(front) {
|
|
18
|
+
const has = (f) => fs.existsSync(path.join(front, f));
|
|
19
|
+
return { dashboard: has('pages/Dashboard.kreft'), users: has('pages/Users.kreft'), profile: has('pages/Profile.kreft'), docs: has('docs/Docs.kreft'), auth: has('pages/auth') };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const js = (v) => JSON.stringify(v).replace(/</g, '\\u003c');
|
|
23
|
+
|
|
24
|
+
function mobileSource(f) {
|
|
25
|
+
const tiles = [
|
|
26
|
+
f.dashboard && { icon: '▦', label: 'Dashboard', to: '/dashboard' },
|
|
27
|
+
f.users && { icon: '☺', label: 'Users', to: '/users' },
|
|
28
|
+
f.profile && { icon: '⚙', label: 'Profile', to: '/profile' },
|
|
29
|
+
f.docs && { icon: '☰', label: 'Docs', to: '/docs' },
|
|
30
|
+
{ icon: '!', label: 'Errors', to: '/error-monitor' },
|
|
31
|
+
].filter(Boolean);
|
|
32
|
+
const tabs = [{ icon: '⌂', label: 'Home', to: '/' }, ...tiles.filter((t) => t.to !== '/error-monitor').slice(0, 3)];
|
|
33
|
+
return `<!-- The home page of the phone app: a top bar, cards and a bottom tab bar, all sized for a thumb.
|
|
34
|
+
@tap, @swipeleft and @longpress are Kreft's touch events. Add ?platform=mobile in a browser to preview it. -->
|
|
35
|
+
|
|
36
|
+
state app = Kreftjs.env.PUBLIC_APP_NAME || 'My app'
|
|
37
|
+
state tiles = ${js(tiles)}
|
|
38
|
+
state tabs = ${js(tabs)}
|
|
39
|
+
state taps = 0
|
|
40
|
+
state note = 'Tap the card. Swipe left to reset. Hold to double.'
|
|
41
|
+
|
|
42
|
+
action hit() { taps++; note = 'Tapped ' + taps + (taps === 1 ? ' time' : ' times') }
|
|
43
|
+
action reset() { taps = 0; note = 'Reset by swipe' }
|
|
44
|
+
action boost() { taps = taps * 2; note = 'Doubled by long press' }
|
|
45
|
+
|
|
46
|
+
<view>
|
|
47
|
+
<div class="phone">
|
|
48
|
+
<header class="bar">
|
|
49
|
+
<img src="logo-mark.svg" alt="" width="28" height="28">
|
|
50
|
+
<h1>{app}</h1>
|
|
51
|
+
</header>
|
|
52
|
+
|
|
53
|
+
<main>
|
|
54
|
+
<section class="hello">
|
|
55
|
+
<p class="small">Welcome back</p>
|
|
56
|
+
<h2>What do you want to do?</h2>
|
|
57
|
+
</section>
|
|
58
|
+
|
|
59
|
+
<section class="grid" aria-label="Shortcuts">
|
|
60
|
+
<kreft-link k-for="t in tiles" to={t.to} class="tile">
|
|
61
|
+
<span class="ico" aria-hidden="true">{t.icon}</span>
|
|
62
|
+
<span class="lbl">{t.label}</span>
|
|
63
|
+
</kreft-link>
|
|
64
|
+
</section>
|
|
65
|
+
|
|
66
|
+
<section class="card try" @tap={hit} @swipeleft={reset} @longpress={boost}>
|
|
67
|
+
<p class="small">Touch events</p>
|
|
68
|
+
<p class="count">{taps}</p>
|
|
69
|
+
<p class="note">{note}</p>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<section class="card">
|
|
73
|
+
<p class="small">This app</p>
|
|
74
|
+
<p>One Kreft codebase: the website, the phone app and the desktop app.</p>
|
|
75
|
+
</section>
|
|
76
|
+
</main>
|
|
77
|
+
|
|
78
|
+
<nav class="tabs" aria-label="Main">
|
|
79
|
+
<kreft-link k-for="t in tabs" to={t.to} class="tab" active-class="on" exact-active-class="on">
|
|
80
|
+
<span class="ico" aria-hidden="true">{t.icon}</span>
|
|
81
|
+
<span class="lbl">{t.label}</span>
|
|
82
|
+
</kreft-link>
|
|
83
|
+
</nav>
|
|
84
|
+
</div>
|
|
85
|
+
</view>
|
|
86
|
+
|
|
87
|
+
<style scoped>
|
|
88
|
+
.phone { min-height: 100vh; display: flex; flex-direction: column; background: var(--accent); }
|
|
89
|
+
.bar { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 10px; padding: 14px 16px; background: var(--background); border-bottom: 1px solid var(--border); }
|
|
90
|
+
.bar h1 { margin: 0; font-size: 18px; font-weight: 700; letter-spacing: -0.02em; }
|
|
91
|
+
main { flex: 1; padding: 16px 16px 96px; display: flex; flex-direction: column; gap: 16px; }
|
|
92
|
+
.small { margin: 0 0 4px; font-size: 13px; color: var(--muted); }
|
|
93
|
+
.hello h2 { margin: 0; font-size: 26px; line-height: 1.2; letter-spacing: -0.03em; }
|
|
94
|
+
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
|
|
95
|
+
.tile { display: flex; flex-direction: column; justify-content: space-between; gap: 18px; min-height: 104px; padding: 16px; background: var(--card); border: 1px solid var(--card-border); border-radius: 16px; color: var(--foreground); text-decoration: none; }
|
|
96
|
+
.tile:active { background: var(--accent-strong); }
|
|
97
|
+
.tile .ico { font-size: 26px; line-height: 1; }
|
|
98
|
+
.tile .lbl { font-weight: 600; font-size: 16px; }
|
|
99
|
+
.card { padding: 18px; background: var(--card); border: 1px solid var(--card-border); border-radius: 16px; }
|
|
100
|
+
.card p:last-child { margin-bottom: 0; }
|
|
101
|
+
.try { user-select: none; -webkit-user-select: none; text-align: center; }
|
|
102
|
+
.try:active { background: var(--accent-strong); }
|
|
103
|
+
.count { margin: 4px 0; font-size: 56px; font-weight: 700; letter-spacing: -0.04em; }
|
|
104
|
+
.note { margin: 0; color: var(--muted); font-size: 14px; }
|
|
105
|
+
.tabs { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; display: flex; padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); background: var(--background); border-top: 1px solid var(--border); }
|
|
106
|
+
.tab { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 0; min-height: 48px; color: var(--muted); text-decoration: none; font-size: 12px; border-radius: 12px; }
|
|
107
|
+
.tab .ico { font-size: 22px; line-height: 1.1; }
|
|
108
|
+
.tab.on { color: var(--foreground); font-weight: 700; }
|
|
109
|
+
@media (min-width: 700px) { .phone { max-width: 520px; margin: 0 auto; border-inline: 1px solid var(--border); } .tabs { max-width: 520px; margin: 0 auto; } }
|
|
110
|
+
</style>
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function desktopSource(f) {
|
|
115
|
+
const nav = [
|
|
116
|
+
{ label: 'Home', to: '/' },
|
|
117
|
+
f.dashboard && { label: 'Dashboard', to: '/dashboard' },
|
|
118
|
+
f.users && { label: 'Users', to: '/users' },
|
|
119
|
+
f.profile && { label: 'Profile', to: '/profile' },
|
|
120
|
+
f.docs && { label: 'Docs', to: '/docs' },
|
|
121
|
+
{ label: 'Error monitor', to: '/error-monitor' },
|
|
122
|
+
].filter(Boolean);
|
|
123
|
+
return `<!-- The home page of the desktop app: a sidebar, a toolbar and a workspace, like a real desktop program.
|
|
124
|
+
Inside the Electron window window.kreftDesktop gives the app name, version and system.
|
|
125
|
+
Add ?platform=desktop in a browser to preview it. -->
|
|
126
|
+
|
|
127
|
+
state app = Kreftjs.env.PUBLIC_APP_NAME || 'My app'
|
|
128
|
+
state nav = ${js(nav)}
|
|
129
|
+
state query = ''
|
|
130
|
+
state info = { name: app, version: '', platform: 'browser' }
|
|
131
|
+
state shortcuts = [
|
|
132
|
+
{ keys: 'F12', does: 'Open or close the developer tools' },
|
|
133
|
+
{ keys: 'Ctrl / ⌘ + R', does: 'Reload the window' },
|
|
134
|
+
{ keys: 'Ctrl / ⌘ + + / −', does: 'Zoom in and out' },
|
|
135
|
+
{ keys: 'F11', does: 'Full screen' },
|
|
136
|
+
]
|
|
137
|
+
derive shown = nav.filter((n) => n.label.toLowerCase().includes(query.trim().toLowerCase()))
|
|
138
|
+
|
|
139
|
+
on ready {
|
|
140
|
+
if (window.kreftDesktop && window.kreftDesktop.getInfo) {
|
|
141
|
+
window.kreftDesktop.getInfo().then((i) => { info = { name: i.name, version: i.version, platform: i.platform + ' ' + i.arch } }).catch(() => {})
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
<view>
|
|
146
|
+
<div class="shell">
|
|
147
|
+
<aside class="side">
|
|
148
|
+
<div class="brand"><img src="logo-mark.svg" alt="" width="22" height="22"><span>{app}</span></div>
|
|
149
|
+
<nav aria-label="Main">
|
|
150
|
+
<kreft-link k-for="n in nav" to={n.to} class="item" active-class="on" exact-active-class="on">{n.label}</kreft-link>
|
|
151
|
+
</nav>
|
|
152
|
+
<p class="foot">{info.name} {info.version}<br>{info.platform}</p>
|
|
153
|
+
</aside>
|
|
154
|
+
|
|
155
|
+
<section class="work">
|
|
156
|
+
<header class="toolbar">
|
|
157
|
+
<h1>Home</h1>
|
|
158
|
+
<input type="search" placeholder="Search pages…" k-model="query" aria-label="Search pages">
|
|
159
|
+
</header>
|
|
160
|
+
|
|
161
|
+
<div class="content">
|
|
162
|
+
<div class="cards">
|
|
163
|
+
<article class="card"><p class="small">Application</p><p class="big">{info.name}</p></article>
|
|
164
|
+
<article class="card"><p class="small">Version</p><p class="big">{info.version || 'dev'}</p></article>
|
|
165
|
+
<article class="card"><p class="small">System</p><p class="big">{info.platform}</p></article>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<h2>Open</h2>
|
|
169
|
+
<div class="list">
|
|
170
|
+
<kreft-link k-for="n in shown" to={n.to} class="row"><span>{n.label}</span><span class="arrow">→</span></kreft-link>
|
|
171
|
+
<p k-if="shown.length === 0" class="empty">No page matches “{query}”.</p>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<h2>Shortcuts</h2>
|
|
175
|
+
<table class="keys">
|
|
176
|
+
<tr k-for="s in shortcuts"><td><kbd>{s.keys}</kbd></td><td>{s.does}</td></tr>
|
|
177
|
+
</table>
|
|
178
|
+
</div>
|
|
179
|
+
</section>
|
|
180
|
+
</div>
|
|
181
|
+
</view>
|
|
182
|
+
|
|
183
|
+
<style scoped>
|
|
184
|
+
.shell { display: grid; grid-template-columns: 232px 1fr; height: 100vh; background: var(--background); color: var(--foreground); }
|
|
185
|
+
.side { display: flex; flex-direction: column; gap: 8px; padding: 16px 12px; background: var(--accent); border-right: 1px solid var(--border); overflow: auto; }
|
|
186
|
+
.brand { display: flex; align-items: center; gap: 8px; padding: 4px 8px 12px; font-weight: 700; letter-spacing: -0.02em; }
|
|
187
|
+
.item { display: block; padding: 8px 10px; border-radius: 6px; color: var(--muted); text-decoration: none; font-size: 14px; }
|
|
188
|
+
.item:hover { background: var(--accent-strong); color: var(--foreground); }
|
|
189
|
+
.item.on { background: var(--accent-strong); color: var(--foreground); font-weight: 600; }
|
|
190
|
+
.foot { margin: auto 0 0; padding: 8px; font-size: 12px; color: var(--muted); }
|
|
191
|
+
.work { display: flex; flex-direction: column; min-width: 0; }
|
|
192
|
+
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 24px; border-bottom: 1px solid var(--border); }
|
|
193
|
+
.toolbar h1 { margin: 0; font-size: 18px; }
|
|
194
|
+
.toolbar input { width: 260px; max-width: 50%; }
|
|
195
|
+
.content { padding: 24px; overflow: auto; }
|
|
196
|
+
.content h2 { margin: 28px 0 12px; font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
|
|
197
|
+
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }
|
|
198
|
+
.card { padding: 16px; background: var(--card); border: 1px solid var(--card-border); border-radius: var(--radius-lg); }
|
|
199
|
+
.small { margin: 0 0 4px; font-size: 12px; color: var(--muted); }
|
|
200
|
+
.big { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; overflow-wrap: anywhere; }
|
|
201
|
+
.list { border: 1px solid var(--card-border); border-radius: var(--radius-lg); overflow: hidden; }
|
|
202
|
+
.row { display: flex; justify-content: space-between; padding: 12px 16px; color: var(--foreground); text-decoration: none; border-bottom: 1px solid var(--border-subtle); }
|
|
203
|
+
.row:last-child { border-bottom: 0; }
|
|
204
|
+
.row:hover { background: var(--accent); }
|
|
205
|
+
.arrow { color: var(--muted); }
|
|
206
|
+
.empty { margin: 0; padding: 12px 16px; color: var(--muted); }
|
|
207
|
+
.keys { border-collapse: collapse; }
|
|
208
|
+
.keys td { padding: 6px 24px 6px 0; font-size: 14px; }
|
|
209
|
+
kbd { padding: 2px 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--accent); font-size: 12px; }
|
|
210
|
+
@media (max-width: 720px) { .shell { grid-template-columns: 1fr; height: auto; } .side { border-right: 0; border-bottom: 1px solid var(--border); } }
|
|
211
|
+
</style>
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// pages/Home.kreft: the platform switch when both exist, otherwise the one that exists
|
|
216
|
+
function homeSource(mobile, desktop) {
|
|
217
|
+
if (mobile && desktop) {
|
|
218
|
+
return `<!-- The home page: the desktop workspace inside the Electron window, the phone screen everywhere else.
|
|
219
|
+
Preview in a browser with ?platform=desktop or ?platform=mobile. -->
|
|
220
|
+
state desktop = (function () {
|
|
221
|
+
const asked = new URLSearchParams(location.search).get('platform')
|
|
222
|
+
if (asked) return asked === 'desktop'
|
|
223
|
+
return Boolean(window.kreftDesktop || window.__KREFT_ELECTRON__)
|
|
224
|
+
})()
|
|
225
|
+
|
|
226
|
+
<view>
|
|
227
|
+
<home-desktop k-if="desktop"></home-desktop>
|
|
228
|
+
<home-mobile k-else></home-mobile>
|
|
229
|
+
</view>
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
return `<!-- The home page of the ${mobile ? 'phone' : 'desktop'} app. Its design is in components/${mobile ? 'HomeMobile' : 'HomeDesktop'}.kreft -->
|
|
233
|
+
<view>
|
|
234
|
+
<home-${mobile ? 'mobile' : 'desktop'}></home-${mobile ? 'mobile' : 'desktop'}>
|
|
235
|
+
</view>
|
|
236
|
+
`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// index.html lists every component: .component('Field', 'components/Field.kreft')
|
|
240
|
+
function register(front, names) {
|
|
241
|
+
const file = path.join(front, 'index.html');
|
|
242
|
+
if (!fs.existsSync(file)) return;
|
|
243
|
+
let html = fs.readFileSync(file, 'utf8');
|
|
244
|
+
const add = names.filter((n) => !html.includes(`.component('${n}'`));
|
|
245
|
+
if (!add.length) return;
|
|
246
|
+
const lines = add.map((n) => `.component('${n}', 'components/${n}.kreft')`);
|
|
247
|
+
const m = html.match(/^([ \t]*)\.component\(/m) || html.match(/^([ \t]*)\.use\(router\)/m);
|
|
248
|
+
if (!m) { console.warn(' Could not find where components are listed in index.html. Add: ' + lines.join(' ')); return; }
|
|
249
|
+
const indent = m[1];
|
|
250
|
+
html = html.replace(m[0], lines.map((l) => indent + l + '\n').join('') + m[0]);
|
|
251
|
+
fs.writeFileSync(file, html);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// existing: what a project that already had one of them keeps when the other is added
|
|
255
|
+
function apply(target, { mobile = false, desktop = false } = {}) {
|
|
256
|
+
const lay = require('./layout.js').layout(target);
|
|
257
|
+
const front = lay.frontend;
|
|
258
|
+
const f = features(front);
|
|
259
|
+
fs.mkdirSync(path.join(front, 'components'), { recursive: true });
|
|
260
|
+
fs.mkdirSync(path.join(front, 'pages'), { recursive: true });
|
|
261
|
+
const has = (n) => fs.existsSync(path.join(front, 'components', n));
|
|
262
|
+
const wantMobile = mobile || has('HomeMobile.kreft');
|
|
263
|
+
const wantDesktop = desktop || has('HomeDesktop.kreft');
|
|
264
|
+
if (mobile) fs.writeFileSync(path.join(front, 'components', 'HomeMobile.kreft'), mobileSource(f));
|
|
265
|
+
if (desktop) fs.writeFileSync(path.join(front, 'components', 'HomeDesktop.kreft'), desktopSource(f));
|
|
266
|
+
fs.writeFileSync(path.join(front, 'pages', 'Home.kreft'), homeSource(wantMobile, wantDesktop));
|
|
267
|
+
register(front, [wantMobile && 'HomeMobile', wantDesktop && 'HomeDesktop'].filter(Boolean));
|
|
268
|
+
return { mobile: wantMobile, desktop: wantDesktop };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function make(args = []) {
|
|
272
|
+
const mobile = args.includes('--mobile'), desktop = args.includes('--desktop') || args.includes('--electron');
|
|
273
|
+
if (!mobile && !desktop) { console.error(' Use kreft make:home --mobile or --desktop (or both).'); process.exit(1); }
|
|
274
|
+
const r = apply(process.cwd(), { mobile, desktop });
|
|
275
|
+
console.log(` Wrote the ${[r.mobile && 'phone', r.desktop && 'desktop'].filter(Boolean).join(' and ')} home page (pages/Home.kreft and components/).`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = { apply, make, mobileSource, desktopSource, homeSource, features };
|
package/bin/kreftjs.js
CHANGED
|
@@ -48,6 +48,7 @@ const commands = {
|
|
|
48
48
|
'electron:init': (a) => require('./electron.js').init(a),
|
|
49
49
|
'electron:help': () => require('./electron.js').help(),
|
|
50
50
|
'make:electron': (a) => require('./electron.js').init(a),
|
|
51
|
+
'make:home': (a) => require('./home-variants.js').make(a),
|
|
51
52
|
'mobile:init': (a) => require('./mobile.js').init(a[0]),
|
|
52
53
|
'mobile:build': (a) => require('./mobile.js').build(a),
|
|
53
54
|
'mobile:open': (a) => require('./mobile.js').open(a),
|
|
@@ -128,6 +129,7 @@ function help() {
|
|
|
128
129
|
kreft electron Open the app in a desktop window only: no browser, no URL (alias: kreft electron:dev)
|
|
129
130
|
kreft electron:build Build and make installers (--mac, --win, --linux; or npm run electron:build:all)
|
|
130
131
|
kreft electron:init Add Electron support to an existing project (alias: kreft make:electron)
|
|
132
|
+
kreft make:home Write an app-style home page: --mobile (phone screen) or --desktop (sidebar workspace)
|
|
131
133
|
kreft mobile:build Build for iOS / Android with Capacitor (--android, --ios, --api-url; see kreft mobile:help)
|
|
132
134
|
kreft electron:help Everything about desktop apps: menu, icon, installers, errors
|
|
133
135
|
|
|
@@ -305,6 +307,7 @@ async function createProject(args) {
|
|
|
305
307
|
fs.writeFileSync(path.join(target, 'package.json'), JSON.stringify(projectPkg, null, 2) + '\n');
|
|
306
308
|
if (electron) require('./electron.js').init(target);
|
|
307
309
|
if (mobile) require('./mobile.js').init(target);
|
|
310
|
+
if (mobile || electron) require('./home-variants.js').apply(target, { mobile, desktop: electron }); // a home page made for the app, not the web
|
|
308
311
|
if (vite) require('./vite.js').init(target, { ts });
|
|
309
312
|
|
|
310
313
|
console.log(`
|
package/bin/mobile.js
CHANGED
package/docs/README.md
CHANGED
|
@@ -2243,6 +2243,8 @@ kreft mobile:open --android # Android Studio (--ios: Xcode, needs a Mac)
|
|
|
2243
2243
|
| `kreft mobile:open` | Opens the native project |
|
|
2244
2244
|
| `kreft mobile:dev` | Runs on a device or emulator with live reload from your dev server (same Wi-Fi) |
|
|
2245
2245
|
|
|
2246
|
+
**Building the Android app needs Java 21** (Capacitor 7). Android Studio includes it; on a command line set `JAVA_HOME` to it, for example on a Mac `export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"`. Running from Android Studio ( `kreft mobile:open --android` ) needs no extra setup. The iOS Simulator needs a full Xcode install, not only the command line tools.
|
|
2247
|
+
|
|
2246
2248
|
**The backend does not run inside the phone.** Run it on a server and give the app its address with `--api-url` (written to `.env` as `PUBLIC_API_URL`), then in your code:
|
|
2247
2249
|
|
|
2248
2250
|
```js
|
|
@@ -2251,6 +2253,17 @@ Kreftjs.api.setup({ base: Kreftjs.env.PUBLIC_API_URL, token: () => Kreftjs.stora
|
|
|
2251
2253
|
|
|
2252
2254
|
Use API tokens for sign-in in the app, not cookie sessions.
|
|
2253
2255
|
|
|
2256
|
+
### Home pages made for apps
|
|
2257
|
+
|
|
2258
|
+
A website's welcome page is not what an app should open on. `kreft new my-app --mobile` writes a **phone home screen** (top bar, shortcut cards, a bottom tab bar, a card that shows the touch events), and `kreft new my-app --electron` writes a **desktop workspace** (sidebar, toolbar with search, info cards, shortcuts). With both flags, `pages/Home.kreft` shows the desktop one inside the Electron window and the phone one everywhere else.
|
|
2259
|
+
|
|
2260
|
+
```bash
|
|
2261
|
+
kreft make:home --mobile # in an existing project: phone home screen (replaces pages/Home.kreft)
|
|
2262
|
+
kreft make:home --desktop # desktop workspace
|
|
2263
|
+
```
|
|
2264
|
+
|
|
2265
|
+
They are normal files (`components/HomeMobile.kreft`, `components/HomeDesktop.kreft`), so change them freely. Preview either in a browser with `?platform=mobile` or `?platform=desktop`. Links to the dashboard, users and profile appear only when the project has them (not with `--no-auth`).
|
|
2266
|
+
|
|
2254
2267
|
### Touch events
|
|
2255
2268
|
|
|
2256
2269
|
```html
|
package/kreftjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.23-beta.1 — 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.
|
|
@@ -5648,7 +5648,7 @@
|
|
|
5648
5648
|
stores, storeLog, busLog,
|
|
5649
5649
|
};
|
|
5650
5650
|
|
|
5651
|
-
const VERSION = '0.0.
|
|
5651
|
+
const VERSION = '0.0.23-beta.1';
|
|
5652
5652
|
const Kreftjs = {
|
|
5653
5653
|
version: VERSION,
|
|
5654
5654
|
// 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.23-beta.
|
|
3
|
+
"version": "0.0.23-beta.1",
|
|
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/kreftjs-com --base / --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 test/menu.test.js test/electron-all.test.js test/build-minify.test.js test/stream.test.js test/syntax.test.js test/memory.test.js test/shield.test.js test/mcp-client.test.js test/dbapi-secrets.test.js test/auth-csrf.test.js test/not-a-project.test.js test/mobile.test.js test/gestures.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 test/electron-all.test.js test/build-minify.test.js test/stream.test.js test/syntax.test.js test/memory.test.js test/shield.test.js test/mcp-client.test.js test/dbapi-secrets.test.js test/auth-csrf.test.js test/not-a-project.test.js test/mobile.test.js test/gestures.test.js test/home-variants.test.js",
|
|
18
18
|
"electron": "kreftjs electron",
|
|
19
19
|
"electron:dev": "kreftjs electron:dev",
|
|
20
20
|
"electron:build": "kreftjs electron:build"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.23-beta.1 — 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.
|
|
@@ -5648,7 +5648,7 @@
|
|
|
5648
5648
|
stores, storeLog, busLog,
|
|
5649
5649
|
};
|
|
5650
5650
|
|
|
5651
|
-
const VERSION = '0.0.
|
|
5651
|
+
const VERSION = '0.0.23-beta.1';
|
|
5652
5652
|
const Kreftjs = {
|
|
5653
5653
|
version: VERSION,
|
|
5654
5654
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|