@monimesl/dot-cli 0.1.0-alpha.2 → 0.1.0-alpha.4

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.
Files changed (68) hide show
  1. package/README.md +34 -15
  2. package/dist/cli.js +386 -57
  3. package/dist/cli.js.map +1 -1
  4. package/dist/server-DFOUQnLA.js +11263 -0
  5. package/dist/server-DFOUQnLA.js.map +1 -0
  6. package/dist/templates/showcase/.env +3 -0
  7. package/dist/templates/showcase/dot.ts +22 -0
  8. package/dist/templates/showcase/pages/carousel/controller.ts +10 -0
  9. package/dist/templates/showcase/pages/carousel/state.ts +40 -0
  10. package/dist/templates/showcase/pages/carousel/view.dml +37 -0
  11. package/dist/templates/showcase/pages/device/controller.ts +70 -0
  12. package/dist/templates/showcase/pages/device/state.ts +7 -0
  13. package/dist/templates/showcase/pages/device/view.dml +44 -0
  14. package/dist/templates/showcase/pages/feedback/controller.ts +16 -0
  15. package/dist/templates/showcase/pages/feedback/state.ts +7 -0
  16. package/dist/templates/showcase/pages/feedback/view.dml +87 -0
  17. package/dist/templates/showcase/pages/files/controller.ts +47 -0
  18. package/dist/templates/showcase/pages/files/state.ts +11 -0
  19. package/dist/templates/showcase/pages/files/view.dml +35 -0
  20. package/dist/templates/showcase/pages/filters/controller.ts +28 -0
  21. package/dist/templates/showcase/pages/filters/state.ts +72 -0
  22. package/dist/templates/showcase/pages/filters/view.dml +43 -0
  23. package/dist/templates/showcase/pages/forms/controller.ts +44 -0
  24. package/dist/templates/showcase/pages/forms/state.ts +15 -0
  25. package/dist/templates/showcase/pages/forms/view.dml +39 -0
  26. package/dist/templates/showcase/pages/images/controller.ts +15 -0
  27. package/dist/templates/showcase/pages/images/state.ts +7 -0
  28. package/dist/templates/showcase/pages/images/view.dml +38 -0
  29. package/dist/templates/showcase/pages/index/controller.ts +10 -0
  30. package/dist/templates/showcase/pages/index/state.ts +116 -0
  31. package/dist/templates/showcase/pages/index/view.dml +20 -0
  32. package/dist/templates/showcase/pages/layout/controller.ts +26 -0
  33. package/dist/templates/showcase/pages/layout/state.ts +14 -0
  34. package/dist/templates/showcase/pages/layout/view.dml +80 -0
  35. package/dist/templates/showcase/pages/lists/controller.ts +36 -0
  36. package/dist/templates/showcase/pages/lists/state.ts +96 -0
  37. package/dist/templates/showcase/pages/lists/view.dml +59 -0
  38. package/dist/templates/showcase/pages/navigation/controller.ts +64 -0
  39. package/dist/templates/showcase/pages/navigation/state.ts +17 -0
  40. package/dist/templates/showcase/pages/navigation/view.dml +34 -0
  41. package/dist/templates/showcase/pages/network/controller.ts +107 -0
  42. package/dist/templates/showcase/pages/network/state.ts +15 -0
  43. package/dist/templates/showcase/pages/network/view.dml +56 -0
  44. package/dist/templates/showcase/pages/payments/controller.ts +42 -0
  45. package/dist/templates/showcase/pages/payments/state.ts +10 -0
  46. package/dist/templates/showcase/pages/payments/view.dml +35 -0
  47. package/dist/templates/showcase/pages/state/controller.ts +22 -0
  48. package/dist/templates/showcase/pages/state/state.ts +10 -0
  49. package/dist/templates/showcase/pages/state/view.dml +33 -0
  50. package/dist/templates/showcase/pages/text/controller.ts +10 -0
  51. package/dist/templates/showcase/pages/text/state.ts +7 -0
  52. package/dist/templates/showcase/pages/text/view.dml +49 -0
  53. package/dist/templates/starter/.env +3 -0
  54. package/dist/templates/starter/dot.ts +3 -0
  55. package/dist/templates/starter/pages/index/controller.ts +9 -0
  56. package/dist/templates/starter/pages/index/state.ts +4 -0
  57. package/dist/templates/starter/pages/index/view.dml +16 -0
  58. package/dist/templates/starter/statics/logo.png +0 -0
  59. package/package.json +12 -7
  60. package/dist/template/.env +0 -3
  61. package/dist/template/dot.ts +0 -6
  62. package/dist/template/pages/help/tips/controller.ts +0 -30
  63. package/dist/template/pages/help/tips/state.ts +0 -11
  64. package/dist/template/pages/help/tips/view.dml +0 -15
  65. package/dist/template/pages/index/controller.ts +0 -67
  66. package/dist/template/pages/index/state.ts +0 -17
  67. package/dist/template/pages/index/view.dml +0 -66
  68. /package/dist/{template → templates/showcase}/statics/logo.png +0 -0
