@geastack/cli 0.1.4 → 0.1.6
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 +4 -4
- package/docs/ESP32-WAVESHARE-AMOLED-QUICKSTART.md +19 -15
- package/docs/NPX-COMMANDS.md +8 -8
- package/docs/SPEC.md +5 -4
- package/package.json +1 -1
- package/src/create-geastack.mjs +45 -28
- package/starters/bundled/counter/package.json +12 -11
- package/starters/bundled/counter/src/App.tsx +28 -0
- package/starters/bundled/counter/src/index.tsx +4 -0
- package/starters/bundled/counter/src/styles.css +20 -0
- package/starters/bundled/counter/tsconfig.json +14 -0
- package/starters/catalog.json +6 -6
- package/starters/bundled/counter/index.tsx +0 -25
- package/starters/bundled/counter/store.ts +0 -7
- package/starters/bundled/counter/styles.css +0 -39
package/README.md
CHANGED
|
@@ -26,15 +26,15 @@ gea inspect --json
|
|
|
26
26
|
|
|
27
27
|
```mermaid
|
|
28
28
|
flowchart TD
|
|
29
|
-
create["
|
|
29
|
+
create["gea create my-app"] --> identity["Resolve app identity<br/>argument, optional --id, optional --name"]
|
|
30
30
|
identity --> starter{"Starter app?"}
|
|
31
31
|
|
|
32
|
-
starter -->|"
|
|
32
|
+
starter -->|"Embedded component counter"| counter["Copy the touchscreen counter used in the embedded tutorial"]
|
|
33
33
|
|
|
34
|
-
starter -->|"
|
|
34
|
+
starter -->|"Blank application"| empty["Generate a minimal browser application"]
|
|
35
35
|
empty --> emptyFiles["index.tsx, styles.css, index.html,<br/>tsconfig.json, vite.config.ts"]
|
|
36
36
|
|
|
37
|
-
starter -->|"
|
|
37
|
+
starter -->|"Example application"| pickExample["Pick from the example gallery<br/>web, ESP32, GeaOS, iOS, macOS, Android"]
|
|
38
38
|
pickExample --> fetchExample["Fetch selected app from GitHub"]
|
|
39
39
|
fetchExample --> copyExample["Copy fetched example files"]
|
|
40
40
|
copyExample --> rewriteExample["Rewrite package name and gea manifest"]
|
|
@@ -30,27 +30,31 @@ You do not clone GeaStack.
|
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
npm login
|
|
33
|
-
|
|
33
|
+
npm install --global @geastack/cli
|
|
34
|
+
gea create my-app
|
|
34
35
|
cd my-app
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
When the wizard asks what to create, choose:
|
|
38
39
|
|
|
39
40
|
```text
|
|
40
|
-
? What do you want to
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
? What do you want to build?
|
|
42
|
+
Embedded component counter
|
|
43
|
+
Touchscreen +/− counter with local state and BLE updates, ready for ESP32.
|
|
44
|
+
Blank application
|
|
45
|
+
A minimal screen for building your own Gea application.
|
|
46
|
+
Example application
|
|
47
|
+
Choose a complete application from the GeaStack example gallery.
|
|
44
48
|
```
|
|
45
49
|
|
|
46
|
-
For the fastest first flash, choose `
|
|
50
|
+
For the fastest first flash, choose `Embedded component counter`.
|
|
47
51
|
|
|
48
|
-
That creates a tiny JSX app
|
|
52
|
+
That creates a tiny JSX app and installs all of its project dependencies.
|
|
49
53
|
|
|
50
54
|
## 3. Set Up The Board
|
|
51
55
|
|
|
52
56
|
```sh
|
|
53
|
-
|
|
57
|
+
gea setup
|
|
54
58
|
```
|
|
55
59
|
|
|
56
60
|
Choose:
|
|
@@ -82,7 +86,7 @@ If ESP-IDF was installed, the CLI prints this for future shells:
|
|
|
82
86
|
. "$HOME/esp/esp-idf/export.sh"
|
|
83
87
|
```
|
|
84
88
|
|
|
85
|
-
You do not need to run that before every command unless `
|
|
89
|
+
You do not need to run that before every command unless `gea doctor` says ESP-IDF is not active.
|
|
86
90
|
|
|
87
91
|
If the wizard finds a connected serial device, pick it. If no board is plugged in yet, that is fine; you can provide the port later.
|
|
88
92
|
|
|
@@ -93,13 +97,13 @@ The wizard writes the board config into your app at `.gea/boards.json` and initi
|
|
|
93
97
|
Flash and open the serial monitor:
|
|
94
98
|
|
|
95
99
|
```sh
|
|
96
|
-
|
|
100
|
+
gea flash --board amoled --monitor
|
|
97
101
|
```
|
|
98
102
|
|
|
99
103
|
If you need to specify the serial port manually:
|
|
100
104
|
|
|
101
105
|
```sh
|
|
102
|
-
|
|
106
|
+
gea flash --board amoled --port /dev/cu.usbmodemXXXX --monitor
|
|
103
107
|
```
|
|
104
108
|
|
|
105
109
|
## Rich Examples
|
|
@@ -109,10 +113,10 @@ The bundled starter is intentionally tiny. Rich examples live in the GeaStack ex
|
|
|
109
113
|
For example:
|
|
110
114
|
|
|
111
115
|
```sh
|
|
112
|
-
|
|
116
|
+
gea create watch-demo --starter example --example watch
|
|
113
117
|
cd watch-demo
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
gea setup
|
|
119
|
+
gea flash --board amoled --monitor
|
|
116
120
|
```
|
|
117
121
|
|
|
118
122
|
The CLI owns the example catalog, so the user does not need to clone the examples repo.
|
|
@@ -122,7 +126,7 @@ The CLI owns the example catalog, so the user does not need to clone the example
|
|
|
122
126
|
Run:
|
|
123
127
|
|
|
124
128
|
```sh
|
|
125
|
-
|
|
129
|
+
gea doctor
|
|
126
130
|
```
|
|
127
131
|
|
|
128
132
|
Most first-run issues are one of:
|
package/docs/NPX-COMMANDS.md
CHANGED
|
@@ -44,20 +44,20 @@ npx @geastack/create-geastack my-app
|
|
|
44
44
|
In an interactive terminal, `create-geastack` asks:
|
|
45
45
|
|
|
46
46
|
```text
|
|
47
|
-
|
|
48
|
-
1.
|
|
49
|
-
2.
|
|
50
|
-
3.
|
|
47
|
+
What do you want to build?
|
|
48
|
+
1. Embedded component counter
|
|
49
|
+
2. Blank application
|
|
50
|
+
3. Example application
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`
|
|
54
|
-
|
|
53
|
+
`Embedded component counter` is the bundled tutorial starter. It uses local
|
|
54
|
+
component state, targets ESP32, and enables BLE updates.
|
|
55
55
|
|
|
56
|
-
`
|
|
56
|
+
`Blank application` creates the smallest browser starter: `index.tsx`, `styles.css`,
|
|
57
57
|
`index.html`, `tsconfig.json`, `vite.config.ts`, `package.json`, and
|
|
58
58
|
`.gea/boards.json`.
|
|
59
59
|
|
|
60
|
-
`
|
|
60
|
+
`Example application` opens an example picker populated from the hard-coded
|
|
61
61
|
`examples/catalog.json` shipped inside `@geastack/cli`. The catalog contains web,
|
|
62
62
|
ESP32, GeaOS, iOS, macOS, and Android examples with names, descriptions, target
|
|
63
63
|
flags, and GitHub paths. When the user selects an example, the CLI fetches that app from
|
package/docs/SPEC.md
CHANGED
|
@@ -115,7 +115,7 @@ Minimum checks:
|
|
|
115
115
|
Human-readable output should point to [SETUP.md](SETUP.md) whenever a required
|
|
116
116
|
or optional dependency is missing.
|
|
117
117
|
|
|
118
|
-
### `create
|
|
118
|
+
### `gea create`
|
|
119
119
|
|
|
120
120
|
Scaffolds a new app folder with:
|
|
121
121
|
|
|
@@ -130,9 +130,10 @@ Scaffolds a new app folder with:
|
|
|
130
130
|
|
|
131
131
|
Interactive starter choices must explain the tradeoff in-line:
|
|
132
132
|
|
|
133
|
-
- `
|
|
134
|
-
|
|
135
|
-
- `
|
|
133
|
+
- `Embedded component counter`: create a touchscreen counter with local
|
|
134
|
+
component state, an ESP32 target, and BLE updates enabled.
|
|
135
|
+
- `Blank application`: generate a minimal browser application as a clean slate.
|
|
136
|
+
- `Example application`: fetch a selected app from `geastack/examples`, then rewrite
|
|
136
137
|
package name, app id, dependencies, and board config for the new project.
|
|
137
138
|
|
|
138
139
|
Rich example choices come from the hard-coded `examples/catalog.json`
|
package/package.json
CHANGED
package/src/create-geastack.mjs
CHANGED
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
formatStarterChoice
|
|
16
16
|
} from './starter-catalog.mjs'
|
|
17
17
|
|
|
18
|
+
const cliVersion = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version
|
|
19
|
+
|
|
18
20
|
export async function runCreateGeastack(argv, io = {}) {
|
|
19
21
|
const parsed = parseArgs(argv)
|
|
20
22
|
const stdout = io.stdout || console.log
|
|
@@ -38,12 +40,9 @@ export async function runCreateGeastack(argv, io = {}) {
|
|
|
38
40
|
const ctx = createContext(parsed, env, cwd)
|
|
39
41
|
const displayName = option(parsed, 'name', titleFromId(appId))
|
|
40
42
|
const coreDependency = option(parsed, 'core-dependency') || '^0.1.4'
|
|
41
|
-
const cliDependency = option(parsed, 'cli-dependency') ||
|
|
43
|
+
const cliDependency = option(parsed, 'cli-dependency') || `^${cliVersion}`
|
|
42
44
|
const starter = await resolveStarter(ctx, parsed, io)
|
|
43
|
-
const entry = projectRelativePath(
|
|
44
|
-
if (option(parsed, 'entry') && starter.kind !== 'empty') {
|
|
45
|
-
fail('--entry can only be used with --starter empty.', ExitCode.usage)
|
|
46
|
-
}
|
|
45
|
+
const entry = projectRelativePath(starter.starter?.entry || starter.example?.entry || 'index.tsx', 'entry')
|
|
47
46
|
|
|
48
47
|
fs.mkdirSync(targetDir, { recursive: true })
|
|
49
48
|
if (starter.kind === 'empty') {
|
|
@@ -68,26 +67,28 @@ export async function runCreateGeastack(argv, io = {}) {
|
|
|
68
67
|
|
|
69
68
|
const sourcePackage = readPackageJson(targetDir)
|
|
70
69
|
const sourceManifest = sourcePackage.gea || starter.starter?.manifest || starter.example?.manifest || {}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
const requestedTargets = optionList(parsed, 'targets')
|
|
71
|
+
const targets = requestedTargets.length > 0
|
|
72
|
+
? targetManifest(requestedTargets)
|
|
73
|
+
: starter.kind === 'empty'
|
|
74
|
+
? targetManifest(['web'])
|
|
75
|
+
: targetManifestFromObject(sourceManifest.targets)
|
|
74
76
|
writeJson(path.join(targetDir, 'package.json'), packageJson({
|
|
75
77
|
appId,
|
|
76
78
|
displayName,
|
|
77
79
|
targets,
|
|
78
80
|
entry,
|
|
79
|
-
bleOta: flag(parsed, 'ble-ota'),
|
|
80
81
|
coreDependency,
|
|
81
82
|
cliDependency,
|
|
82
83
|
sourcePackage,
|
|
83
84
|
sourceManifest
|
|
84
85
|
}))
|
|
85
|
-
ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName, entry))
|
|
86
|
+
if (targets.web) ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName, entry))
|
|
86
87
|
fs.mkdirSync(path.join(targetDir, '.gea'), { recursive: true })
|
|
87
88
|
writeJson(path.join(targetDir, '.gea', 'boards.json'), {})
|
|
88
89
|
ensureJson(path.join(targetDir, 'tsconfig.json'), tsconfigJson)
|
|
89
|
-
ensureFile(path.join(targetDir, 'vite.config.ts'), viteConfigTs)
|
|
90
|
-
fs.writeFileSync(path.join(targetDir, 'README.md'), readme({ appId, displayName, starter }))
|
|
90
|
+
if (targets.web) ensureFile(path.join(targetDir, 'vite.config.ts'), viteConfigTs)
|
|
91
|
+
fs.writeFileSync(path.join(targetDir, 'README.md'), readme({ appId, displayName, starter, targets }))
|
|
91
92
|
|
|
92
93
|
const installDependencies = shouldInstallDependencies(parsed, io)
|
|
93
94
|
if (installDependencies) {
|
|
@@ -155,11 +156,23 @@ async function resolveStarter(ctx, parsed, io) {
|
|
|
155
156
|
async function chooseStarterMode({ interactive, prompt, bundled, examples }) {
|
|
156
157
|
if (!interactive) return bundled.length > 0 ? 'counter' : 'empty'
|
|
157
158
|
return choose(prompt, {
|
|
158
|
-
message: '
|
|
159
|
+
message: 'What do you want to build?',
|
|
159
160
|
choices: [
|
|
160
|
-
...(bundled.length > 0 ? [{
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
...(bundled.length > 0 ? [{
|
|
162
|
+
value: 'counter',
|
|
163
|
+
label: 'Embedded component counter',
|
|
164
|
+
description: 'Touchscreen +/− counter with local state and BLE updates, ready for ESP32.'
|
|
165
|
+
}] : []),
|
|
166
|
+
{
|
|
167
|
+
value: 'empty',
|
|
168
|
+
label: 'Blank application',
|
|
169
|
+
description: 'A minimal screen for building your own Gea application.'
|
|
170
|
+
},
|
|
171
|
+
...(examples.length > 0 ? [{
|
|
172
|
+
value: 'example',
|
|
173
|
+
label: 'Example application',
|
|
174
|
+
description: 'Choose a complete application from the GeaStack example gallery.'
|
|
175
|
+
}] : [])
|
|
163
176
|
],
|
|
164
177
|
defaultValue: bundled.length > 0 ? 'counter' : 'empty'
|
|
165
178
|
})
|
|
@@ -211,7 +224,7 @@ function targetManifestFromObject(targets = {}) {
|
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
226
|
|
|
214
|
-
function packageJson({ appId, displayName, targets, entry,
|
|
227
|
+
function packageJson({ appId, displayName, targets, entry, coreDependency, cliDependency, sourcePackage = {}, sourceManifest = {} }) {
|
|
215
228
|
const geaManifest = {
|
|
216
229
|
...sourceManifest,
|
|
217
230
|
id: appId,
|
|
@@ -219,7 +232,6 @@ function packageJson({ appId, displayName, targets, entry, bleOta, coreDependenc
|
|
|
219
232
|
entry,
|
|
220
233
|
targets
|
|
221
234
|
}
|
|
222
|
-
if (bleOta) geaManifest.ota = { ...(geaManifest.ota || {}), ble: true }
|
|
223
235
|
if (!geaManifest.runtime || geaManifest.runtime === 'gea') delete geaManifest.runtime
|
|
224
236
|
|
|
225
237
|
return {
|
|
@@ -229,8 +241,7 @@ function packageJson({ appId, displayName, targets, entry, bleOta, coreDependenc
|
|
|
229
241
|
type: 'module',
|
|
230
242
|
scripts: {
|
|
231
243
|
...(sourcePackage.scripts || {}),
|
|
232
|
-
dev: 'gea dev',
|
|
233
|
-
build: 'gea build --target web',
|
|
244
|
+
...(targets.web ? { dev: 'gea dev', build: 'gea build --target web' } : {}),
|
|
234
245
|
check: 'tsc --noEmit'
|
|
235
246
|
},
|
|
236
247
|
dependencies: {
|
|
@@ -242,7 +253,7 @@ function packageJson({ appId, displayName, targets, entry, bleOta, coreDependenc
|
|
|
242
253
|
...(sourcePackage.devDependencies || {}),
|
|
243
254
|
'@geastack/cli': cliDependency,
|
|
244
255
|
typescript: sourcePackage.devDependencies?.typescript || 'latest',
|
|
245
|
-
vite: sourcePackage.devDependencies?.vite || 'latest'
|
|
256
|
+
...(targets.web ? { vite: sourcePackage.devDependencies?.vite || 'latest' } : {})
|
|
246
257
|
},
|
|
247
258
|
gea: geaManifest,
|
|
248
259
|
license: 'MIT'
|
|
@@ -356,12 +367,22 @@ export default defineConfig({
|
|
|
356
367
|
`
|
|
357
368
|
}
|
|
358
369
|
|
|
359
|
-
function readme({ appId, displayName, starter }) {
|
|
370
|
+
function readme({ appId, displayName, starter, targets }) {
|
|
360
371
|
const starterLine = starter.kind === 'example'
|
|
361
372
|
? `Started from GitHub example: \`${starter.example.name}\` (\`${starter.example.id}\`).`
|
|
362
373
|
: starter.kind === 'bundled'
|
|
363
374
|
? `Started from bundled starter: \`${starter.starter.name}\` (\`${starter.starter.id}\`).`
|
|
364
|
-
: 'Started from
|
|
375
|
+
: 'Started from a blank app.'
|
|
376
|
+
const commands = targets.web
|
|
377
|
+
? `npx gea setup
|
|
378
|
+
npx gea dev
|
|
379
|
+
npx gea build --target web`
|
|
380
|
+
: targets.esp32
|
|
381
|
+
? `npx gea setup
|
|
382
|
+
npx gea build --board <alias>
|
|
383
|
+
npx gea flash --board <alias> --monitor`
|
|
384
|
+
: `npx gea setup
|
|
385
|
+
npx gea build`
|
|
365
386
|
return `# ${displayName}
|
|
366
387
|
|
|
367
388
|
GeaStack app id: \`${appId}\`.
|
|
@@ -369,9 +390,7 @@ GeaStack app id: \`${appId}\`.
|
|
|
369
390
|
${starterLine}
|
|
370
391
|
|
|
371
392
|
\`\`\`sh
|
|
372
|
-
|
|
373
|
-
npx gea dev
|
|
374
|
-
npx gea build --target web
|
|
393
|
+
${commands}
|
|
375
394
|
\`\`\`
|
|
376
395
|
`
|
|
377
396
|
}
|
|
@@ -439,8 +458,6 @@ Options:
|
|
|
439
458
|
--examples-repo <git-url-or-local-path>
|
|
440
459
|
--examples-ref <git-ref>
|
|
441
460
|
--targets web,esp32,rp2350,geaos,macos,ios,android
|
|
442
|
-
--entry <relative-path>
|
|
443
|
-
--ble-ota
|
|
444
461
|
--core-dependency <specifier>
|
|
445
462
|
--cli-dependency <specifier>
|
|
446
463
|
--install / --no-install
|
|
@@ -3,30 +3,31 @@
|
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "Touchscreen counter with component-local reactive state.",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "vite build",
|
|
9
8
|
"check": "tsc --noEmit"
|
|
10
9
|
},
|
|
11
10
|
"dependencies": {
|
|
12
|
-
"@geajs/core": "
|
|
11
|
+
"@geajs/core": "latest"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
|
-
"typescript": "latest"
|
|
16
|
-
"vite": "latest"
|
|
14
|
+
"typescript": "latest"
|
|
17
15
|
},
|
|
18
16
|
"gea": {
|
|
19
17
|
"id": "counter",
|
|
20
|
-
"name": "Counter",
|
|
21
|
-
"description": "
|
|
22
|
-
"entry": "index.tsx",
|
|
18
|
+
"name": "Component Counter",
|
|
19
|
+
"description": "Touchscreen counter with component-local reactive state.",
|
|
20
|
+
"entry": "src/index.tsx",
|
|
23
21
|
"targets": {
|
|
24
|
-
"web":
|
|
22
|
+
"web": false,
|
|
25
23
|
"esp32": true,
|
|
26
|
-
"rp2350":
|
|
27
|
-
"geaos":
|
|
24
|
+
"rp2350": false,
|
|
25
|
+
"geaos": false,
|
|
28
26
|
"macos": false,
|
|
29
27
|
"ios": false
|
|
28
|
+
},
|
|
29
|
+
"ota": {
|
|
30
|
+
"ble": true
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactiveComponent } from '@geastack/core'
|
|
2
|
+
import './styles.css'
|
|
3
|
+
|
|
4
|
+
export class App extends ReactiveComponent {
|
|
5
|
+
count = 0
|
|
6
|
+
|
|
7
|
+
decrement() {
|
|
8
|
+
this.count = this.count - 1
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
increment() {
|
|
12
|
+
this.count = this.count + 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
template() {
|
|
16
|
+
return (
|
|
17
|
+
<div class="screen">
|
|
18
|
+
<span class="eyebrow">GEASTACK</span>
|
|
19
|
+
<span class="title">Component state</span>
|
|
20
|
+
<span class="count">{this.count}</span>
|
|
21
|
+
<div class="controls">
|
|
22
|
+
<button class="button secondary" onClick={() => this.decrement()}>−</button>
|
|
23
|
+
<button class="button primary" onClick={() => this.increment()}>+</button>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.screen {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100vw;
|
|
5
|
+
height: 100vh;
|
|
6
|
+
padding: 28px;
|
|
7
|
+
gap: 16px;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
background-color: #080b12;
|
|
11
|
+
color: #f8fafc;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.eyebrow { color: #2dd4bf; font-size: 13px; }
|
|
15
|
+
.title { color: #cbd5e1; font-size: 22px; }
|
|
16
|
+
.count { color: #ffffff; font-size: 76px; line-height: 1; }
|
|
17
|
+
.controls { display: flex; flex-direction: row; gap: 16px; }
|
|
18
|
+
.button { width: 92px; height: 58px; border-radius: 14px; border-width: 2px; font-size: 30px; }
|
|
19
|
+
.secondary { color: #f8fafc; background-color: #1e293b; border-color: #475569; }
|
|
20
|
+
.primary { color: #042f2e; background-color: #2dd4bf; border-color: #5eead4; }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"jsx": "preserve",
|
|
11
|
+
"types": []
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts"]
|
|
14
|
+
}
|
package/starters/catalog.json
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
"starters": [
|
|
4
4
|
{
|
|
5
5
|
"id": "counter",
|
|
6
|
-
"name": "Counter",
|
|
7
|
-
"description": "
|
|
6
|
+
"name": "Component Counter",
|
|
7
|
+
"description": "Touchscreen counter with component-local reactive state and BLE updates.",
|
|
8
8
|
"path": "bundled/counter",
|
|
9
|
-
"entry": "index.tsx",
|
|
9
|
+
"entry": "src/index.tsx",
|
|
10
10
|
"targets": {
|
|
11
|
-
"web":
|
|
11
|
+
"web": false,
|
|
12
12
|
"esp32": true,
|
|
13
|
-
"rp2350":
|
|
14
|
-
"geaos":
|
|
13
|
+
"rp2350": false,
|
|
14
|
+
"geaos": false,
|
|
15
15
|
"macos": false,
|
|
16
16
|
"ios": false,
|
|
17
17
|
"android": false
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { mount } from '@geastack/core'
|
|
2
|
-
import { counter } from './store'
|
|
3
|
-
import './styles.css'
|
|
4
|
-
|
|
5
|
-
function App() {
|
|
6
|
-
function increment() {
|
|
7
|
-
const value = counter.increment()
|
|
8
|
-
const count = document.querySelector('[data-count]')
|
|
9
|
-
if (count) count.textContent = String(value)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<body class="app">
|
|
14
|
-
<main class="panel">
|
|
15
|
-
<p class="eyebrow">GeaStack</p>
|
|
16
|
-
<h1>Counter</h1>
|
|
17
|
-
<button class="button" onClick={increment}>
|
|
18
|
-
Count <span data-count>0</span>
|
|
19
|
-
</button>
|
|
20
|
-
</main>
|
|
21
|
-
</body>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
mount(App)
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
.app {
|
|
2
|
-
width: 100vw;
|
|
3
|
-
height: 100vh;
|
|
4
|
-
margin: 0;
|
|
5
|
-
display: flex;
|
|
6
|
-
align-items: center;
|
|
7
|
-
justify-content: center;
|
|
8
|
-
background: #101418;
|
|
9
|
-
color: #f8fafc;
|
|
10
|
-
font-family: Inter, system-ui, sans-serif;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.panel {
|
|
14
|
-
width: min(320px, calc(100vw - 32px));
|
|
15
|
-
padding: 24px;
|
|
16
|
-
border: 1px solid #2dd4bf;
|
|
17
|
-
background: #182026;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.eyebrow {
|
|
21
|
-
margin: 0 0 8px;
|
|
22
|
-
color: #2dd4bf;
|
|
23
|
-
font-size: 12px;
|
|
24
|
-
text-transform: uppercase;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
h1 {
|
|
28
|
-
margin: 0 0 16px;
|
|
29
|
-
font-size: 28px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.button {
|
|
33
|
-
min-width: 120px;
|
|
34
|
-
min-height: 40px;
|
|
35
|
-
border: 0;
|
|
36
|
-
background: #2dd4bf;
|
|
37
|
-
color: #081018;
|
|
38
|
-
font: inherit;
|
|
39
|
-
}
|