@monimesl/dot-cli 1.0.0-beta.1 → 1.0.0-beta.3

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 (76) hide show
  1. package/README.md +22 -9
  2. package/dist/cli.js +13 -11
  3. package/dist/cli.js.map +1 -1
  4. package/dist/templates/showcase/.env +2 -2
  5. package/dist/templates/showcase/dot.ts +2 -1
  6. package/dist/templates/showcase/pages/basics/bars/controller.ts +2 -2
  7. package/dist/templates/showcase/pages/basics/bars/view.dml +2 -1
  8. package/dist/templates/showcase/pages/basics/bindings/state.ts +2 -2
  9. package/dist/templates/showcase/pages/basics/bindings/view.dml +2 -2
  10. package/dist/templates/showcase/pages/basics/colors/controller.ts +1 -1
  11. package/dist/templates/showcase/pages/basics/concert/view.dml +1 -1
  12. package/dist/templates/showcase/pages/basics/control-flow/controller.ts +1 -1
  13. package/dist/templates/showcase/pages/basics/control-flow/view.dml +1 -1
  14. package/dist/templates/showcase/pages/basics/events/controller.ts +1 -1
  15. package/dist/templates/showcase/pages/basics/events/view.dml +1 -1
  16. package/dist/templates/showcase/pages/basics/hooks/controller.ts +2 -1
  17. package/dist/templates/showcase/pages/basics/hooks/view.dml +2 -2
  18. package/dist/templates/showcase/pages/basics/navigation/controller.ts +1 -0
  19. package/dist/templates/showcase/pages/basics/navigation/view.dml +1 -1
  20. package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +3 -3
  21. package/dist/templates/showcase/pages/basics/share/view.dml +2 -2
  22. package/dist/templates/showcase/pages/basics/state/controller.ts +9 -0
  23. package/dist/templates/showcase/pages/basics/state/state.ts +3 -0
  24. package/dist/templates/showcase/pages/components/carousel/view.dml +2 -2
  25. package/dist/templates/showcase/pages/components/feedback/controller.ts +2 -1
  26. package/dist/templates/showcase/pages/components/feedback/state.ts +2 -2
  27. package/dist/templates/showcase/pages/components/feedback/view.dml +2 -2
  28. package/dist/templates/showcase/pages/components/forms/controller.ts +2 -2
  29. package/dist/templates/showcase/pages/components/forms/state.ts +1 -1
  30. package/dist/templates/showcase/pages/components/forms/view.dml +5 -5
  31. package/dist/templates/showcase/pages/components/icons/controller.ts +1 -0
  32. package/dist/templates/showcase/pages/components/icons/state.ts +1 -1
  33. package/dist/templates/showcase/pages/components/images/controller.ts +1 -1
  34. package/dist/templates/showcase/pages/components/images/state.ts +1 -1
  35. package/dist/templates/showcase/pages/components/images/view.dml +4 -4
  36. package/dist/templates/showcase/pages/components/layout/controller.ts +3 -1
  37. package/dist/templates/showcase/pages/components/layout/view.dml +5 -5
  38. package/dist/templates/showcase/pages/components/lists/view.dml +8 -8
  39. package/dist/templates/showcase/pages/components/money/controller.ts +1 -1
  40. package/dist/templates/showcase/pages/components/money/view.dml +2 -2
  41. package/dist/templates/showcase/pages/components/reading/state.ts +2 -2
  42. package/dist/templates/showcase/pages/components/sheets/controller.ts +1 -1
  43. package/dist/templates/showcase/pages/components/sheets/view.dml +1 -1
  44. package/dist/templates/showcase/pages/components/styles/view.dml +3 -3
  45. package/dist/templates/showcase/pages/components/tabs/state.ts +2 -2
  46. package/dist/templates/showcase/pages/components/tabs/view.dml +2 -2
  47. package/dist/templates/showcase/pages/components/text/view.dml +3 -3
  48. package/dist/templates/showcase/pages/dash/account/controller.ts +3 -0
  49. package/dist/templates/showcase/pages/dash/account/view.dml +2 -2
  50. package/dist/templates/showcase/pages/dash/cache/controller.ts +3 -0
  51. package/dist/templates/showcase/pages/dash/calls/controller.ts +3 -2
  52. package/dist/templates/showcase/pages/dash/contacts/controller.ts +1 -0
  53. package/dist/templates/showcase/pages/dash/crypto/controller.ts +2 -0
  54. package/dist/templates/showcase/pages/dash/crypto/view.dml +1 -1
  55. package/dist/templates/showcase/pages/dash/files/controller.ts +6 -1
  56. package/dist/templates/showcase/pages/dash/files/view.dml +1 -1
  57. package/dist/templates/showcase/pages/dash/media/controller.ts +7 -1
  58. package/dist/templates/showcase/pages/dash/media/state.ts +2 -0
  59. package/dist/templates/showcase/pages/dash/network/controller.ts +5 -1
  60. package/dist/templates/showcase/pages/dash/network/view.dml +1 -1
  61. package/dist/templates/showcase/pages/dash/payments/cases.ts +18 -18
  62. package/dist/templates/showcase/pages/dash/payments/controller.ts +21 -3
  63. package/dist/templates/showcase/pages/dash/payments/state.ts +2 -0
  64. package/dist/templates/showcase/pages/dash/payments/view.dml +3 -1
  65. package/dist/templates/showcase/pages/dash/secrets/controller.ts +3 -0
  66. package/dist/templates/showcase/pages/dash/system/controller.ts +5 -0
  67. package/dist/templates/showcase/pages/dash/system/view.dml +4 -4
  68. package/dist/templates/showcase/pages/dash/ui/controller.ts +6 -1
  69. package/dist/templates/showcase/pages/index/controller.ts +1 -0
  70. package/dist/templates/showcase/pages/index/state.ts +3 -3
  71. package/dist/templates/starter/.env +2 -2
  72. package/dist/templates/starter/dot.ts +1 -0
  73. package/dist/templates/starter/pages/index/controller.ts +2 -0
  74. package/dist/templates/starter/pages/index/state.ts +2 -0
  75. package/dist/templates/starter/pages/index/view.dml +2 -1
  76. package/package.json +6 -6
