@monimesl/dot-cli 0.1.0-alpha.9 → 1.0.0-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/README.md +72 -59
- package/dist/cli.js +539 -341
- package/dist/cli.js.map +1 -1
- package/dist/{server-BfPAnsSf.js → server-DMnWDdJ6.js} +570 -478
- package/dist/server-DMnWDdJ6.js.map +1 -0
- package/dist/templates/showcase/dot.ts +53 -16
- package/dist/templates/showcase/pages/basics/bars/controller.ts +47 -0
- package/dist/templates/showcase/pages/basics/bars/state.ts +7 -0
- package/dist/templates/showcase/pages/basics/bars/view.dml +36 -0
- package/dist/templates/showcase/pages/{text → basics/bindings}/controller.ts +5 -0
- package/dist/templates/showcase/pages/basics/bindings/state.ts +14 -0
- package/dist/templates/showcase/pages/basics/bindings/view.dml +41 -0
- package/dist/templates/showcase/pages/basics/colors/controller.ts +112 -0
- package/dist/templates/showcase/pages/basics/colors/palette.ts +52 -0
- package/dist/templates/showcase/pages/basics/colors/state.ts +17 -0
- package/dist/templates/showcase/pages/basics/colors/view.dml +142 -0
- package/dist/templates/showcase/pages/basics/concert/controller.ts +16 -0
- package/dist/templates/showcase/pages/basics/concert/state.ts +7 -0
- package/dist/templates/showcase/pages/basics/concert/view.dml +20 -0
- package/dist/templates/showcase/pages/basics/control-flow/controller.ts +18 -0
- package/dist/templates/showcase/pages/basics/control-flow/state.ts +16 -0
- package/dist/templates/showcase/pages/basics/control-flow/view.dml +55 -0
- package/dist/templates/showcase/pages/basics/events/controller.ts +43 -0
- package/dist/templates/showcase/pages/basics/events/state.ts +11 -0
- package/dist/templates/showcase/pages/basics/events/view.dml +51 -0
- package/dist/templates/showcase/pages/basics/hooks/controller.ts +43 -0
- package/dist/templates/showcase/pages/basics/hooks/state.ts +10 -0
- package/dist/templates/showcase/pages/basics/hooks/view.dml +37 -0
- package/dist/templates/showcase/pages/basics/navigation/controller.ts +41 -0
- package/dist/templates/showcase/pages/basics/navigation/state.ts +11 -0
- package/dist/templates/showcase/pages/basics/navigation/view.dml +48 -0
- package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +18 -0
- package/dist/templates/showcase/pages/basics/pick-genre/state.ts +3 -0
- package/dist/templates/showcase/pages/basics/pick-genre/view.dml +10 -0
- package/dist/templates/showcase/pages/basics/share/concerts.ts +31 -0
- package/dist/templates/showcase/pages/basics/share/controller.ts +12 -0
- package/dist/templates/showcase/pages/basics/share/state.ts +5 -0
- package/dist/templates/showcase/pages/basics/share/view.dml +21 -0
- package/dist/templates/showcase/pages/{state → basics/state}/controller.ts +1 -0
- package/dist/templates/showcase/pages/basics/state/view.dml +46 -0
- package/dist/templates/showcase/pages/{carousel → components/carousel}/controller.ts +2 -1
- package/dist/templates/showcase/pages/{carousel → components/carousel}/state.ts +5 -5
- package/dist/templates/showcase/pages/{carousel → components/carousel}/view.dml +7 -5
- package/dist/templates/showcase/pages/{feedback → components/feedback}/controller.ts +13 -2
- package/dist/templates/showcase/pages/components/feedback/state.ts +41 -0
- package/dist/templates/showcase/pages/{feedback → components/feedback}/view.dml +38 -9
- package/dist/templates/showcase/pages/{forms → components/forms}/controller.ts +23 -19
- package/dist/templates/showcase/pages/{forms → components/forms}/state.ts +6 -3
- package/dist/templates/showcase/pages/components/forms/view.dml +97 -0
- package/dist/templates/showcase/pages/components/icons/controller.ts +15 -0
- package/dist/templates/showcase/pages/components/icons/state.ts +75 -0
- package/dist/templates/showcase/pages/components/icons/view.dml +36 -0
- package/dist/templates/showcase/pages/{images → components/images}/controller.ts +4 -1
- package/dist/templates/showcase/pages/components/images/view.dml +83 -0
- package/dist/templates/showcase/pages/{layout → components/layout}/controller.ts +3 -2
- package/dist/templates/showcase/pages/components/layout/view.dml +143 -0
- package/dist/templates/showcase/pages/components/lists/controller.ts +18 -0
- package/dist/templates/showcase/pages/{lists → components/lists}/state.ts +43 -30
- package/dist/templates/showcase/pages/components/lists/view.dml +88 -0
- package/dist/templates/showcase/pages/{payments → components/money}/controller.ts +7 -8
- package/dist/templates/showcase/pages/components/money/view.dml +54 -0
- package/dist/templates/showcase/pages/components/reading/controller.ts +6 -0
- package/dist/templates/showcase/pages/components/reading/state.ts +23 -0
- package/dist/templates/showcase/pages/components/reading/view.dml +42 -0
- package/dist/templates/showcase/pages/{lists → components/sheets}/controller.ts +10 -11
- package/dist/templates/showcase/pages/components/sheets/state.ts +26 -0
- package/dist/templates/showcase/pages/components/sheets/view.dml +38 -0
- package/dist/templates/showcase/pages/components/styles/controller.ts +6 -0
- package/dist/templates/showcase/pages/components/styles/state.ts +3 -0
- package/dist/templates/showcase/pages/components/styles/view.dml +101 -0
- package/dist/templates/showcase/pages/components/tabs/controller.ts +41 -0
- package/dist/templates/showcase/pages/{filters → components/tabs}/state.ts +32 -23
- package/dist/templates/showcase/pages/components/tabs/view.dml +57 -0
- package/dist/templates/showcase/pages/components/text/controller.ts +10 -0
- package/dist/templates/showcase/pages/components/text/state.ts +3 -0
- package/dist/templates/showcase/pages/components/text/view.dml +95 -0
- package/dist/templates/showcase/pages/dash/account/controller.ts +32 -0
- package/dist/templates/showcase/pages/dash/account/state.ts +9 -0
- package/dist/templates/showcase/pages/dash/account/view.dml +33 -0
- package/dist/templates/showcase/pages/{cache → dash/cache}/controller.ts +9 -4
- package/dist/templates/showcase/pages/dash/cache/view.dml +48 -0
- package/dist/templates/showcase/pages/dash/calls/controller.ts +67 -0
- package/dist/templates/showcase/pages/dash/calls/state.ts +9 -0
- package/dist/templates/showcase/pages/dash/calls/view.dml +69 -0
- package/dist/templates/showcase/pages/dash/contacts/controller.ts +30 -0
- package/dist/templates/showcase/pages/dash/contacts/state.ts +6 -0
- package/dist/templates/showcase/pages/dash/contacts/view.dml +33 -0
- package/dist/templates/showcase/pages/dash/crypto/controller.ts +38 -0
- package/dist/templates/showcase/pages/dash/crypto/state.ts +10 -0
- package/dist/templates/showcase/pages/dash/crypto/view.dml +48 -0
- package/dist/templates/showcase/pages/{files → dash/files}/controller.ts +7 -2
- package/dist/templates/showcase/pages/{files → dash/files}/state.ts +4 -0
- package/dist/templates/showcase/pages/dash/files/view.dml +78 -0
- package/dist/templates/showcase/pages/dash/media/controller.ts +65 -0
- package/dist/templates/showcase/pages/dash/media/state.ts +12 -0
- package/dist/templates/showcase/pages/dash/media/view.dml +53 -0
- package/dist/templates/showcase/pages/{network → dash/network}/controller.ts +84 -20
- package/dist/templates/showcase/pages/{network → dash/network}/state.ts +14 -1
- package/dist/templates/showcase/pages/dash/network/view.dml +108 -0
- package/dist/templates/showcase/pages/dash/payments/cases.ts +445 -0
- package/dist/templates/showcase/pages/dash/payments/controller.ts +149 -0
- package/dist/templates/showcase/pages/dash/payments/state.ts +33 -0
- package/dist/templates/showcase/pages/dash/payments/view.dml +71 -0
- package/dist/templates/showcase/pages/{secrets → dash/secrets}/controller.ts +2 -1
- package/dist/templates/showcase/pages/dash/secrets/view.dml +26 -0
- package/dist/templates/showcase/pages/dash/system/controller.ts +89 -0
- package/dist/templates/showcase/pages/dash/system/state.ts +13 -0
- package/dist/templates/showcase/pages/dash/system/view.dml +96 -0
- package/dist/templates/showcase/pages/dash/ui/controller.ts +70 -0
- package/dist/templates/showcase/pages/dash/ui/state.ts +8 -0
- package/dist/templates/showcase/pages/dash/ui/view.dml +31 -0
- package/dist/templates/showcase/pages/index/controller.ts +1 -1
- package/dist/templates/showcase/pages/index/state.ts +175 -60
- package/dist/templates/showcase/pages/index/view.dml +6 -3
- package/package.json +6 -6
- package/dist/server-BfPAnsSf.js.map +0 -1
- package/dist/templates/showcase/pages/cache/view.dml +0 -36
- package/dist/templates/showcase/pages/device/controller.ts +0 -80
- package/dist/templates/showcase/pages/device/state.ts +0 -7
- package/dist/templates/showcase/pages/device/view.dml +0 -49
- package/dist/templates/showcase/pages/feedback/state.ts +0 -8
- package/dist/templates/showcase/pages/files/view.dml +0 -50
- package/dist/templates/showcase/pages/filters/controller.ts +0 -27
- package/dist/templates/showcase/pages/filters/view.dml +0 -44
- package/dist/templates/showcase/pages/forms/view.dml +0 -49
- package/dist/templates/showcase/pages/images/view.dml +0 -53
- package/dist/templates/showcase/pages/layout/view.dml +0 -103
- package/dist/templates/showcase/pages/lists/view.dml +0 -59
- package/dist/templates/showcase/pages/navigation/controller.ts +0 -65
- package/dist/templates/showcase/pages/navigation/state.ts +0 -17
- package/dist/templates/showcase/pages/navigation/view.dml +0 -34
- package/dist/templates/showcase/pages/network/view.dml +0 -67
- package/dist/templates/showcase/pages/payments/view.dml +0 -45
- package/dist/templates/showcase/pages/secrets/view.dml +0 -24
- package/dist/templates/showcase/pages/state/view.dml +0 -33
- package/dist/templates/showcase/pages/text/state.ts +0 -8
- package/dist/templates/showcase/pages/text/view.dml +0 -58
- /package/dist/templates/showcase/pages/{state → basics/state}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{images → components/images}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{layout → components/layout}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{payments → components/money}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{cache → dash/cache}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{secrets → dash/secrets}/state.ts +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface Show {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
city: string;
|
|
5
|
+
left: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
shows: [
|
|
10
|
+
{ id: 'freetown', title: 'Salone Sounds Live', city: 'Freetown', left: 120 },
|
|
11
|
+
{ id: 'bo', title: 'Palm-wine evening', city: 'Bo', left: 6 },
|
|
12
|
+
{ id: 'kenema', title: 'Gospel night', city: 'Kenema', left: 1 },
|
|
13
|
+
] as Show[],
|
|
14
|
+
genres: ['Palm-wine', 'Gumbe', 'Milo jazz', 'Afropop', 'Kriofusion'],
|
|
15
|
+
signedIn: false,
|
|
16
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">If and For</Text>
|
|
3
|
+
<Text>If shows a part of the view only when its condition is true. For shows a part once for each item of a list.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="subtitle">If and Else</Text>
|
|
7
|
+
<Text variant="caption" tone="muted">Else shows when the If before it doesn't.</Text>
|
|
8
|
+
<View variant="card" gap="small">
|
|
9
|
+
<If condition="{{ signedIn }}">
|
|
10
|
+
<Text>Welcome back, Mariama</Text>
|
|
11
|
+
</If>
|
|
12
|
+
<Else>
|
|
13
|
+
<Text tone="muted">You're not signed in</Text>
|
|
14
|
+
</Else>
|
|
15
|
+
<Button variant="secondary" onClick="toggleSignedIn">{{ signedIn ? 'Sign out' : 'Sign in' }}</Button>
|
|
16
|
+
</View>
|
|
17
|
+
</View>
|
|
18
|
+
|
|
19
|
+
<View gap="small">
|
|
20
|
+
<Text variant="subtitle">For, with ElseIf inside</Text>
|
|
21
|
+
<Text variant="caption" tone="muted">item names each show. key gives each a lasting id, so its row stays the same row when the list changes. ElseIf checks another condition when the one above is false.</Text>
|
|
22
|
+
<View variant="card" gap="medium">
|
|
23
|
+
<For each="{{ shows }}" item="show" key="id">
|
|
24
|
+
<View direction="row" align="center" gap="small">
|
|
25
|
+
<View grow gap="none">
|
|
26
|
+
<Text weight="medium">{{ show.title }}</Text>
|
|
27
|
+
<Text variant="caption" tone="muted">{{ show.city }}</Text>
|
|
28
|
+
</View>
|
|
29
|
+
<If condition="{{ show.left === 0 }}">
|
|
30
|
+
<Badge tone="danger">Sold out</Badge>
|
|
31
|
+
</If>
|
|
32
|
+
<ElseIf condition="{{ show.left < 10 }}">
|
|
33
|
+
<Badge tone="warning">{{ show.left }} left</Badge>
|
|
34
|
+
</ElseIf>
|
|
35
|
+
<Else>
|
|
36
|
+
<Badge tone="success">On sale</Badge>
|
|
37
|
+
</Else>
|
|
38
|
+
<Button variant="secondary" data-id="{{ show.id }}" onClick="sell" disabled="{{ show.left === 0 }}">Sell 5</Button>
|
|
39
|
+
</View>
|
|
40
|
+
</For>
|
|
41
|
+
<Button variant="secondary" onClick="restock">Restock every show</Button>
|
|
42
|
+
</View>
|
|
43
|
+
</View>
|
|
44
|
+
|
|
45
|
+
<View gap="small">
|
|
46
|
+
<Text variant="subtitle">For with index</Text>
|
|
47
|
+
<Text variant="caption" tone="muted">index counts from 0. A list of plain text has no id, so key="*this" uses the text itself.</Text>
|
|
48
|
+
<View variant="card" gap="small">
|
|
49
|
+
<For each="{{ genres }}" item="genre" index="position" key="*this">
|
|
50
|
+
<Text>{{ position + 1 }}. {{ genre }}</Text>
|
|
51
|
+
</For>
|
|
52
|
+
<Button variant="secondary" onClick="shuffle">Move the first to the end</Button>
|
|
53
|
+
</View>
|
|
54
|
+
</View>
|
|
55
|
+
</View>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
// What each handler below shows of its event.
|
|
4
|
+
function describe(handler: string, event: DotEvent) {
|
|
5
|
+
return {
|
|
6
|
+
handler,
|
|
7
|
+
type: event.type,
|
|
8
|
+
detail: JSON.stringify(event.detail),
|
|
9
|
+
data: JSON.stringify(event.data),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default definePage({
|
|
14
|
+
initialState: state,
|
|
15
|
+
configs: { navigationBar: { title: 'Events' } },
|
|
16
|
+
mutations: {
|
|
17
|
+
// No detail: a tap is all there is to know.
|
|
18
|
+
countTap: (state, event: DotEvent) => ({
|
|
19
|
+
taps: state.taps + 1,
|
|
20
|
+
...describe('countTap', event),
|
|
21
|
+
}),
|
|
22
|
+
// `detail` is what the component sends: text for an Input...
|
|
23
|
+
setSong: (_state, event: ValueEvent) => ({
|
|
24
|
+
song: event.detail.value,
|
|
25
|
+
...describe('setSong', event),
|
|
26
|
+
}),
|
|
27
|
+
// ...a number for a Slider...
|
|
28
|
+
setVolume: (_state, event: ValueEvent<number>) => ({
|
|
29
|
+
volume: event.detail.value,
|
|
30
|
+
...describe('setVolume', event),
|
|
31
|
+
}),
|
|
32
|
+
// ...and checked for a Switch.
|
|
33
|
+
setLoud: (_state, event: CheckedEvent) => ({
|
|
34
|
+
loud: event.detail.checked,
|
|
35
|
+
...describe('setLoud', event),
|
|
36
|
+
}),
|
|
37
|
+
// `data` holds the element's data- attributes, as text.
|
|
38
|
+
play: (_state, event: DataEvent<{ artist: string; year: string }>) => ({
|
|
39
|
+
song: `${event.data.artist}, ${event.data.year}`,
|
|
40
|
+
...describe('play', event),
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Events</Text>
|
|
3
|
+
<Text>An attribute such as onClick or onChange names the handler to run. The handler gets the state and the event.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="subtitle">The last event</Text>
|
|
7
|
+
<View variant="card" gap="none">
|
|
8
|
+
<If condition="{{ handler }}">
|
|
9
|
+
<DetailRow label="Handler" value="{{ handler }}" />
|
|
10
|
+
<DetailRow label="event.type" value="{{ type }}" />
|
|
11
|
+
<DetailRow label="event.detail" value="{{ detail }}" />
|
|
12
|
+
<DetailRow label="event.data" value="{{ data }}" />
|
|
13
|
+
</If>
|
|
14
|
+
<Else>
|
|
15
|
+
<Text tone="muted">Use anything below to see its event here.</Text>
|
|
16
|
+
</Else>
|
|
17
|
+
</View>
|
|
18
|
+
</View>
|
|
19
|
+
|
|
20
|
+
<View gap="small">
|
|
21
|
+
<Text variant="subtitle">Taps</Text>
|
|
22
|
+
<Text variant="caption" tone="muted">Button raises click. View, ListItem, Link and Chip raise tap.</Text>
|
|
23
|
+
<View variant="card" direction="row" align="center" gap="small">
|
|
24
|
+
<Button variant="secondary" onClick="countTap">Tap me</Button>
|
|
25
|
+
<View variant="card" grow onTap="countTap">
|
|
26
|
+
<Text>Or tap this box</Text>
|
|
27
|
+
</View>
|
|
28
|
+
<Text numeric>{{ taps }}</Text>
|
|
29
|
+
</View>
|
|
30
|
+
</View>
|
|
31
|
+
|
|
32
|
+
<View gap="small">
|
|
33
|
+
<Text variant="subtitle">event.detail</Text>
|
|
34
|
+
<Text variant="caption" tone="muted">What the component sends, such as the text typed or the switch's new state. In the controller, type the event as ValueEvent, CheckedEvent or IndexEvent.</Text>
|
|
35
|
+
<View variant="card">
|
|
36
|
+
<Input label="Song" placeholder="Exodus" value="{{ song }}" onChange="setSong" />
|
|
37
|
+
<Slider label="Volume" min="0" max="10" showValue value="{{ volume }}" onChange="setVolume" />
|
|
38
|
+
<Switch label="Loud" checked="{{ loud }}" onChange="setLoud" />
|
|
39
|
+
</View>
|
|
40
|
+
</View>
|
|
41
|
+
|
|
42
|
+
<View gap="small">
|
|
43
|
+
<Text variant="subtitle">event.data</Text>
|
|
44
|
+
<Text variant="caption" tone="muted">The data- attributes of the element, such as data-artist. They tell one handler which item was used. Their values arrive as text. In the controller, type the event as DataEvent.</Text>
|
|
45
|
+
<View variant="card" direction="row" wrap gap="small">
|
|
46
|
+
<Button variant="secondary" data-artist="Drizilik" data-year="2021" onClick="play">Exodus</Button>
|
|
47
|
+
<Button variant="secondary" data-artist="ApreeL" data-year="2025" onClick="play">Control</Button>
|
|
48
|
+
<Button variant="secondary" data-artist="Emmerson" data-year="2004" onClick="play">Borbor Bele</Button>
|
|
49
|
+
</View>
|
|
50
|
+
</View>
|
|
51
|
+
</View>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { HookRun } from './state';
|
|
2
|
+
import state from './state';
|
|
3
|
+
|
|
4
|
+
// Outside the page, so it outlives each copy of it while the dot runs.
|
|
5
|
+
let lastClosed = '';
|
|
6
|
+
|
|
7
|
+
function ran(runs: readonly HookRun[], hook: string): HookRun[] {
|
|
8
|
+
return [...runs, { id: runs.length + 1, hook }];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default definePage({
|
|
12
|
+
initialState: state,
|
|
13
|
+
configs: { navigationBar: { title: 'Page hooks' } },
|
|
14
|
+
hooks: {
|
|
15
|
+
// Runs once, when the page opens, with the options it opened with.
|
|
16
|
+
onLoad(options) {
|
|
17
|
+
this.setState({ lastClosed, runs: ran([], `onLoad ${JSON.stringify(options)}`) });
|
|
18
|
+
},
|
|
19
|
+
// Runs each time the page comes into view: after onLoad, and when a page above it closes.
|
|
20
|
+
onShow() {
|
|
21
|
+
this.setState((current) => ({ runs: ran(current.runs, 'onShow') }));
|
|
22
|
+
},
|
|
23
|
+
// Runs when another page opens on top, or the dot goes into the background.
|
|
24
|
+
onHide() {
|
|
25
|
+
this.setState((current) => ({ runs: ran(current.runs, 'onHide') }));
|
|
26
|
+
},
|
|
27
|
+
// Runs once, when the page closes. Its state goes with it.
|
|
28
|
+
onUnload() {
|
|
29
|
+
lastClosed = new Date().toLocaleTimeString('en-GB');
|
|
30
|
+
},
|
|
31
|
+
// Runs when the person pulls the page down from its top. The spinner shows until it finishes,
|
|
32
|
+
// here after a second, as a real page would wait for its server.
|
|
33
|
+
async onRefresh() {
|
|
34
|
+
await this.dash.system.delay(1000);
|
|
35
|
+
this.setState((current) => ({ runs: ran(current.runs, 'onRefresh') }));
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
actions: {
|
|
39
|
+
openAnother() {
|
|
40
|
+
this.navigation.push('basics/state');
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Page hooks</Text>
|
|
3
|
+
<Text>Hooks run at points in a page's life, such as when it opens. Use them to load data or to save it.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="subtitle">The hooks this page ran, in order</Text>
|
|
7
|
+
<View variant="card" gap="small">
|
|
8
|
+
<For each="{{ runs }}" item="run" key="id">
|
|
9
|
+
<Text>{{ run.id }}. {{ run.hook }}</Text>
|
|
10
|
+
</For>
|
|
11
|
+
</View>
|
|
12
|
+
<Text variant="caption" tone="muted">Open another page, then come back: this page runs onHide, then onShow.</Text>
|
|
13
|
+
<Button variant="secondary" onClick="openAnother">Open another page</Button>
|
|
14
|
+
</View>
|
|
15
|
+
|
|
16
|
+
<View gap="small">
|
|
17
|
+
<Text variant="subtitle">onRefresh</Text>
|
|
18
|
+
<Text variant="caption" tone="muted">Pull this page down from its top, then let go. Only a page with onRefresh can be pulled, and its spinner shows until the hook finishes.</Text>
|
|
19
|
+
</View>
|
|
20
|
+
|
|
21
|
+
<View gap="small">
|
|
22
|
+
<Text variant="subtitle">onUnload</Text>
|
|
23
|
+
<View variant="card">
|
|
24
|
+
<If condition="{{ lastClosed }}">
|
|
25
|
+
<Text>This page last closed at {{ lastClosed }}</Text>
|
|
26
|
+
</If>
|
|
27
|
+
<Else>
|
|
28
|
+
<Text tone="muted">Go back, then open this page again. It says when it closed.</Text>
|
|
29
|
+
</Else>
|
|
30
|
+
</View>
|
|
31
|
+
</View>
|
|
32
|
+
|
|
33
|
+
<View gap="small">
|
|
34
|
+
<Text variant="subtitle">The dot's hooks</Text>
|
|
35
|
+
<Text variant="caption" tone="muted">dot.ts can have hooks too: onLaunch runs once when the dot starts, and onError gets any error a page doesn't catch.</Text>
|
|
36
|
+
</View>
|
|
37
|
+
</View>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
export default definePage({
|
|
4
|
+
initialState: state,
|
|
5
|
+
configs: { navigationBar: { title: 'Navigation' } },
|
|
6
|
+
hooks: {
|
|
7
|
+
// Options come from the page that opened this one, as text.
|
|
8
|
+
onLoad(options) {
|
|
9
|
+
const depth = Number(options.depth ?? '1') + 1;
|
|
10
|
+
const from = options.trail ?? 'Home';
|
|
11
|
+
this.setState({ depth, from, trail: `${from} › ${depth}`, options: JSON.stringify(options) });
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
actions: {
|
|
15
|
+
openAnother(state) {
|
|
16
|
+
this.navigation.push('basics/navigation', { depth: String(state.depth), trail: state.trail });
|
|
17
|
+
},
|
|
18
|
+
replaceThis(state) {
|
|
19
|
+
this.navigation.replace('basics/navigation', {
|
|
20
|
+
depth: String(state.depth - 1),
|
|
21
|
+
trail: state.from,
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
back() {
|
|
25
|
+
this.navigation.back();
|
|
26
|
+
},
|
|
27
|
+
backTwo() {
|
|
28
|
+
this.navigation.back(2);
|
|
29
|
+
},
|
|
30
|
+
home() {
|
|
31
|
+
this.navigation.reset('index');
|
|
32
|
+
},
|
|
33
|
+
async chooseGenre() {
|
|
34
|
+
const genre = await this.navigation.pushForResult<string>('basics/pick-genre');
|
|
35
|
+
// Undefined when the person went back without choosing.
|
|
36
|
+
if (genre) {
|
|
37
|
+
this.setState({ genre });
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="caption" tone="muted">{{ trail }}</Text>
|
|
3
|
+
<Text variant="title">Navigation</Text>
|
|
4
|
+
<Text>Actions open pages with this.navigation. Each new page opens on top, and back returns to the one below. A dot can have {{ maxDepth }} pages open at once.</Text>
|
|
5
|
+
|
|
6
|
+
<View variant="card" gap="small">
|
|
7
|
+
<Text>This is page {{ depth }} of {{ maxDepth }}</Text>
|
|
8
|
+
<Text variant="caption" tone="muted">It opened with {{ options }}</Text>
|
|
9
|
+
</View>
|
|
10
|
+
|
|
11
|
+
<View gap="small">
|
|
12
|
+
<Text variant="subtitle">push</Text>
|
|
13
|
+
<Text variant="caption" tone="muted">Opens a page on top, with options it reads in onLoad.</Text>
|
|
14
|
+
<Button onClick="openAnother" disabled="{{ depth >= maxDepth }}">Open another</Button>
|
|
15
|
+
</View>
|
|
16
|
+
|
|
17
|
+
<View gap="small">
|
|
18
|
+
<Text variant="subtitle">replace</Text>
|
|
19
|
+
<Text variant="caption" tone="muted">Opens a page in this one's place, so back skips this one.</Text>
|
|
20
|
+
<Button variant="secondary" onClick="replaceThis">Replace this one</Button>
|
|
21
|
+
</View>
|
|
22
|
+
|
|
23
|
+
<View gap="small">
|
|
24
|
+
<Text variant="subtitle">back</Text>
|
|
25
|
+
<Text variant="caption" tone="muted">Closes this page, or as many as you ask. On the first page, it closes the dot.</Text>
|
|
26
|
+
<View direction="row" gap="small">
|
|
27
|
+
<Button variant="secondary" onClick="back">Back</Button>
|
|
28
|
+
<Button variant="secondary" onClick="backTwo" disabled="{{ depth < 3 }}">Back two</Button>
|
|
29
|
+
</View>
|
|
30
|
+
</View>
|
|
31
|
+
|
|
32
|
+
<View gap="small">
|
|
33
|
+
<Text variant="subtitle">reset</Text>
|
|
34
|
+
<Text variant="caption" tone="muted">Closes every page and opens one, such as the home page.</Text>
|
|
35
|
+
<Button variant="secondary" onClick="home">Start over</Button>
|
|
36
|
+
</View>
|
|
37
|
+
|
|
38
|
+
<View gap="small">
|
|
39
|
+
<Text variant="subtitle">pushForResult and backWithResult</Text>
|
|
40
|
+
<Text variant="caption" tone="muted">Opens a page that gives something back, such as a choice. It gives undefined when the person goes back without choosing.</Text>
|
|
41
|
+
<View variant="card" direction="row" align="center" gap="medium">
|
|
42
|
+
<View grow>
|
|
43
|
+
<Text>{{ genre ? 'Your genre: ' + genre : 'No genre chosen yet' }}</Text>
|
|
44
|
+
</View>
|
|
45
|
+
<Button variant="secondary" onClick="chooseGenre">Choose a genre</Button>
|
|
46
|
+
</View>
|
|
47
|
+
</View>
|
|
48
|
+
</View>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
// Opened by the navigation page with pushForResult. It gives back the genre the person taps.
|
|
4
|
+
export default definePage({
|
|
5
|
+
initialState: state,
|
|
6
|
+
configs: {
|
|
7
|
+
navigationBar: { title: 'Choose a genre' },
|
|
8
|
+
// This page's own background: a warm Salone sunset by day, the evening after it by dark. Dash
|
|
9
|
+
// paints it behind the page, makes the list's cards to match, and picks text and bar colours
|
|
10
|
+
// that read on it. Going back shows the page below in its own colours again.
|
|
11
|
+
colors: { background: { light: '#FFF3E0', dark: '#2B1A0E' } },
|
|
12
|
+
},
|
|
13
|
+
actions: {
|
|
14
|
+
pick(_state, event: DataEvent<{ genre: string }>) {
|
|
15
|
+
this.navigation.backWithResult(event.data.genre);
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Choose a genre</Text>
|
|
3
|
+
<Text>Tap one to give it back to the page that opened this one. Going back gives nothing.</Text>
|
|
4
|
+
<Text variant="caption" tone="muted">This page sets its own background in configs.colors, and its cards follow it. Going back shows the page below in its own colours.</Text>
|
|
5
|
+
<List>
|
|
6
|
+
<For each="{{ genres }}" item="genre" key="*this">
|
|
7
|
+
<ListItem icon="music" title="{{ genre }}" data-genre="{{ genre }}" onTap="pick" />
|
|
8
|
+
</For>
|
|
9
|
+
</List>
|
|
10
|
+
</View>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface Concert {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
place: string;
|
|
5
|
+
date: string;
|
|
6
|
+
price: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const CONCERTS: Concert[] = [
|
|
10
|
+
{
|
|
11
|
+
id: 'jazz-night',
|
|
12
|
+
title: 'Freetown Jazz Night',
|
|
13
|
+
place: 'Family Kingdom, Freetown',
|
|
14
|
+
date: 'Saturday 24 October',
|
|
15
|
+
price: 'SLE 150',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'emmerson-live',
|
|
19
|
+
title: 'Emmerson Live',
|
|
20
|
+
place: 'National Stadium, Freetown',
|
|
21
|
+
date: 'Friday 18 December',
|
|
22
|
+
price: 'SLE 300',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'gumbe-night',
|
|
26
|
+
title: 'Gumbe Night',
|
|
27
|
+
place: 'Coronation Field, Bo',
|
|
28
|
+
date: 'Saturday 7 November',
|
|
29
|
+
price: 'SLE 100',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
export default definePage({
|
|
4
|
+
initialState: state,
|
|
5
|
+
configs: { navigationBar: { title: 'Share links' } },
|
|
6
|
+
actions: {
|
|
7
|
+
// buyer is for this person only. The concert page leaves it out of its link.
|
|
8
|
+
open(_state, event: DataEvent<{ concert: string }>) {
|
|
9
|
+
this.navigation.push('basics/concert', { concert: event.data.concert, buyer: 'Aminata' });
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Share links</Text>
|
|
3
|
+
<Text>Dash's ••• menu has Share. It shares a link to the dot, which opens its first page. A page can let the link open it instead, with some of its options.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="subtitle">definePage({ share })</Text>
|
|
7
|
+
<Text variant="caption" tone="muted">share: { options: ['concert'] } lets the link open the page with its concert option. Options not on the list stay out of the link, so nothing private goes in it. Write share out in place: the build reads it.</Text>
|
|
8
|
+
<Text variant="caption" tone="muted">Open a concert, then tap ••• and Share.</Text>
|
|
9
|
+
<List>
|
|
10
|
+
<For each="{{ concerts }}" item="concert" key="id">
|
|
11
|
+
<ListItem icon="ticket" title="{{ concert.title }}" subtitle="{{ concert.place }} · {{ concert.date }}" data-concert="{{ concert.id }}" onTap="open" />
|
|
12
|
+
</For>
|
|
13
|
+
</List>
|
|
14
|
+
</View>
|
|
15
|
+
|
|
16
|
+
<View gap="small">
|
|
17
|
+
<Text variant="subtitle">Opening a link</Text>
|
|
18
|
+
<Text variant="caption" tone="muted">Dash opens the dot on its first page, with the linked page on top, so Back leads home. If the dot is open, it starts again from the link. A page that doesn't share, or that the dot no longer has, opens the first page.</Text>
|
|
19
|
+
<Notice tone="warning">Anyone can write a link, so check its options in onLoad, as the concert page does.</Notice>
|
|
20
|
+
</View>
|
|
21
|
+
</View>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">State, mutations and actions</Text>
|
|
3
|
+
<Text>A page keeps its data in state.ts. Handlers in controller.ts change it, and the view shows the change. Here, the crowd wants one more song.</Text>
|
|
4
|
+
|
|
5
|
+
<View variant="card" gap="small">
|
|
6
|
+
<Text variant="subtitle">{{ count }} of {{ limit }} {{ title }}</Text>
|
|
7
|
+
<If condition="{{ count >= limit }}">
|
|
8
|
+
<Text>Encore! The band comes back on</Text>
|
|
9
|
+
</If>
|
|
10
|
+
<ElseIf condition="{{ count > 0 }}">
|
|
11
|
+
<Text>{{ limit - count }} more and the band comes back</Text>
|
|
12
|
+
</ElseIf>
|
|
13
|
+
<Else>
|
|
14
|
+
<Text>Tap Cheer to start</Text>
|
|
15
|
+
</Else>
|
|
16
|
+
<View direction="row" wrap gap="small">
|
|
17
|
+
<Button onClick="increment" disabled="{{ count >= limit }}">Cheer</Button>
|
|
18
|
+
<Button variant="secondary" onClick="reset" disabled="{{ count === 0 }}">Reset</Button>
|
|
19
|
+
<Button variant="secondary" onClick="fillUp" disabled="{{ count >= limit }}">Whole crowd</Button>
|
|
20
|
+
<Button variant="secondary" onClick="undo" disabled="{{ count === 0 }}">Undo</Button>
|
|
21
|
+
</View>
|
|
22
|
+
</View>
|
|
23
|
+
|
|
24
|
+
<View gap="small">
|
|
25
|
+
<Text variant="subtitle">Mutations</Text>
|
|
26
|
+
<Text>Cheer and Reset are mutations. A mutation gets the state and returns the changes to make, such as { count: 1 }. It can't wait for anything.</Text>
|
|
27
|
+
</View>
|
|
28
|
+
|
|
29
|
+
<View gap="small">
|
|
30
|
+
<Text variant="subtitle">Actions</Text>
|
|
31
|
+
<Text>Whole crowd and Undo are actions. An action can take several steps, call other handlers with this.mutations and this.actions, and wait for Dash.</Text>
|
|
32
|
+
<Text>Whole crowd calls the Cheer mutation until the crowd is full. Undo calls this.setState with a function, which gets the latest state.</Text>
|
|
33
|
+
</View>
|
|
34
|
+
|
|
35
|
+
<View gap="small">
|
|
36
|
+
<Text variant="subtitle">Each cheer, newest first</Text>
|
|
37
|
+
<View variant="card" gap="small">
|
|
38
|
+
<For each="{{ taps }}" index="position" item="tap" key="id">
|
|
39
|
+
<Text>{{ position + 1 }}. Cheer #{{ tap.id }}</Text>
|
|
40
|
+
</For>
|
|
41
|
+
<If condition="{{ taps.length === 0 }}">
|
|
42
|
+
<Text variant="caption" tone="muted">No cheers yet</Text>
|
|
43
|
+
</If>
|
|
44
|
+
</View>
|
|
45
|
+
</View>
|
|
46
|
+
</View>
|
|
@@ -6,6 +6,7 @@ interface Lookup {
|
|
|
6
6
|
|
|
7
7
|
export default definePage({
|
|
8
8
|
initialState: state,
|
|
9
|
+
configs: { navigationBar: { title: 'Carousel' } },
|
|
9
10
|
hooks: {
|
|
10
11
|
// Each artist's photo is the cover of one of their releases, from Apple's catalog.
|
|
11
12
|
async onLoad() {
|
|
@@ -33,7 +34,7 @@ export default definePage({
|
|
|
33
34
|
},
|
|
34
35
|
},
|
|
35
36
|
mutations: {
|
|
36
|
-
showChapter: (_state, event:
|
|
37
|
+
showChapter: (_state, event: IndexEvent) => ({ chapter: event.detail.index }),
|
|
37
38
|
back: (state) => ({ chapter: Math.max(state.chapter - 1, 0) }),
|
|
38
39
|
next: (state) => ({ chapter: Math.min(state.chapter + 1, state.chapters.length - 1) }),
|
|
39
40
|
},
|
|
@@ -18,28 +18,28 @@ export default {
|
|
|
18
18
|
{
|
|
19
19
|
id: 'drizilik',
|
|
20
20
|
name: 'Drizilik',
|
|
21
|
-
text: 'Kriofusion rapped in Krio. "Lemonade"
|
|
21
|
+
text: 'Kriofusion rapped in Krio. "Lemonade" is from his album Wait and See.',
|
|
22
22
|
release: 1788321371,
|
|
23
23
|
photo: '',
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
id: 'the-therapist',
|
|
27
27
|
name: 'The Therapist',
|
|
28
|
-
text: 'Had
|
|
28
|
+
text: 'Had a big following online before his first single, "Nack", in 2022.',
|
|
29
29
|
release: 1612124616,
|
|
30
30
|
photo: '',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
id: 'boii',
|
|
34
34
|
name: 'Boii',
|
|
35
|
-
text:
|
|
35
|
+
text: 'One of the most-streamed Sierra Leonean women of 2024. Her first EP, Money or Honey, came in 2025.',
|
|
36
36
|
release: 1776449163,
|
|
37
37
|
photo: '',
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
id: 'apreel',
|
|
41
41
|
name: 'ApreeL',
|
|
42
|
-
text: '"O\'way", and "Control", a Krio love song
|
|
42
|
+
text: '"O\'way", and "Control", a Krio love song.',
|
|
43
43
|
release: 1831185667,
|
|
44
44
|
photo: '',
|
|
45
45
|
},
|
|
@@ -70,7 +70,7 @@ export default {
|
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
title: 'Gen Z',
|
|
73
|
-
text: 'Drizilik, Boii and ApreeL sing in Krio over Afrobeats,
|
|
73
|
+
text: 'Drizilik, Boii and ApreeL sing in Krio over Afrobeats, and new stars break through online.',
|
|
74
74
|
},
|
|
75
75
|
] as Chapter[],
|
|
76
76
|
chapter: 0,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<View>
|
|
2
2
|
<Text variant="title">Carousel</Text>
|
|
3
|
-
<Text>A
|
|
3
|
+
<Text>A Carousel shows one slide at a time. Swipe, or tap a dot.</Text>
|
|
4
4
|
|
|
5
5
|
<View gap="small">
|
|
6
|
-
<Text variant="
|
|
7
|
-
<
|
|
6
|
+
<Text variant="subtitle">autoplay, loop and effect</Text>
|
|
7
|
+
<Text variant="caption" tone="muted">Gen Z artists. The slides move on their own every 3 seconds, start over at the end, and pause when you touch them. effect="scale" shrinks the slides beside the one in view.</Text>
|
|
8
|
+
<Carousel autoplay loop interval="3000" gap="medium" effect="scale" indicator="dots">
|
|
8
9
|
<For each="{{ artists }}" item="artist" key="id">
|
|
9
10
|
<View variant="card" align="center" gap="medium">
|
|
10
11
|
<If condition="{{ artist.photo }}">
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
</View>
|
|
22
23
|
|
|
23
24
|
<View gap="small">
|
|
24
|
-
<Text variant="
|
|
25
|
-
<
|
|
25
|
+
<Text variant="subtitle">index and onChange</Text>
|
|
26
|
+
<Text variant="caption" tone="muted">How Salone music grew, from palm-wine to Gen Z. The page sets the slide with index, and onChange tells it when you swipe. The buttons move the slides, so indicator="none" hides the dots.</Text>
|
|
27
|
+
<Carousel index="{{ chapter }}" indicator="none" effect="slide" gap="small" padding="small" onChange="showChapter">
|
|
26
28
|
<For each="{{ chapters }}" item="card" key="title">
|
|
27
29
|
<View variant="card" align="center" gap="medium">
|
|
28
30
|
<Image src="statics/logo.png" alt="" width="48" height="48" />
|