@monimesl/dot-cli 0.1.0-alpha.10
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 +96 -0
- package/bin/dotctl.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +942 -0
- package/dist/cli.js.map +1 -0
- package/dist/server-Dbrgkelo.js +11215 -0
- package/dist/server-Dbrgkelo.js.map +1 -0
- package/dist/templates/showcase/.env +3 -0
- package/dist/templates/showcase/dot.ts +24 -0
- package/dist/templates/showcase/pages/cache/controller.ts +45 -0
- package/dist/templates/showcase/pages/cache/state.ts +17 -0
- package/dist/templates/showcase/pages/cache/view.dml +36 -0
- package/dist/templates/showcase/pages/carousel/controller.ts +40 -0
- package/dist/templates/showcase/pages/carousel/state.ts +77 -0
- package/dist/templates/showcase/pages/carousel/view.dml +40 -0
- package/dist/templates/showcase/pages/device/controller.ts +80 -0
- package/dist/templates/showcase/pages/device/state.ts +7 -0
- package/dist/templates/showcase/pages/device/view.dml +49 -0
- package/dist/templates/showcase/pages/feedback/controller.ts +21 -0
- package/dist/templates/showcase/pages/feedback/state.ts +8 -0
- package/dist/templates/showcase/pages/feedback/view.dml +87 -0
- package/dist/templates/showcase/pages/files/controller.ts +66 -0
- package/dist/templates/showcase/pages/files/state.ts +19 -0
- package/dist/templates/showcase/pages/files/view.dml +50 -0
- package/dist/templates/showcase/pages/filters/controller.ts +27 -0
- package/dist/templates/showcase/pages/filters/state.ts +118 -0
- package/dist/templates/showcase/pages/filters/view.dml +44 -0
- package/dist/templates/showcase/pages/forms/controller.ts +68 -0
- package/dist/templates/showcase/pages/forms/state.ts +34 -0
- package/dist/templates/showcase/pages/forms/view.dml +49 -0
- package/dist/templates/showcase/pages/images/controller.ts +41 -0
- package/dist/templates/showcase/pages/images/state.ts +10 -0
- package/dist/templates/showcase/pages/images/view.dml +53 -0
- package/dist/templates/showcase/pages/index/controller.ts +10 -0
- package/dist/templates/showcase/pages/index/state.ts +128 -0
- package/dist/templates/showcase/pages/index/view.dml +20 -0
- package/dist/templates/showcase/pages/layout/controller.ts +60 -0
- package/dist/templates/showcase/pages/layout/state.ts +34 -0
- package/dist/templates/showcase/pages/layout/view.dml +103 -0
- package/dist/templates/showcase/pages/lists/controller.ts +37 -0
- package/dist/templates/showcase/pages/lists/state.ts +117 -0
- package/dist/templates/showcase/pages/lists/view.dml +59 -0
- package/dist/templates/showcase/pages/navigation/controller.ts +65 -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 +151 -0
- package/dist/templates/showcase/pages/network/state.ts +22 -0
- package/dist/templates/showcase/pages/network/view.dml +67 -0
- package/dist/templates/showcase/pages/payments/controller.ts +46 -0
- package/dist/templates/showcase/pages/payments/state.ts +13 -0
- package/dist/templates/showcase/pages/payments/view.dml +45 -0
- package/dist/templates/showcase/pages/secrets/controller.ts +43 -0
- package/dist/templates/showcase/pages/secrets/state.ts +5 -0
- package/dist/templates/showcase/pages/secrets/view.dml +24 -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 +8 -0
- package/dist/templates/showcase/pages/text/view.dml +58 -0
- package/dist/templates/showcase/statics/logo.png +0 -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 +53 -0
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
interface Lookup {
|
|
10
|
+
results: { collectionId: number; artworkUrl100: string }[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default definePage({
|
|
14
|
+
initialState: state,
|
|
15
|
+
hooks: {
|
|
16
|
+
// The shelf's covers come from Apple's catalog.
|
|
17
|
+
async onLoad() {
|
|
18
|
+
const ids = this.state.releases.map((release) => release.id).join(',');
|
|
19
|
+
try {
|
|
20
|
+
const { body } = await this.dash.network.http.request<Lookup>({
|
|
21
|
+
url: `https://itunes.apple.com/lookup?id=${ids}`,
|
|
22
|
+
as: 'json',
|
|
23
|
+
});
|
|
24
|
+
const covers = new Map(
|
|
25
|
+
body.results.map((result) => [
|
|
26
|
+
result.collectionId,
|
|
27
|
+
result.artworkUrl100.replace('100x100bb', '300x300bb'),
|
|
28
|
+
]),
|
|
29
|
+
);
|
|
30
|
+
this.setState((current) => ({
|
|
31
|
+
releases: current.releases.map((release) => ({
|
|
32
|
+
...release,
|
|
33
|
+
cover: covers.get(release.id) ?? '',
|
|
34
|
+
})),
|
|
35
|
+
}));
|
|
36
|
+
} catch {
|
|
37
|
+
// Without the catalog, the shelf shows its titles alone.
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
mutations: {
|
|
42
|
+
nextDirection: (state) => ({ direction: after(DIRECTIONS, state.direction) }),
|
|
43
|
+
nextJustify: (state) => ({ justify: after(JUSTIFIES, state.justify) }),
|
|
44
|
+
nextAlign: (state) => ({ align: after(ALIGNS, state.align) }),
|
|
45
|
+
nextGap: (state) => ({ gap: after(SPACES, state.gap) }),
|
|
46
|
+
toggleWrap: (state) => ({ wrap: !state.wrap }),
|
|
47
|
+
openSection: (_state, event: DotEvent<unknown, { name: string }>) => ({
|
|
48
|
+
section: event.data.name,
|
|
49
|
+
}),
|
|
50
|
+
showFirst: (_state, event: DotEvent<{ index: number }>) => ({ first: event.detail.index }),
|
|
51
|
+
shelfStart: () => ({ first: 0 }),
|
|
52
|
+
shelfEnd: (state) => ({ first: state.releases.length - 1 }),
|
|
53
|
+
playSong: (state) => ({ playing: !state.playing }),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
function after<Value>(values: Value[], current: Value): Value {
|
|
58
|
+
const next = (values.indexOf(current) + 1) % values.length;
|
|
59
|
+
return values[next]!;
|
|
60
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 interface Release {
|
|
7
|
+
// Its id in Apple's catalog, which has its cover.
|
|
8
|
+
id: number;
|
|
9
|
+
title: string;
|
|
10
|
+
year: number;
|
|
11
|
+
cover: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
direction: 'row' as Direction,
|
|
16
|
+
justify: 'start' as Justify,
|
|
17
|
+
align: 'center' as Align,
|
|
18
|
+
gap: 'small' as Space,
|
|
19
|
+
wrap: true,
|
|
20
|
+
// The section tapped in the grid.
|
|
21
|
+
section: '',
|
|
22
|
+
// Whether the tapped song card is playing.
|
|
23
|
+
playing: false,
|
|
24
|
+
// Drizilik's releases, newest first, for the shelf.
|
|
25
|
+
releases: [
|
|
26
|
+
{ id: 6811765244, title: 'AUDACITY', year: 2026, cover: '' },
|
|
27
|
+
{ id: 1788321371, title: 'Wait and See', year: 2025, cover: '' },
|
|
28
|
+
{ id: 1745452762, title: 'Send Money', year: 2024, cover: '' },
|
|
29
|
+
{ id: 1638724918, title: 'Ashobi', year: 2022, cover: '' },
|
|
30
|
+
{ id: 1590578915, title: 'Exodus', year: 2021, cover: '' },
|
|
31
|
+
] as Release[],
|
|
32
|
+
// The release at the start of the shelf.
|
|
33
|
+
first: 0,
|
|
34
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Layout</Text>
|
|
3
|
+
<Text>A View puts its items in a column or 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">Palm-wine</Button>
|
|
7
|
+
<Button variant="secondary">Gumbe</Button>
|
|
8
|
+
<Text variant="title">Afropop</Text>
|
|
9
|
+
<Button variant="secondary">Bubu</Button>
|
|
10
|
+
<Text variant="caption" tone="muted">Milo jazz</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 fills the space left over: the song grows, the year does not. Tap the song: a View can be tapped.</Text>
|
|
42
|
+
<View direction="row" gap="small">
|
|
43
|
+
<View variant="card" grow onTap="playSong">
|
|
44
|
+
<Text>{{ playing ? 'Playing Exodus, by Drizilik' : 'Exodus, by Drizilik' }}</Text>
|
|
45
|
+
</View>
|
|
46
|
+
<View variant="card">
|
|
47
|
+
<Text>2021</Text>
|
|
48
|
+
</View>
|
|
49
|
+
</View>
|
|
50
|
+
|
|
51
|
+
<Text variant="caption" tone="muted">A Scroll moves a row sideways. It stops at the start of each release. The buttons scroll it too.</Text>
|
|
52
|
+
<Scroll gap="medium" snap="start" index="{{ first }}" onChange="showFirst">
|
|
53
|
+
<For each="{{ releases }}" item="release" key="id">
|
|
54
|
+
<View gap="small">
|
|
55
|
+
<If condition="{{ release.cover }}">
|
|
56
|
+
<Image src="{{ release.cover }}" alt="{{ release.title }}" width="128" height="128" />
|
|
57
|
+
</If>
|
|
58
|
+
<Else>
|
|
59
|
+
<Skeleton shape="box" height="128" />
|
|
60
|
+
</Else>
|
|
61
|
+
<Text weight="medium" maxLines="2">{{ release.title }}</Text>
|
|
62
|
+
<Text variant="caption" tone="muted">{{ release.year }}</Text>
|
|
63
|
+
</View>
|
|
64
|
+
</For>
|
|
65
|
+
</Scroll>
|
|
66
|
+
<Text tone="muted">First on the shelf: {{ releases[first].title }}</Text>
|
|
67
|
+
<View direction="row" gap="small">
|
|
68
|
+
<Button variant="secondary" onClick="shelfStart" disabled="{{ first === 0 }}">To the start</Button>
|
|
69
|
+
<Button variant="secondary" onClick="shelfEnd" disabled="{{ first === releases.length - 1 }}">To the end</Button>
|
|
70
|
+
</View>
|
|
71
|
+
|
|
72
|
+
<Text variant="caption" tone="muted">padding, on every side or on one side</Text>
|
|
73
|
+
<View direction="row" gap="small">
|
|
74
|
+
<View variant="card" padding="small">
|
|
75
|
+
<Text>small</Text>
|
|
76
|
+
</View>
|
|
77
|
+
<View variant="card" padding="large">
|
|
78
|
+
<Text>large</Text>
|
|
79
|
+
</View>
|
|
80
|
+
<View variant="card" padding="small" paddingStart="large">
|
|
81
|
+
<Text>start</Text>
|
|
82
|
+
</View>
|
|
83
|
+
</View>
|
|
84
|
+
<Text variant="caption" tone="muted">Text, List, Notice and Grid take padding too</Text>
|
|
85
|
+
<Notice title="Heads up" paddingTop="large" paddingBottom="large">This notice has large padding above and below.</Notice>
|
|
86
|
+
|
|
87
|
+
<Text variant="caption" tone="muted">A Grid keeps its columns the same width</Text>
|
|
88
|
+
<View variant="card" gap="medium">
|
|
89
|
+
<Grid columns="4">
|
|
90
|
+
<GridItem icon="microphone" label="Artists" data-name="Artists" onTap="openSection" />
|
|
91
|
+
<GridItem icon="music" label="Albums" data-name="Albums" onTap="openSection" />
|
|
92
|
+
<GridItem icon="playlist" label="Playlists" data-name="Playlists" onTap="openSection" />
|
|
93
|
+
<GridItem icon="star" label="Charts" badge="New" data-name="Charts" onTap="openSection" />
|
|
94
|
+
<GridItem icon="calendar" label="Shows" data-name="Shows" onTap="openSection" />
|
|
95
|
+
<GridItem icon="ticket" label="Tickets" data-name="Tickets" onTap="openSection" />
|
|
96
|
+
<GridItem icon="headphones" label="Library" data-name="Library" onTap="openSection" />
|
|
97
|
+
<GridItem image="statics/logo.png" label="Salone" data-name="Salone" onTap="openSection" />
|
|
98
|
+
</Grid>
|
|
99
|
+
<If condition="{{ section }}">
|
|
100
|
+
<Text tone="muted">You tapped {{ section }}</Text>
|
|
101
|
+
</If>
|
|
102
|
+
</View>
|
|
103
|
+
</View>
|
|
@@ -0,0 +1,37 @@
|
|
|
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 artist = state.artists.find((candidate) => candidate.id === event.data.id);
|
|
8
|
+
return { chosen: artist?.name ?? '' };
|
|
9
|
+
},
|
|
10
|
+
openRelease: (state, event: DotEvent<unknown, { id: string }>) => ({
|
|
11
|
+
selected: state.releases.find((release) => release.id === event.data.id) ?? null,
|
|
12
|
+
}),
|
|
13
|
+
closeSheet: () => ({ selected: null }),
|
|
14
|
+
clearToast: () => ({ toast: '' }),
|
|
15
|
+
},
|
|
16
|
+
actions: {
|
|
17
|
+
async copyTitle(state) {
|
|
18
|
+
if (!state.selected) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const { title, artist } = state.selected;
|
|
22
|
+
await this.dash.system.copyText(`${title}, by ${artist}`);
|
|
23
|
+
this.setState({ selected: null, toast: 'Title copied' });
|
|
24
|
+
},
|
|
25
|
+
async shareRelease(state) {
|
|
26
|
+
if (!state.selected) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const { title, artist, year, note } = state.selected;
|
|
30
|
+
this.setState({ selected: null });
|
|
31
|
+
await this.dash.system.share({
|
|
32
|
+
title,
|
|
33
|
+
text: `${title}, by ${artist} (${year}): ${note.toLowerCase()}.`,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export interface Artist {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
song: string;
|
|
5
|
+
genre: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Release {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
artist: string;
|
|
13
|
+
year: number;
|
|
14
|
+
note: string;
|
|
15
|
+
tone: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
artists: [
|
|
20
|
+
{
|
|
21
|
+
id: 'drizilik',
|
|
22
|
+
name: 'Drizilik',
|
|
23
|
+
song: 'Lemonade, with The Therapist',
|
|
24
|
+
genre: 'Kriofusion',
|
|
25
|
+
icon: 'microphone',
|
|
26
|
+
},
|
|
27
|
+
{ id: 'boii', name: 'Boii', song: 'Love Na Scam', genre: 'Afrobeats', icon: 'microphone' },
|
|
28
|
+
{ id: 'apreel', name: 'ApreeL', song: 'Control', genre: 'Afropop', icon: 'microphone' },
|
|
29
|
+
{ id: 'donii-major', name: 'Donii Major', song: 'Hannah', genre: 'R&B', icon: 'microphone' },
|
|
30
|
+
{
|
|
31
|
+
id: 'star-zee',
|
|
32
|
+
name: 'Star Zee',
|
|
33
|
+
song: 'Leader, with Stonebwoy',
|
|
34
|
+
genre: 'Hip hop',
|
|
35
|
+
icon: 'microphone',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'kao-denero',
|
|
39
|
+
name: 'Kao Denero',
|
|
40
|
+
song: 'Kenyatta',
|
|
41
|
+
genre: 'Hip hop',
|
|
42
|
+
icon: 'microphone',
|
|
43
|
+
},
|
|
44
|
+
{ id: 'laj', name: 'LAJ', song: 'Shock, with Cassidy', genre: 'Hip hop', icon: 'microphone' },
|
|
45
|
+
{
|
|
46
|
+
id: 'k-man',
|
|
47
|
+
name: 'K-Man',
|
|
48
|
+
song: 'Leh Wi Make Salone',
|
|
49
|
+
genre: 'Hip hop',
|
|
50
|
+
icon: 'microphone',
|
|
51
|
+
},
|
|
52
|
+
] as Artist[],
|
|
53
|
+
releases: [
|
|
54
|
+
{
|
|
55
|
+
id: 'rise-and-shine',
|
|
56
|
+
title: 'Rise & Shine',
|
|
57
|
+
artist: "Sierra Leone's Refugee All Stars",
|
|
58
|
+
year: 2010,
|
|
59
|
+
note: 'Album of the year',
|
|
60
|
+
tone: 'success',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'kormot-bi-en-me',
|
|
64
|
+
title: 'Kormot Bi En Me',
|
|
65
|
+
artist: 'Steady Bongo',
|
|
66
|
+
year: 1996,
|
|
67
|
+
note: 'Best album',
|
|
68
|
+
tone: 'success',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'salone',
|
|
72
|
+
title: 'Salone',
|
|
73
|
+
artist: 'Bai Kamara Jr.',
|
|
74
|
+
year: 2020,
|
|
75
|
+
note: 'Nominated',
|
|
76
|
+
tone: 'warning',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'red-album',
|
|
80
|
+
title: 'Red Album',
|
|
81
|
+
artist: 'LAJ',
|
|
82
|
+
year: 2013,
|
|
83
|
+
note: 'Launched at the stadium',
|
|
84
|
+
tone: 'info',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'let-me-love-you',
|
|
88
|
+
title: 'Let Me Love You',
|
|
89
|
+
artist: 'Bunny Mack',
|
|
90
|
+
year: 1981,
|
|
91
|
+
note: 'Gold disc',
|
|
92
|
+
tone: 'info',
|
|
93
|
+
},
|
|
94
|
+
] as Release[],
|
|
95
|
+
chosen: '',
|
|
96
|
+
// The record whose actions the sheet shows.
|
|
97
|
+
selected: null as Release | null,
|
|
98
|
+
toast: '',
|
|
99
|
+
icons: [
|
|
100
|
+
'music',
|
|
101
|
+
'playlist',
|
|
102
|
+
'microphone',
|
|
103
|
+
'headphones',
|
|
104
|
+
'ticket',
|
|
105
|
+
'video',
|
|
106
|
+
'globe',
|
|
107
|
+
'link',
|
|
108
|
+
'external-link',
|
|
109
|
+
'heart',
|
|
110
|
+
'star',
|
|
111
|
+
'share',
|
|
112
|
+
'download',
|
|
113
|
+
'calendar',
|
|
114
|
+
'location',
|
|
115
|
+
'search',
|
|
116
|
+
],
|
|
117
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="title">Lists and icons</Text>
|
|
3
|
+
<Text>A List shows rows in a card. Small lists are compact, and medium lists have more room. A row can show an icon or a picture, a value at its end, and an arrow when you can tap it.</Text>
|
|
4
|
+
|
|
5
|
+
<View gap="small">
|
|
6
|
+
<Text variant="caption" tone="muted">Artists in a small list. Tap one: its data- attributes tell the page which one.</Text>
|
|
7
|
+
<List>
|
|
8
|
+
<For each="{{ artists }}" item="artist" key="id">
|
|
9
|
+
<ListItem icon="{{ artist.icon }}" title="{{ artist.name }}" subtitle="{{ artist.song }}" value="{{ artist.genre }}" data-id="{{ artist.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">Famous records in a medium list, each with a badge. Tap one to see its actions.</Text>
|
|
19
|
+
<List size="md">
|
|
20
|
+
<For each="{{ releases }}" item="release" key="id">
|
|
21
|
+
<ListItem title="{{ release.title }}" subtitle="{{ release.artist }} · {{ release.year }}" data-id="{{ release.id }}" onTap="openRelease">
|
|
22
|
+
<Badge tone="{{ release.tone }}">{{ release.note }}</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, including music icons</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</Text>
|
|
46
|
+
<View variant="card">
|
|
47
|
+
<Text>Side A</Text>
|
|
48
|
+
<Divider />
|
|
49
|
+
<Text>Side B</Text>
|
|
50
|
+
</View>
|
|
51
|
+
</View>
|
|
52
|
+
|
|
53
|
+
<Sheet open="{{ selected !== null }}" title="{{ selected.title }} · {{ selected.year }}" showCloseIcon onClose="closeSheet">
|
|
54
|
+
<Button variant="secondary" onClick="copyTitle">Copy the title</Button>
|
|
55
|
+
<Button variant="secondary" onClick="shareRelease">Share it</Button>
|
|
56
|
+
<Button onClick="closeSheet">Cancel</Button>
|
|
57
|
+
</Sheet>
|
|
58
|
+
<Toast message="{{ toast }}" tone="success" onHide="clearToast" />
|
|
59
|
+
</View>
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
// The green of Sierra Leone's flag.
|
|
45
|
+
backgroundColor: colored ? '#1EB53A' : undefined,
|
|
46
|
+
textColor: colored ? '#FFFFFF' : undefined,
|
|
47
|
+
});
|
|
48
|
+
this.setState({ colored });
|
|
49
|
+
},
|
|
50
|
+
toggleNavigationBar(state) {
|
|
51
|
+
const navigationBarHidden = !state.navigationBarHidden;
|
|
52
|
+
this.setNavigationBar({ hidden: navigationBarHidden });
|
|
53
|
+
this.setState({ navigationBarHidden });
|
|
54
|
+
},
|
|
55
|
+
toggleTabBar(state) {
|
|
56
|
+
const tabBarHidden = !state.tabBarHidden;
|
|
57
|
+
this.setTabBar({ hidden: tabBarHidden });
|
|
58
|
+
this.setState({ tabBarHidden });
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function ran(hooks: readonly HookRun[], hook: string): HookRun[] {
|
|
64
|
+
return [...hooks, { id: hooks.length + 1, hook }];
|
|
65
|
+
}
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<View>
|
|
2
|
+
<Text variant="caption" tone="muted">{{ trail }}</Text>
|
|
3
|
+
<Text variant="title">Navigation and hooks</Text>
|
|
4
|
+
<Text>Each new page opens on top. Back returns to the page 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
|
+
<View direction="row" wrap gap="small">
|
|
9
|
+
<Button onClick="openAnother" disabled="{{ depth >= maxDepth }}">Open another</Button>
|
|
10
|
+
<Button variant="secondary" onClick="replaceThis">Replace this one</Button>
|
|
11
|
+
<Button variant="secondary" onClick="back">Back</Button>
|
|
12
|
+
<Button variant="secondary" onClick="backTwo" disabled="{{ depth < 3 }}">Back two</Button>
|
|
13
|
+
<Button variant="secondary" onClick="home">Start over</Button>
|
|
14
|
+
</View>
|
|
15
|
+
</View>
|
|
16
|
+
|
|
17
|
+
<Text variant="caption" tone="muted">Each page sets Dash's bars. This page's title is its number.</Text>
|
|
18
|
+
<View variant="card" gap="small">
|
|
19
|
+
<View direction="row" wrap gap="small">
|
|
20
|
+
<Button variant="secondary" onClick="toggleColors">{{ colored ? 'Plain bar' : 'Green bar' }}</Button>
|
|
21
|
+
<Button variant="secondary" onClick="toggleNavigationBar">{{ navigationBarHidden ? 'Show the navigation bar' : 'Hide the navigation bar' }}</Button>
|
|
22
|
+
<Button variant="secondary" onClick="toggleTabBar">{{ tabBarHidden ? 'Show the tab bar' : 'Hide the tab bar' }}</Button>
|
|
23
|
+
</View>
|
|
24
|
+
<Text variant="caption" tone="muted">Going back shows that page's bars again. Leaving the dot brings back Dash's bars.</Text>
|
|
25
|
+
</View>
|
|
26
|
+
|
|
27
|
+
<Text variant="caption" tone="muted">The hooks this page ran, in order</Text>
|
|
28
|
+
<View variant="card" gap="small">
|
|
29
|
+
<For each="{{ hooks }}" item="run" key="id">
|
|
30
|
+
<Text>{{ run.id }}. {{ run.hook }}</Text>
|
|
31
|
+
</For>
|
|
32
|
+
<Text variant="caption" tone="muted">Open another page and come back. This page runs onHide, then onShow.</Text>
|
|
33
|
+
</View>
|
|
34
|
+
</View>
|