@@ -0,0 +1,34 @@
1
+ <View>
2
+ <Text variant="caption" tone="muted">{{ trail }}</Text>
3
+ <Text variant="title">Navigation and hooks</Text>
4
+ <Text>Each page opens on top of the one before it; back returns to the one below. A dot has room for {{ maxDepth }} pages at once.</Text>
5
+
6
+ <View variant="card" gap="small">
7
+ <Text>This is page {{ depth }} of {{ maxDepth }}</Text>
8
+ <View direction="row" wrap gap="small">
9
+ <Button onClick="openAnother" disabled="{{ depth >= maxDepth }}">Open another</Button>
10
+ <Button variant="secondary" onClick="replaceThis">Replace this one</Button>
11
+ <Button variant="secondary" onClick="back">Back</Button>
12
+ <Button variant="secondary" onClick="backTwo" disabled="{{ depth < 3 }}">Back two</Button>
13
+ <Button variant="secondary" onClick="home">Start over</Button>
14
+ </View>
15
+ </View>
16
+
17
+ <Text variant="caption" tone="muted">Dash's bars, which each page sets: this one's title is its number</Text>
18
+ <View variant="card" gap="small">
19
+ <View direction="row" wrap gap="small">
20
+ <Button variant="secondary" onClick="toggleColors">{{ colored ? 'Plain bar' : 'Blue bar' }}</Button>
21
+ <Button variant="secondary" onClick="toggleNavigationBar">{{ navigationBarHidden ? 'Show the navigation bar' : 'Hide the navigation bar' }}</Button>
22
+ <Button variant="secondary" onClick="toggleTabBar">{{ tabBarHidden ? 'Show the tab bar' : 'Hide the tab bar' }}</Button>
23
+ </View>
24
+ <Text variant="caption" tone="muted">Going back to a page shows its bars again, and leaving the dot puts Dash's own back.</Text>
25
+ </View>
26
+
27
+ <Text variant="caption" tone="muted">The hooks this page ran, in order</Text>
28
+ <View variant="card" gap="small">
29
+ <For each="{{ hooks }}" item="run" key="id">
30
+ <Text>{{ run.id }}. {{ run.hook }}</Text>
31
+ </For>
32
+ <Text variant="caption" tone="muted">Open another page and come back: this one runs onHide, then onShow.</Text>
33
+ </View>
34
+ </View>
@@ -0,0 +1,107 @@
1
+ import state from './state';
2
+
3
+ const PICTURE = 'pictures/octocat.png';
4
+
5
+ interface GitHubUser {
6
+ login: string;
7
+ name: string | null;
8
+ followers: number;
9
+ }
10
+
11
+ interface Echo {
12
+ json: unknown;
13
+ files: Record<string, string>;
14
+ }
15
+
16
+ export default definePage({
17
+ initialState: state,
18
+ actions: {
19
+ async fetchZen() {
20
+ try {
21
+ const response = await this.dash.network.http.request({
22
+ url: 'https://api.github.com/zen',
23
+ });
24
+ this.setState({ zen: response.ok ? response.body : `GitHub answered ${response.status}` });
25
+ } catch (error) {
26
+ this.setState({ note: (error as Error).message });
27
+ }
28
+ },
29
+ async fetchProfile() {
30
+ try {
31
+ const { body } = await this.dash.network.http.request<GitHubUser>(
32
+ { url: 'https://api.github.com/users/octocat', as: 'json' },
33
+ { timeout: 10_000 },
34
+ );
35
+ this.setState({
36
+ profile: { login: body.login, name: body.name ?? body.login, followers: body.followers },
37
+ });
38
+ } catch (error) {
39
+ this.setState({ note: (error as Error).message });
40
+ }
41
+ },
42
+ async sendJson() {
43
+ try {
44
+ const { body } = await this.dash.network.http.request<Echo>({
45
+ url: 'https://httpbin.org/post',
46
+ method: 'POST',
47
+ body: { item: 'rice', count: 2 },
48
+ as: 'json',
49
+ });
50
+ this.setState({ echo: JSON.stringify(body.json) });
51
+ } catch (error) {
52
+ this.setState({ note: (error as Error).message });
53
+ }
54
+ },
55
+ async download() {
56
+ try {
57
+ const response = await this.dash.network.http.download({
58
+ url: 'https://avatars.githubusercontent.com/u/583231?s=128',
59
+ name: 'octocat.png',
60
+ });
61
+ if (response.ok) {
62
+ const { id, url, size } = response.file;
63
+ this.setState({ picture: { id, url, size }, kept: false });
64
+ } else {
65
+ this.setState({ note: `GitHub answered ${response.status}` });
66
+ }
67
+ } catch (error) {
68
+ this.setState({ note: (error as Error).message });
69
+ }
70
+ },
71
+ async upload(state) {
72
+ try {
73
+ const { body } = await this.dash.network.http.upload<Echo>({
74
+ url: 'https://httpbin.org/post',
75
+ fields: { title: 'Octocat' },
76
+ files: [{ field: 'picture', file: state.picture.id }],
77
+ as: 'json',
78
+ });
79
+ this.setState({ uploaded: Object.keys(body.files).join(', ') });
80
+ } catch (error) {
81
+ this.setState({ note: (error as Error).message });
82
+ }
83
+ },
84
+ async sharePicture(state) {
85
+ try {
86
+ await this.dash.system.share({ file: state.picture.id });
87
+ } catch (error) {
88
+ this.setState({ note: (error as Error).message });
89
+ }
90
+ },
91
+ async keep(state) {
92
+ try {
93
+ await this.dash.file.save(state.picture.id, PICTURE, { overwrite: true });
94
+ this.setState({ kept: true });
95
+ } catch (error) {
96
+ this.setState({ note: (error as Error).message });
97
+ }
98
+ },
99
+ async tryUnlistedHost() {
100
+ try {
101
+ await this.dash.network.http.request({ url: 'https://example.com' });
102
+ } catch (error) {
103
+ this.setState({ note: (error as Error).message });
104
+ }
105
+ },
106
+ },
107
+ });
@@ -0,0 +1,15 @@
1
+ export interface Profile {
2
+ login: string;
3
+ name: string;
4
+ followers: number;
5
+ }
6
+
7
+ export default {
8
+ zen: '',
9
+ profile: null as Profile | null,
10
+ echo: '',
11
+ picture: { id: '', url: '', size: 0 },
12
+ uploaded: '',
13
+ kept: false,
14
+ note: '',
15
+ };
@@ -0,0 +1,56 @@
1
+ <View>
2
+ <Text variant="title">Network</Text>
3
+ <Text>Dash sends a dot's requests, and only to the hosts its dot.json lists.</Text>
4
+
5
+ <Text variant="caption" tone="muted">A request, read as text</Text>
6
+ <View variant="card" gap="small">
7
+ <Button variant="secondary" onClick="fetchZen">Ask GitHub for wisdom</Button>
8
+ <If condition="{{ zen }}">
9
+ <Text>"{{ zen }}"</Text>
10
+ </If>
11
+ </View>
12
+
13
+ <Text variant="caption" tone="muted">JSON, parsed with as: 'json'</Text>
14
+ <View variant="card" gap="small">
15
+ <View direction="row" wrap gap="small">
16
+ <Button variant="secondary" onClick="fetchProfile">Load a profile</Button>
17
+ <Button variant="secondary" onClick="sendJson">Send JSON</Button>
18
+ </View>
19
+ <If condition="{{ profile }}">
20
+ <Text>{{ profile.name }} (@{{ profile.login }}) has {{ profile.followers }} followers</Text>
21
+ </If>
22
+ <If condition="{{ echo }}">
23
+ <Text>httpbin got {{ echo }}</Text>
24
+ </If>
25
+ </View>
26
+
27
+ <Text variant="caption" tone="muted">Files: download, upload and keep</Text>
28
+ <View variant="card" gap="small">
29
+ <View direction="row" wrap gap="small">
30
+ <Button variant="secondary" onClick="download">Download</Button>
31
+ <Button variant="secondary" onClick="upload" disabled="{{ !picture.id }}">Upload</Button>
32
+ <Button variant="secondary" onClick="sharePicture" disabled="{{ !picture.id }}">Share</Button>
33
+ <Button variant="secondary" onClick="keep" disabled="{{ !picture.id || kept }}">Keep</Button>
34
+ </View>
35
+ <If condition="{{ picture.url }}">
36
+ <View direction="row" align="center" gap="medium">
37
+ <Image src="{{ picture.url }}" alt="Octocat" width="64" height="64" />
38
+ <Text variant="caption" tone="muted">{{ picture.size }} bytes, in a temporary file until the dot closes</Text>
39
+ </View>
40
+ </If>
41
+ <If condition="{{ uploaded }}">
42
+ <Text>httpbin got the file field "{{ uploaded }}"</Text>
43
+ </If>
44
+ <If condition="{{ kept }}">
45
+ <Text>Kept in the dot's own files: see the Files page</Text>
46
+ </If>
47
+ </View>
48
+
49
+ <Text variant="caption" tone="muted">A host dot.json doesn't list</Text>
50
+ <View variant="card" gap="small">
51
+ <Button variant="secondary" onClick="tryUnlistedHost">Reach example.com</Button>
52
+ <If condition="{{ note }}">
53
+ <Text variant="caption" tone="muted">{{ note }}</Text>
54
+ </If>
55
+ </View>
56
+ </View>
@@ -0,0 +1,42 @@
1
+ import state from './state';
2
+
3
+ type Typed = DotEvent<{ value: string }>;
4
+
5
+ // The code this page accepts; a real dot checks it with its server.
6
+ const RIGHT_CODE = '123456';
7
+
8
+ export default definePage({
9
+ initialState: state,
10
+ mutations: {
11
+ setAmount: (_state, event: DotEvent<{ value: number | null }>) => {
12
+ const amount = event.detail.value;
13
+ if (!amount) {
14
+ return { amount, amountText: '', request: '' };
15
+ }
16
+ return {
17
+ amount,
18
+ amountText: groupThousands(amount),
19
+ request: `https://pay.example.com/request?amount=${amount}&currency=SLE`,
20
+ };
21
+ },
22
+ setCode: (_state, event: Typed) => ({ code: event.detail.value, codeError: '' }),
23
+ checkCode: (_state, event: Typed) => {
24
+ if (event.detail.value === RIGHT_CODE) {
25
+ return { verified: true };
26
+ }
27
+ return { code: '', codeError: 'That code is wrong. Try again.' };
28
+ },
29
+ startAgain: () => ({ verified: false, code: '' }),
30
+ setPin: (_state, event: Typed) => ({ pin: event.detail.value }),
31
+ },
32
+ });
33
+
34
+ // 1250000 -> "1,250,000"
35
+ function groupThousands(amount: number): string {
36
+ const digits = String(Math.round(amount));
37
+ const groups: string[] = [];
38
+ for (let end = digits.length; end > 0; end -= 3) {
39
+ groups.unshift(digits.slice(Math.max(0, end - 3), end));
40
+ }
41
+ return groups.join(',');
42
+ }
@@ -0,0 +1,10 @@
1
+ export default {
2
+ amount: null as number | null,
3
+ // The amount with its thousands grouped, and what the QR code asks for.
4
+ amountText: '',
5
+ request: '',
6
+ code: '',
7
+ codeError: '',
8
+ verified: false,
9
+ pin: '',
10
+ };
@@ -0,0 +1,35 @@
1
+ <View>
2
+ <Text variant="title">Payments</Text>
3
+ <Text>Fields for money and codes, and a QR code to be paid with.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="caption" tone="muted">An amount, grouped as it's typed and sent to the page as a number</Text>
7
+ <AmountInput label="Amount to request" currency="Le" value="{{ amount }}" onChange="setAmount" hint="The QR code below asks for it" />
8
+ <View variant="card" align="center" gap="medium">
9
+ <If condition="{{ request }}">
10
+ <QRCode value="{{ request }}" size="180" label="A QR code to pay Le {{ amountText }}" />
11
+ <Text tone="muted">Scan to pay Le {{ amountText }}</Text>
12
+ </If>
13
+ <Else>
14
+ <EmptyState icon="qr-code" title="No amount yet" text="Type an amount above to make a QR code for it." />
15
+ </Else>
16
+ </View>
17
+ </View>
18
+
19
+ <View gap="small">
20
+ <Text variant="caption" tone="muted">A one-time code: type it, paste it, or let the phone fill it in from an SMS</Text>
21
+ <If condition="{{ verified }}">
22
+ <Notice tone="success" title="Code accepted">The payment is confirmed.</Notice>
23
+ <Button variant="secondary" onClick="startAgain">Start again</Button>
24
+ </If>
25
+ <Else>
26
+ <CodeInput label="The code we sent to 076 •••• 21" value="{{ code }}" onChange="setCode" onComplete="checkCode" error="{{ codeError }}" hint="For this page, it's 123456" />
27
+ </Else>
28
+ </View>
29
+
30
+ <View gap="small">
31
+ <Text variant="caption" tone="muted">A PIN, hidden as it's typed</Text>
32
+ <CodeInput label="PIN" length="4" secure value="{{ pin }}" onChange="setPin" />
33
+ <Text tone="muted">{{ pin.length }} of 4 digits</Text>
34
+ </View>
35
+ </View>
@@ -0,0 +1,22 @@
1
+ import state from './state';
2
+
3
+ export default definePage({
4
+ initialState: state,
5
+ mutations: {
6
+ increment: (state) => {
7
+ const count = state.count + 1;
8
+ return { count, taps: [{ id: count }, ...state.taps] };
9
+ },
10
+ reset: () => ({ count: 0, taps: [] }),
11
+ },
12
+ actions: {
13
+ fillUp() {
14
+ while (this.state.count < this.state.limit) {
15
+ this.mutations.increment();
16
+ }
17
+ },
18
+ undo() {
19
+ this.setState((current) => ({ count: current.count - 1, taps: current.taps.slice(1) }));
20
+ },
21
+ },
22
+ });
@@ -0,0 +1,10 @@
1
+ export interface Tap {
2
+ id: number;
3
+ }
4
+
5
+ export default {
6
+ title: 'taps',
7
+ count: 0,
8
+ limit: 5,
9
+ taps: [] as Tap[],
10
+ };
@@ -0,0 +1,33 @@
1
+ <View>
2
+ <Text variant="title">State, mutations and actions</Text>
3
+ <Text>The page's state lives in the controller. A mutation turns an event into new state; an action can run several, or wait for Dash.</Text>
4
+
5
+ <View variant="card" gap="small">
6
+ <Text variant="title">{{ count }} of {{ limit }} {{ title }}</Text>
7
+ <If condition="{{ count >= limit }}">
8
+ <Text>That's the limit</Text>
9
+ </If>
10
+ <ElseIf condition="{{ count > 0 }}">
11
+ <Text>{{ limit - count }} to go</Text>
12
+ </ElseIf>
13
+ <Else>
14
+ <Text>Tap Add one to start</Text>
15
+ </Else>
16
+ <View direction="row" wrap gap="small">
17
+ <Button onClick="increment" disabled="{{ count >= limit }}">Add one</Button>
18
+ <Button variant="secondary" onClick="fillUp" disabled="{{ count >= limit }}">Fill up</Button>
19
+ <Button variant="secondary" onClick="undo" disabled="{{ count === 0 }}">Undo</Button>
20
+ <Button variant="secondary" onClick="reset" disabled="{{ count === 0 }}">Reset</Button>
21
+ </View>
22
+ </View>
23
+
24
+ <Text variant="caption" tone="muted">Each tap, newest first</Text>
25
+ <View variant="card" gap="small">
26
+ <For each="{{ taps }}" index="position" item="tap" key="id">
27
+ <Text>{{ position + 1 }}. Tap #{{ tap.id }}</Text>
28
+ </For>
29
+ <If condition="{{ taps.length === 0 }}">
30
+ <Text variant="caption" tone="muted">No taps yet</Text>
31
+ </If>
32
+ </View>
33
+ </View>
@@ -0,0 +1,10 @@
1
+ import state from './state';
2
+
3
+ export default definePage({
4
+ initialState: state,
5
+ mutations: {
6
+ addOne: (state) => ({ quantity: state.quantity + 1 }),
7
+ removeOne: (state) => ({ quantity: Math.max(0, state.quantity - 1) }),
8
+ toggleNickname: (state) => ({ nickname: state.nickname === null ? 'Countess' : null }),
9
+ },
10
+ });
@@ -0,0 +1,7 @@
1
+ export default {
2
+ name: 'Ada',
3
+ nickname: null as string | null,
4
+ price: 2.5,
5
+ quantity: 4,
6
+ tags: ['fast', 'small', 'typed'],
7
+ };
@@ -0,0 +1,49 @@
1
+ <View>
2
+ <Text variant="title">Text and bindings</Text>
3
+
4
+ <View variant="card" gap="small">
5
+ <Text variant="title">A title</Text>
6
+ <Text>Body text, the default</Text>
7
+ <Text variant="caption" tone="muted">A caption</Text>
8
+ <Text>Text can hold{{ ' ' }}<Text variant="title">bigger</Text>{{ ' ' }}and{{ ' ' }}<Text variant="caption" tone="muted">smaller</Text>{{ ' ' }}words.</Text>
9
+ </View>
10
+
11
+ <Text variant="caption" tone="muted">Tones, weights and alignment</Text>
12
+ <View variant="card" gap="small">
13
+ <View direction="row" wrap gap="medium">
14
+ <Text tone="muted">muted</Text>
15
+ <Text tone="info">info</Text>
16
+ <Text tone="success">success</Text>
17
+ <Text tone="warning">warning</Text>
18
+ <Text tone="danger">danger</Text>
19
+ </View>
20
+ <View direction="row" gap="medium">
21
+ <Text weight="regular">regular</Text>
22
+ <Text weight="medium">medium</Text>
23
+ <Text weight="bold">bold</Text>
24
+ </View>
25
+ <Text align="center">In the center</Text>
26
+ <Text align="end">At the end</Text>
27
+ <Text maxLines="2">A long description is cut off after the lines you allow, so a list of them stays tidy however much each one says about itself.</Text>
28
+ </View>
29
+
30
+ <Text variant="caption" tone="muted">Bindings put state into the view</Text>
31
+ <View variant="card" gap="small">
32
+ <Text>Hello, {{ name }}</Text>
33
+ <Text>{{ quantity }} {{ quantity === 1 ? 'item' : 'items' }} at {{ price }} each: {{ quantity * price }}</Text>
34
+ <Text>Nickname: {{ nickname ?? 'none yet' }}</Text>
35
+ <Text>{{ tags.length }} tags, the first is "{{ tags[0] }}"</Text>
36
+ <View direction="row" wrap gap="small">
37
+ <Button variant="secondary" onClick="addOne">Add one</Button>
38
+ <Button variant="secondary" onClick="removeOne" disabled="{{ quantity === 0 }}">Remove one</Button>
39
+ <Button variant="secondary" onClick="toggleNickname">{{ nickname === null ? 'Give a nickname' : 'Drop the nickname' }}</Button>
40
+ </View>
41
+ </View>
42
+
43
+ <Text variant="caption" tone="muted">A list, one line per item</Text>
44
+ <View variant="card" gap="small">
45
+ <For each="{{ tags }}" item="tag" index="position" key="*this">
46
+ <Text>{{ position + 1 }}. {{ tag }}</Text>
47
+ </For>
48
+ </View>
49
+ </View>
@@ -0,0 +1,3 @@
1
+ # Public configuration for the dot. Anyone with the dot can read these variables: never put a
2
+ # secret here. Read them in the service as `env.GREETING`.
3
+ GREETING=Hello from your dot
@@ -0,0 +1,3 @@
1
+ export default defineDot({
2
+ pages: ['index'],
3
+ });
@@ -0,0 +1,9 @@
1
+ import state from './state';
2
+
3
+ export default definePage({
4
+ initialState: state,
5
+ mutations: {
6
+ increment: (state) => ({ count: state.count + 1 }),
7
+ reset: () => ({ count: 0 }),
8
+ },
9
+ });
@@ -0,0 +1,4 @@
1
+ export default {
2
+ greeting: env.GREETING,
3
+ count: 0,
4
+ };
@@ -0,0 +1,16 @@
1
+ <View>
2
+ <View direction="row" align="center" gap="medium">
3
+ <Image src="statics/logo.png" alt="Logo" width="40" height="40" />
4
+ <Text variant="title">{{ greeting }}</Text>
5
+ </View>
6
+ <Text>Change pages/index/view.dml and save: the simulator shows it at once.</Text>
7
+
8
+ <View variant="card" align="center" gap="medium">
9
+ <Text variant="title">{{ count }}</Text>
10
+ <Text tone="muted">{{ count === 1 ? 'tap' : 'taps' }} so far</Text>
11
+ <View direction="row" gap="small">
12
+ <Button variant="secondary" onClick="reset" disabled="{{ count === 0 }}">Reset</Button>
13
+ <Button onClick="increment">Tap me</Button>
14
+ </View>
15
+ </View>
16
+ </View>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monimesl/dot-cli",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "The dotctl command: build mini apps and run them in the simulator",
5
5
  "type": "module",