@@ -3,7 +3,7 @@ import { logger } from '@monimesl/dot-runtime';
3
3
  import { swatchColors } from './pages/basics/colors/palette';
4
4
 
5
5
  export default defineDot({
6
- // Folders under pages/, as the home page lists them. The first opens when the dot starts.
6
+ // Each page is a folder under pages/, here in the home page's order. The dot opens on the first.
7
7
  pages: [
8
8
  'index',
9
9
  // How a page works.
@@ -57,5 +57,6 @@ export default defineDot({
57
57
  },
58
58
  },
59
59
  },
60
+ // logger() writes each page load, event, navigation and state change to the console.
60
61
  plugins: [logger()],
61
62
  });
@@ -24,8 +24,8 @@ export default definePage({
24
24
  },
25
25
  togglePainted(state) {
26
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.
27
+ // A pale sky in light mode, the night over Freetown in dark. Undefined puts the theme's back.
28
+ // Cards, fields and quieter text follow the background, unless the page sets those too.
29
29
  if (painted) {
30
30
  this.setColors({ background: { light: '#E3F2FD', dark: '#0B1A2E' } });
31
31
  } else {
@@ -16,12 +16,13 @@
16
16
  <Button variant="secondary" onClick="toggleColors">{{ colored ? 'Plain bar' : 'Green bar' }}</Button>
17
17
  <Button variant="secondary" onClick="toggleNavigationBar">{{ navigationBarHidden ? 'Show the bar' : 'Hide the bar' }}</Button>
18
18
  </View>
19
+ <Text variant="caption" tone="muted">A title can be up to 60 characters. With the bar hidden, Dash still shows a capsule at the top right with the dot's menu, so keep that corner free.</Text>
19
20
  </View>
20
21
  </View>
21
22
 
22
23
  <View gap="small">
23
24
  <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
+ <Text variant="caption" tone="muted">configs.colors or setColors give a page its own colours, for light and dark, such as its background. Dash picks text and bar colours that read on it. The Page colours page has more.</Text>
25
26
  <View variant="card">
26
27
  <Button variant="secondary" onClick="togglePainted">{{ painted ? 'Theme background' : 'Sky background' }}</Button>
27
28
  </View>
@@ -3,11 +3,11 @@ export default {
3
3
  syntax: '{{ name }}',
4
4
  name: 'Mariama',
5
5
  stageName: null as string | null,
6
- // Le, in the leone since 2022, when it dropped three zeros.
6
+ // In leones (SLE), the new leone of 2022.
7
7
  price: 150,
8
8
  tickets: 4,
9
9
  genres: ['kriofusion', 'palm-wine', 'gumbe'],
10
- // state.ts runs in the service, so it can read the .env file's values too.
10
+ // A binding reads only the page's state, so a value from .env goes in it first.
11
11
  greeting: env.GREETING,
12
12
  // Worked out in the controller, since a binding can't call a function.
13
13
  shout: 'MARIAMA',
@@ -13,7 +13,7 @@
13
13
 
14
14
  <View gap="small">
15
15
  <Text variant="subtitle">Expressions</Text>
16
- <Text variant="caption" tone="muted">Maths, comparisons, ? : and ?? work. Calling a function doesn't: work the value out in the controller, as shout is here.</Text>
16
+ <Text variant="caption" tone="muted">Maths, comparisons, ? : and ?? work. A binding can't call a function, so work the value out in the controller, as shout is here.</Text>
17
17
  <View variant="card" gap="small">
18
18
  <Text>{{ tickets }} {{ tickets === 1 ? 'ticket' : 'tickets' }} at Le {{ price }} each: Le {{ tickets * price }}</Text>
19
19
  <Text>Stage name: {{ stageName ?? 'none yet' }}</Text>
@@ -33,7 +33,7 @@
33
33
 
34
34
  <View gap="small">
35
35
  <Text variant="subtitle">env</Text>
36
- <Text variant="caption" tone="muted">Values in the dot's .env file. Anyone with the dot can read them, so never put a secret there.</Text>
36
+ <Text variant="caption" tone="muted">Values in the dot's .env file, copied into state.ts to show here. Anyone with the dot can read them, so never put a secret there.</Text>
37
37
  <View variant="card">
38
38
  <Text>{{ greeting }}</Text>
39
39
  </View>
@@ -31,7 +31,7 @@ export default definePage({
31
31
  },
32
32
  useCustom(state) {
33
33
  const light = state.customLight.trim();
34
- // One colour is enough: it's used in dark too.
34
+ // One colour is enough. It's used in dark mode too.
35
35
  const dark = state.customDark.trim() || light;
36
36
  if (!HEX_COLOR.test(light) || !HEX_COLOR.test(dark)) {
37
37
  this.setState({ customError: 'Write a colour as # and six digits, such as #FFF3E0' });
@@ -10,7 +10,7 @@
10
10
  <Notice tone="info">Opened for {{ buyer }}. buyer isn't in share's options, so a shared link leaves it out.</Notice>
11
11
  </If>
12
12
  <Else>
13
- <Notice tone="success">Opened from a link: it carried the concert, and nothing else.</Notice>
13
+ <Notice tone="success">Opened from a link. It carried the concert and nothing else.</Notice>
14
14
  </Else>
15
15
  <Text variant="caption" tone="muted">Tap ••• then Share. The link opens this concert.</Text>
16
16
  </If>
@@ -12,7 +12,7 @@ export default definePage({
12
12
  }),
13
13
  restock: (state) => ({ shows: state.shows.map((show) => ({ ...show, left: 20 })) }),
14
14
  toggleSignedIn: (state) => ({ signedIn: !state.signedIn }),
15
- // Changes the list's order. The key keeps each row's place right.
15
+ // Changes the list's order. The For's key lets each row move with its item.
16
16
  shuffle: (state) => ({ genres: [...state.genres.slice(1), state.genres[0]!] }),
17
17
  },
18
18
  });
@@ -18,7 +18,7 @@
18
18
 
19
19
  <View gap="small">
20
20
  <Text variant="subtitle">For, with ElseIf inside</Text>
21
- <Text variant="caption" tone="muted">item names each show. key gives each a lasting id, so its row stays the same row when the list changes. ElseIf checks another condition when the one above is false.</Text>
21
+ <Text variant="caption" tone="muted">item names each show. key names the field that tells the shows apart, so each row stays with its show when the list changes. ElseIf checks another condition when the one above is false.</Text>
22
22
  <View variant="card" gap="medium">
23
23
  <For each="{{ shows }}" item="show" key="id">
24
24
  <View direction="row" align="center" gap="small">
@@ -14,7 +14,7 @@ export default definePage({
14
14
  initialState: state,
15
15
  configs: { navigationBar: { title: 'Events' } },
16
16
  mutations: {
17
- // No detail: a tap is all there is to know.
17
+ // A tap has no detail. It only says the tap happened.
18
18
  countTap: (state, event: DotEvent) => ({
19
19
  taps: state.taps + 1,
20
20
  ...describe('countTap', event),
@@ -19,7 +19,7 @@
19
19
 
20
20
  <View gap="small">
21
21
  <Text variant="subtitle">Taps</Text>
22
- <Text variant="caption" tone="muted">Button raises click. View, ListItem, Link and Chip raise tap.</Text>
22
+ <Text variant="caption" tone="muted">A Button raises click, so it takes onClick. View, ListItem, Link and Chip raise tap, so they take onTap.</Text>
23
23
  <View variant="card" direction="row" align="center" gap="small">
24
24
  <Button variant="secondary" onClick="countTap">Tap me</Button>
25
25
  <View variant="card" grow onTap="countTap">
@@ -16,7 +16,8 @@ export default definePage({
16
16
  onLoad(options) {
17
17
  this.setState({ lastClosed, runs: ran([], `onLoad ${JSON.stringify(options)}`) });
18
18
  },
19
- // Runs each time the page comes into view: after onLoad, and when a page above it closes.
19
+ // Runs each time the page comes into view: after onLoad, when a page above it closes, and when
20
+ // the dot comes back from the background.
20
21
  onShow() {
21
22
  this.setState((current) => ({ runs: ran(current.runs, 'onShow') }));
22
23
  },
@@ -9,7 +9,7 @@
9
9
  <Text>{{ run.id }}. {{ run.hook }}</Text>
10
10
  </For>
11
11
  </View>
12
- <Text variant="caption" tone="muted">Open another page, then come back: this page runs onHide, then onShow.</Text>
12
+ <Text variant="caption" tone="muted">Open another page, then come back. This page runs onHide, then onShow.</Text>
13
13
  <Button variant="secondary" onClick="openAnother">Open another page</Button>
14
14
  </View>
15
15
 
@@ -32,6 +32,6 @@
32
32
 
33
33
  <View gap="small">
34
34
  <Text variant="subtitle">The dot's hooks</Text>
35
- <Text variant="caption" tone="muted">dot.ts can have hooks too: onLaunch runs once when the dot starts, and onError gets any error a page doesn't catch.</Text>
35
+ <Text variant="caption" tone="muted">dot.ts can have hooks too. onLaunch runs once when the dot starts. onError gets any error a page doesn't catch.</Text>
36
36
  </View>
37
37
  </View>
@@ -11,6 +11,7 @@ export default definePage({
11
11
  this.setState({ depth, from, trail: `${from} › ${depth}`, options: JSON.stringify(options) });
12
12
  },
13
13
  },
14
+ // Only actions have this.navigation, so only they open and close pages.
14
15
  actions: {
15
16
  openAnother(state) {
16
17
  this.navigation.push('basics/navigation', { depth: String(state.depth), trail: state.trail });
@@ -22,7 +22,7 @@
22
22
 
23
23
  <View gap="small">
24
24
  <Text variant="subtitle">back</Text>
25
- <Text variant="caption" tone="muted">Closes this page, or as many as you ask. On the first page, it closes the dot.</Text>
25
+ <Text variant="caption" tone="muted">Closes this page, or as many as you ask. It never closes the first page. To close the dot, call this.dash.dot.close().</Text>
26
26
  <View direction="row" gap="small">
27
27
  <Button variant="secondary" onClick="back">Back</Button>
28
28
  <Button variant="secondary" onClick="backTwo" disabled="{{ depth < 3 }}">Back two</Button>
@@ -5,9 +5,9 @@ export default definePage({
5
5
  initialState: state,
6
6
  configs: {
7
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.
8
+ // This page's own background, a warm Salone sunset in light mode and the evening after it in
9
+ // dark. Dash paints it behind the page, makes the list's cards to match, and picks text and bar
10
+ // colours that read on it. Going back shows the page below in its own colours again.
11
11
  colors: { background: { light: '#FFF3E0', dark: '#2B1A0E' } },
12
12
  },
13
13
  actions: {
@@ -1,10 +1,10 @@
1
1
  <View>
2
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>
3
+ <Text>Dash's menu, ••• (⋮ on Android), 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
4
 
5
5
  <View gap="small">
6
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>
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, as the build reads it without running the code.</Text>
8
8
  <Text variant="caption" tone="muted">Open a concert, then tap ••• and Share.</Text>
9
9
  <List>
10
10
  <For each="{{ concerts }}" item="concert" key="id">
@@ -2,21 +2,30 @@ import state from './state';
2
2
 
3
3
  export default definePage({
4
4
  initialState: state,
5
+ // What Dash's bars show on this page. The Bars page has more.
5
6
  configs: { navigationBar: { title: 'State' } },
7
+ // A mutation gets the state and returns only the fields that change. It can't wait, so it can't
8
+ // call Dash.
6
9
  mutations: {
7
10
  increment: (state) => {
8
11
  const count = state.count + 1;
12
+ // State is read-only, so make a new list rather than change the old one.
9
13
  return { count, taps: [{ id: count }, ...state.taps] };
10
14
  },
11
15
  reset: () => ({ count: 0, taps: [] }),
12
16
  },
17
+ // An action can wait, call Dash, open pages and run other handlers. It changes the state with
18
+ // this.setState or a mutation.
13
19
  actions: {
14
20
  fillUp() {
21
+ // this.state is the latest state. The state an action gets is from when it started, so it
22
+ // wouldn't see the cheers this loop adds.
15
23
  while (this.state.count < this.state.limit) {
16
24
  this.mutations.increment();
17
25
  }
18
26
  },
19
27
  undo() {
28
+ // setState takes the fields to change, or a function that gets the latest state.
20
29
  this.setState((current) => ({ count: current.count - 1, taps: current.taps.slice(1) }));
21
30
  },
22
31
  },
@@ -2,9 +2,12 @@ export interface Tap {
2
2
  id: number;
3
3
  }
4
4
 
5
+ // State is plain data, as in JSON: text, numbers, true and false, null, lists and objects. Each
6
+ // open copy of the page gets its own. For "no value", use null, as setState skips undefined fields.
5
7
  export default {
6
8
  title: 'cheers for an encore',
7
9
  count: 0,
8
10
  limit: 5,
11
+ // `as Tap[]` tells TypeScript what the empty list will hold.
9
12
  taps: [] as Tap[],
10
13
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  <View gap="small">
6
6
  <Text variant="subtitle">autoplay, loop and effect</Text>
7
- <Text variant="caption" tone="muted">Gen Z artists. The slides move on their own every 3 seconds, start over at the end, and pause when you touch them. effect="scale" shrinks the slides beside the one in view.</Text>
7
+ <Text variant="caption" tone="muted">Gen Z artists. autoplay moves the slides every interval, here 3000 milliseconds, and pauses while you touch them. loop goes on from the last slide to the first. effect="scale" shrinks the slides beside the one in view.</Text>
8
8
  <Carousel autoplay loop interval="3000" gap="medium" effect="scale" indicator="dots">
9
9
  <For each="{{ artists }}" item="artist" key="id">
10
10
  <View variant="card" align="center" gap="medium">
@@ -23,7 +23,7 @@
23
23
 
24
24
  <View gap="small">
25
25
  <Text variant="subtitle">index and onChange</Text>
26
- <Text variant="caption" tone="muted">How Salone music grew, from palm-wine to Gen Z. The page sets the slide with index, and onChange tells it when you swipe. The buttons move the slides, so indicator="none" hides the dots.</Text>
26
+ <Text variant="caption" tone="muted">How Salone music grew, from palm-wine to Gen Z. index sets the slide. When you swipe, onChange sends the new slide's index. The buttons move the slides here, so indicator="none" hides the dots.</Text>
27
27
  <Carousel index="{{ chapter }}" indicator="none" effect="slide" gap="small" padding="small" onChange="showChapter">
28
28
  <For each="{{ chapters }}" item="card" key="title">
29
29
  <View variant="card" align="center" gap="medium">
@@ -8,7 +8,8 @@ export default definePage({
8
8
  restart: () => ({ progress: 0 }),
9
9
  toggleBusy: (state) => ({ busy: !state.busy }),
10
10
  toggleLoaded: (state) => ({ loaded: !state.loaded }),
11
- // A toast lasts its default time unless the button gives one, in milliseconds.
11
+ // A button's data-duration, in milliseconds, is how long its Toast stays. Without one, the
12
+ // Toast stays for its default time.
12
13
  showToast: (
13
14
  _state,
14
15
  event: DataEvent<{ message: string; tone: string; duration?: string }>,
@@ -6,9 +6,9 @@ export interface PaymentStep {
6
6
  status: StepStatus;
7
7
  }
8
8
 
9
- // Sending Le 500 to Fatmata Conteh in Bo.
9
+ // Sending SLE 500 to Fatmata Conteh in Bo.
10
10
  const PAYMENT = [
11
- { title: 'Paid', text: 'Le 500 from your wallet' },
11
+ { title: 'Paid', text: 'SLE 500 from your wallet' },
12
12
  { title: 'Sent', text: 'On its way to Bo' },
13
13
  { title: 'Received', text: 'By Fatmata Conteh' },
14
14
  ];
@@ -14,7 +14,7 @@
14
14
 
15
15
  <View gap="small">
16
16
  <Text variant="subtitle">Skeleton</Text>
17
- <Text variant="caption" tone="muted">Shows the shape of what is loading: lines of text, a circle or a box.</Text>
17
+ <Text variant="caption" tone="muted">Shows the shape of what's loading, as lines of text, a circle or a box.</Text>
18
18
  <View variant="card">
19
19
  <If condition="{{ loaded }}">
20
20
  <View direction="row" align="center" gap="large">
@@ -65,7 +65,7 @@
65
65
  <Text variant="subtitle">A busy Button</Text>
66
66
  <Text variant="caption" tone="muted">loading shows a spinner, and the button ignores taps.</Text>
67
67
  <View variant="card">
68
- <Button loading="{{ busy }}">{{ busy ? 'Paying…' : 'Pay Le 300 for two tickets' }}</Button>
68
+ <Button loading="{{ busy }}">{{ busy ? 'Paying…' : 'Pay SLE 300 for two tickets' }}</Button>
69
69
  <Switch label="Busy" checked="{{ busy }}" onChange="toggleBusy" />
70
70
  </View>
71
71
  </View>
@@ -3,10 +3,10 @@ import { errorMessage } from '@monimesl/dot-runtime';
3
3
  import type { TicketType } from './state';
4
4
  import state, { SHOWS, TICKETS } from './state';
5
5
 
6
- // 2 tickets of a Le 1,200 type -> "Le 2,400"
6
+ // 2 tickets of an SLE 1,200 type -> "SLE 2,400"
7
7
  function total(tickets: number, ticket: TicketType): string {
8
8
  const leones = tickets * TICKETS[ticket].price;
9
- return `Le ${leones.toLocaleString('en-US')}`;
9
+ return `SLE ${leones.toLocaleString('en-US')}`;
10
10
  }
11
11
 
12
12
  export default definePage({
@@ -18,7 +18,7 @@ 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: `Le ${2 * TICKETS.regular.price}`,
21
+ total: `SLE ${2 * TICKETS.regular.price}`,
22
22
  name: '',
23
23
  email: '',
24
24
  phone: '',
@@ -15,7 +15,7 @@
15
15
 
16
16
  <View gap="small">
17
17
  <Text variant="subtitle">Input</Text>
18
- <Text variant="caption" tone="muted">type sets the keyboard: text, email, phone, number or password. prefix and suffix sit inside the field. error shows under it.</Text>
18
+ <Text variant="caption" tone="muted">type sets the keyboard, such as email, phone, number or password. prefix and suffix sit inside the field. error shows under it, in place of hint. onSubmit comes when the person presses return, here in the promo code.</Text>
19
19
  <View variant="card">
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" />
@@ -37,9 +37,9 @@
37
37
  <Text variant="caption" tone="muted">One choice from a few. A Radio, or the whole group, can be disabled.</Text>
38
38
  <View variant="card">
39
39
  <RadioGroup label="Ticket" value="{{ ticket }}" disabled="{{ sending }}" onChange="setTicket">
40
- <Radio value="regular" label="Regular · Le 150" />
41
- <Radio value="vip" label="VIP, near the stage · Le 400" />
42
- <Radio value="table" label="Table for four · Le 1,200" />
40
+ <Radio value="regular" label="Regular · SLE 150" />
41
+ <Radio value="vip" label="VIP, near the stage · SLE 400" />
42
+ <Radio value="table" label="Table for four · SLE 1,200" />
43
43
  <Radio value="backstage" label="Backstage · sold out" disabled />
44
44
  </RadioGroup>
45
45
  </View>
@@ -90,7 +90,7 @@
90
90
  <Notice tone="danger" title="Not booked">{{ failure }}</Notice>
91
91
  </If>
92
92
 
93
- <Text variant="caption" tone="muted">A Footer keeps its buttons at the bottom of the screen.</Text>
93
+ <Text variant="caption" tone="muted">A Footer keeps its buttons at the bottom of the screen. Put it last in the page's View.</Text>
94
94
  <Footer>
95
95
  <Button onClick="send" loading="{{ sending }}" disabled="{{ !agreed }}">Buy tickets</Button>
96
96
  </Footer>
@@ -4,6 +4,7 @@ export default definePage({
4
4
  initialState: state,
5
5
  configs: { navigationBar: { title: 'Icons' } },
6
6
  mutations: {
7
+ // The Toast raises onHide once it goes. Clearing its message lets the same one show again.
7
8
  clearToast: () => ({ toast: '' }),
8
9
  },
9
10
  actions: {
@@ -1,5 +1,5 @@
1
1
  export default {
2
- // Every icon name, as Icon's name, and ListItem's, Chip's, GridItem's and EmptyState's icon take.
2
+ // Every icon name. Icon's name, and the icon of ListItem, Chip, GridItem and EmptyState, take these.
3
3
  names: [
4
4
  'arrow-down',
5
5
  'arrow-left',
@@ -2,7 +2,7 @@ import { errorMessage } from '@monimesl/dot-runtime';
2
2
 
3
3
  import state from './state';
4
4
 
5
- // AUDACITY's id in Apple's catalog; its cover's address can change, so the page looks it up.
5
+ // AUDACITY's id in Apple's catalog. Its cover's address can change, so the page looks it up.
6
6
  const AUDACITY = 6811765244;
7
7
 
8
8
  interface Lookup {
@@ -1,7 +1,7 @@
1
1
  export default {
2
2
  size: 64,
3
3
  loaded: '',
4
- // Built at run time, so the build doesn't check that the file exists.
4
+ // Kept in state, not written in the view, so the build doesn't check that the file exists.
5
5
  missing: 'statics/missing.png',
6
6
  failure: '',
7
7
  // The cover of Drizilik's album AUDACITY, which the page asks Apple's catalog for.
@@ -14,7 +14,7 @@
14
14
 
15
15
  <View gap="small">
16
16
  <Text variant="subtitle">From the web</Text>
17
- <Text variant="caption" tone="muted">The cover of Drizilik's album AUDACITY. With aspect="1:1" and no width, it fills the card.</Text>
17
+ <Text variant="caption" tone="muted">The cover of Drizilik's album AUDACITY. A web picture loads only from a host in dot.json's network.hosts. With aspect="1:1" and no width, it fills the card.</Text>
18
18
  <View variant="card" gap="small">
19
19
  <If condition="{{ cover }}">
20
20
  <Image src="{{ cover }}" alt="The cover of AUDACITY, by Drizilik" aspect="1:1" />
@@ -32,7 +32,7 @@
32
32
 
33
33
  <View gap="small">
34
34
  <Text variant="subtitle">shape and fit</Text>
35
- <Text variant="caption" tone="muted">Rounded, square or circle. fit="contain" shows the whole picture; cover, the default, fills the box.</Text>
35
+ <Text variant="caption" tone="muted">shape is rounded, square or circle. fit="cover", the default, fills the box and crops. fit="contain" shows the whole picture.</Text>
36
36
  <View variant="card" direction="row" align="center" gap="large">
37
37
  <Image src="statics/logo.png" alt="Rounded" width="56" height="56" shape="rounded" />
38
38
  <Image src="statics/logo.png" alt="Square" width="56" height="56" shape="square" />
@@ -44,7 +44,7 @@
44
44
 
45
45
  <View gap="small">
46
46
  <Text variant="subtitle">onLoad</Text>
47
- <Text variant="caption" tone="muted">Tells the page the picture's own size once it loads. The size on screen comes from state here.</Text>
47
+ <Text variant="caption" tone="muted">Comes once the picture loads, with its own size in event.detail.width and height. The size on screen comes from state here.</Text>
48
48
  <View variant="card" gap="small">
49
49
  <Image src="statics/logo.png" alt="Logo" width="{{ size }}" height="{{ size }}" onLoad="logoLoaded" />
50
50
  <Text>{{ size }} × {{ size }} on screen, {{ loaded }} in the file</Text>
@@ -57,7 +57,7 @@
57
57
 
58
58
  <View gap="small">
59
59
  <Text variant="subtitle">onError</Text>
60
- <Text variant="caption" tone="muted">Tells the page why a picture didn't load.</Text>
60
+ <Text variant="caption" tone="muted">Comes when a picture fails to load. event.detail.message says which one.</Text>
61
61
  <View variant="card">
62
62
  <If condition="{{ failure }}">
63
63
  <Text>{{ failure }}</Text>
@@ -14,7 +14,8 @@ export default definePage({
14
14
  initialState: state,
15
15
  configs: { navigationBar: { title: 'Layout' } },
16
16
  hooks: {
17
- // The shelf's covers come from Apple's catalog.
17
+ // The shelf's covers come from Apple's catalog. Dash sends requests only to the hosts in
18
+ // dot.json's network.hosts. The Network page shows more.
18
19
  async onLoad() {
19
20
  const ids = this.state.releases.map((release) => release.id).join(',');
20
21
  try {
@@ -48,6 +49,7 @@ export default definePage({
48
49
  openSection: (_state, event: DataEvent<{ name: string }>) => ({
49
50
  section: event.data.name,
50
51
  }),
52
+ // Scroll's change carries the index of the child at the start, once the row stops.
51
53
  showFirst: (_state, event: IndexEvent) => ({ first: event.detail.index }),
52
54
  shelfStart: () => ({ first: 0 }),
53
55
  shelfEnd: (state) => ({ first: state.releases.length - 1 }),
@@ -4,7 +4,7 @@
4
4
 
5
5
  <View gap="small">
6
6
  <Text variant="subtitle">View</Text>
7
- <Text variant="caption" tone="muted">A View puts its items in a column or a row. variant="card" gives it a card's look. Change the one below.</Text>
7
+ <Text variant="caption" tone="muted">A View puts its children in a column, or in a row with direction="row". variant="card" gives it a card's look. Change the one below.</Text>
8
8
  <View variant="card" direction="{{ direction }}" justify="{{ justify }}" align="{{ align }}" gap="{{ gap }}" wrap="{{ wrap }}">
9
9
  <Button variant="secondary">Palm-wine</Button>
10
10
  <Button variant="secondary">Gumbe</Button>
@@ -43,7 +43,7 @@
43
43
 
44
44
  <View gap="small">
45
45
  <Text variant="subtitle">grow and onTap</Text>
46
- <Text variant="caption" tone="muted">grow fills the space left over: the song grows, the year does not. A View can be tapped: tap the song.</Text>
46
+ <Text variant="caption" tone="muted">grow makes a View fill the space left over. The song grows and the year doesn't. A View with onTap can be tapped, so tap the song.</Text>
47
47
  <View direction="row" gap="small">
48
48
  <View variant="card" grow onTap="playSong">
49
49
  <Text>{{ playing ? 'Playing Exodus, by Drizilik' : 'Exodus, by Drizilik' }}</Text>
@@ -72,7 +72,7 @@
72
72
 
73
73
  <View gap="small">
74
74
  <Text variant="subtitle">Stack</Text>
75
- <Text variant="caption" tone="muted">A Stack lays its children on top of each other, such as words over a picture.</Text>
75
+ <Text variant="caption" tone="muted">A Stack lays its children on top of each other, the first at the bottom, such as words over a picture.</Text>
76
76
  <Stack radius="large" aspect="16:9">
77
77
  <View background="gold" />
78
78
  <View justify="end" padding="large">
@@ -89,7 +89,7 @@
89
89
 
90
90
  <View gap="small">
91
91
  <Text variant="subtitle">Scroll</Text>
92
- <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>
92
+ <Text variant="caption" tone="muted">A Scroll moves a row sideways. snap="start" stops it at the start of a release. Once it stops, onChange sends the index of the first release in view. Setting index scrolls there, as the buttons do.</Text>
93
93
  <Scroll gap="medium" snap="start" index="{{ first }}" onChange="showFirst">
94
94
  <For each="{{ releases }}" item="release" key="id">
95
95
  <View gap="small">
@@ -113,7 +113,7 @@
113
113
 
114
114
  <View gap="small">
115
115
  <Text variant="subtitle">Grid</Text>
116
- <Text variant="caption" tone="muted">A Grid keeps its columns the same width. A GridItem shows an icon or a picture, with a label.</Text>
116
+ <Text variant="caption" tone="muted">A Grid keeps its columns the same width, 4 unless columns says. A GridItem shows an icon or a picture, with a label and an optional badge.</Text>
117
117
  <View variant="card" gap="medium">
118
118
  <Grid columns="4" gap="small">
119
119
  <GridItem icon="microphone" label="Artists" data-name="Artists" onTap="openSection" />
@@ -1,10 +1,10 @@
1
1
  <View>
2
2
  <Text variant="title">Lists</Text>
3
- <Text>A List shows rows in a card. A ListItem can show an icon or a picture, a subtitle, and a value or a badge at its end. A row you can tap shows an arrow.</Text>
3
+ <Text>A List shows rows in a card. A ListItem can show an icon or a picture, a subtitle, and a value or a badge at its end. A row with onTap shows an arrow.</Text>
4
4
 
5
5
  <View gap="small">
6
6
  <Text variant="subtitle">List and ListItem</Text>
7
- <Text variant="caption" tone="muted">Artists in a small list. Tap one: its data-id tells the page which one.</Text>
7
+ <Text variant="caption" tone="muted">Tap an artist. The row's data-id tells the page which one.</Text>
8
8
  <List>
9
9
  <For each="{{ artists }}" item="artist" key="id">
10
10
  <ListItem icon="microphone" title="{{ artist.name }}" subtitle="{{ artist.song }}" value="{{ artist.genre }}" data-id="{{ artist.id }}" onTap="choose" />
@@ -16,9 +16,9 @@
16
16
  </View>
17
17
 
18
18
  <View gap="small">
19
- <Text variant="subtitle">size="md", with a picture and a badge</Text>
20
- <Text variant="caption" tone="muted">Medium lists have more room. A ListItem's children show at its end, in place of value.</Text>
21
- <List size="md">
19
+ <Text variant="subtitle">A picture and a badge</Text>
20
+ <Text variant="caption" tone="muted">A ListItem's children show at its end, in place of value.</Text>
21
+ <List>
22
22
  <For each="{{ releases }}" item="release" key="id">
23
23
  <ListItem image="statics/logo.png" title="{{ release.title }}" subtitle="{{ release.artist }} · {{ release.year }}">
24
24
  <Badge tone="{{ release.tone }}">{{ release.note }}</Badge>
@@ -29,7 +29,7 @@
29
29
 
30
30
  <View gap="small">
31
31
  <Text variant="subtitle">onEndReached</Text>
32
- <Text variant="caption" tone="muted">Comes when the last row scrolls into view, so the page can add more. {{ chart.length }} of {{ chartSize }} songs so far.</Text>
32
+ <Text variant="caption" tone="muted">Comes as the last row nears the screen, so the page can add more. It comes again once there's a new last row. {{ chart.length }} of {{ chartSize }} songs so far.</Text>
33
33
  <List onEndReached="showMore">
34
34
  <For each="{{ chart }}" item="song" key="id">
35
35
  <ListItem title="{{ song.id }}. {{ song.title }}" value="{{ song.plays }}" />
@@ -52,7 +52,7 @@
52
52
 
53
53
  <View gap="small">
54
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>
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. onToggle sends event.detail.open each time.</Text>
56
56
  <View variant="card" gap="none">
57
57
  <Disclosure title="Can I get a refund?" subtitle="Tickets and refunds" open>
58
58
  <Text>Yes, until the Friday before the show. After that, you can give your ticket to someone else.</Text>
@@ -70,7 +70,7 @@
70
70
 
71
71
  <View gap="small">
72
72
  <Text variant="subtitle">EmptyState</Text>
73
- <Text variant="caption" tone="muted">Shows when a list has nothing in it, with a way forward.</Text>
73
+ <Text variant="caption" tone="muted">Shows where a list has nothing yet. Its children, such as a button, show under its text.</Text>
74
74
  <View variant="card">
75
75
  <If condition="{{ saved.length > 0 }}">
76
76
  <For each="{{ saved }}" item="title" key="*this">
@@ -1,6 +1,6 @@
1
1
  import state from './state';
2
2
 
3
- // The code this page accepts; a real dot checks it with its server.
3
+ // The code this page accepts. A real dot checks it with its server.
4
4
  const RIGHT_CODE = '123456';
5
5
 
6
6
  // In dollars, as the pledge field sends them.
@@ -4,7 +4,7 @@
4
4
 
5
5
  <View gap="small">
6
6
  <Text variant="subtitle">AmountInput</Text>
7
- <Text variant="caption" tone="muted">Formats the amount as you type. It sends a number in cents, the minor unit, so 150 is SLE 1.50.</Text>
7
+ <Text variant="caption" tone="muted">Formats the amount as you type. onChange sends a number in cents, the minor unit, so 150 is SLE 1.50. An empty field sends null.</Text>
8
8
  <AmountInput label="Tip for the band" placeholder="0.00" value="{{ amount }}" disabled="{{ locked }}" onChange="setAmount" hint="The QR code below asks for it" />
9
9
  <Switch label="Lock the tip" checked="{{ locked }}" onChange="setLocked" />
10
10
  </View>
@@ -31,7 +31,7 @@
31
31
 
32
32
  <View gap="small">
33
33
  <Text variant="subtitle">CodeInput</Text>
34
- <Text variant="caption" tone="muted">A one-time code, one box per digit. Type it, paste it, or let the phone fill it from an SMS. onComplete comes when the last box fills.</Text>
34
+ <Text variant="caption" tone="muted">A one-time code, one box per digit. Type it, paste it, or let the phone fill it from an SMS. onComplete comes when the last box fills, with the code in event.detail.value.</Text>
35
35
  <If condition="{{ verified }}">
36
36
  <Notice tone="success" title="Code accepted">Your two tickets are confirmed.</Notice>
37
37
  <Button variant="secondary" onClick="startAgain">Start again</Button>