@monimesl/dot-cli 0.1.0-alpha.19 → 0.1.0-alpha.21
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/dist/cli.js +381 -261
- package/dist/cli.js.map +1 -1
- package/dist/{server-uIyYmYnp.js → server-B9-F93mS.js} +539 -464
- package/dist/server-B9-F93mS.js.map +1 -0
- package/dist/templates/showcase/dot.ts +2 -0
- package/dist/templates/showcase/pages/basics/bars/controller.ts +1 -1
- package/dist/templates/showcase/pages/basics/control-flow/controller.ts +1 -1
- package/dist/templates/showcase/pages/basics/events/controller.ts +4 -4
- package/dist/templates/showcase/pages/basics/events/view.dml +2 -2
- package/dist/templates/showcase/pages/basics/hooks/controller.ts +6 -0
- package/dist/templates/showcase/pages/basics/hooks/view.dml +5 -0
- package/dist/templates/showcase/pages/basics/navigation/controller.ts +7 -0
- package/dist/templates/showcase/pages/basics/navigation/state.ts +2 -0
- package/dist/templates/showcase/pages/basics/navigation/view.dml +11 -0
- package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +12 -0
- package/dist/templates/showcase/pages/basics/pick-genre/state.ts +3 -0
- package/dist/templates/showcase/pages/basics/pick-genre/view.dml +9 -0
- package/dist/templates/showcase/pages/components/carousel/controller.ts +1 -1
- package/dist/templates/showcase/pages/components/feedback/controller.ts +12 -2
- package/dist/templates/showcase/pages/components/feedback/state.ts +33 -0
- package/dist/templates/showcase/pages/components/feedback/view.dml +21 -1
- package/dist/templates/showcase/pages/components/forms/controller.ts +22 -22
- package/dist/templates/showcase/pages/components/forms/state.ts +3 -3
- package/dist/templates/showcase/pages/components/forms/view.dml +9 -2
- package/dist/templates/showcase/pages/components/icons/controller.ts +1 -1
- package/dist/templates/showcase/pages/components/images/controller.ts +3 -1
- package/dist/templates/showcase/pages/components/images/view.dml +13 -0
- package/dist/templates/showcase/pages/components/layout/controller.ts +2 -2
- package/dist/templates/showcase/pages/components/lists/controller.ts +1 -1
- package/dist/templates/showcase/pages/components/lists/view.dml +18 -0
- package/dist/templates/showcase/pages/components/money/controller.ts +6 -8
- package/dist/templates/showcase/pages/components/sheets/controller.ts +2 -2
- package/dist/templates/showcase/pages/components/tabs/controller.ts +22 -10
- package/dist/templates/showcase/pages/components/tabs/state.ts +1 -0
- package/dist/templates/showcase/pages/components/tabs/view.dml +4 -3
- package/dist/templates/showcase/pages/dash/cache/controller.ts +2 -2
- package/dist/templates/showcase/pages/dash/calls/controller.ts +7 -6
- package/dist/templates/showcase/pages/dash/calls/state.ts +1 -1
- package/dist/templates/showcase/pages/dash/calls/view.dml +3 -2
- 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/files/controller.ts +15 -13
- package/dist/templates/showcase/pages/dash/files/state.ts +3 -6
- package/dist/templates/showcase/pages/dash/media/controller.ts +16 -13
- package/dist/templates/showcase/pages/dash/network/controller.ts +71 -16
- package/dist/templates/showcase/pages/dash/network/state.ts +10 -0
- package/dist/templates/showcase/pages/dash/network/view.dml +32 -4
- package/dist/templates/showcase/pages/dash/secrets/controller.ts +1 -1
- package/dist/templates/showcase/pages/dash/system/controller.ts +32 -5
- package/dist/templates/showcase/pages/dash/system/state.ts +6 -2
- package/dist/templates/showcase/pages/dash/system/view.dml +39 -1
- package/dist/templates/showcase/pages/dash/ui/controller.ts +23 -23
- package/dist/templates/showcase/pages/dash/ui/view.dml +1 -1
- package/dist/templates/showcase/pages/index/controller.ts +1 -1
- package/dist/templates/showcase/pages/index/state.ts +17 -10
- package/package.json +6 -6
- package/dist/server-uIyYmYnp.js.map +0 -1
|
@@ -10,6 +10,7 @@ export default defineDot({
|
|
|
10
10
|
'basics/control-flow',
|
|
11
11
|
'basics/events',
|
|
12
12
|
'basics/navigation',
|
|
13
|
+
'basics/pick-genre',
|
|
13
14
|
'basics/hooks',
|
|
14
15
|
'basics/bars',
|
|
15
16
|
// What a view can show.
|
|
@@ -30,6 +31,7 @@ export default defineDot({
|
|
|
30
31
|
'dash/ui',
|
|
31
32
|
'dash/system',
|
|
32
33
|
'dash/media',
|
|
34
|
+
'dash/contacts',
|
|
33
35
|
'dash/network',
|
|
34
36
|
'dash/files',
|
|
35
37
|
'dash/cache',
|
|
@@ -5,7 +5,7 @@ export default definePage({
|
|
|
5
5
|
// What Dash's bars show when the page opens, on top of the configs in dot.ts.
|
|
6
6
|
configs: { navigationBar: { title: 'Bars' } },
|
|
7
7
|
mutations: {
|
|
8
|
-
setTitle: (_state, event:
|
|
8
|
+
setTitle: (_state, event: ValueEvent) => ({ title: event.detail.value }),
|
|
9
9
|
},
|
|
10
10
|
actions: {
|
|
11
11
|
// While the page runs, setNavigationBar changes what configs set.
|
|
@@ -5,7 +5,7 @@ export default definePage({
|
|
|
5
5
|
configs: { navigationBar: { title: 'If and For' } },
|
|
6
6
|
mutations: {
|
|
7
7
|
// Sells five tickets for the show the button belongs to.
|
|
8
|
-
sell: (state, event:
|
|
8
|
+
sell: (state, event: DataEvent<{ id: string }>) => ({
|
|
9
9
|
shows: state.shows.map((show) =>
|
|
10
10
|
show.id === event.data.id ? { ...show, left: Math.max(0, show.left - 5) } : show,
|
|
11
11
|
),
|
|
@@ -20,22 +20,22 @@ export default definePage({
|
|
|
20
20
|
...describe('countTap', event),
|
|
21
21
|
}),
|
|
22
22
|
// `detail` is what the component sends: text for an Input...
|
|
23
|
-
setSong: (_state, event:
|
|
23
|
+
setSong: (_state, event: ValueEvent) => ({
|
|
24
24
|
song: event.detail.value,
|
|
25
25
|
...describe('setSong', event),
|
|
26
26
|
}),
|
|
27
27
|
// ...a number for a Slider...
|
|
28
|
-
setVolume: (_state, event:
|
|
28
|
+
setVolume: (_state, event: ValueEvent<number>) => ({
|
|
29
29
|
volume: event.detail.value,
|
|
30
30
|
...describe('setVolume', event),
|
|
31
31
|
}),
|
|
32
32
|
// ...and checked for a Switch.
|
|
33
|
-
setLoud: (_state, event:
|
|
33
|
+
setLoud: (_state, event: CheckedEvent) => ({
|
|
34
34
|
loud: event.detail.checked,
|
|
35
35
|
...describe('setLoud', event),
|
|
36
36
|
}),
|
|
37
37
|
// `data` holds the element's data- attributes, as text.
|
|
38
|
-
play: (_state, event:
|
|
38
|
+
play: (_state, event: DataEvent<{ artist: string; year: string }>) => ({
|
|
39
39
|
song: `${event.data.artist}, ${event.data.year}`,
|
|
40
40
|
...describe('play', event),
|
|
41
41
|
}),
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
<View gap="small">
|
|
33
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.</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
35
|
<View variant="card">
|
|
36
36
|
<Input label="Song" placeholder="Exodus" value="{{ song }}" onChange="setSong" />
|
|
37
37
|
<Slider label="Volume" min="0" max="10" showValue value="{{ volume }}" onChange="setVolume" />
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
<View gap="small">
|
|
43
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.</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
45
|
<View variant="card" direction="row" wrap gap="small">
|
|
46
46
|
<Button variant="secondary" data-artist="Drizilik" data-year="2021" onClick="play">Exodus</Button>
|
|
47
47
|
<Button variant="secondary" data-artist="ApreeL" data-year="2025" onClick="play">Control</Button>
|
|
@@ -28,6 +28,12 @@ export default definePage({
|
|
|
28
28
|
onUnload() {
|
|
29
29
|
lastClosed = new Date().toLocaleTimeString('en-GB');
|
|
30
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
|
+
},
|
|
31
37
|
},
|
|
32
38
|
actions: {
|
|
33
39
|
openAnother() {
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
<Button variant="secondary" onClick="openAnother">Open another page</Button>
|
|
14
14
|
</View>
|
|
15
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
|
+
|
|
16
21
|
<View gap="small">
|
|
17
22
|
<Text variant="subtitle">onUnload</Text>
|
|
18
23
|
<View variant="card">
|
|
@@ -30,5 +30,12 @@ export default definePage({
|
|
|
30
30
|
home() {
|
|
31
31
|
this.navigation.reset('index');
|
|
32
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
|
+
},
|
|
33
40
|
},
|
|
34
41
|
});
|
|
@@ -34,4 +34,15 @@
|
|
|
34
34
|
<Text variant="caption" tone="muted">Closes every page and opens one, such as the home page.</Text>
|
|
35
35
|
<Button variant="secondary" onClick="home">Start over</Button>
|
|
36
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>
|
|
37
48
|
</View>
|
|
@@ -0,0 +1,12 @@
|
|
|
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: { navigationBar: { title: 'Choose a genre' } },
|
|
7
|
+
actions: {
|
|
8
|
+
pick(_state, event: DataEvent<{ genre: string }>) {
|
|
9
|
+
this.navigation.backWithResult(event.data.genre);
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
<List>
|
|
5
|
+
<For each="{{ genres }}" item="genre" key="*this">
|
|
6
|
+
<ListItem icon="music" title="{{ genre }}" data-genre="{{ genre }}" onTap="pick" />
|
|
7
|
+
</For>
|
|
8
|
+
</List>
|
|
9
|
+
</View>
|
|
@@ -34,7 +34,7 @@ export default definePage({
|
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
mutations: {
|
|
37
|
-
showChapter: (_state, event:
|
|
37
|
+
showChapter: (_state, event: IndexEvent) => ({ chapter: event.detail.index }),
|
|
38
38
|
back: (state) => ({ chapter: Math.max(state.chapter - 1, 0) }),
|
|
39
39
|
next: (state) => ({ chapter: Math.min(state.chapter + 1, state.chapters.length - 1) }),
|
|
40
40
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import state from './state';
|
|
1
|
+
import state, { paymentSteps } from './state';
|
|
2
2
|
|
|
3
3
|
export default definePage({
|
|
4
4
|
initialState: state,
|
|
@@ -11,12 +11,22 @@ export default definePage({
|
|
|
11
11
|
// A toast lasts its default time unless the button gives one, in milliseconds.
|
|
12
12
|
showToast: (
|
|
13
13
|
_state,
|
|
14
|
-
event:
|
|
14
|
+
event: DataEvent<{ message: string; tone: string; duration?: string }>,
|
|
15
15
|
) => ({
|
|
16
16
|
toast: event.data.message,
|
|
17
17
|
toastTone: event.data.tone,
|
|
18
18
|
toastDuration: event.data.duration ? Number(event.data.duration) : undefined,
|
|
19
19
|
}),
|
|
20
20
|
clearToast: () => ({ toast: '' }),
|
|
21
|
+
hideTip: () => ({ tipShown: false }),
|
|
22
|
+
advancePayment: (state) => {
|
|
23
|
+
const paymentStage = state.paymentStage + 1;
|
|
24
|
+
return { paymentStage, payment: paymentSteps(paymentStage) };
|
|
25
|
+
},
|
|
26
|
+
failPayment: (state) => ({
|
|
27
|
+
paymentFailed: true,
|
|
28
|
+
payment: paymentSteps(state.paymentStage, true),
|
|
29
|
+
}),
|
|
30
|
+
restartPayment: () => ({ paymentStage: 0, paymentFailed: false, payment: paymentSteps(0) }),
|
|
21
31
|
},
|
|
22
32
|
});
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
export type StepStatus = 'done' | 'current' | 'upcoming' | 'failed';
|
|
2
|
+
|
|
3
|
+
export interface PaymentStep {
|
|
4
|
+
title: string;
|
|
5
|
+
text: string;
|
|
6
|
+
status: StepStatus;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Sending Le 500 to Fatmata Conteh in Bo.
|
|
10
|
+
const PAYMENT = [
|
|
11
|
+
{ title: 'Paid', text: 'Le 500 from your wallet' },
|
|
12
|
+
{ title: 'Sent', text: 'On its way to Bo' },
|
|
13
|
+
{ title: 'Received', text: 'By Fatmata Conteh' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// The payment's steps when `stage` of them are done. The next one is under way, or failed.
|
|
17
|
+
export function paymentSteps(stage: number, failed = false): PaymentStep[] {
|
|
18
|
+
return PAYMENT.map((step, index) => {
|
|
19
|
+
let status: StepStatus = 'upcoming';
|
|
20
|
+
if (index < stage) {
|
|
21
|
+
status = 'done';
|
|
22
|
+
} else if (index === stage) {
|
|
23
|
+
status = failed ? 'failed' : 'current';
|
|
24
|
+
}
|
|
25
|
+
return { ...step, status };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
1
29
|
export default {
|
|
2
30
|
progress: 40,
|
|
3
31
|
busy: false,
|
|
@@ -5,4 +33,9 @@ export default {
|
|
|
5
33
|
toast: '',
|
|
6
34
|
toastTone: 'default',
|
|
7
35
|
toastDuration: undefined as number | undefined,
|
|
36
|
+
tipShown: true,
|
|
37
|
+
// How many steps are done, and whether the next one failed, which ends the payment.
|
|
38
|
+
paymentStage: 0,
|
|
39
|
+
paymentFailed: false,
|
|
40
|
+
payment: paymentSteps(0),
|
|
8
41
|
};
|
|
@@ -72,7 +72,10 @@
|
|
|
72
72
|
|
|
73
73
|
<View gap="small">
|
|
74
74
|
<Text variant="subtitle">Notice</Text>
|
|
75
|
-
<Text variant="caption" tone="muted">A message that stays in the page, in a tone.</Text>
|
|
75
|
+
<Text variant="caption" tone="muted">A message that stays in the page, in a tone. With onClose it shows a close button, and the page hides it.</Text>
|
|
76
|
+
<If condition="{{ tipShown }}">
|
|
77
|
+
<Notice tone="info" title="Tip" onClose="hideTip">Hold a song to add it to a playlist.</Notice>
|
|
78
|
+
</If>
|
|
76
79
|
<Notice title="Heads up">Doors open at 7 pm, and the music starts at 8.</Notice>
|
|
77
80
|
<Notice tone="info" title="New">Tickets for gospel night in Kenema are on sale.</Notice>
|
|
78
81
|
<Notice tone="success" title="Booked">Two tickets for Salone Sounds Live.</Notice>
|
|
@@ -80,6 +83,23 @@
|
|
|
80
83
|
<Notice tone="danger" title="Payment failed">The bank didn't answer. Try again.</Notice>
|
|
81
84
|
</View>
|
|
82
85
|
|
|
86
|
+
<View gap="small">
|
|
87
|
+
<Text variant="subtitle">Steps</Text>
|
|
88
|
+
<Text variant="caption" tone="muted">What happened and what comes next, such as a payment's progress. Each Step is done, current, upcoming or failed.</Text>
|
|
89
|
+
<View variant="card">
|
|
90
|
+
<Steps>
|
|
91
|
+
<For each="{{ payment }}" item="step" key="title">
|
|
92
|
+
<Step title="{{ step.title }}" text="{{ step.text }}" status="{{ step.status }}" />
|
|
93
|
+
</For>
|
|
94
|
+
</Steps>
|
|
95
|
+
<View direction="row" gap="small">
|
|
96
|
+
<Button variant="secondary" onClick="advancePayment" disabled="{{ paymentFailed || paymentStage === payment.length }}">Next step</Button>
|
|
97
|
+
<Button variant="secondary" onClick="failPayment" disabled="{{ paymentFailed || paymentStage === payment.length }}">Fail it</Button>
|
|
98
|
+
<Button variant="secondary" onClick="restartPayment" disabled="{{ paymentStage === 0 }}">Start over</Button>
|
|
99
|
+
</View>
|
|
100
|
+
</View>
|
|
101
|
+
</View>
|
|
102
|
+
|
|
83
103
|
<View gap="small">
|
|
84
104
|
<Text variant="subtitle">Badge</Text>
|
|
85
105
|
<Text variant="caption" tone="muted">A short status.</Text>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import { errorMessage } from '@monimesl/dot-runtime';
|
|
2
|
+
|
|
1
3
|
import type { TicketType } from './state';
|
|
2
4
|
import state, { SHOWS, TICKETS } from './state';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// "2" tickets of a Le 1,200 type -> "Le 2,400"
|
|
8
|
-
function total(tickets: string, ticket: TicketType): string {
|
|
9
|
-
const leones = (Number(tickets) || 0) * TICKETS[ticket].price;
|
|
6
|
+
// 2 tickets of a Le 1,200 type -> "Le 2,400"
|
|
7
|
+
function total(tickets: number, ticket: TicketType): string {
|
|
8
|
+
const leones = tickets * TICKETS[ticket].price;
|
|
10
9
|
return `Le ${leones.toLocaleString('en-US')}`;
|
|
11
10
|
}
|
|
12
11
|
|
|
@@ -14,36 +13,35 @@ export default definePage({
|
|
|
14
13
|
initialState: state,
|
|
15
14
|
configs: { navigationBar: { title: 'Forms' } },
|
|
16
15
|
mutations: {
|
|
17
|
-
setShow: (_state, event:
|
|
16
|
+
setShow: (_state, event: ValueEvent) => ({
|
|
18
17
|
show: event.detail.value,
|
|
19
18
|
showName: SHOWS[event.detail.value] ?? 'Not chosen yet',
|
|
20
19
|
}),
|
|
21
|
-
setName: (_state, event:
|
|
22
|
-
setEmail: (_state, event:
|
|
23
|
-
setPhone: (_state, event:
|
|
24
|
-
setTickets: (state, event:
|
|
20
|
+
setName: (_state, event: ValueEvent) => ({ name: event.detail.value }),
|
|
21
|
+
setEmail: (_state, event: ValueEvent) => ({ email: event.detail.value }),
|
|
22
|
+
setPhone: (_state, event: ValueEvent) => ({ phone: event.detail.value }),
|
|
23
|
+
setTickets: (state, event: ValueEvent<number>) => ({
|
|
25
24
|
tickets: event.detail.value,
|
|
26
25
|
total: total(event.detail.value, state.ticket),
|
|
27
26
|
}),
|
|
28
|
-
setShoutOut: (_state, event:
|
|
29
|
-
setPromo: (_state, event:
|
|
30
|
-
setChairs: (_state, event:
|
|
31
|
-
setTip: (_state, event:
|
|
32
|
-
setTicket: (state, event:
|
|
27
|
+
setShoutOut: (_state, event: ValueEvent) => ({ shoutOut: event.detail.value }),
|
|
28
|
+
setPromo: (_state, event: ValueEvent) => ({ promo: event.detail.value }),
|
|
29
|
+
setChairs: (_state, event: ValueEvent<number>) => ({ chairs: event.detail.value }),
|
|
30
|
+
setTip: (_state, event: ValueEvent<number>) => ({ tip: event.detail.value }),
|
|
31
|
+
setTicket: (state, event: ValueEvent<TicketType>) => ({
|
|
33
32
|
ticket: event.detail.value,
|
|
34
33
|
ticketName: TICKETS[event.detail.value].name,
|
|
35
34
|
total: total(state.tickets, event.detail.value),
|
|
36
35
|
}),
|
|
37
|
-
setETickets: (_state, event:
|
|
38
|
-
setAgreed: (_state, event:
|
|
36
|
+
setETickets: (_state, event: CheckedEvent) => ({ eTickets: event.detail.checked }),
|
|
37
|
+
setAgreed: (_state, event: CheckedEvent) => ({ agreed: event.detail.checked }),
|
|
39
38
|
},
|
|
40
39
|
actions: {
|
|
41
40
|
async send(state) {
|
|
42
|
-
const count =
|
|
41
|
+
const count = state.tickets;
|
|
43
42
|
const errors = {
|
|
44
43
|
show: state.show ? '' : 'Choose a show',
|
|
45
44
|
phone: state.phone.length < 8 ? 'Enter a phone number, such as 76 123456' : '',
|
|
46
|
-
tickets: count >= 1 && count <= 10 ? '' : 'Buy from 1 to 10 tickets',
|
|
47
45
|
shoutOut: state.shoutOut.includes('http')
|
|
48
46
|
? 'Links are not read out. Write words only.'
|
|
49
47
|
: '',
|
|
@@ -64,9 +62,11 @@ export default definePage({
|
|
|
64
62
|
sent: `${count} ${count === 1 ? 'ticket' : 'tickets'}, sent to +232 ${phone}`,
|
|
65
63
|
});
|
|
66
64
|
} catch (error) {
|
|
67
|
-
this.setState({ failure: (error
|
|
65
|
+
this.setState({ failure: errorMessage(error) });
|
|
66
|
+
} finally {
|
|
67
|
+
// However the request ends, the button stops spinning and takes taps again.
|
|
68
|
+
this.setState({ sending: false });
|
|
68
69
|
}
|
|
69
|
-
this.setState({ sending: false });
|
|
70
70
|
},
|
|
71
71
|
},
|
|
72
72
|
});
|
|
@@ -18,11 +18,11 @@ export default {
|
|
|
18
18
|
// The order, as the summary shows it.
|
|
19
19
|
showName: 'Not chosen yet',
|
|
20
20
|
ticketName: TICKETS.regular.name,
|
|
21
|
-
total:
|
|
21
|
+
total: `Le ${2 * TICKETS.regular.price}`,
|
|
22
22
|
name: '',
|
|
23
23
|
email: '',
|
|
24
24
|
phone: '',
|
|
25
|
-
tickets:
|
|
25
|
+
tickets: 2,
|
|
26
26
|
promo: '',
|
|
27
27
|
chairs: 2,
|
|
28
28
|
tip: 20,
|
|
@@ -30,7 +30,7 @@ export default {
|
|
|
30
30
|
ticket: 'regular' as TicketType,
|
|
31
31
|
eTickets: true,
|
|
32
32
|
agreed: false,
|
|
33
|
-
errors: { show: '', phone: '',
|
|
33
|
+
errors: { show: '', phone: '', shoutOut: '' },
|
|
34
34
|
sending: false,
|
|
35
35
|
sent: '',
|
|
36
36
|
failure: '',
|
|
@@ -20,11 +20,18 @@
|
|
|
20
20
|
<Input label="Name" placeholder="Mariama Kamara" value="{{ name }}" maxLength="40" onChange="setName" />
|
|
21
21
|
<Input label="Email" type="email" placeholder="mariama@example.com" hint="{{ eTickets ? 'For the e-tickets' : 'Turn on e-tickets below to use it' }}" value="{{ email }}" disabled="{{ !eTickets }}" onChange="setEmail" />
|
|
22
22
|
<Input label="Phone" type="phone" prefix="+232" placeholder="76 123456" value="{{ phone }}" error="{{ errors.phone }}" onChange="setPhone" />
|
|
23
|
-
<Input label="Tickets" type="number" placeholder="2" suffix="at most 10" value="{{ tickets }}" error="{{ errors.tickets }}" onChange="setTickets" />
|
|
24
23
|
<Input label="Promo code" type="password" placeholder="Hidden as you type" value="{{ promo }}" onChange="setPromo" onSubmit="send" />
|
|
25
24
|
</View>
|
|
26
25
|
</View>
|
|
27
26
|
|
|
27
|
+
<View gap="small">
|
|
28
|
+
<Text variant="subtitle">Stepper</Text>
|
|
29
|
+
<Text variant="caption" tone="muted">A count changed one at a time. min and max keep it in range, so there's nothing to check.</Text>
|
|
30
|
+
<View variant="card">
|
|
31
|
+
<Stepper label="Tickets" min="1" max="10" hint="At most 10 for each person" value="{{ tickets }}" onChange="setTickets" />
|
|
32
|
+
</View>
|
|
33
|
+
</View>
|
|
34
|
+
|
|
28
35
|
<View gap="small">
|
|
29
36
|
<Text variant="subtitle">RadioGroup and Radio</Text>
|
|
30
37
|
<Text variant="caption" tone="muted">One choice from a few. A Radio, or the whole group, can be disabled.</Text>
|
|
@@ -69,7 +76,7 @@
|
|
|
69
76
|
<View variant="card" gap="none">
|
|
70
77
|
<DetailRow label="Show" value="{{ showName }}" />
|
|
71
78
|
<DetailRow label="Ticket" value="{{ ticketName }}" />
|
|
72
|
-
<DetailRow label="How many" value="{{ tickets
|
|
79
|
+
<DetailRow label="How many" value="{{ tickets }}" />
|
|
73
80
|
<Divider />
|
|
74
81
|
<DetailRow label="Total" value="{{ total }}" weight="bold" paddingTop="medium" />
|
|
75
82
|
<DetailRow label="Paid" value="{{ sent ? 'Yes' : 'Not yet' }}" tone="{{ sent ? 'success' : 'warning' }}" />
|
|
@@ -7,7 +7,7 @@ export default definePage({
|
|
|
7
7
|
clearToast: () => ({ toast: '' }),
|
|
8
8
|
},
|
|
9
9
|
actions: {
|
|
10
|
-
async copyName(_state, event:
|
|
10
|
+
async copyName(_state, event: DataEvent<{ name: string }>) {
|
|
11
11
|
await this.dash.system.copyText(event.data.name);
|
|
12
12
|
this.setState({ toast: `Copied "${event.data.name}"` });
|
|
13
13
|
},
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { errorMessage } from '@monimesl/dot-runtime';
|
|
2
|
+
|
|
1
3
|
import state from './state';
|
|
2
4
|
|
|
3
5
|
// AUDACITY's id in Apple's catalog; its cover's address can change, so the page looks it up.
|
|
@@ -25,7 +27,7 @@ export default definePage({
|
|
|
25
27
|
: { coverNote: "Apple's catalog has no cover for it" },
|
|
26
28
|
);
|
|
27
29
|
} catch (error) {
|
|
28
|
-
this.setState({ coverNote: (error
|
|
30
|
+
this.setState({ coverNote: errorMessage(error) });
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
33
|
},
|
|
@@ -67,4 +67,17 @@
|
|
|
67
67
|
</Else>
|
|
68
68
|
</View>
|
|
69
69
|
</View>
|
|
70
|
+
|
|
71
|
+
<View gap="small">
|
|
72
|
+
<Text variant="subtitle">Avatar</Text>
|
|
73
|
+
<Text variant="caption" tone="muted">A person's photo, round. Without one, or when it fails to load, their initials show.</Text>
|
|
74
|
+
<View variant="card" direction="row" align="center" gap="large">
|
|
75
|
+
<Avatar name="Salone Sounds" image="statics/logo.png" size="large" />
|
|
76
|
+
<Avatar name="Mariama Kamara" size="large" />
|
|
77
|
+
<Avatar name="Fatmata Conteh" />
|
|
78
|
+
<Avatar name="Boii" size="small" />
|
|
79
|
+
<Avatar name="Kao Denero" image="{{ missing }}" />
|
|
80
|
+
</View>
|
|
81
|
+
<Text variant="caption" tone="muted">The last one's picture is missing, so it shows KD.</Text>
|
|
82
|
+
</View>
|
|
70
83
|
</View>
|
|
@@ -45,10 +45,10 @@ export default definePage({
|
|
|
45
45
|
nextAlign: (state) => ({ align: after(ALIGNS, state.align) }),
|
|
46
46
|
nextGap: (state) => ({ gap: after(SPACES, state.gap) }),
|
|
47
47
|
toggleWrap: (state) => ({ wrap: !state.wrap }),
|
|
48
|
-
openSection: (_state, event:
|
|
48
|
+
openSection: (_state, event: DataEvent<{ name: string }>) => ({
|
|
49
49
|
section: event.data.name,
|
|
50
50
|
}),
|
|
51
|
-
showFirst: (_state, event:
|
|
51
|
+
showFirst: (_state, event: IndexEvent) => ({ first: event.detail.index }),
|
|
52
52
|
shelfStart: () => ({ first: 0 }),
|
|
53
53
|
shelfEnd: (state) => ({ first: state.releases.length - 1 }),
|
|
54
54
|
playSong: (state) => ({ playing: !state.playing }),
|
|
@@ -7,7 +7,7 @@ export default definePage({
|
|
|
7
7
|
initialState: state,
|
|
8
8
|
configs: { navigationBar: { title: 'Lists' } },
|
|
9
9
|
mutations: {
|
|
10
|
-
choose: (state, event:
|
|
10
|
+
choose: (state, event: DataEvent<{ id: string }>) => {
|
|
11
11
|
const artist = state.artists.find((candidate) => candidate.id === event.data.id);
|
|
12
12
|
return { chosen: artist?.name ?? '' };
|
|
13
13
|
},
|
|
@@ -50,6 +50,24 @@
|
|
|
50
50
|
</View>
|
|
51
51
|
</View>
|
|
52
52
|
|
|
53
|
+
<View gap="small">
|
|
54
|
+
<Text variant="subtitle">Disclosure</Text>
|
|
55
|
+
<Text variant="caption" tone="muted">A row that opens to show more, such as an answer. The person opens and closes it, and open sets how it starts.</Text>
|
|
56
|
+
<View variant="card" gap="none">
|
|
57
|
+
<Disclosure title="Can I get a refund?" subtitle="Tickets and refunds" open>
|
|
58
|
+
<Text>Yes, until the Friday before the show. After that, you can give your ticket to someone else.</Text>
|
|
59
|
+
</Disclosure>
|
|
60
|
+
<Divider />
|
|
61
|
+
<Disclosure title="When do doors open?">
|
|
62
|
+
<Text>At 6 pm. The music starts at 7.</Text>
|
|
63
|
+
</Disclosure>
|
|
64
|
+
<Divider />
|
|
65
|
+
<Disclosure title="Is there parking?">
|
|
66
|
+
<Text>Yes, at the Lumley junction car park, a short walk away.</Text>
|
|
67
|
+
</Disclosure>
|
|
68
|
+
</View>
|
|
69
|
+
</View>
|
|
70
|
+
|
|
53
71
|
<View gap="small">
|
|
54
72
|
<Text variant="subtitle">EmptyState</Text>
|
|
55
73
|
<Text variant="caption" tone="muted">Shows when a list has nothing in it, with a way forward.</Text>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import state from './state';
|
|
2
2
|
|
|
3
|
-
type Typed = DotEvent<{ value: string }>;
|
|
4
|
-
|
|
5
3
|
// The code this page accepts; a real dot checks it with its server.
|
|
6
4
|
const RIGHT_CODE = '123456';
|
|
7
5
|
|
|
@@ -12,7 +10,7 @@ export default definePage({
|
|
|
12
10
|
initialState: state,
|
|
13
11
|
configs: { navigationBar: { title: 'Money and codes' } },
|
|
14
12
|
mutations: {
|
|
15
|
-
setAmount: (_state, event:
|
|
13
|
+
setAmount: (_state, event: ValueEvent<number | null>) => {
|
|
16
14
|
const amount = event.detail.value;
|
|
17
15
|
if (!amount) {
|
|
18
16
|
return { amount, amountText: '', request: '' };
|
|
@@ -23,20 +21,20 @@ export default definePage({
|
|
|
23
21
|
request: `https://pay.example.com/tip?amount=${amount}¤cy=SLE&in=cents`,
|
|
24
22
|
};
|
|
25
23
|
},
|
|
26
|
-
setCode: (_state, event:
|
|
27
|
-
checkCode: (_state, event:
|
|
24
|
+
setCode: (_state, event: ValueEvent) => ({ code: event.detail.value, codeError: '' }),
|
|
25
|
+
checkCode: (_state, event: ValueEvent) => {
|
|
28
26
|
if (event.detail.value === RIGHT_CODE) {
|
|
29
27
|
return { verified: true };
|
|
30
28
|
}
|
|
31
29
|
return { code: '', codeError: 'That code is wrong. Try again.' };
|
|
32
30
|
},
|
|
33
31
|
startAgain: () => ({ verified: false, code: '' }),
|
|
34
|
-
setPin: (_state, event:
|
|
32
|
+
setPin: (_state, event: ValueEvent) => ({ pin: event.detail.value }),
|
|
35
33
|
clearPin: () => ({ pin: '' }),
|
|
36
|
-
setLocked: (_state, event:
|
|
34
|
+
setLocked: (_state, event: CheckedEvent) => ({
|
|
37
35
|
locked: event.detail.checked,
|
|
38
36
|
}),
|
|
39
|
-
setPledge: (_state, event:
|
|
37
|
+
setPledge: (_state, event: ValueEvent<number | null>) => {
|
|
40
38
|
const pledge = event.detail.value;
|
|
41
39
|
return {
|
|
42
40
|
pledge,
|
|
@@ -4,14 +4,14 @@ export default definePage({
|
|
|
4
4
|
initialState: state,
|
|
5
5
|
configs: { navigationBar: { title: 'Sheets' } },
|
|
6
6
|
mutations: {
|
|
7
|
-
openRelease: (state, event:
|
|
7
|
+
openRelease: (state, event: DataEvent<{ id: string }>) => ({
|
|
8
8
|
selected: state.releases.find((release) => release.id === event.data.id) ?? null,
|
|
9
9
|
}),
|
|
10
10
|
// A sheet doesn't close itself: the page sets `open` back to false.
|
|
11
11
|
closeRelease: () => ({ selected: null }),
|
|
12
12
|
openRating: () => ({ rating: true }),
|
|
13
13
|
closeRating: () => ({ rating: false }),
|
|
14
|
-
setStars: (_state, event:
|
|
14
|
+
setStars: (_state, event: ValueEvent<number>) => ({ stars: event.detail.value }),
|
|
15
15
|
saveRating: (state) => ({ rating: false, saved: state.stars, toast: 'Thanks for rating' }),
|
|
16
16
|
clearToast: () => ({ toast: '' }),
|
|
17
17
|
},
|