@monimesl/dot-cli 0.1.0-alpha.4 → 0.1.0-alpha.40

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 (161) hide show
  1. package/README.md +84 -29
  2. package/dist/cli.js +686 -319
  3. package/dist/cli.js.map +1 -1
  4. package/dist/{server-DFOUQnLA.js → server-DMnWDdJ6.js} +582 -537
  5. package/dist/server-DMnWDdJ6.js.map +1 -0
  6. package/dist/templates/showcase/.env +1 -1
  7. package/dist/templates/showcase/dot.ts +53 -14
  8. package/dist/templates/showcase/pages/basics/bars/controller.ts +47 -0
  9. package/dist/templates/showcase/pages/basics/bars/state.ts +7 -0
  10. package/dist/templates/showcase/pages/basics/bars/view.dml +36 -0
  11. package/dist/templates/showcase/pages/basics/bindings/controller.ts +15 -0
  12. package/dist/templates/showcase/pages/basics/bindings/state.ts +14 -0
  13. package/dist/templates/showcase/pages/basics/bindings/view.dml +41 -0
  14. package/dist/templates/showcase/pages/basics/colors/controller.ts +112 -0
  15. package/dist/templates/showcase/pages/basics/colors/palette.ts +52 -0
  16. package/dist/templates/showcase/pages/basics/colors/state.ts +17 -0
  17. package/dist/templates/showcase/pages/basics/colors/view.dml +142 -0
  18. package/dist/templates/showcase/pages/basics/concert/controller.ts +16 -0
  19. package/dist/templates/showcase/pages/basics/concert/state.ts +7 -0
  20. package/dist/templates/showcase/pages/basics/concert/view.dml +20 -0
  21. package/dist/templates/showcase/pages/basics/control-flow/controller.ts +18 -0
  22. package/dist/templates/showcase/pages/basics/control-flow/state.ts +16 -0
  23. package/dist/templates/showcase/pages/basics/control-flow/view.dml +55 -0
  24. package/dist/templates/showcase/pages/basics/events/controller.ts +43 -0
  25. package/dist/templates/showcase/pages/basics/events/state.ts +11 -0
  26. package/dist/templates/showcase/pages/basics/events/view.dml +51 -0
  27. package/dist/templates/showcase/pages/basics/hooks/controller.ts +43 -0
  28. package/dist/templates/showcase/pages/basics/hooks/state.ts +10 -0
  29. package/dist/templates/showcase/pages/basics/hooks/view.dml +37 -0
  30. package/dist/templates/showcase/pages/basics/navigation/controller.ts +41 -0
  31. package/dist/templates/showcase/pages/basics/navigation/state.ts +11 -0
  32. package/dist/templates/showcase/pages/basics/navigation/view.dml +48 -0
  33. package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +18 -0
  34. package/dist/templates/showcase/pages/basics/pick-genre/state.ts +3 -0
  35. package/dist/templates/showcase/pages/basics/pick-genre/view.dml +10 -0
  36. package/dist/templates/showcase/pages/basics/share/concerts.ts +31 -0
  37. package/dist/templates/showcase/pages/basics/share/controller.ts +12 -0
  38. package/dist/templates/showcase/pages/basics/share/state.ts +5 -0
  39. package/dist/templates/showcase/pages/basics/share/view.dml +21 -0
  40. package/dist/templates/showcase/pages/{state → basics/state}/controller.ts +1 -0
  41. package/dist/templates/showcase/pages/{state → basics/state}/state.ts +1 -1
  42. package/dist/templates/showcase/pages/basics/state/view.dml +46 -0
  43. package/dist/templates/showcase/pages/components/carousel/controller.ts +41 -0
  44. package/dist/templates/showcase/pages/components/carousel/state.ts +77 -0
  45. package/dist/templates/showcase/pages/components/carousel/view.dml +42 -0
  46. package/dist/templates/showcase/pages/components/feedback/controller.ts +32 -0
  47. package/dist/templates/showcase/pages/components/feedback/state.ts +41 -0
  48. package/dist/templates/showcase/pages/components/feedback/view.dml +116 -0
  49. package/dist/templates/showcase/pages/components/forms/controller.ts +72 -0
  50. package/dist/templates/showcase/pages/components/forms/state.ts +37 -0
  51. package/dist/templates/showcase/pages/components/forms/view.dml +97 -0
  52. package/dist/templates/showcase/pages/components/icons/controller.ts +15 -0
  53. package/dist/templates/showcase/pages/components/icons/state.ts +75 -0
  54. package/dist/templates/showcase/pages/components/icons/view.dml +36 -0
  55. package/dist/templates/showcase/pages/components/images/controller.ts +44 -0
  56. package/dist/templates/showcase/pages/{images → components/images}/state.ts +3 -0
  57. package/dist/templates/showcase/pages/components/images/view.dml +83 -0
  58. package/dist/templates/showcase/pages/components/layout/controller.ts +61 -0
  59. package/dist/templates/showcase/pages/components/layout/state.ts +34 -0
  60. package/dist/templates/showcase/pages/components/layout/view.dml +143 -0
  61. package/dist/templates/showcase/pages/components/lists/controller.ts +18 -0
  62. package/dist/templates/showcase/pages/components/lists/state.ts +130 -0
  63. package/dist/templates/showcase/pages/components/lists/view.dml +88 -0
  64. package/dist/templates/showcase/pages/components/money/controller.ts +45 -0
  65. package/dist/templates/showcase/pages/{payments → components/money}/state.ts +3 -0
  66. package/dist/templates/showcase/pages/components/money/view.dml +54 -0
  67. package/dist/templates/showcase/pages/components/reading/controller.ts +6 -0
  68. package/dist/templates/showcase/pages/components/reading/state.ts +23 -0
  69. package/dist/templates/showcase/pages/components/reading/view.dml +42 -0
  70. package/dist/templates/showcase/pages/components/sheets/controller.ts +36 -0
  71. package/dist/templates/showcase/pages/components/sheets/state.ts +26 -0
  72. package/dist/templates/showcase/pages/components/sheets/view.dml +38 -0
  73. package/dist/templates/showcase/pages/components/styles/controller.ts +6 -0
  74. package/dist/templates/showcase/pages/components/styles/state.ts +3 -0
  75. package/dist/templates/showcase/pages/components/styles/view.dml +101 -0
  76. package/dist/templates/showcase/pages/components/tabs/controller.ts +41 -0
  77. package/dist/templates/showcase/pages/components/tabs/state.ts +127 -0
  78. package/dist/templates/showcase/pages/components/tabs/view.dml +57 -0
  79. package/dist/templates/showcase/pages/components/text/controller.ts +10 -0
  80. package/dist/templates/showcase/pages/components/text/state.ts +3 -0
  81. package/dist/templates/showcase/pages/components/text/view.dml +95 -0
  82. package/dist/templates/showcase/pages/dash/account/controller.ts +32 -0
  83. package/dist/templates/showcase/pages/dash/account/state.ts +9 -0
  84. package/dist/templates/showcase/pages/dash/account/view.dml +33 -0
  85. package/dist/templates/showcase/pages/dash/cache/controller.ts +50 -0
  86. package/dist/templates/showcase/pages/dash/cache/state.ts +17 -0
  87. package/dist/templates/showcase/pages/dash/cache/view.dml +48 -0
  88. package/dist/templates/showcase/pages/dash/calls/controller.ts +67 -0
  89. package/dist/templates/showcase/pages/dash/calls/state.ts +9 -0
  90. package/dist/templates/showcase/pages/dash/calls/view.dml +69 -0
  91. package/dist/templates/showcase/pages/dash/contacts/controller.ts +30 -0
  92. package/dist/templates/showcase/pages/dash/contacts/state.ts +6 -0
  93. package/dist/templates/showcase/pages/dash/contacts/view.dml +33 -0
  94. package/dist/templates/showcase/pages/dash/crypto/controller.ts +38 -0
  95. package/dist/templates/showcase/pages/dash/crypto/state.ts +10 -0
  96. package/dist/templates/showcase/pages/dash/crypto/view.dml +48 -0
  97. package/dist/templates/showcase/pages/dash/files/controller.ts +71 -0
  98. package/dist/templates/showcase/pages/dash/files/state.ts +23 -0
  99. package/dist/templates/showcase/pages/dash/files/view.dml +78 -0
  100. package/dist/templates/showcase/pages/dash/media/controller.ts +65 -0
  101. package/dist/templates/showcase/pages/dash/media/state.ts +12 -0
  102. package/dist/templates/showcase/pages/dash/media/view.dml +53 -0
  103. package/dist/templates/showcase/pages/dash/network/controller.ts +215 -0
  104. package/dist/templates/showcase/pages/dash/network/state.ts +35 -0
  105. package/dist/templates/showcase/pages/dash/network/view.dml +108 -0
  106. package/dist/templates/showcase/pages/dash/payments/controller.ts +83 -0
  107. package/dist/templates/showcase/pages/dash/payments/state.ts +10 -0
  108. package/dist/templates/showcase/pages/dash/payments/view.dml +38 -0
  109. package/dist/templates/showcase/pages/dash/secrets/controller.ts +44 -0
  110. package/dist/templates/showcase/pages/dash/secrets/state.ts +5 -0
  111. package/dist/templates/showcase/pages/dash/secrets/view.dml +26 -0
  112. package/dist/templates/showcase/pages/dash/system/controller.ts +89 -0
  113. package/dist/templates/showcase/pages/dash/system/state.ts +13 -0
  114. package/dist/templates/showcase/pages/dash/system/view.dml +96 -0
  115. package/dist/templates/showcase/pages/dash/ui/controller.ts +70 -0
  116. package/dist/templates/showcase/pages/dash/ui/state.ts +8 -0
  117. package/dist/templates/showcase/pages/dash/ui/view.dml +31 -0
  118. package/dist/templates/showcase/pages/index/controller.ts +1 -1
  119. package/dist/templates/showcase/pages/index/state.ts +181 -54
  120. package/dist/templates/showcase/pages/index/view.dml +8 -5
  121. package/dist/templates/showcase/statics/logo.png +0 -0
  122. package/package.json +6 -6
  123. package/dist/server-DFOUQnLA.js.map +0 -1
  124. package/dist/templates/showcase/pages/carousel/controller.ts +0 -10
  125. package/dist/templates/showcase/pages/carousel/state.ts +0 -40
  126. package/dist/templates/showcase/pages/carousel/view.dml +0 -37
  127. package/dist/templates/showcase/pages/device/controller.ts +0 -70
  128. package/dist/templates/showcase/pages/device/state.ts +0 -7
  129. package/dist/templates/showcase/pages/device/view.dml +0 -44
  130. package/dist/templates/showcase/pages/feedback/controller.ts +0 -16
  131. package/dist/templates/showcase/pages/feedback/state.ts +0 -7
  132. package/dist/templates/showcase/pages/feedback/view.dml +0 -87
  133. package/dist/templates/showcase/pages/files/controller.ts +0 -47
  134. package/dist/templates/showcase/pages/files/state.ts +0 -11
  135. package/dist/templates/showcase/pages/files/view.dml +0 -35
  136. package/dist/templates/showcase/pages/filters/controller.ts +0 -28
  137. package/dist/templates/showcase/pages/filters/state.ts +0 -72
  138. package/dist/templates/showcase/pages/filters/view.dml +0 -43
  139. package/dist/templates/showcase/pages/forms/controller.ts +0 -44
  140. package/dist/templates/showcase/pages/forms/state.ts +0 -15
  141. package/dist/templates/showcase/pages/forms/view.dml +0 -39
  142. package/dist/templates/showcase/pages/images/controller.ts +0 -15
  143. package/dist/templates/showcase/pages/images/view.dml +0 -38
  144. package/dist/templates/showcase/pages/layout/controller.ts +0 -26
  145. package/dist/templates/showcase/pages/layout/state.ts +0 -14
  146. package/dist/templates/showcase/pages/layout/view.dml +0 -80
  147. package/dist/templates/showcase/pages/lists/controller.ts +0 -36
  148. package/dist/templates/showcase/pages/lists/state.ts +0 -96
  149. package/dist/templates/showcase/pages/lists/view.dml +0 -59
  150. package/dist/templates/showcase/pages/navigation/controller.ts +0 -64
  151. package/dist/templates/showcase/pages/navigation/state.ts +0 -17
  152. package/dist/templates/showcase/pages/navigation/view.dml +0 -34
  153. package/dist/templates/showcase/pages/network/controller.ts +0 -107
  154. package/dist/templates/showcase/pages/network/state.ts +0 -15
  155. package/dist/templates/showcase/pages/network/view.dml +0 -56
  156. package/dist/templates/showcase/pages/payments/controller.ts +0 -42
  157. package/dist/templates/showcase/pages/payments/view.dml +0 -35
  158. package/dist/templates/showcase/pages/state/view.dml +0 -33
  159. package/dist/templates/showcase/pages/text/controller.ts +0 -10
  160. package/dist/templates/showcase/pages/text/state.ts +0 -7
  161. package/dist/templates/showcase/pages/text/view.dml +0 -49