6
6
  "repository": {
@@ -22,18 +22,23 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "dependencies": {
25
- "@monimesl/dot-dml-parser": "0.1.0-alpha.2",
26
- "@monimesl/dot-script-parser": "0.1.0-alpha.2",
27
- "@monimesl/dot-compiler": "0.1.0-alpha.2",
28
- "@monimesl/dot-simulator": "0.1.0-alpha.2"
25
+ "typescript": "^5.9.3",
26
+ "uqr": "^0.1.3",
27
+ "@monimesl/dot-compiler": "0.1.0-alpha.4",
28
+ "@monimesl/dot-core": "0.1.0-alpha.4",
29
+ "@monimesl/dot-dml-parser": "0.1.0-alpha.4",
30
+ "@monimesl/dot-script-parser": "0.1.0-alpha.4",
31
+ "@monimesl/dot-simulator": "0.1.0-alpha.4"
29
32
  },
30
33
  "devDependencies": {
31
34
  "@types/node": "^22.20.4",
32
35
  "publint": "^0.3.24",
33
36
  "rimraf": "^6.1.3",
34
37
  "tsdown": "^0.23.0",
35
- "typescript": "^5.9.3",
36
- "vitest": "^5.0.1"
38
+ "vitest": "^5.0.1",
39
+ "vscode-languageserver": "^9.0.1",
40
+ "vscode-languageserver-protocol": "^3.17.5",
41
+ "vscode-languageserver-textdocument": "^1.0.15"
37
42
  },
38
43
  "publishConfig": {
39
44
  "access": "public"
@@ -1,3 +0,0 @@
1
- # Public configuration for the dot. Only DOT_PUBLIC_ variables reach it, and anyone with the dot
2
- # can read them: never put a secret here. Read them in the service as `env.DOT_PUBLIC_…`.
3
- DOT_PUBLIC_GREETING=Dash draws this alert, not the dot.
@@ -1,6 +0,0 @@
1
- import { logger } from '@monimesl/dot-runtime';
2
-
3
- export default defineDot({
4
- pages: ['index', 'help/tips'],
5
- plugins: [logger()],
6
- });
@@ -1,30 +0,0 @@
1
- import state from './state';
2
-
3
- export default definePage({
4
- initialState: state,
5
- hooks: {
6
- // The page that opens this one passes its own trail and depth.
7
- onLoad(options) {
8
- this.setState({
9
- count: Number(options.count ?? 0),
10
- trail: `${options.trail ?? 'Home'} › Tips`,
11
- depth: Number(options.depth ?? 1) + 1,
12
- });
13
- },
14
- },
15
- actions: {
16
- back() {
17
- this.navigation.back();
18
- },
19
- openAnother(state) {
20
- this.navigation.push('help/tips', {
21
- count: String(state.count),
22
- trail: state.trail,
23
- depth: String(state.depth),
24
- });
25
- },
26
- startOver() {
27
- this.navigation.reset('index');
28
- },
29
- },
30
- });
@@ -1,11 +0,0 @@
1
- export default {
2
- count: 0,
3
- trail: '',
4
- depth: 0,
5
- maxPages: 8,
6
- tips: [
7
- 'Every tap is handled by controller.ts in a Worker',
8
- 'The view only renders the state it receives',
9
- 'Pages open on top of each other; Back returns to the one below',
10
- ],
11
- };
@@ -1,15 +0,0 @@
1
- <Text variant="caption">{{ trail }}</Text>
2
- <Text variant="title">Tips</Text>
3
- <Text>Page {{ depth }} of {{ maxPages }}, opened at {{ count }} taps.</Text>
4
-
5
- <View variant="card" gap="small">
6
- <For each="{{ tips }}" item="tip" key="*this">
7
- <Text>{{ tip }}</Text>
8
- </For>
9
- </View>
10
-
11
- <View direction="row">
12
- <Button onClick="back">Back</Button>
13
- <Button variant="secondary" onClick="openAnother" disabled="{{ depth >= maxPages }}">Open another</Button>
14
- <Button variant="secondary" onClick="startOver">Start over</Button>
15
- </View>