@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.
- package/README.md +34 -15
- package/dist/cli.js +386 -57
- package/dist/cli.js.map +1 -1
- package/dist/server-DFOUQnLA.js +11263 -0
- package/dist/server-DFOUQnLA.js.map +1 -0
- package/dist/templates/showcase/.env +3 -0
- package/dist/templates/showcase/dot.ts +22 -0
- package/dist/templates/showcase/pages/carousel/controller.ts +10 -0
- package/dist/templates/showcase/pages/carousel/state.ts +40 -0
- package/dist/templates/showcase/pages/carousel/view.dml +37 -0
- package/dist/templates/showcase/pages/device/controller.ts +70 -0
- package/dist/templates/showcase/pages/device/state.ts +7 -0
- package/dist/templates/showcase/pages/device/view.dml +44 -0
- package/dist/templates/showcase/pages/feedback/controller.ts +16 -0
- package/dist/templates/showcase/pages/feedback/state.ts +7 -0
- package/dist/templates/showcase/pages/feedback/view.dml +87 -0
- package/dist/templates/showcase/pages/files/controller.ts +47 -0
- package/dist/templates/showcase/pages/files/state.ts +11 -0
- package/dist/templates/showcase/pages/files/view.dml +35 -0
- package/dist/templates/showcase/pages/filters/controller.ts +28 -0
- package/dist/templates/showcase/pages/filters/state.ts +72 -0
- package/dist/templates/showcase/pages/filters/view.dml +43 -0
- package/dist/templates/showcase/pages/forms/controller.ts +44 -0
- package/dist/templates/showcase/pages/forms/state.ts +15 -0
- package/dist/templates/showcase/pages/forms/view.dml +39 -0
- package/dist/templates/showcase/pages/images/controller.ts +15 -0
- package/dist/templates/showcase/pages/images/state.ts +7 -0
- package/dist/templates/showcase/pages/images/view.dml +38 -0
- package/dist/templates/showcase/pages/index/controller.ts +10 -0
- package/dist/templates/showcase/pages/index/state.ts +116 -0
- package/dist/templates/showcase/pages/index/view.dml +20 -0
- package/dist/templates/showcase/pages/layout/controller.ts +26 -0
- package/dist/templates/showcase/pages/layout/state.ts +14 -0
- package/dist/templates/showcase/pages/layout/view.dml +80 -0
- package/dist/templates/showcase/pages/lists/controller.ts +36 -0
- package/dist/templates/showcase/pages/lists/state.ts +96 -0
- package/dist/templates/showcase/pages/lists/view.dml +59 -0
- package/dist/templates/showcase/pages/navigation/controller.ts +64 -0
- package/dist/templates/showcase/pages/navigation/state.ts +17 -0
- package/dist/templates/showcase/pages/navigation/view.dml +34 -0
- package/dist/templates/showcase/pages/network/controller.ts +107 -0
- package/dist/templates/showcase/pages/network/state.ts +15 -0
- package/dist/templates/showcase/pages/network/view.dml +56 -0
- package/dist/templates/showcase/pages/payments/controller.ts +42 -0
- package/dist/templates/showcase/pages/payments/state.ts +10 -0
- package/dist/templates/showcase/pages/payments/view.dml +35 -0
- package/dist/templates/showcase/pages/state/controller.ts +22 -0
- package/dist/templates/showcase/pages/state/state.ts +10 -0
- package/dist/templates/showcase/pages/state/view.dml +33 -0
- package/dist/templates/showcase/pages/text/controller.ts +10 -0
- package/dist/templates/showcase/pages/text/state.ts +7 -0
- package/dist/templates/showcase/pages/text/view.dml +49 -0
- package/dist/templates/starter/.env +3 -0
- package/dist/templates/starter/dot.ts +3 -0
- package/dist/templates/starter/pages/index/controller.ts +9 -0
- package/dist/templates/starter/pages/index/state.ts +4 -0
- package/dist/templates/starter/pages/index/view.dml +16 -0
- package/dist/templates/starter/statics/logo.png +0 -0
- package/package.json +12 -7
- package/dist/template/.env +0 -3
- package/dist/template/dot.ts +0 -6
- package/dist/template/pages/help/tips/controller.ts +0 -30
- package/dist/template/pages/help/tips/state.ts +0 -11
- package/dist/template/pages/help/tips/view.dml +0 -15
- package/dist/template/pages/index/controller.ts +0 -67
- package/dist/template/pages/index/state.ts +0 -17
- package/dist/template/pages/index/view.dml +0 -66
- /package/dist/{template → templates/showcase}/statics/logo.png +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Forms</Text>
|
|
3
|
+
<Text>Each change reaches the controller, which keeps the value in state and checks it when the form is sent.</Text>
|
|
4
|
+
|
|
5
|
+
<View variant="card">
|
|
6
|
+
<Select label="Pay from" placeholder="Choose an account" value="{{ account }}" onChange="setAccount">
|
|
7
|
+
<Option value="savings" label="Savings · Le 1,250,000" />
|
|
8
|
+
<Option value="wallet" label="Mobile wallet · Le 84,500" />
|
|
9
|
+
<Option value="card" label="Debit card · Le 310,000" />
|
|
10
|
+
</Select>
|
|
11
|
+
<Input label="Name" placeholder="Ada Lovelace" value="{{ name }}" maxLength="40" onChange="setName" />
|
|
12
|
+
<Input label="Email" type="email" placeholder="ada@example.com" hint="For the receipt" value="{{ email }}" onChange="setEmail" />
|
|
13
|
+
<Input label="Phone" type="phone" placeholder="076 123456" value="{{ phone }}" error="{{ errors.phone }}" onChange="setPhone" />
|
|
14
|
+
<Input label="Amount" type="number" prefix="Le" placeholder="0" value="{{ amount }}" error="{{ errors.amount }}" onChange="setAmount" />
|
|
15
|
+
<TextArea label="Note" placeholder="What it's for" rows="3" maxLength="140" hint="{{ note.length }} of 140" value="{{ note }}" onChange="setNote" />
|
|
16
|
+
</View>
|
|
17
|
+
|
|
18
|
+
<View variant="card">
|
|
19
|
+
<RadioGroup label="How often" value="{{ plan }}" onChange="setPlan">
|
|
20
|
+
<Radio value="once" label="Just once" />
|
|
21
|
+
<Radio value="monthly" label="Every month" />
|
|
22
|
+
<Radio value="yearly" label="Every year" />
|
|
23
|
+
</RadioGroup>
|
|
24
|
+
<Divider />
|
|
25
|
+
<Switch label="Send me receipts" checked="{{ receipts }}" onChange="setReceipts" />
|
|
26
|
+
<Checkbox label="I agree to the terms" checked="{{ agreed }}" onChange="setAgreed" />
|
|
27
|
+
</View>
|
|
28
|
+
|
|
29
|
+
<If condition="{{ sent }}">
|
|
30
|
+
<Notice tone="success" title="Sent">{{ sent }}</Notice>
|
|
31
|
+
</If>
|
|
32
|
+
<If condition="{{ failure }}">
|
|
33
|
+
<Notice tone="danger" title="Not sent">{{ failure }}</Notice>
|
|
34
|
+
</If>
|
|
35
|
+
|
|
36
|
+
<Footer>
|
|
37
|
+
<Button onClick="send" loading="{{ sending }}" disabled="{{ !agreed }}">Send</Button>
|
|
38
|
+
</Footer>
|
|
39
|
+
</View>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
export default definePage({
|
|
4
|
+
initialState: state,
|
|
5
|
+
mutations: {
|
|
6
|
+
grow: (state) => ({ size: Math.min(state.size + 16, 128) }),
|
|
7
|
+
shrink: (state) => ({ size: Math.max(state.size - 16, 16) }),
|
|
8
|
+
logoLoaded: (_state, event: DotEvent<{ width: number; height: number }>) => ({
|
|
9
|
+
loaded: `${event.detail.width} × ${event.detail.height}`,
|
|
10
|
+
}),
|
|
11
|
+
missingFailed: (_state, event: DotEvent<{ message: string }>) => ({
|
|
12
|
+
failure: event.detail.message,
|
|
13
|
+
}),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Images</Text>
|
|
3
|
+
<Text>Pictures in the dot's statics/ folder ship with it. The build checks each one.</Text>
|
|
4
|
+
|
|
5
|
+
<View variant="card" direction="row" align="end" gap="large">
|
|
6
|
+
<Image src="statics/logo.png" alt="Small logo" width="24" height="24" />
|
|
7
|
+
<Image src="statics/logo.png" alt="Medium logo" width="48" height="48" />
|
|
8
|
+
<Image src="statics/logo.png" alt="Large logo" width="96" height="96" />
|
|
9
|
+
</View>
|
|
10
|
+
|
|
11
|
+
<Text variant="caption" tone="muted">Shapes, and how a picture fills its box</Text>
|
|
12
|
+
<View variant="card" direction="row" align="center" gap="large">
|
|
13
|
+
<Image src="statics/logo.png" alt="Rounded" width="56" height="56" />
|
|
14
|
+
<Image src="statics/logo.png" alt="Square" width="56" height="56" shape="square" />
|
|
15
|
+
<Image src="statics/logo.png" alt="Circle" width="56" height="56" shape="circle" />
|
|
16
|
+
<Image src="statics/logo.png" alt="Contained" width="96" height="56" fit="contain" />
|
|
17
|
+
</View>
|
|
18
|
+
|
|
19
|
+
<Text variant="caption" tone="muted">Sizes can come from state</Text>
|
|
20
|
+
<View variant="card" gap="small">
|
|
21
|
+
<Image src="statics/logo.png" alt="Logo" width="{{ size }}" height="{{ size }}" onLoad="logoLoaded" />
|
|
22
|
+
<Text>{{ size }} × {{ size }} on screen, {{ loaded }} in the file</Text>
|
|
23
|
+
<View direction="row" gap="small">
|
|
24
|
+
<Button variant="secondary" onClick="shrink" disabled="{{ size <= 16 }}">Smaller</Button>
|
|
25
|
+
<Button variant="secondary" onClick="grow" disabled="{{ size >= 128 }}">Bigger</Button>
|
|
26
|
+
</View>
|
|
27
|
+
</View>
|
|
28
|
+
|
|
29
|
+
<Text variant="caption" tone="muted">An image that fails says why</Text>
|
|
30
|
+
<View variant="card">
|
|
31
|
+
<If condition="{{ failure }}">
|
|
32
|
+
<Text>{{ failure }}</Text>
|
|
33
|
+
</If>
|
|
34
|
+
<Else>
|
|
35
|
+
<Image src="{{ missing }}" alt="" width="48" height="48" onError="missingFailed" />
|
|
36
|
+
</Else>
|
|
37
|
+
</View>
|
|
38
|
+
</View>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export interface Feature {
|
|
2
|
+
page: PageId;
|
|
3
|
+
title: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
icon: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Section {
|
|
9
|
+
title: string;
|
|
10
|
+
features: Feature[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
title: 'Showcase',
|
|
15
|
+
sections: [
|
|
16
|
+
{
|
|
17
|
+
title: 'Views',
|
|
18
|
+
features: [
|
|
19
|
+
{
|
|
20
|
+
page: 'layout',
|
|
21
|
+
title: 'Layout',
|
|
22
|
+
summary: 'Rows, columns, grids, gaps, alignment and cards',
|
|
23
|
+
icon: 'grid',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
page: 'text',
|
|
27
|
+
title: 'Text and bindings',
|
|
28
|
+
summary: 'Text styles and tones, and values from state',
|
|
29
|
+
icon: 'edit',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
page: 'images',
|
|
33
|
+
title: 'Images',
|
|
34
|
+
summary: 'Pictures from statics/, their shapes and events',
|
|
35
|
+
icon: 'image',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
page: 'carousel',
|
|
39
|
+
title: 'Carousel',
|
|
40
|
+
summary: 'Slides to swipe, played by themselves, with dots',
|
|
41
|
+
icon: 'image',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
page: 'lists',
|
|
45
|
+
title: 'Lists and icons',
|
|
46
|
+
summary: 'Rows to tap, sheets of actions, badges and icons',
|
|
47
|
+
icon: 'list',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
page: 'filters',
|
|
51
|
+
title: 'Tabs and filters',
|
|
52
|
+
summary: 'Tabs, chips to narrow a list, and an empty state',
|
|
53
|
+
icon: 'search',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
page: 'forms',
|
|
57
|
+
title: 'Forms',
|
|
58
|
+
summary: 'Fields, choices, switches, and a footer to send them',
|
|
59
|
+
icon: 'check',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
page: 'payments',
|
|
63
|
+
title: 'Payments',
|
|
64
|
+
summary: 'Amounts, one-time codes, PINs and QR codes',
|
|
65
|
+
icon: 'cash',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
page: 'feedback',
|
|
69
|
+
title: 'Feedback',
|
|
70
|
+
summary: 'Skeletons, toasts, spinners, progress and notices',
|
|
71
|
+
icon: 'bell',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
title: 'Logic',
|
|
77
|
+
features: [
|
|
78
|
+
{
|
|
79
|
+
page: 'state',
|
|
80
|
+
title: 'State, mutations and actions',
|
|
81
|
+
summary: 'A counter, conditions and lists',
|
|
82
|
+
icon: 'refresh',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
page: 'navigation',
|
|
86
|
+
title: 'Navigation and hooks',
|
|
87
|
+
summary: 'The page stack, and when each hook runs',
|
|
88
|
+
icon: 'arrow-right',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: 'Dash',
|
|
94
|
+
features: [
|
|
95
|
+
{
|
|
96
|
+
page: 'device',
|
|
97
|
+
title: 'Alerts and device',
|
|
98
|
+
summary: 'Native alerts, the clipboard, sharing, delays and the torch',
|
|
99
|
+
icon: 'mobile',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
page: 'network',
|
|
103
|
+
title: 'Network',
|
|
104
|
+
summary: 'Requests, JSON, downloads and uploads',
|
|
105
|
+
icon: 'wifi',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
page: 'files',
|
|
109
|
+
title: 'Files',
|
|
110
|
+
summary: "The dot's own files, kept between runs",
|
|
111
|
+
icon: 'file',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
] as Section[],
|
|
116
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<View direction="row" align="center" gap="large">
|
|
3
|
+
<Image src="statics/logo.png" alt="Dot logo" width="48" height="48" />
|
|
4
|
+
<View gap="none">
|
|
5
|
+
<Text variant="title">{{ title }}</Text>
|
|
6
|
+
<Text variant="caption" tone="muted">What a dot can do, one page each</Text>
|
|
7
|
+
</View>
|
|
8
|
+
</View>
|
|
9
|
+
|
|
10
|
+
<For each="{{ sections }}" item="section" key="title">
|
|
11
|
+
<View gap="small">
|
|
12
|
+
<Text variant="caption" tone="muted">{{ section.title }}</Text>
|
|
13
|
+
<List>
|
|
14
|
+
<For each="{{ section.features }}" item="feature" key="page">
|
|
15
|
+
<ListItem icon="{{ feature.icon }}" title="{{ feature.title }}" subtitle="{{ feature.summary }}" data-page="{{ feature.page }}" onTap="open" />
|
|
16
|
+
</For>
|
|
17
|
+
</List>
|
|
18
|
+
</View>
|
|
19
|
+
</For>
|
|
20
|
+
</View>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Align, Direction, Justify, Space } from './state';
|
|
2
|
+
import state from './state';
|
|
3
|
+
|
|
4
|
+
const DIRECTIONS: Direction[] = ['row', 'column'];
|
|
5
|
+
const JUSTIFIES: Justify[] = ['start', 'center', 'end', 'between'];
|
|
6
|
+
const ALIGNS: Align[] = ['stretch', 'start', 'center', 'end'];
|
|
7
|
+
const SPACES: Space[] = ['none', 'small', 'medium', 'large'];
|
|
8
|
+
|
|
9
|
+
export default definePage({
|
|
10
|
+
initialState: state,
|
|
11
|
+
mutations: {
|
|
12
|
+
nextDirection: (state) => ({ direction: after(DIRECTIONS, state.direction) }),
|
|
13
|
+
nextJustify: (state) => ({ justify: after(JUSTIFIES, state.justify) }),
|
|
14
|
+
nextAlign: (state) => ({ align: after(ALIGNS, state.align) }),
|
|
15
|
+
nextGap: (state) => ({ gap: after(SPACES, state.gap) }),
|
|
16
|
+
toggleWrap: (state) => ({ wrap: !state.wrap }),
|
|
17
|
+
openService: (_state, event: DotEvent<unknown, { name: string }>) => ({
|
|
18
|
+
service: event.data.name,
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function after<Value>(values: Value[], current: Value): Value {
|
|
24
|
+
const next = (values.indexOf(current) + 1) % values.length;
|
|
25
|
+
return values[next]!;
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Direction = 'row' | 'column';
|
|
2
|
+
export type Justify = 'start' | 'center' | 'end' | 'between';
|
|
3
|
+
export type Align = 'stretch' | 'start' | 'center' | 'end';
|
|
4
|
+
export type Space = 'none' | 'small' | 'medium' | 'large';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
direction: 'row' as Direction,
|
|
8
|
+
justify: 'start' as Justify,
|
|
9
|
+
align: 'center' as Align,
|
|
10
|
+
gap: 'small' as Space,
|
|
11
|
+
wrap: true,
|
|
12
|
+
// The service tapped in the grid.
|
|
13
|
+
service: '',
|
|
14
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Layout</Text>
|
|
3
|
+
<Text>A View lays out what it holds in a column, or in a row. Change the one below.</Text>
|
|
4
|
+
|
|
5
|
+
<View variant="card" direction="{{ direction }}" justify="{{ justify }}" align="{{ align }}" gap="{{ gap }}" wrap="{{ wrap }}">
|
|
6
|
+
<Button variant="secondary">One</Button>
|
|
7
|
+
<Button variant="secondary">Two</Button>
|
|
8
|
+
<Text variant="title">Three</Text>
|
|
9
|
+
<Button variant="secondary">Four</Button>
|
|
10
|
+
<Text variant="caption" tone="muted">Five</Text>
|
|
11
|
+
</View>
|
|
12
|
+
|
|
13
|
+
<View gap="small">
|
|
14
|
+
<View direction="row" align="center">
|
|
15
|
+
<Text>direction="{{ direction }}"</Text>
|
|
16
|
+
<View grow />
|
|
17
|
+
<Button variant="secondary" onClick="nextDirection">Change</Button>
|
|
18
|
+
</View>
|
|
19
|
+
<View direction="row" align="center">
|
|
20
|
+
<Text>justify="{{ justify }}"</Text>
|
|
21
|
+
<View grow />
|
|
22
|
+
<Button variant="secondary" onClick="nextJustify">Change</Button>
|
|
23
|
+
</View>
|
|
24
|
+
<View direction="row" align="center">
|
|
25
|
+
<Text>align="{{ align }}"</Text>
|
|
26
|
+
<View grow />
|
|
27
|
+
<Button variant="secondary" onClick="nextAlign">Change</Button>
|
|
28
|
+
</View>
|
|
29
|
+
<View direction="row" align="center">
|
|
30
|
+
<Text>gap="{{ gap }}"</Text>
|
|
31
|
+
<View grow />
|
|
32
|
+
<Button variant="secondary" onClick="nextGap">Change</Button>
|
|
33
|
+
</View>
|
|
34
|
+
<View direction="row" align="center">
|
|
35
|
+
<Text>wrap="{{ wrap }}"</Text>
|
|
36
|
+
<View grow />
|
|
37
|
+
<Button variant="secondary" onClick="toggleWrap">Change</Button>
|
|
38
|
+
</View>
|
|
39
|
+
</View>
|
|
40
|
+
|
|
41
|
+
<Text variant="caption" tone="muted">grow takes the space that's left</Text>
|
|
42
|
+
<View direction="row" gap="small">
|
|
43
|
+
<View variant="card" grow>
|
|
44
|
+
<Text>grow</Text>
|
|
45
|
+
</View>
|
|
46
|
+
<View variant="card">
|
|
47
|
+
<Text>fixed</Text>
|
|
48
|
+
</View>
|
|
49
|
+
</View>
|
|
50
|
+
|
|
51
|
+
<Text variant="caption" tone="muted">padding, on every side or just one</Text>
|
|
52
|
+
<View direction="row" gap="small">
|
|
53
|
+
<View variant="card" padding="small">
|
|
54
|
+
<Text>small</Text>
|
|
55
|
+
</View>
|
|
56
|
+
<View variant="card" padding="large">
|
|
57
|
+
<Text>large</Text>
|
|
58
|
+
</View>
|
|
59
|
+
<View variant="card" padding="small" paddingStart="large">
|
|
60
|
+
<Text>start</Text>
|
|
61
|
+
</View>
|
|
62
|
+
</View>
|
|
63
|
+
|
|
64
|
+
<Text variant="caption" tone="muted">A Grid keeps equal columns, here of services to tap</Text>
|
|
65
|
+
<View variant="card" gap="medium">
|
|
66
|
+
<Grid columns="4">
|
|
67
|
+
<GridItem icon="send" label="Send" data-name="Send" onTap="openService" />
|
|
68
|
+
<GridItem icon="phone" label="Airtime" data-name="Airtime" onTap="openService" />
|
|
69
|
+
<GridItem icon="bolt" label="Electricity" badge="New" data-name="Electricity" onTap="openService" />
|
|
70
|
+
<GridItem icon="water" label="Water" data-name="Water" onTap="openService" />
|
|
71
|
+
<GridItem icon="qr-code" label="Scan to pay" data-name="Scan to pay" onTap="openService" />
|
|
72
|
+
<GridItem icon="wallet" label="Save" data-name="Save" onTap="openService" />
|
|
73
|
+
<GridItem icon="receipt" label="Receipts" data-name="Receipts" onTap="openService" />
|
|
74
|
+
<GridItem icon="more" label="More" data-name="More" onTap="openService" />
|
|
75
|
+
</Grid>
|
|
76
|
+
<If condition="{{ service }}">
|
|
77
|
+
<Text tone="muted">You tapped {{ service }}</Text>
|
|
78
|
+
</If>
|
|
79
|
+
</View>
|
|
80
|
+
</View>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import state from './state';
|
|
2
|
+
|
|
3
|
+
export default definePage({
|
|
4
|
+
initialState: state,
|
|
5
|
+
mutations: {
|
|
6
|
+
choose: (state, event: DotEvent<unknown, { id: string }>) => {
|
|
7
|
+
const account = state.accounts.find((candidate) => candidate.id === event.data.id);
|
|
8
|
+
return { chosen: account?.name ?? '' };
|
|
9
|
+
},
|
|
10
|
+
openPayment: (state, event: DotEvent<unknown, { id: string }>) => ({
|
|
11
|
+
selected: state.payments.find((payment) => payment.id === event.data.id) ?? null,
|
|
12
|
+
}),
|
|
13
|
+
closeSheet: () => ({ selected: null }),
|
|
14
|
+
clearToast: () => ({ toast: '' }),
|
|
15
|
+
},
|
|
16
|
+
actions: {
|
|
17
|
+
async copyReference(state) {
|
|
18
|
+
if (!state.selected) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
await this.dash.system.copyText(state.selected.reference);
|
|
22
|
+
this.setState({ selected: null, toast: 'Reference copied' });
|
|
23
|
+
},
|
|
24
|
+
async shareReceipt(state) {
|
|
25
|
+
if (!state.selected) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const { title, amount, status, reference } = state.selected;
|
|
29
|
+
this.setState({ selected: null });
|
|
30
|
+
await this.dash.system.share({
|
|
31
|
+
title: `${title} receipt`,
|
|
32
|
+
text: `${title}: ${amount}, ${status}. Reference ${reference}.`,
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export interface Account {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
number: string;
|
|
5
|
+
balance: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Payment {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
date: string;
|
|
13
|
+
amount: string;
|
|
14
|
+
status: string;
|
|
15
|
+
tone: string;
|
|
16
|
+
reference: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
accounts: [
|
|
21
|
+
{
|
|
22
|
+
id: 'savings',
|
|
23
|
+
name: 'Savings',
|
|
24
|
+
number: '•••• 2041',
|
|
25
|
+
balance: 'Le 1,250,000',
|
|
26
|
+
icon: 'bank',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'wallet',
|
|
30
|
+
name: 'Mobile wallet',
|
|
31
|
+
number: '076 •••• 21',
|
|
32
|
+
balance: 'Le 84,500',
|
|
33
|
+
icon: 'mobile',
|
|
34
|
+
},
|
|
35
|
+
{ id: 'card', name: 'Debit card', number: '•••• 7730', balance: 'Le 310,000', icon: 'card' },
|
|
36
|
+
] as Account[],
|
|
37
|
+
payments: [
|
|
38
|
+
{
|
|
39
|
+
id: 'p1',
|
|
40
|
+
title: 'Electricity',
|
|
41
|
+
date: 'Today',
|
|
42
|
+
amount: 'Le 50,000',
|
|
43
|
+
status: 'Paid',
|
|
44
|
+
tone: 'success',
|
|
45
|
+
reference: 'EDSA-58213',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'p2',
|
|
49
|
+
title: 'Airtime',
|
|
50
|
+
date: 'Yesterday',
|
|
51
|
+
amount: 'Le 10,000',
|
|
52
|
+
status: 'Pending',
|
|
53
|
+
tone: 'warning',
|
|
54
|
+
reference: 'AIR-11907',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'p3',
|
|
58
|
+
title: 'Water',
|
|
59
|
+
date: '12 September',
|
|
60
|
+
amount: 'Le 35,000',
|
|
61
|
+
status: 'Failed',
|
|
62
|
+
tone: 'danger',
|
|
63
|
+
reference: 'GVWC-40022',
|
|
64
|
+
},
|
|
65
|
+
] as Payment[],
|
|
66
|
+
chosen: '',
|
|
67
|
+
// The payment whose actions the sheet shows.
|
|
68
|
+
selected: null as Payment | null,
|
|
69
|
+
toast: '',
|
|
70
|
+
icons: [
|
|
71
|
+
'home',
|
|
72
|
+
'search',
|
|
73
|
+
'bell',
|
|
74
|
+
'user',
|
|
75
|
+
'settings',
|
|
76
|
+
'wallet',
|
|
77
|
+
'bank',
|
|
78
|
+
'card',
|
|
79
|
+
'cash',
|
|
80
|
+
'send',
|
|
81
|
+
'receipt',
|
|
82
|
+
'qr-code',
|
|
83
|
+
'bolt',
|
|
84
|
+
'water',
|
|
85
|
+
'phone',
|
|
86
|
+
'mail',
|
|
87
|
+
'calendar',
|
|
88
|
+
'clock',
|
|
89
|
+
'location',
|
|
90
|
+
'lock',
|
|
91
|
+
'share',
|
|
92
|
+
'copy',
|
|
93
|
+
'download',
|
|
94
|
+
'star',
|
|
95
|
+
],
|
|
96
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Lists and icons</Text>
|
|
3
|
+
<Text>A List draws rows in a card. A row shows an icon or a picture, a value or anything at its end, and a chevron when it can be tapped.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="caption" tone="muted">Rows know which one was tapped from their data- attributes</Text>
|
|
7
|
+
<List>
|
|
8
|
+
<For each="{{ accounts }}" item="account" key="id">
|
|
9
|
+
<ListItem icon="{{ account.icon }}" title="{{ account.name }}" subtitle="{{ account.number }}" value="{{ account.balance }}" data-id="{{ account.id }}" onTap="choose" />
|
|
10
|
+
</For>
|
|
11
|
+
</List>
|
|
12
|
+
<If condition="{{ chosen }}">
|
|
13
|
+
<Text>You chose {{ chosen }}</Text>
|
|
14
|
+
</If>
|
|
15
|
+
</View>
|
|
16
|
+
|
|
17
|
+
<View gap="small">
|
|
18
|
+
<Text variant="caption" tone="muted">A badge at the end of each row; tap one for its actions</Text>
|
|
19
|
+
<List>
|
|
20
|
+
<For each="{{ payments }}" item="payment" key="id">
|
|
21
|
+
<ListItem title="{{ payment.title }}" subtitle="{{ payment.date }} · {{ payment.amount }}" data-id="{{ payment.id }}" onTap="openPayment">
|
|
22
|
+
<Badge tone="{{ payment.tone }}">{{ payment.status }}</Badge>
|
|
23
|
+
</ListItem>
|
|
24
|
+
</For>
|
|
25
|
+
</List>
|
|
26
|
+
</View>
|
|
27
|
+
|
|
28
|
+
<View gap="small">
|
|
29
|
+
<Text variant="caption" tone="muted">Icons, by name, in any tone</Text>
|
|
30
|
+
<View variant="card" direction="row" wrap gap="large">
|
|
31
|
+
<For each="{{ icons }}" item="icon" key="*this">
|
|
32
|
+
<Icon name="{{ icon }}" />
|
|
33
|
+
</For>
|
|
34
|
+
</View>
|
|
35
|
+
<View variant="card" direction="row" wrap gap="large" align="center">
|
|
36
|
+
<Icon name="info" tone="info" size="small" />
|
|
37
|
+
<Icon name="success" tone="success" />
|
|
38
|
+
<Icon name="warning" tone="warning" size="large" />
|
|
39
|
+
<Icon name="error" tone="danger" size="large" />
|
|
40
|
+
<Icon name="star" tone="muted" />
|
|
41
|
+
</View>
|
|
42
|
+
</View>
|
|
43
|
+
|
|
44
|
+
<View gap="small">
|
|
45
|
+
<Text variant="caption" tone="muted">A divider between things</Text>
|
|
46
|
+
<View variant="card">
|
|
47
|
+
<Text>Above the line</Text>
|
|
48
|
+
<Divider />
|
|
49
|
+
<Text>Below the line</Text>
|
|
50
|
+
</View>
|
|
51
|
+
</View>
|
|
52
|
+
|
|
53
|
+
<Sheet open="{{ selected !== null }}" title="{{ selected.title }} · {{ selected.amount }}" onClose="closeSheet">
|
|
54
|
+
<Button variant="secondary" onClick="copyReference">Copy reference {{ selected.reference }}</Button>
|
|
55
|
+
<Button variant="secondary" onClick="shareReceipt">Share receipt</Button>
|
|
56
|
+
<Button onClick="closeSheet">Cancel</Button>
|
|
57
|
+
</Sheet>
|
|
58
|
+
<Toast message="{{ toast }}" tone="success" onHide="clearToast" />
|
|
59
|
+
</View>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { HookRun } from './state';
|
|
2
|
+
import state from './state';
|
|
3
|
+
|
|
4
|
+
export default definePage({
|
|
5
|
+
initialState: state,
|
|
6
|
+
// What Dash's navigation bar shows until the page changes it.
|
|
7
|
+
configs: { navigationBar: { title: 'Navigation' } },
|
|
8
|
+
hooks: {
|
|
9
|
+
// Options come from the page that opened this one, as strings.
|
|
10
|
+
onLoad(options) {
|
|
11
|
+
const depth = Number(options.depth ?? '1') + 1;
|
|
12
|
+
const from = options.trail ?? 'Home';
|
|
13
|
+
this.setState({ depth, from, trail: `${from} › ${depth}` });
|
|
14
|
+
this.setNavigationBar({ title: `Page ${depth}` });
|
|
15
|
+
this.setState((current) => ({ hooks: ran(current.hooks, 'onLoad') }));
|
|
16
|
+
},
|
|
17
|
+
onShow() {
|
|
18
|
+
this.setState((current) => ({ hooks: ran(current.hooks, 'onShow') }));
|
|
19
|
+
},
|
|
20
|
+
onHide() {
|
|
21
|
+
this.setState((current) => ({ hooks: ran(current.hooks, 'onHide') }));
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
actions: {
|
|
25
|
+
openAnother(state) {
|
|
26
|
+
this.navigation.push('navigation', { depth: String(state.depth), trail: state.trail });
|
|
27
|
+
},
|
|
28
|
+
replaceThis(state) {
|
|
29
|
+
this.navigation.replace('navigation', { depth: String(state.depth - 1), trail: state.from });
|
|
30
|
+
},
|
|
31
|
+
back() {
|
|
32
|
+
this.navigation.back();
|
|
33
|
+
},
|
|
34
|
+
backTwo() {
|
|
35
|
+
this.navigation.back(2);
|
|
36
|
+
},
|
|
37
|
+
home() {
|
|
38
|
+
this.navigation.reset('index');
|
|
39
|
+
},
|
|
40
|
+
toggleColors(state) {
|
|
41
|
+
const colored = !state.colored;
|
|
42
|
+
// Undefined puts Dash's own colors back.
|
|
43
|
+
this.setNavigationBar({
|
|
44
|
+
backgroundColor: colored ? '#1A73E8' : undefined,
|
|
45
|
+
textColor: colored ? '#FFFFFF' : undefined,
|
|
46
|
+
});
|
|
47
|
+
this.setState({ colored });
|
|
48
|
+
},
|
|
49
|
+
toggleNavigationBar(state) {
|
|
50
|
+
const navigationBarHidden = !state.navigationBarHidden;
|
|
51
|
+
this.setNavigationBar({ hidden: navigationBarHidden });
|
|
52
|
+
this.setState({ navigationBarHidden });
|
|
53
|
+
},
|
|
54
|
+
toggleTabBar(state) {
|
|
55
|
+
const tabBarHidden = !state.tabBarHidden;
|
|
56
|
+
this.setTabBar({ hidden: tabBarHidden });
|
|
57
|
+
this.setState({ tabBarHidden });
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
function ran(hooks: readonly HookRun[], hook: string): HookRun[] {
|
|
63
|
+
return [...hooks, { id: hooks.length + 1, hook }];
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface HookRun {
|
|
2
|
+
id: number;
|
|
3
|
+
hook: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
depth: 1,
|
|
8
|
+
maxDepth: 8,
|
|
9
|
+
// The trail of the page that opened this one.
|
|
10
|
+
from: '',
|
|
11
|
+
trail: '',
|
|
12
|
+
hooks: [] as HookRun[],
|
|
13
|
+
// What this page set in Dash's bars.
|
|
14
|
+
colored: false,
|
|
15
|
+
navigationBarHidden: false,
|
|
16
|
+
tabBarHidden: false,
|
|
17
|
+
};
|