@@ -0,0 +1,77 @@
1
+ export interface Artist {
2
+ id: string;
3
+ name: string;
4
+ text: string;
5
+ // A release whose cover shows the artist, by its id in Apple's catalog.
6
+ release: number;
7
+ photo: string;
8
+ }
9
+
10
+ export interface Chapter {
11
+ title: string;
12
+ text: string;
13
+ }
14
+
15
+ export default {
16
+ // Gen Z, the new school.
17
+ artists: [
18
+ {
19
+ id: 'drizilik',
20
+ name: 'Drizilik',
21
+ text: 'Kriofusion rapped in Krio. "Lemonade" is from his album Wait and See.',
22
+ release: 1788321371,
23
+ photo: '',
24
+ },
25
+ {
26
+ id: 'the-therapist',
27
+ name: 'The Therapist',
28
+ text: 'Had a big following online before his first single, "Nack", in 2022.',
29
+ release: 1612124616,
30
+ photo: '',
31
+ },
32
+ {
33
+ id: 'boii',
34
+ name: 'Boii',
35
+ text: 'One of the most-streamed Sierra Leonean women of 2024. Her first EP, Money or Honey, came in 2025.',
36
+ release: 1776449163,
37
+ photo: '',
38
+ },
39
+ {
40
+ id: 'apreel',
41
+ name: 'ApreeL',
42
+ text: '"O\'way", and "Control", a Krio love song.',
43
+ release: 1831185667,
44
+ photo: '',
45
+ },
46
+ {
47
+ id: 'donii-major',
48
+ name: 'Donii Major',
49
+ text: 'R&B from Freetown, from "Hannah" in 2021 to "Shadow" in 2026.',
50
+ release: 6770467984,
51
+ photo: '',
52
+ },
53
+ ] as Artist[],
54
+ chapters: [
55
+ {
56
+ title: 'Palm-wine and gumbe',
57
+ text: 'Ebenezer Calendar & His Maringa Band made Creole palm-wine and gumbe popular, and S. E. Rogie sang palm-wine in four languages.',
58
+ },
59
+ {
60
+ title: 'Milo jazz',
61
+ text: 'Dr. Oloh led Milo Jazz, a street-band sound grown out of gumbe.',
62
+ },
63
+ {
64
+ title: 'Afropop',
65
+ text: 'Bunny Mack\'s "Let Me Love You" was a disco hit in 1981, and Emmerson\'s Borbor Bele sang against corruption in 2004.',
66
+ },
67
+ {
68
+ title: 'Salone hip hop',
69
+ text: 'Rapped mostly in Krio, it rose after the civil war with Daddy Saj, K-Man, LAJ, Kao Denero and Star Zee.',
70
+ },
71
+ {
72
+ title: 'Gen Z',
73
+ text: 'Drizilik, Boii and ApreeL sing in Krio over Afrobeats, and new stars break through online.',
74
+ },
75
+ ] as Chapter[],
76
+ chapter: 0,
77
+ };
@@ -0,0 +1,42 @@
1
+ <View>
2
+ <Text variant="title">Carousel</Text>
3
+ <Text>A Carousel shows one slide at a time. Swipe, or tap a dot.</Text>
4
+
5
+ <View gap="small">
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>
8
+ <Carousel autoplay loop interval="3000" gap="medium" effect="scale" indicator="dots">
9
+ <For each="{{ artists }}" item="artist" key="id">
10
+ <View variant="card" align="center" gap="medium">
11
+ <If condition="{{ artist.photo }}">
12
+ <Image src="{{ artist.photo }}" alt="{{ artist.name }}" aspect="1:1" />
13
+ </If>
14
+ <Else>
15
+ <Skeleton shape="box" height="240" />
16
+ </Else>
17
+ <Text weight="bold">{{ artist.name }}</Text>
18
+ <Text tone="muted" align="center">{{ artist.text }}</Text>
19
+ </View>
20
+ </For>
21
+ </Carousel>
22
+ </View>
23
+
24
+ <View gap="small">
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>
27
+ <Carousel index="{{ chapter }}" indicator="none" effect="slide" gap="small" padding="small" onChange="showChapter">
28
+ <For each="{{ chapters }}" item="card" key="title">
29
+ <View variant="card" align="center" gap="medium">
30
+ <Image src="statics/logo.png" alt="" width="48" height="48" />
31
+ <Text weight="bold">{{ card.title }}</Text>
32
+ <Text tone="muted" align="center">{{ card.text }}</Text>
33
+ </View>
34
+ </For>
35
+ </Carousel>
36
+ <View direction="row" gap="small">
37
+ <Button variant="secondary" onClick="back" disabled="{{ chapter === 0 }}">Back</Button>
38
+ <Button onClick="next" disabled="{{ chapter === chapters.length - 1 }}">Next</Button>
39
+ </View>
40
+ <Text>Chapter {{ chapter + 1 }} of {{ chapters.length }}</Text>
41
+ </View>
42
+ </View>
@@ -0,0 +1,32 @@
1
+ import state, { paymentSteps } from './state';
2
+
3
+ export default definePage({
4
+ initialState: state,
5
+ configs: { navigationBar: { title: 'Feedback' } },
6
+ mutations: {
7
+ advance: (state) => ({ progress: Math.min(100, state.progress + 20) }),
8
+ restart: () => ({ progress: 0 }),
9
+ toggleBusy: (state) => ({ busy: !state.busy }),
10
+ toggleLoaded: (state) => ({ loaded: !state.loaded }),
11
+ // A toast lasts its default time unless the button gives one, in milliseconds.
12
+ showToast: (
13
+ _state,
14
+ event: DataEvent<{ message: string; tone: string; duration?: string }>,
15
+ ) => ({
16
+ toast: event.data.message,
17
+ toastTone: event.data.tone,
18
+ toastDuration: event.data.duration ? Number(event.data.duration) : undefined,
19
+ }),
20
+ clearToast: () => ({ toast: '' }),
21
+ hideTip: () => ({ tipShown: false }),
22
+ advancePayment: (state) => {
23
+ const paymentStage = state.paymentStage + 1;
24
+ return { paymentStage, payment: paymentSteps(paymentStage) };
25
+ },
26
+ failPayment: (state) => ({
27
+ paymentFailed: true,
28
+ payment: paymentSteps(state.paymentStage, true),
29
+ }),
30
+ restartPayment: () => ({ paymentStage: 0, paymentFailed: false, payment: paymentSteps(0) }),
31
+ },
32
+ });
@@ -0,0 +1,41 @@
1
+ export type StepStatus = 'done' | 'current' | 'upcoming' | 'failed';
2
+
3
+ export interface PaymentStep {
4
+ title: string;
5
+ text: string;
6
+ status: StepStatus;
7
+ }
8
+
9
+ // Sending Le 500 to Fatmata Conteh in Bo.
10
+ const PAYMENT = [
11
+ { title: 'Paid', text: 'Le 500 from your wallet' },
12
+ { title: 'Sent', text: 'On its way to Bo' },
13
+ { title: 'Received', text: 'By Fatmata Conteh' },
14
+ ];
15
+
16
+ // The payment's steps when `stage` of them are done. The next one is under way, or failed.
17
+ export function paymentSteps(stage: number, failed = false): PaymentStep[] {
18
+ return PAYMENT.map((step, index) => {
19
+ let status: StepStatus = 'upcoming';
20
+ if (index < stage) {
21
+ status = 'done';
22
+ } else if (index === stage) {
23
+ status = failed ? 'failed' : 'current';
24
+ }
25
+ return { ...step, status };
26
+ });
27
+ }
28
+
29
+ export default {
30
+ progress: 40,
31
+ busy: false,
32
+ loaded: false,
33
+ toast: '',
34
+ toastTone: 'default',
35
+ toastDuration: undefined as number | undefined,
36
+ tipShown: true,
37
+ // How many steps are done, and whether the next one failed, which ends the payment.
38
+ paymentStage: 0,
39
+ paymentFailed: false,
40
+ payment: paymentSteps(0),
41
+ };
@@ -0,0 +1,116 @@
1
+ <View>
2
+ <Text variant="title">Feedback</Text>
3
+ <Text>Show that something is loading, how far it has gone, and how it ended.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="subtitle">Spinner</Text>
7
+ <Text variant="caption" tone="muted">While something loads, in three sizes.</Text>
8
+ <View variant="card" direction="row" gap="large" align="center">
9
+ <Spinner size="small" />
10
+ <Spinner />
11
+ <Spinner size="large" />
12
+ </View>
13
+ </View>
14
+
15
+ <View gap="small">
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>
18
+ <View variant="card">
19
+ <If condition="{{ loaded }}">
20
+ <View direction="row" align="center" gap="large">
21
+ <Image src="statics/logo.png" alt="Logo" width="40" height="40" shape="circle" />
22
+ <View gap="none">
23
+ <Text weight="medium">Salone Sounds Radio</Text>
24
+ <Text variant="caption" tone="muted">The loaded content, in place of the skeleton</Text>
25
+ </View>
26
+ </View>
27
+ <Image src="statics/logo.png" alt="Banner" width="320" height="80" fit="contain" />
28
+ </If>
29
+ <Else>
30
+ <View direction="row" align="center" gap="large">
31
+ <Skeleton shape="circle" />
32
+ <Skeleton shape="text" lines="2" />
33
+ </View>
34
+ <Skeleton shape="box" height="80" />
35
+ </Else>
36
+ <Switch label="Loaded" checked="{{ loaded }}" onChange="toggleLoaded" />
37
+ </View>
38
+ </View>
39
+
40
+ <View gap="small">
41
+ <Text variant="subtitle">Toast</Text>
42
+ <Text variant="caption" tone="muted">A short message over the page that goes on its own. The offline one stays for 6 seconds.</Text>
43
+ <View direction="row" wrap gap="small">
44
+ <Button variant="secondary" data-message="Added to your library" data-tone="success" onClick="showToast">Add a song</Button>
45
+ <Button variant="secondary" data-message="You're offline. Only downloads will play." data-tone="warning" data-duration="6000" onClick="showToast">Go offline</Button>
46
+ <Button variant="secondary" data-message="A new song from Boii" data-tone="info" onClick="showToast">New song</Button>
47
+ <Button variant="secondary" data-message="That song can't play here" data-tone="danger" onClick="showToast">Fail</Button>
48
+ </View>
49
+ </View>
50
+
51
+ <View gap="small">
52
+ <Text variant="subtitle">ProgressBar</Text>
53
+ <Text variant="caption" tone="muted">How far something has gone, from 0 to 100, such as an album download.</Text>
54
+ <View variant="card">
55
+ <ProgressBar value="{{ progress }}" />
56
+ <Text>{{ progress }}% downloaded</Text>
57
+ <View direction="row" gap="small">
58
+ <Button variant="secondary" onClick="advance" disabled="{{ progress >= 100 }}">Advance</Button>
59
+ <Button variant="secondary" onClick="restart" disabled="{{ progress === 0 }}">Restart</Button>
60
+ </View>
61
+ </View>
62
+ </View>
63
+
64
+ <View gap="small">
65
+ <Text variant="subtitle">A busy Button</Text>
66
+ <Text variant="caption" tone="muted">loading shows a spinner, and the button ignores taps.</Text>
67
+ <View variant="card">
68
+ <Button loading="{{ busy }}">{{ busy ? 'Paying…' : 'Pay Le 300 for two tickets' }}</Button>
69
+ <Switch label="Busy" checked="{{ busy }}" onChange="toggleBusy" />
70
+ </View>
71
+ </View>
72
+
73
+ <View gap="small">
74
+ <Text variant="subtitle">Notice</Text>
75
+ <Text variant="caption" tone="muted">A message that stays in the page, in a tone. With onClose it shows a close button, and the page hides it.</Text>
76
+ <If condition="{{ tipShown }}">
77
+ <Notice tone="info" title="Tip" onClose="hideTip">Hold a song to add it to a playlist.</Notice>
78
+ </If>
79
+ <Notice title="Heads up">Doors open at 7 pm, and the music starts at 8.</Notice>
80
+ <Notice tone="info" title="New">Tickets for gospel night in Kenema are on sale.</Notice>
81
+ <Notice tone="success" title="Booked">Two tickets for Salone Sounds Live.</Notice>
82
+ <Notice tone="warning" title="Almost sold out">Twelve VIP tickets are left.</Notice>
83
+ <Notice tone="danger" title="Payment failed">The bank didn't answer. Try again.</Notice>
84
+ </View>
85
+
86
+ <View gap="small">
87
+ <Text variant="subtitle">Steps</Text>
88
+ <Text variant="caption" tone="muted">What happened and what comes next, such as a payment's progress. Each Step is done, current, upcoming or failed.</Text>
89
+ <View variant="card">
90
+ <Steps>
91
+ <For each="{{ payment }}" item="step" key="title">
92
+ <Step title="{{ step.title }}" text="{{ step.text }}" status="{{ step.status }}" />
93
+ </For>
94
+ </Steps>
95
+ <View direction="row" gap="small">
96
+ <Button variant="secondary" onClick="advancePayment" disabled="{{ paymentFailed || paymentStage === payment.length }}">Next step</Button>
97
+ <Button variant="secondary" onClick="failPayment" disabled="{{ paymentFailed || paymentStage === payment.length }}">Fail it</Button>
98
+ <Button variant="secondary" onClick="restartPayment" disabled="{{ paymentStage === 0 }}">Start over</Button>
99
+ </View>
100
+ </View>
101
+ </View>
102
+
103
+ <View gap="small">
104
+ <Text variant="subtitle">Badge</Text>
105
+ <Text variant="caption" tone="muted">A short status.</Text>
106
+ <View direction="row" wrap gap="small">
107
+ <Badge>Demo</Badge>
108
+ <Badge tone="info">New release</Badge>
109
+ <Badge tone="success">Booked</Badge>
110
+ <Badge tone="warning">Few left</Badge>
111
+ <Badge tone="danger">Sold out</Badge>
112
+ </View>
113
+ </View>
114
+
115
+ <Toast message="{{ toast }}" tone="{{ toastTone }}" duration="{{ toastDuration }}" onHide="clearToast" />
116
+ </View>
@@ -0,0 +1,72 @@
1
+ import { errorMessage } from '@monimesl/dot-runtime';
2
+
3
+ import type { TicketType } from './state';
4
+ import state, { SHOWS, TICKETS } from './state';
5
+
6
+ // 2 tickets of a Le 1,200 type -> "Le 2,400"
7
+ function total(tickets: number, ticket: TicketType): string {
8
+ const leones = tickets * TICKETS[ticket].price;
9
+ return `Le ${leones.toLocaleString('en-US')}`;
10
+ }
11
+
12
+ export default definePage({
13
+ initialState: state,
14
+ configs: { navigationBar: { title: 'Forms' } },
15
+ mutations: {
16
+ setShow: (_state, event: ValueEvent) => ({
17
+ show: event.detail.value,
18
+ showName: SHOWS[event.detail.value] ?? 'Not chosen yet',
19
+ }),
20
+ setName: (_state, event: ValueEvent) => ({ name: event.detail.value }),
21
+ setEmail: (_state, event: ValueEvent) => ({ email: event.detail.value }),
22
+ setPhone: (_state, event: ValueEvent) => ({ phone: event.detail.value }),
23
+ setTickets: (state, event: ValueEvent<number>) => ({
24
+ tickets: event.detail.value,
25
+ total: total(event.detail.value, state.ticket),
26
+ }),
27
+ setShoutOut: (_state, event: ValueEvent) => ({ shoutOut: event.detail.value }),
28
+ setPromo: (_state, event: ValueEvent) => ({ promo: event.detail.value }),
29
+ setChairs: (_state, event: ValueEvent<number>) => ({ chairs: event.detail.value }),
30
+ setTip: (_state, event: ValueEvent<number>) => ({ tip: event.detail.value }),
31
+ setTicket: (state, event: ValueEvent<TicketType>) => ({
32
+ ticket: event.detail.value,
33
+ ticketName: TICKETS[event.detail.value].name,
34
+ total: total(state.tickets, event.detail.value),
35
+ }),
36
+ setETickets: (_state, event: CheckedEvent) => ({ eTickets: event.detail.checked }),
37
+ setAgreed: (_state, event: CheckedEvent) => ({ agreed: event.detail.checked }),
38
+ },
39
+ actions: {
40
+ async send(state) {
41
+ const count = state.tickets;
42
+ const errors = {
43
+ show: state.show ? '' : 'Choose a show',
44
+ phone: state.phone.length < 8 ? 'Enter a phone number, such as 76 123456' : '',
45
+ shoutOut: state.shoutOut.includes('http')
46
+ ? 'Links are not read out. Write words only.'
47
+ : '',
48
+ };
49
+ this.setState({ errors, sent: '', failure: '' });
50
+ if (Object.values(errors).some(Boolean)) {
51
+ return;
52
+ }
53
+ this.setState({ sending: true });
54
+ try {
55
+ const { show, name, email, phone, shoutOut, ticket, eTickets } = state;
56
+ await this.dash.network.http.request({
57
+ url: 'https://httpbin.org/post',
58
+ method: 'POST',
59
+ body: { show, name, email, phone, tickets: count, shoutOut, ticket, eTickets },
60
+ });
61
+ this.setState({
62
+ sent: `${count} ${count === 1 ? 'ticket' : 'tickets'}, sent to +232 ${phone}`,
63
+ });
64
+ } catch (error) {
65
+ this.setState({ failure: errorMessage(error) });
66
+ } finally {
67
+ // However the request ends, the button stops spinning and takes taps again.
68
+ this.setState({ sending: false });
69
+ }
70
+ },
71
+ },
72
+ });
@@ -0,0 +1,37 @@
1
+ export type TicketType = 'regular' | 'vip' | 'table';
2
+
3
+ // The made-up shows on sale, and the price of each ticket, in leones.
4
+ export const SHOWS: Record<string, string> = {
5
+ freetown: 'Salone Sounds Live · Freetown',
6
+ bo: 'Palm-wine evening · Bo',
7
+ kenema: 'Gospel night · Kenema',
8
+ };
9
+
10
+ export const TICKETS: Record<TicketType, { name: string; price: number }> = {
11
+ regular: { name: 'Regular', price: 150 },
12
+ vip: { name: 'VIP, near the stage', price: 400 },
13
+ table: { name: 'Table for four', price: 1200 },
14
+ };
15
+
16
+ export default {
17
+ show: '',
18
+ // The order, as the summary shows it.
19
+ showName: 'Not chosen yet',
20
+ ticketName: TICKETS.regular.name,
21
+ total: `Le ${2 * TICKETS.regular.price}`,
22
+ name: '',
23
+ email: '',
24
+ phone: '',
25
+ tickets: 2,
26
+ promo: '',
27
+ chairs: 2,
28
+ tip: 20,
29
+ shoutOut: '',
30
+ ticket: 'regular' as TicketType,
31
+ eTickets: true,
32
+ agreed: false,
33
+ errors: { show: '', phone: '', shoutOut: '' },
34
+ sending: false,
35
+ sent: '',
36
+ failure: '',
37
+ };
@@ -0,0 +1,97 @@
1
+ <View>
2
+ <Text variant="title">Forms</Text>
3
+ <Text>Buy tickets for a show. Each field sends onChange as you use it, and the page keeps its value in state. The page checks the form when you send it.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="subtitle">Select</Text>
7
+ <View variant="card">
8
+ <Select label="Show" placeholder="Choose a show" hint="Every show has the same prices" value="{{ show }}" error="{{ errors.show }}" disabled="{{ sending }}" onChange="setShow">
9
+ <Option value="freetown" label="Salone Sounds Live · Freetown" />
10
+ <Option value="bo" label="Palm-wine evening · Bo" />
11
+ <Option value="kenema" label="Gospel night · Kenema" />
12
+ </Select>
13
+ </View>
14
+ </View>
15
+
16
+ <View gap="small">
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>
19
+ <View variant="card">
20
+ <Input label="Name" placeholder="Mariama Kamara" value="{{ name }}" maxLength="40" onChange="setName" />
21
+ <Input label="Email" type="email" placeholder="mariama@example.com" hint="{{ eTickets ? 'For the e-tickets' : 'Turn on e-tickets below to use it' }}" value="{{ email }}" disabled="{{ !eTickets }}" onChange="setEmail" />
22
+ <Input label="Phone" type="phone" prefix="+232" placeholder="76 123456" value="{{ phone }}" error="{{ errors.phone }}" onChange="setPhone" />
23
+ <Input label="Promo code" type="password" placeholder="Hidden as you type" value="{{ promo }}" onChange="setPromo" onSubmit="send" />
24
+ </View>
25
+ </View>
26
+
27
+ <View gap="small">
28
+ <Text variant="subtitle">Stepper</Text>
29
+ <Text variant="caption" tone="muted">A count changed one at a time. min and max keep it in range, so there's nothing to check.</Text>
30
+ <View variant="card">
31
+ <Stepper label="Tickets" min="1" max="10" hint="At most 10 for each person" value="{{ tickets }}" onChange="setTickets" />
32
+ </View>
33
+ </View>
34
+
35
+ <View gap="small">
36
+ <Text variant="subtitle">RadioGroup and Radio</Text>
37
+ <Text variant="caption" tone="muted">One choice from a few. A Radio, or the whole group, can be disabled.</Text>
38
+ <View variant="card">
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" />
43
+ <Radio value="backstage" label="Backstage · sold out" disabled />
44
+ </RadioGroup>
45
+ </View>
46
+ </View>
47
+
48
+ <View gap="small">
49
+ <Text variant="subtitle">TextArea</Text>
50
+ <View variant="card">
51
+ <TextArea label="Shout-out" placeholder="A message for the band, read out on the night" rows="3" maxLength="140" hint="{{ ticket === 'regular' ? 'Shout-outs come with VIP and table tickets' : shoutOut.length + ' of 140' }}" value="{{ shoutOut }}" error="{{ errors.shoutOut }}" disabled="{{ ticket === 'regular' }}" onChange="setShoutOut" />
52
+ </View>
53
+ </View>
54
+
55
+ <View gap="small">
56
+ <Text variant="subtitle">Slider</Text>
57
+ <Text variant="caption" tone="muted">A number between min and max, in steps. showValue shows it beside the label.</Text>
58
+ <View variant="card">
59
+ <Slider label="Chairs near the stage" min="0" max="10" showValue value="{{ chairs }}" disabled="{{ ticket === 'regular' }}" hint="{{ ticket === 'regular' ? 'Chairs come with VIP and table tickets' : '' }}" onChange="setChairs" />
60
+ <Slider label="Tip for the band, in leones" min="0" max="100" step="10" showValue value="{{ tip }}" onChange="setTip" />
61
+ </View>
62
+ </View>
63
+
64
+ <View gap="small">
65
+ <Text variant="subtitle">Switch and Checkbox</Text>
66
+ <View variant="card">
67
+ <Switch label="Email me the e-tickets" checked="{{ eTickets }}" onChange="setETickets" />
68
+ <Switch label="Text me on the night" disabled />
69
+ <Checkbox label="I agree to the terms" checked="{{ agreed }}" onChange="setAgreed" />
70
+ <Checkbox label="I'm over 18" checked disabled />
71
+ </View>
72
+ </View>
73
+
74
+ <View gap="small">
75
+ <Text variant="subtitle">Your order</Text>
76
+ <View variant="card" gap="none">
77
+ <DetailRow label="Show" value="{{ showName }}" />
78
+ <DetailRow label="Ticket" value="{{ ticketName }}" />
79
+ <DetailRow label="How many" value="{{ tickets }}" />
80
+ <Divider />
81
+ <DetailRow label="Total" value="{{ total }}" weight="bold" paddingTop="medium" />
82
+ <DetailRow label="Paid" value="{{ sent ? 'Yes' : 'Not yet' }}" tone="{{ sent ? 'success' : 'warning' }}" />
83
+ </View>
84
+ </View>
85
+
86
+ <If condition="{{ sent }}">
87
+ <Notice tone="success" title="Booked">{{ sent }}</Notice>
88
+ </If>
89
+ <If condition="{{ failure }}">
90
+ <Notice tone="danger" title="Not booked">{{ failure }}</Notice>
91
+ </If>
92
+
93
+ <Text variant="caption" tone="muted">A Footer keeps its buttons at the bottom of the screen.</Text>
94
+ <Footer>
95
+ <Button onClick="send" loading="{{ sending }}" disabled="{{ !agreed }}">Buy tickets</Button>
96
+ </Footer>
97
+ </View>
@@ -0,0 +1,15 @@
1
+ import state from './state';
2
+
3
+ export default definePage({
4
+ initialState: state,
5
+ configs: { navigationBar: { title: 'Icons' } },
6
+ mutations: {
7
+ clearToast: () => ({ toast: '' }),
8
+ },
9
+ actions: {
10
+ async copyName(_state, event: DataEvent<{ name: string }>) {
11
+ await this.dash.system.copyText(event.data.name);
12
+ this.setState({ toast: `Copied "${event.data.name}"` });
13
+ },
14
+ },
15
+ });
@@ -0,0 +1,75 @@
1
+ export default {
2
+ // Every icon name, as Icon's name, and ListItem's, Chip's, GridItem's and EmptyState's icon take.
3
+ names: [
4
+ 'arrow-down',
5
+ 'arrow-left',
6
+ 'arrow-right',
7
+ 'arrow-up',
8
+ 'bank',
9
+ 'bell',
10
+ 'bolt',
11
+ 'calendar',
12
+ 'card',
13
+ 'cart',
14
+ 'cash',
15
+ 'check',
16
+ 'chevron-down',
17
+ 'chevron-left',
18
+ 'chevron-right',
19
+ 'chevron-up',
20
+ 'clock',
21
+ 'close',
22
+ 'copy',
23
+ 'download',
24
+ 'edit',
25
+ 'error',
26
+ 'external-link',
27
+ 'eye',
28
+ 'eye-off',
29
+ 'file',
30
+ 'gift',
31
+ 'globe',
32
+ 'grid',
33
+ 'headphones',
34
+ 'heart',
35
+ 'help',
36
+ 'history',
37
+ 'home',
38
+ 'image',
39
+ 'info',
40
+ 'link',
41
+ 'list',
42
+ 'location',
43
+ 'lock',
44
+ 'logout',
45
+ 'mail',
46
+ 'microphone',
47
+ 'minus',
48
+ 'mobile',
49
+ 'more',
50
+ 'music',
51
+ 'phone',
52
+ 'playlist',
53
+ 'plus',
54
+ 'qr-code',
55
+ 'receipt',
56
+ 'refresh',
57
+ 'search',
58
+ 'send',
59
+ 'settings',
60
+ 'share',
61
+ 'star',
62
+ 'success',
63
+ 'ticket',
64
+ 'trash',
65
+ 'upload',
66
+ 'user',
67
+ 'users',
68
+ 'video',
69
+ 'wallet',
70
+ 'warning',
71
+ 'water',
72
+ 'wifi',
73
+ ],
74
+ toast: '',
75
+ };
@@ -0,0 +1,36 @@
1
+ <View>
2
+ <Text variant="title">Icons</Text>
3
+ <Text>Icon shows a small picture by its name. Lists, chips, grids and empty states take the same names.</Text>
4
+
5
+ <View gap="small">
6
+ <Text variant="subtitle">size and tone</Text>
7
+ <View variant="card" direction="row" wrap gap="large" align="center">
8
+ <Icon name="music" size="small" />
9
+ <Icon name="music" size="medium" />
10
+ <Icon name="music" size="large" />
11
+ <Icon name="info" tone="info" />
12
+ <Icon name="success" tone="success" />
13
+ <Icon name="warning" tone="warning" />
14
+ <Icon name="error" tone="danger" />
15
+ <Icon name="star" tone="muted" />
16
+ <Icon name="heart" tone="default" />
17
+ </View>
18
+ </View>
19
+
20
+ <View gap="small">
21
+ <Text variant="subtitle">Every name</Text>
22
+ <Text variant="caption" tone="muted">Tap one to copy its name.</Text>
23
+ <View variant="card">
24
+ <Grid columns="3" gap="medium">
25
+ <For each="{{ names }}" item="name" key="*this">
26
+ <View align="center" gap="small" padding="small" data-name="{{ name }}" onTap="copyName">
27
+ <Icon name="{{ name }}" />
28
+ <Text variant="caption" tone="muted" align="center">{{ name }}</Text>
29
+ </View>
30
+ </For>
31
+ </Grid>
32
+ </View>
33
+ </View>
34
+
35
+ <Toast message="{{ toast }}" tone="success" onHide="clearToast" />
36
+ </View>