@monimesl/dot-cli 0.1.0-alpha.21 → 0.1.0-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/cli.js +42 -25
  2. package/dist/cli.js.map +1 -1
  3. package/dist/{server-B9-F93mS.js → server-DMnWDdJ6.js} +47 -34
  4. package/dist/{server-B9-F93mS.js.map → server-DMnWDdJ6.js.map} +1 -1
  5. package/dist/templates/showcase/dot.ts +9 -1
  6. package/dist/templates/showcase/pages/basics/bars/controller.ts +13 -2
  7. package/dist/templates/showcase/pages/basics/bars/state.ts +1 -0
  8. package/dist/templates/showcase/pages/basics/bars/view.dml +8 -0
  9. package/dist/templates/showcase/pages/basics/colors/controller.ts +112 -0
  10. package/dist/templates/showcase/pages/basics/colors/state.ts +17 -0
  11. package/dist/templates/showcase/pages/basics/colors/view.dml +142 -0
  12. package/dist/templates/showcase/pages/basics/concert/controller.ts +16 -0
  13. package/dist/templates/showcase/pages/basics/concert/state.ts +7 -0
  14. package/dist/templates/showcase/pages/basics/concert/view.dml +20 -0
  15. package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +7 -1
  16. package/dist/templates/showcase/pages/basics/pick-genre/view.dml +1 -0
  17. package/dist/templates/showcase/pages/basics/share/concerts.ts +31 -0
  18. package/dist/templates/showcase/pages/basics/share/controller.ts +12 -0
  19. package/dist/templates/showcase/pages/basics/share/state.ts +5 -0
  20. package/dist/templates/showcase/pages/basics/share/view.dml +21 -0
  21. package/dist/templates/showcase/pages/components/styles/view.dml +1 -1
  22. package/dist/templates/showcase/pages/dash/account/controller.ts +23 -0
  23. package/dist/templates/showcase/pages/dash/account/state.ts +7 -0
  24. package/dist/templates/showcase/pages/dash/account/view.dml +23 -0
  25. package/dist/templates/showcase/pages/dash/cache/controller.ts +2 -2
  26. package/dist/templates/showcase/pages/dash/cache/view.dml +1 -1
  27. package/dist/templates/showcase/pages/dash/calls/controller.ts +14 -0
  28. package/dist/templates/showcase/pages/dash/calls/state.ts +3 -0
  29. package/dist/templates/showcase/pages/dash/calls/view.dml +15 -0
  30. package/dist/templates/showcase/pages/dash/crypto/controller.ts +34 -0
  31. package/dist/templates/showcase/pages/dash/crypto/state.ts +10 -0
  32. package/dist/templates/showcase/pages/dash/crypto/view.dml +48 -0
  33. package/dist/templates/showcase/pages/dash/files/controller.ts +0 -20
  34. package/dist/templates/showcase/pages/dash/files/state.ts +1 -2
  35. package/dist/templates/showcase/pages/dash/files/view.dml +4 -5
  36. package/dist/templates/showcase/pages/dash/media/controller.ts +29 -0
  37. package/dist/templates/showcase/pages/dash/media/state.ts +4 -0
  38. package/dist/templates/showcase/pages/dash/media/view.dml +20 -1
  39. package/dist/templates/showcase/pages/dash/secrets/view.dml +1 -1
  40. package/dist/templates/showcase/pages/dash/system/controller.ts +3 -3
  41. package/dist/templates/showcase/pages/dash/system/state.ts +2 -2
  42. package/dist/templates/showcase/pages/dash/system/view.dml +1 -1
  43. package/dist/templates/showcase/pages/index/state.ts +28 -3
  44. package/package.json +6 -6
@@ -1,5 +1,7 @@
1
1
  import { logger } from '@monimesl/dot-runtime';
2
2
 
3
+ import { swatchColors } from './palette';
4
+
3
5
  export default defineDot({
4
6
  // Folders under pages/, as the home page lists them. The first opens when the dot starts.
5
7
  pages: [
@@ -13,6 +15,9 @@ export default defineDot({
13
15
  'basics/pick-genre',
14
16
  'basics/hooks',
15
17
  'basics/bars',
18
+ 'basics/colors',
19
+ 'basics/share',
20
+ 'basics/concert',
16
21
  // What a view can show.
17
22
  'components/layout',
18
23
  'components/styles',
@@ -32,19 +37,22 @@ export default defineDot({
32
37
  'dash/system',
33
38
  'dash/media',
34
39
  'dash/contacts',
40
+ 'dash/account',
41
+ 'dash/crypto',
35
42
  'dash/network',
36
43
  'dash/files',
37
44
  'dash/cache',
38
45
  'dash/secrets',
39
46
  'dash/calls',
40
47
  ],
41
- // The showcase's own colours, used by name on the Styles page.
48
+ // The showcase's own colours, used by name on the Styles page, and the Page colours swatches.
42
49
  theme: {
43
50
  colors: {
44
51
  custom: {
45
52
  gold: { light: '#f5c542', dark: '#d4a72c' },
46
53
  // Dark text that reads on gold in both light and dark.
47
54
  ink: { light: '#1c1c1e', dark: '#1c1c1e' },
55
+ ...swatchColors(),
48
56
  },
49
57
  },
50
58
  },
@@ -14,14 +14,25 @@ export default definePage({
14
14
  },
15
15
  toggleColors(state) {
16
16
  const colored = !state.colored;
17
- // Undefined puts Dash's own colours back.
17
+ // Undefined puts Dash's own colours back. Without a textColor, Dash picks text that reads on
18
+ // the bar.
18
19
  this.setNavigationBar({
19
20
  // The green of Sierra Leone's flag.
20
21
  backgroundColor: colored ? '#1EB53A' : undefined,
21
- textColor: colored ? '#FFFFFF' : undefined,
22
22
  });
23
23
  this.setState({ colored });
24
24
  },
25
+ togglePainted(state) {
26
+ const painted = !state.painted;
27
+ // A pale sky by day, the night over Freetown by dark. Undefined puts the theme's back. Cards,
28
+ // fields and quieter text follow the background, unless the page sets those too.
29
+ if (painted) {
30
+ this.setColors({ background: { light: '#E3F2FD', dark: '#0B1A2E' } });
31
+ } else {
32
+ this.setColors({ background: { light: undefined, dark: undefined } });
33
+ }
34
+ this.setState({ painted });
35
+ },
25
36
  toggleNavigationBar(state) {
26
37
  const navigationBarHidden = !state.navigationBarHidden;
27
38
  this.setNavigationBar({ hidden: navigationBarHidden });
@@ -1,6 +1,7 @@
1
1
  export default {
2
2
  title: 'Bars',
3
3
  colored: false,
4
+ painted: false,
4
5
  navigationBarHidden: false,
5
6
  tabBarHidden: false,
6
7
  };
@@ -19,6 +19,14 @@
19
19
  </View>
20
20
  </View>
21
21
 
22
+ <View gap="small">
23
+ <Text variant="subtitle">setColors</Text>
24
+ <Text variant="caption" tone="muted">configs.colors or setColors give a page its own colours, for light and dark, such as its background. Dash paints the background behind the page too, makes cards and fields that sit on it, and picks text, bar and status bar colours that read on it. The Page colours page has more.</Text>
25
+ <View variant="card">
26
+ <Button variant="secondary" onClick="togglePainted">{{ painted ? 'Theme background' : 'Sky background' }}</Button>
27
+ </View>
28
+ </View>
29
+
22
30
  <View gap="small">
23
31
  <Text variant="subtitle">setTabBar</Text>
24
32
  <View variant="card">
@@ -0,0 +1,112 @@
1
+ import type { HexColor, PageColors, SchemeColor } from '@monimesl/dot-runtime';
2
+
3
+ import type { Swatch } from '../../../palette';
4
+ import { BACKGROUNDS, BAR_COLORS, OWN_SURFACES, PRIMARIES } from '../../../palette';
5
+ import state from './state';
6
+
7
+ const HEX_COLOR = /^#[0-9a-fA-F]{6}$/;
8
+ // Undefined for light and dark puts the theme's colour back.
9
+ const THEME: SchemeColor = { light: undefined, dark: undefined };
10
+
11
+ interface Choices {
12
+ background: string;
13
+ primary: string;
14
+ surfaces: string;
15
+ customLight: string;
16
+ customDark: string;
17
+ }
18
+
19
+ export default definePage({
20
+ initialState: state,
21
+ configs: { navigationBar: { title: 'Page colours' } },
22
+ mutations: {
23
+ setCustomLight: (_state, event: ValueEvent) => ({ customLight: event.detail.value }),
24
+ setCustomDark: (_state, event: ValueEvent) => ({ customDark: event.detail.value }),
25
+ },
26
+ actions: {
27
+ chooseBackground(state, event: DataEvent<{ name: string }>) {
28
+ const choices = { ...state, background: event.data.name };
29
+ this.setColors(colorsFor(choices));
30
+ this.setState({ background: choices.background, code: codeFor(choices) });
31
+ },
32
+ useCustom(state) {
33
+ const light = state.customLight.trim();
34
+ // One colour is enough: it's used in dark too.
35
+ const dark = state.customDark.trim() || light;
36
+ if (!HEX_COLOR.test(light) || !HEX_COLOR.test(dark)) {
37
+ this.setState({ customError: 'Write a colour as # and six digits, such as #FFF3E0' });
38
+ return;
39
+ }
40
+ const choices = { ...state, background: 'custom', customLight: light, customDark: dark };
41
+ this.setColors(colorsFor(choices));
42
+ this.setState({ background: 'custom', customError: '', code: codeFor(choices) });
43
+ },
44
+ choosePrimary(state, event: DataEvent<{ name: string }>) {
45
+ const choices = { ...state, primary: event.data.name };
46
+ this.setColors(colorsFor(choices));
47
+ this.setState({ primary: choices.primary, code: codeFor(choices) });
48
+ },
49
+ chooseSurfaces(state, event: ValueEvent) {
50
+ const choices = { ...state, surfaces: event.detail.value };
51
+ this.setColors(colorsFor(choices));
52
+ this.setState({ surfaces: choices.surfaces, code: codeFor(choices) });
53
+ },
54
+ chooseNavigationBar(_state, event: DataEvent<{ name: string }>) {
55
+ const color = BAR_COLORS.find((swatch) => swatch.name === event.data.name);
56
+ // Without a textColor, Dash picks text that reads on the bar.
57
+ this.setNavigationBar({ backgroundColor: color?.light });
58
+ this.setState({ navigationBar: event.data.name });
59
+ },
60
+ reset(state) {
61
+ const choices = { ...state, background: '', primary: '', surfaces: 'derived' };
62
+ this.setColors(colorsFor(choices));
63
+ this.setNavigationBar({ backgroundColor: undefined });
64
+ this.setState({
65
+ background: '',
66
+ primary: '',
67
+ surfaces: 'derived',
68
+ navigationBar: '',
69
+ customError: '',
70
+ code: codeFor(choices),
71
+ });
72
+ },
73
+ },
74
+ });
75
+
76
+ // Every colour the page can change here, so one put back to the theme's is cleared too.
77
+ function colorsFor(choices: Choices): PageColors {
78
+ const own = choices.surfaces === 'own';
79
+ return {
80
+ background: backgroundFor(choices),
81
+ primary: swatchFor(PRIMARIES, choices.primary),
82
+ surface: own ? OWN_SURFACES.surface : THEME,
83
+ muted: own ? OWN_SURFACES.muted : THEME,
84
+ border: own ? OWN_SURFACES.border : THEME,
85
+ };
86
+ }
87
+
88
+ function backgroundFor(choices: Choices): SchemeColor {
89
+ if (choices.background === 'custom') {
90
+ return { light: choices.customLight as HexColor, dark: choices.customDark as HexColor };
91
+ }
92
+ return swatchFor(BACKGROUNDS, choices.background);
93
+ }
94
+
95
+ function swatchFor(swatches: readonly Swatch[], name: string): SchemeColor {
96
+ const swatch = swatches.find((candidate) => candidate.name === name);
97
+ if (!swatch) {
98
+ return THEME;
99
+ }
100
+ return { light: swatch.light, dark: swatch.dark };
101
+ }
102
+
103
+ // The colours chosen, one line each, as they go in a setColors call.
104
+ function codeFor(choices: Choices): string[] {
105
+ const lines: string[] = [];
106
+ for (const [name, color] of Object.entries(colorsFor(choices))) {
107
+ if (color?.light) {
108
+ lines.push(`${name}: { light: '${color.light}', dark: '${color.dark}' },`);
109
+ }
110
+ }
111
+ return lines;
112
+ }
@@ -0,0 +1,17 @@
1
+ import { BACKGROUNDS, PRIMARIES } from '../../../palette';
2
+
3
+ export default {
4
+ backgrounds: BACKGROUNDS,
5
+ primaries: PRIMARIES,
6
+ // The swatch chosen for each, or '' for the theme's own.
7
+ background: '',
8
+ primary: '',
9
+ navigationBar: '',
10
+ // 'derived' lets Dash work out cards and fields from the background. 'own' sets them.
11
+ surfaces: 'derived',
12
+ customLight: '',
13
+ customDark: '',
14
+ customError: '',
15
+ // The colours the choices add up to, as lines of a setColors call.
16
+ code: [] as string[],
17
+ };
@@ -0,0 +1,142 @@
1
+ <View>
2
+ <Text variant="title">Page colours</Text>
3
+ <Text>A page can have its own colours, for light and dark, on top of the theme's. Pick some and watch the page follow. Dash paints the background behind the page, and picks text, bar and status bar colours that read on it. Try each with the phone in dark mode too.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="subtitle">background</Text>
7
+ <Text variant="caption" tone="muted">Each swatch has a light and a dark colour. On the strong ones, Dash turns the text and the status bar light.</Text>
8
+ <View variant="card">
9
+ <Grid columns="3" gap="medium">
10
+ <View align="center" gap="small" data-name="" onTap="chooseBackground">
11
+ <View width="52" height="52" radius="full" background="muted" border="{{ background === '' ? 'strong' : 'subtle' }}" justify="center" align="center">
12
+ <Icon name="refresh" tone="muted" />
13
+ </View>
14
+ <Text variant="caption" align="center" weight="{{ background === '' ? 'bold' : 'regular' }}">Theme's</Text>
15
+ </View>
16
+ <For each="{{ backgrounds }}" item="swatch" key="name">
17
+ <View align="center" gap="small" data-name="{{ swatch.name }}" onTap="chooseBackground">
18
+ <View width="52" height="52" radius="full" background="{{ swatch.name }}" border="{{ background === swatch.name ? 'strong' : 'subtle' }}" />
19
+ <Text variant="caption" align="center" maxLines="2" weight="{{ background === swatch.name ? 'bold' : 'regular' }}">{{ swatch.label }}</Text>
20
+ </View>
21
+ </For>
22
+ </Grid>
23
+ </View>
24
+ </View>
25
+
26
+ <View gap="small">
27
+ <Text variant="subtitle">Your own background</Text>
28
+ <Text variant="caption" tone="muted">Any colour as # and six digits. Leave dark empty to use the light one in dark too. If text can't be read on it, dotctl dev warns you.</Text>
29
+ <View variant="card" gap="small">
30
+ <View direction="row" gap="small">
31
+ <View grow>
32
+ <Input label="Light" placeholder="#FFF3E0" value="{{ customLight }}" maxLength="7" onChange="setCustomLight" onSubmit="useCustom" />
33
+ </View>
34
+ <View grow>
35
+ <Input label="Dark" placeholder="#2B1A0E" value="{{ customDark }}" maxLength="7" onChange="setCustomDark" onSubmit="useCustom" />
36
+ </View>
37
+ </View>
38
+ <If condition="{{ customError }}">
39
+ <Text variant="caption" tone="danger">{{ customError }}</Text>
40
+ </If>
41
+ <Button variant="secondary" onClick="useCustom" disabled="{{ !customLight }}">Use this background</Button>
42
+ </View>
43
+ </View>
44
+
45
+ <View gap="small">
46
+ <Text variant="subtitle">primary</Text>
47
+ <Text variant="caption" tone="muted">Buttons, switches, links and selected chips. Text on it, with tone="onPrimary", turns dark or light to read.</Text>
48
+ <View variant="card">
49
+ <Grid columns="5" gap="small">
50
+ <View align="center" gap="small" data-name="" onTap="choosePrimary">
51
+ <View width="40" height="40" radius="full" background="muted" border="{{ primary === '' ? 'strong' : 'subtle' }}" justify="center" align="center">
52
+ <Icon name="refresh" size="small" tone="muted" />
53
+ </View>
54
+ <Text variant="caption" align="center" weight="{{ primary === '' ? 'bold' : 'regular' }}">Theme's</Text>
55
+ </View>
56
+ <For each="{{ primaries }}" item="swatch" key="name">
57
+ <View align="center" gap="small" data-name="{{ swatch.name }}" onTap="choosePrimary">
58
+ <View width="40" height="40" radius="full" background="{{ swatch.name }}" border="{{ primary === swatch.name ? 'strong' : 'none' }}" />
59
+ <Text variant="caption" align="center" maxLines="2" weight="{{ primary === swatch.name ? 'bold' : 'regular' }}">{{ swatch.label }}</Text>
60
+ </View>
61
+ </For>
62
+ </Grid>
63
+ </View>
64
+ </View>
65
+
66
+ <View gap="small">
67
+ <Text variant="subtitle">surface, muted and border</Text>
68
+ <Text variant="caption" tone="muted">Left out, Dash works out cards, fields, quiet fills and lines from the background, so they sit well on it. A page can set them itself instead.</Text>
69
+ <Tabs variant="segmented" value="{{ surfaces }}" onChange="chooseSurfaces">
70
+ <Tab value="derived" label="Worked out" />
71
+ <Tab value="own" label="The page's own" />
72
+ </Tabs>
73
+ </View>
74
+
75
+ <View gap="small">
76
+ <Text variant="subtitle">The navigation bar</Text>
77
+ <Text variant="caption" tone="muted">setNavigationBar gives the bar its own colour. Without a textColor, Dash picks text that reads on it.</Text>
78
+ <View direction="row" gap="small" wrap>
79
+ <Chip label="Dash's" selected="{{ navigationBar === '' }}" data-name="" onTap="chooseNavigationBar" />
80
+ <Chip label="Flag green" selected="{{ navigationBar === 'flagGreen' }}" data-name="flagGreen" onTap="chooseNavigationBar" />
81
+ <Chip label="Atlantic" selected="{{ navigationBar === 'atlantic' }}" data-name="atlantic" onTap="chooseNavigationBar" />
82
+ <Chip label="Ink" selected="{{ navigationBar === 'ink' }}" data-name="ink" onTap="chooseNavigationBar" />
83
+ </View>
84
+ </View>
85
+
86
+ <View gap="small">
87
+ <Text variant="subtitle">What follows</Text>
88
+ <Text variant="caption" tone="muted">Everything on the page takes its colours from these, so nothing here sets one.</Text>
89
+ <View variant="card" gap="small">
90
+ <View direction="row" align="center" gap="medium">
91
+ <Avatar name="Emmerson Bockarie" />
92
+ <View gap="none" grow>
93
+ <Text weight="bold">Emmerson</Text>
94
+ <Text variant="caption" tone="muted">Kill Me Pikin · 2008</Text>
95
+ </View>
96
+ <Badge tone="success">New</Badge>
97
+ </View>
98
+ <Input label="Your name" placeholder="Aminata Kamara" />
99
+ <Switch label="Tell me about new songs" checked />
100
+ <ProgressBar value="60" />
101
+ <View direction="row" gap="small" wrap>
102
+ <Chip label="Afropop" selected />
103
+ <Chip label="Gumbe" />
104
+ <Chip label="Palm-wine" />
105
+ </View>
106
+ <View direction="row" gap="small" wrap>
107
+ <Button>Play</Button>
108
+ <Button variant="secondary">Add to a playlist</Button>
109
+ </View>
110
+ <Text>Read about <Link href="https://en.wikipedia.org/wiki/Music_of_Sierra_Leone">the music of Sierra Leone</Link>.</Text>
111
+ </View>
112
+ <List>
113
+ <ListItem icon="music" title="Ballot Paper" subtitle="Emmerson" value="4:12" />
114
+ <ListItem icon="music" title="Salone" subtitle="Drizilik" value="3:48" />
115
+ </List>
116
+ <View background="muted" radius="medium" padding="medium">
117
+ <Text variant="caption">A quiet fill, such as for a note</Text>
118
+ </View>
119
+ <View background="primary" radius="medium" padding="medium">
120
+ <Text tone="onPrimary" weight="medium">On the primary colour</Text>
121
+ </View>
122
+ </View>
123
+
124
+ <View gap="small">
125
+ <Text variant="subtitle">The call</Text>
126
+ <Text variant="caption" tone="muted">What you picked, as a dot would write it. configs.colors in definePage takes the same.</Text>
127
+ <View variant="card" gap="none">
128
+ <If condition="{{ code.length > 0 }}">
129
+ <Text selectable>this.setColors({</Text>
130
+ <For each="{{ code }}" item="line" key="*this">
131
+ <Text paddingStart="large" selectable>{{ line }}</Text>
132
+ </For>
133
+ <Text selectable>});</Text>
134
+ </If>
135
+ <Else>
136
+ <Text tone="muted">The theme's own colours. Pick some above to see the call.</Text>
137
+ </Else>
138
+ </View>
139
+ </View>
140
+
141
+ <Button variant="secondary" onClick="reset">Put the theme's colours back</Button>
142
+ </View>
@@ -0,0 +1,16 @@
1
+ import { CONCERTS } from '../share/concerts';
2
+ import state from './state';
3
+
4
+ export default definePage({
5
+ initialState: state,
6
+ configs: { navigationBar: { title: 'Concert' } },
7
+ // Dash's Share opens this page, with its concert option and no other.
8
+ share: { options: ['concert'] },
9
+ hooks: {
10
+ // From a link, the options can be anything, so look the concert up rather than trust it.
11
+ onLoad(options) {
12
+ const concert = CONCERTS.find((candidate) => candidate.id === options.concert) ?? null;
13
+ this.setState({ concert, buyer: options.buyer ?? '' });
14
+ },
15
+ },
16
+ });
@@ -0,0 +1,7 @@
1
+ import type { Concert } from '../share/concerts';
2
+
3
+ export default {
4
+ concert: null as Concert | null,
5
+ // Who the page was opened for. A shared link never carries it.
6
+ buyer: '',
7
+ };
@@ -0,0 +1,20 @@
1
+ <View>
2
+ <If condition="{{ concert }}">
3
+ <Text variant="title">{{ concert.title }}</Text>
4
+ <View variant="card" gap="small">
5
+ <DetailRow label="Where" value="{{ concert.place }}" />
6
+ <DetailRow label="When" value="{{ concert.date }}" />
7
+ <DetailRow label="From" value="{{ concert.price }}" />
8
+ </View>
9
+ <If condition="{{ buyer }}">
10
+ <Notice tone="info">Opened for {{ buyer }}. buyer isn't in share's options, so a shared link leaves it out.</Notice>
11
+ </If>
12
+ <Else>
13
+ <Notice tone="success">Opened from a link: it carried the concert, and nothing else.</Notice>
14
+ </Else>
15
+ <Text variant="caption" tone="muted">Tap ••• then Share. The link opens this concert.</Text>
16
+ </If>
17
+ <Else>
18
+ <EmptyState icon="search" title="No such concert" text="The link may be old, or written by hand." />
19
+ </Else>
20
+ </View>
@@ -3,7 +3,13 @@ import state from './state';
3
3
  // Opened by the navigation page with pushForResult. It gives back the genre the person taps.
4
4
  export default definePage({
5
5
  initialState: state,
6
- configs: { navigationBar: { title: 'Choose a genre' } },
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
+ },
7
13
  actions: {
8
14
  pick(_state, event: DataEvent<{ genre: string }>) {
9
15
  this.navigation.backWithResult(event.data.genre);
@@ -1,6 +1,7 @@
1
1
  <View>
2
2
  <Text variant="title">Choose a genre</Text>
3
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>
4
5
  <List>
5
6
  <For each="{{ genres }}" item="genre" key="*this">
6
7
  <ListItem icon="music" title="{{ genre }}" data-genre="{{ genre }}" onTap="pick" />
@@ -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,5 @@
1
+ import { CONCERTS } from './concerts';
2
+
3
+ export default {
4
+ concerts: CONCERTS,
5
+ };
@@ -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>
@@ -40,7 +40,7 @@
40
40
 
41
41
  <View gap="small">
42
42
  <Text variant="subtitle">Theme colours</Text>
43
- <Text variant="caption" tone="muted">The dot's own colours, named in dot.ts: gold and ink. Use the names as a background or a text tone.</Text>
43
+ <Text variant="caption" tone="muted">The theme in dot.ts can set primary, background, surface, text, muted, border and subtle, for light and dark, and a page can set its own with configs.colors. Left out, they're Dash's, or worked out from a new background. The theme can also name its own colours, such as gold and ink here, to use as a background or a text tone.</Text>
44
44
  <View direction="row" gap="small" align="center">
45
45
  <View background="gold" radius="full" paddingTop="small" paddingBottom="small" paddingStart="medium" paddingEnd="medium">
46
46
  <Text weight="medium" tone="ink">Gold member</Text>
@@ -0,0 +1,23 @@
1
+ import { errorMessage } from '@monimesl/dot-runtime';
2
+
3
+ import state from './state';
4
+
5
+ export default definePage({
6
+ initialState: state,
7
+ configs: { navigationBar: { title: 'dash.account' } },
8
+ mutations: {
9
+ setNonce: (_state, event: ValueEvent) => ({ nonce: event.detail.value }),
10
+ },
11
+ actions: {
12
+ async read(state) {
13
+ try {
14
+ const { fullName, accountIdToken } = await this.dash.account.readProfile({
15
+ nonce: state.nonce,
16
+ });
17
+ this.setState({ fullName, accountIdToken, note: '' });
18
+ } catch (error) {
19
+ this.setState({ note: errorMessage(error) });
20
+ }
21
+ },
22
+ },
23
+ });
@@ -0,0 +1,7 @@
1
+ export default {
2
+ // A fixed nonce, so the token names the person the same way each time in this dot.
3
+ nonce: 'salone-sounds',
4
+ fullName: '',
5
+ accountIdToken: '',
6
+ note: '',
7
+ };
@@ -0,0 +1,23 @@
1
+ <View>
2
+ <Text variant="title">dash.account</Text>
3
+ <Text>Who is signed in to Dash. It needs the account permission in dot.json.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="subtitle">readProfile</Text>
7
+ <Text variant="caption" tone="muted">Gives the person's full name, and a token: a hash of their Monimeer id, this dot's id and the nonce. The same nonce gives the same token. Dash makes it on the phone, so it names the person, but proves nothing to the dot's server.</Text>
8
+ <View variant="card" gap="medium">
9
+ <Input label="Nonce" value="{{ nonce }}" onChange="setNonce" />
10
+ <Button onClick="read">Read the profile</Button>
11
+ <If condition="{{ fullName }}">
12
+ <View gap="none">
13
+ <DetailRow label="fullName" value="{{ fullName }}" />
14
+ <DetailRow label="accountIdToken" value="{{ accountIdToken }}" />
15
+ </View>
16
+ </If>
17
+ </View>
18
+ </View>
19
+
20
+ <If condition="{{ note }}">
21
+ <Notice tone="danger">{{ note }}</Notice>
22
+ </If>
23
+ </View>
@@ -2,7 +2,7 @@ import state from './state';
2
2
 
3
3
  const RECENT = 'recent/';
4
4
  const GENRE = 'genre';
5
- const RECENT_SECONDS = 30;
5
+ const RECENT_MILLISECONDS = 30_000;
6
6
 
7
7
  export default definePage({
8
8
  initialState: state,
@@ -29,7 +29,7 @@ export default definePage({
29
29
  // Each view lasts 30 seconds, then the cache forgets it.
30
30
  async view(_state, event: DataEvent<{ id: string; name: string }>) {
31
31
  await this.dash.storage.cache.set(`${RECENT}${event.data.id}`, event.data.name, {
32
- ttl: RECENT_SECONDS,
32
+ ttl: RECENT_MILLISECONDS,
33
33
  });
34
34
  await this.actions.refresh();
35
35
  },
@@ -4,7 +4,7 @@
4
4
 
5
5
  <View gap="small">
6
6
  <Text variant="subtitle">set with a ttl, keys and get</Text>
7
- <Text variant="caption" tone="muted">Tap an artist. ttl: 30 keeps it for 30 seconds.</Text>
7
+ <Text variant="caption" tone="muted">Tap an artist. ttl: 30_000 keeps it for 30 seconds, as times are in milliseconds.</Text>
8
8
  <List>
9
9
  <For each="{{ artists }}" item="artist" key="id">
10
10
  <ListItem icon="microphone" title="{{ artist.name }}" data-id="{{ artist.id }}" data-name="{{ artist.name }}" onTap="view" />
@@ -9,6 +9,17 @@ let wait: DashRequest<void> | null = null;
9
9
  export default definePage({
10
10
  initialState: state,
11
11
  configs: { navigationBar: { title: 'Calls and errors' } },
12
+ hooks: {
13
+ async onLoad() {
14
+ this.setState({ picksPhones: this.dash.supports('contacts.pickPhone') });
15
+ try {
16
+ const { apiVersions } = await this.dash.system.info();
17
+ this.setState({ apiVersions: apiVersions.join(', ') });
18
+ } catch (error) {
19
+ this.setState({ apiVersions: errorMessage(error) });
20
+ }
21
+ },
22
+ },
12
23
  actions: {
13
24
  // Makes the call a button names, and shows how it ended.
14
25
  async show(_state, event: DataEvent<{ call: string }>) {
@@ -43,6 +54,9 @@ export default definePage({
43
54
  this.setState({ waiting: false });
44
55
  }
45
56
  },
57
+ async closeDot() {
58
+ await this.dash.dot.close();
59
+ },
46
60
  cancelWait() {
47
61
  wait?.cancel();
48
62
  },