create-foldkit-app 0.32.0 → 0.32.1

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 (149) hide show
  1. package/dist/commands/create.js +9 -7
  2. package/dist/templates/base/FOLDKIT.md +22 -6
  3. package/dist/templates/examples/api-cache/src/data.ts +14 -14
  4. package/dist/templates/examples/api-cache/src/main.ts +42 -39
  5. package/dist/templates/examples/auth/src/command.ts +3 -3
  6. package/dist/templates/examples/auth/src/domain/session.ts +8 -6
  7. package/dist/templates/examples/auth/src/main.ts +11 -11
  8. package/dist/templates/examples/auth/src/message.ts +3 -3
  9. package/dist/templates/examples/auth/src/model.ts +2 -2
  10. package/dist/templates/examples/auth/src/page/loggedIn/index.ts +1 -1
  11. package/dist/templates/examples/auth/src/page/loggedIn/view.ts +3 -3
  12. package/dist/templates/examples/auth/src/page/loggedOut/index.ts +1 -1
  13. package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +9 -17
  14. package/dist/templates/examples/auth/src/page/loggedOut/update.ts +4 -6
  15. package/dist/templates/examples/auth/src/page/loggedOut/view.ts +3 -3
  16. package/dist/templates/examples/auth/src/route.ts +2 -2
  17. package/dist/templates/examples/auth/src/update.ts +37 -40
  18. package/dist/templates/examples/auth/src/view.ts +6 -6
  19. package/dist/templates/examples/canvas-art/src/main.ts +22 -30
  20. package/dist/templates/examples/charting/src/command.ts +3 -3
  21. package/dist/templates/examples/charting/src/domain.ts +53 -48
  22. package/dist/templates/examples/charting/src/echarts.ts +6 -6
  23. package/dist/templates/examples/charting/src/githubApi.ts +33 -34
  24. package/dist/templates/examples/charting/src/http.ts +7 -7
  25. package/dist/templates/examples/charting/src/message.ts +6 -6
  26. package/dist/templates/examples/charting/src/model.ts +6 -6
  27. package/dist/templates/examples/charting/src/npmApi.ts +19 -15
  28. package/dist/templates/examples/charting/src/subscription.ts +5 -5
  29. package/dist/templates/examples/charting/src/telemetry.test.ts +18 -12
  30. package/dist/templates/examples/charting/src/telemetry.ts +11 -18
  31. package/dist/templates/examples/charting/src/update.ts +17 -23
  32. package/dist/templates/examples/charting/src/view/chart.ts +2 -2
  33. package/dist/templates/examples/counter/src/main.ts +2 -2
  34. package/dist/templates/examples/counters/src/counter.ts +2 -2
  35. package/dist/templates/examples/counters/src/main.ts +8 -8
  36. package/dist/templates/examples/embedding/src/main.ts +10 -7
  37. package/dist/templates/examples/form/src/main.ts +18 -14
  38. package/dist/templates/examples/generative-art/src/command.ts +7 -2
  39. package/dist/templates/examples/generative-art/src/message.ts +14 -14
  40. package/dist/templates/examples/generative-art/src/model.ts +21 -21
  41. package/dist/templates/examples/generative-art/src/update.ts +15 -17
  42. package/dist/templates/examples/interrupting-commands/src/main.ts +30 -27
  43. package/dist/templates/examples/job-application/src/domain/proficiencyLevel.ts +2 -2
  44. package/dist/templates/examples/job-application/src/domain/pronounOption.ts +2 -2
  45. package/dist/templates/examples/job-application/src/domain/step.ts +11 -11
  46. package/dist/templates/examples/job-application/src/main.ts +5 -5
  47. package/dist/templates/examples/job-application/src/message.ts +2 -2
  48. package/dist/templates/examples/job-application/src/model.ts +5 -5
  49. package/dist/templates/examples/job-application/src/step/attachments.ts +32 -34
  50. package/dist/templates/examples/job-application/src/step/coverLetter.ts +4 -4
  51. package/dist/templates/examples/job-application/src/step/education/education.ts +11 -14
  52. package/dist/templates/examples/job-application/src/step/education/entry.ts +21 -22
  53. package/dist/templates/examples/job-application/src/step/personalInfo.ts +44 -54
  54. package/dist/templates/examples/job-application/src/step/skills/entry.ts +12 -14
  55. package/dist/templates/examples/job-application/src/step/skills/skills.ts +11 -14
  56. package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +43 -45
  57. package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +11 -14
  58. package/dist/templates/examples/job-application/src/update.ts +17 -17
  59. package/dist/templates/examples/job-application/src/view/attachments.ts +5 -5
  60. package/dist/templates/examples/job-application/src/view/datePicker.ts +3 -3
  61. package/dist/templates/examples/job-application/src/view/field.ts +5 -5
  62. package/dist/templates/examples/job-application/src/view/index.ts +28 -22
  63. package/dist/templates/examples/kanban/src/command.ts +4 -4
  64. package/dist/templates/examples/kanban/src/domain/card.ts +6 -6
  65. package/dist/templates/examples/kanban/src/domain/column.ts +9 -9
  66. package/dist/templates/examples/kanban/src/main.ts +4 -4
  67. package/dist/templates/examples/kanban/src/message.ts +6 -6
  68. package/dist/templates/examples/kanban/src/model.ts +11 -9
  69. package/dist/templates/examples/kanban/src/update.ts +5 -5
  70. package/dist/templates/examples/managed-resource-layer/src/main.ts +20 -20
  71. package/dist/templates/examples/map/src/locations.ts +7 -7
  72. package/dist/templates/examples/map/src/main.ts +83 -44
  73. package/dist/templates/examples/map/src/mount.test.ts +127 -0
  74. package/dist/templates/examples/pixel-art/src/command.ts +12 -5
  75. package/dist/templates/examples/pixel-art/src/main.ts +4 -4
  76. package/dist/templates/examples/pixel-art/src/message.ts +7 -7
  77. package/dist/templates/examples/pixel-art/src/model.ts +34 -29
  78. package/dist/templates/examples/pixel-art/src/subscription.ts +2 -2
  79. package/dist/templates/examples/pixel-art/src/update.ts +79 -86
  80. package/dist/templates/examples/query-sync/src/main.ts +106 -102
  81. package/dist/templates/examples/route-transitions/src/data.ts +6 -6
  82. package/dist/templates/examples/route-transitions/src/main.ts +23 -29
  83. package/dist/templates/examples/route-transitions/src/route.ts +3 -3
  84. package/dist/templates/examples/routing/src/fileTree.ts +10 -8
  85. package/dist/templates/examples/routing/src/main.ts +23 -21
  86. package/dist/templates/examples/routing/src/page/people.ts +14 -22
  87. package/dist/templates/examples/routing/src/route.ts +7 -7
  88. package/dist/templates/examples/shopping-cart/src/main.ts +30 -31
  89. package/dist/templates/examples/shopping-cart/src/page/products.ts +10 -10
  90. package/dist/templates/examples/shopping-cart/src/route.ts +6 -4
  91. package/dist/templates/examples/slow-warnings/src/main.ts +35 -43
  92. package/dist/templates/examples/snake/src/domain/snake.ts +2 -2
  93. package/dist/templates/examples/snake/src/main.ts +39 -47
  94. package/dist/templates/examples/ssg/src/main.ts +5 -5
  95. package/dist/templates/examples/ssg/src/route.ts +2 -2
  96. package/dist/templates/examples/ssr/src/cookie.ts +3 -3
  97. package/dist/templates/examples/ssr/src/main.ts +10 -10
  98. package/dist/templates/examples/state-machine/src/main.ts +55 -53
  99. package/dist/templates/examples/state-machine/src/view.ts +7 -7
  100. package/dist/templates/examples/stopwatch/src/main.ts +10 -10
  101. package/dist/templates/examples/todo/src/main.ts +41 -34
  102. package/dist/templates/examples/ui-showcase/src/main.ts +54 -42
  103. package/dist/templates/examples/ui-showcase/src/scene.test.ts +1 -1
  104. package/dist/templates/examples/ui-showcase/src/ui/init.ts +1 -2
  105. package/dist/templates/examples/ui-showcase/src/ui/message.ts +17 -18
  106. package/dist/templates/examples/ui-showcase/src/ui/model.ts +47 -44
  107. package/dist/templates/examples/ui-showcase/src/ui/subscriptions.ts +1 -1
  108. package/dist/templates/examples/ui-showcase/src/ui/toast.ts +4 -4
  109. package/dist/templates/examples/ui-showcase/src/ui/update.ts +287 -298
  110. package/dist/templates/examples/ui-showcase/src/ui/view/animation.ts +2 -2
  111. package/dist/templates/examples/ui-showcase/src/ui/view/button.ts +1 -1
  112. package/dist/templates/examples/ui-showcase/src/ui/view/calendar.ts +4 -4
  113. package/dist/templates/examples/ui-showcase/src/ui/view/checkbox.ts +1 -1
  114. package/dist/templates/examples/ui-showcase/src/ui/view/combobox.ts +1 -1
  115. package/dist/templates/examples/ui-showcase/src/ui/view/datePicker.ts +4 -4
  116. package/dist/templates/examples/ui-showcase/src/ui/view/dialog.ts +1 -1
  117. package/dist/templates/examples/ui-showcase/src/ui/view/disclosure.ts +1 -1
  118. package/dist/templates/examples/ui-showcase/src/ui/view/dragAndDrop.ts +1 -1
  119. package/dist/templates/examples/ui-showcase/src/ui/view/fieldset.ts +1 -1
  120. package/dist/templates/examples/ui-showcase/src/ui/view/fileDrop.ts +6 -6
  121. package/dist/templates/examples/ui-showcase/src/ui/view/hoverIntent.ts +9 -20
  122. package/dist/templates/examples/ui-showcase/src/ui/view/input.ts +1 -1
  123. package/dist/templates/examples/ui-showcase/src/ui/view/listbox.ts +1 -1
  124. package/dist/templates/examples/ui-showcase/src/ui/view/menu.ts +15 -15
  125. package/dist/templates/examples/ui-showcase/src/ui/view/popover.ts +1 -1
  126. package/dist/templates/examples/ui-showcase/src/ui/view/radioGroup.ts +1 -1
  127. package/dist/templates/examples/ui-showcase/src/ui/view/select.ts +1 -1
  128. package/dist/templates/examples/ui-showcase/src/ui/view/slider.ts +1 -1
  129. package/dist/templates/examples/ui-showcase/src/ui/view/switch.ts +1 -1
  130. package/dist/templates/examples/ui-showcase/src/ui/view/tabs.ts +7 -7
  131. package/dist/templates/examples/ui-showcase/src/ui/view/textarea.ts +1 -1
  132. package/dist/templates/examples/ui-showcase/src/ui/view/toast.ts +8 -8
  133. package/dist/templates/examples/ui-showcase/src/ui/view/tooltip.ts +1 -1
  134. package/dist/templates/examples/ui-showcase/src/ui/view/virtualList.ts +7 -7
  135. package/dist/templates/examples/view-transitions/src/artwork.ts +7 -7
  136. package/dist/templates/examples/view-transitions/src/main.ts +6 -6
  137. package/dist/templates/examples/view-transitions/src/route.ts +3 -3
  138. package/dist/templates/examples/weather/src/main.ts +42 -42
  139. package/dist/templates/examples/weather/src/story.test.ts +5 -5
  140. package/dist/templates/examples/web-components/src/main.ts +16 -16
  141. package/dist/templates/examples/websocket-chat/src/main.ts +30 -30
  142. package/dist/templates/release.json +13 -13
  143. package/dist/templates/rendering/ssg/src/main.ts +5 -5
  144. package/dist/templates/rendering/ssg/src/route.ts +2 -2
  145. package/dist/templates/rendering/ssr/server/main.ts +15 -15
  146. package/dist/templates/rendering/ssr/src/cookie.ts +3 -3
  147. package/dist/templates/rendering/ssr/src/main.ts +10 -10
  148. package/dist/utils/packages.js +17 -0
  149. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import clsx from 'clsx'
2
- import { Array, Equal, HashSet, Match as M, Option, pipe } from 'effect'
2
+ import { Array, Equal, HashSet, Match, Option, pipe } from 'effect'
3
3
  import type { ChildAttribute, Document, Html, HtmlBuilder } from 'foldkit/html'
4
4
 
5
5
  import { Button, Tabs } from '@foldkit/ui'
@@ -23,23 +23,29 @@ const StepTabs = Tabs.create<Step.Step>()
23
23
  const stepHasErrors =
24
24
  (model: Model) =>
25
25
  (step: Step.Step): boolean =>
26
- M.value(step).pipe(
27
- M.when('PersonalInfo', () => PersonalInfo.hasErrors(model.personalInfo)),
28
- M.when('WorkHistory', () => WorkHistory.hasErrors(model.workHistory)),
29
- M.when('Education', () => Education.hasErrors(model.education)),
30
- M.when('Skills', () => Skills.hasErrors(model.skills)),
31
- M.orElse(() => false),
26
+ Match.value(step).pipe(
27
+ Match.when('PersonalInfo', () =>
28
+ PersonalInfo.hasErrors(model.personalInfo),
29
+ ),
30
+ Match.when('WorkHistory', () => WorkHistory.hasErrors(model.workHistory)),
31
+ Match.when('Education', () => Education.hasErrors(model.education)),
32
+ Match.when('Skills', () => Skills.hasErrors(model.skills)),
33
+ Match.orElse(() => false),
32
34
  )
33
35
 
34
36
  const stepIsComplete =
35
37
  (model: Model) =>
36
38
  (step: Step.Step): boolean =>
37
- M.value(step).pipe(
38
- M.when('PersonalInfo', () => PersonalInfo.isComplete(model.personalInfo)),
39
- M.when('WorkHistory', () => WorkHistory.isComplete(model.workHistory)),
40
- M.when('Education', () => Education.isComplete(model.education)),
41
- M.when('Skills', () => Skills.isComplete(model.skills)),
42
- M.orElse(() => true),
39
+ Match.value(step).pipe(
40
+ Match.when('PersonalInfo', () =>
41
+ PersonalInfo.isComplete(model.personalInfo),
42
+ ),
43
+ Match.when('WorkHistory', () =>
44
+ WorkHistory.isComplete(model.workHistory),
45
+ ),
46
+ Match.when('Education', () => Education.isComplete(model.education)),
47
+ Match.when('Skills', () => Skills.isComplete(model.skills)),
48
+ Match.orElse(() => true),
43
49
  )
44
50
 
45
51
  const stepNeedsAttention =
@@ -56,8 +62,8 @@ const stepContent = (
56
62
  attentionSteps: ReadonlyArray<Step.Step>,
57
63
  h: HtmlBuilder<Message>,
58
64
  ): Html =>
59
- M.value(model.currentStep).pipe(
60
- M.when('PersonalInfo', () =>
65
+ Match.value(model.currentStep).pipe(
66
+ Match.when('PersonalInfo', () =>
61
67
  h.submodel({
62
68
  slotId: 'personal-info',
63
69
  model: model.personalInfo,
@@ -65,7 +71,7 @@ const stepContent = (
65
71
  toParentMessage: message => Message.GotPersonalInfoMessage({ message }),
66
72
  }),
67
73
  ),
68
- M.when('WorkHistory', () =>
74
+ Match.when('WorkHistory', () =>
69
75
  h.submodel({
70
76
  slotId: 'work-history',
71
77
  model: model.workHistory,
@@ -73,7 +79,7 @@ const stepContent = (
73
79
  toParentMessage: message => Message.GotWorkHistoryMessage({ message }),
74
80
  }),
75
81
  ),
76
- M.when('Education', () =>
82
+ Match.when('Education', () =>
77
83
  h.submodel({
78
84
  slotId: 'education',
79
85
  model: model.education,
@@ -81,7 +87,7 @@ const stepContent = (
81
87
  toParentMessage: message => Message.GotEducationMessage({ message }),
82
88
  }),
83
89
  ),
84
- M.when('Skills', () =>
90
+ Match.when('Skills', () =>
85
91
  h.submodel({
86
92
  slotId: 'skills',
87
93
  model: model.skills,
@@ -89,7 +95,7 @@ const stepContent = (
89
95
  toParentMessage: message => Message.GotSkillsMessage({ message }),
90
96
  }),
91
97
  ),
92
- M.when('CoverLetter', () =>
98
+ Match.when('CoverLetter', () =>
93
99
  h.submodel({
94
100
  slotId: 'cover-letter',
95
101
  model: model.coverLetter,
@@ -97,7 +103,7 @@ const stepContent = (
97
103
  toParentMessage: message => Message.GotCoverLetterMessage({ message }),
98
104
  }),
99
105
  ),
100
- M.when('Attachments', () =>
106
+ Match.when('Attachments', () =>
101
107
  h.submodel({
102
108
  slotId: 'attachments',
103
109
  model: model.attachments,
@@ -105,8 +111,8 @@ const stepContent = (
105
111
  toParentMessage: message => Message.GotAttachmentsMessage({ message }),
106
112
  }),
107
113
  ),
108
- M.when('Review', () => review(model, attentionSteps, h)),
109
- M.exhaustive,
114
+ Match.when('Review', () => review(model, attentionSteps, h)),
115
+ Match.exhaustive,
110
116
  )
111
117
 
112
118
  const isFirstStep = (model: Model): boolean =>
@@ -1,4 +1,4 @@
1
- import { Crypto, Effect, Schema as S } from 'effect'
1
+ import { Crypto, Effect, Schema } from 'effect'
2
2
  import { KeyValueStore } from 'effect/unstable/persistence'
3
3
  import { Command, Dom } from 'foldkit'
4
4
 
@@ -10,7 +10,7 @@ import { Message } from './message'
10
10
  import { SavedBoardJsonString } from './model'
11
11
 
12
12
  export const GenerateCardId = Command.define('GenerateCardId', {
13
- args: { columnId: S.String, title: S.String },
13
+ args: { columnId: Schema.String, title: Schema.String },
14
14
  messages: [Message.CompletedGenerateCardId],
15
15
  execute: ({ columnId, title }) =>
16
16
  Effect.gen(function* () {
@@ -21,14 +21,14 @@ export const GenerateCardId = Command.define('GenerateCardId', {
21
21
  })
22
22
 
23
23
  export const SaveBoard = Command.define('SaveBoard', {
24
- args: { columns: S.Array(Column.Column) },
24
+ args: { columns: Schema.Array(Column.Column) },
25
25
  messages: [Message.CompletedSaveBoard],
26
26
  execute: ({ columns }) =>
27
27
  Effect.gen(function* () {
28
28
  const store = yield* KeyValueStore.KeyValueStore
29
29
  yield* store.set(
30
30
  STORAGE_KEY,
31
- S.encodeSync(SavedBoardJsonString)({ columns }),
31
+ Schema.encodeSync(SavedBoardJsonString)({ columns }),
32
32
  )
33
33
  return Message.CompletedSaveBoard()
34
34
  }).pipe(
@@ -1,10 +1,10 @@
1
- import { Schema as S } from 'effect'
1
+ import { Schema } from 'effect'
2
2
 
3
- export const Card = S.Struct({
4
- id: S.String,
5
- title: S.String,
6
- description: S.String,
7
- sortKey: S.String,
3
+ export const Card = Schema.Struct({
4
+ id: Schema.String,
5
+ title: Schema.String,
6
+ description: Schema.String,
7
+ sortKey: Schema.String,
8
8
  })
9
9
 
10
10
  export type Card = typeof Card.Type
@@ -1,14 +1,14 @@
1
- import { Array, Match as M, Option, Schema as S, pipe } from 'effect'
1
+ import { Array, Match, Option, Schema, pipe } from 'effect'
2
2
  import { evo } from 'foldkit/struct'
3
3
  import { generateKeyBetween } from 'fractional-indexing'
4
4
 
5
5
  import type { Card } from './card'
6
6
  import { Card as CardSchema } from './card'
7
7
 
8
- export const Column = S.Struct({
9
- id: S.String,
10
- name: S.String,
11
- cards: S.Array(CardSchema),
8
+ export const Column = Schema.Struct({
9
+ id: Schema.String,
10
+ name: Schema.String,
11
+ cards: Schema.Array(CardSchema),
12
12
  })
13
13
 
14
14
  export type Column = typeof Column.Type
@@ -105,10 +105,10 @@ export const reorder = (
105
105
  onNone: () => columns,
106
106
  onSome: card =>
107
107
  Array.map(columns, column =>
108
- M.value(column.id).pipe(
109
- M.when(fromContainerId, () => removeCard(column, itemId).column),
110
- M.when(toContainerId, () => insertCard(column, card, toIndex)),
111
- M.orElse(() => column),
108
+ Match.value(column.id).pipe(
109
+ Match.when(fromContainerId, () => removeCard(column, itemId).column),
110
+ Match.when(toContainerId, () => insertCard(column, card, toIndex)),
111
+ Match.orElse(() => column),
112
112
  ),
113
113
  ),
114
114
  })
@@ -1,4 +1,4 @@
1
- import { Effect, Option, Schema as S } from 'effect'
1
+ import { Effect, Option, Schema } from 'effect'
2
2
  import { KeyValueStore } from 'effect/unstable/persistence'
3
3
  import { Runtime } from 'foldkit'
4
4
 
@@ -14,8 +14,8 @@ import { view } from './view'
14
14
 
15
15
  // FLAGS
16
16
 
17
- export const Flags = S.Struct({
18
- maybeSavedBoard: S.Option(SavedBoard),
17
+ export const Flags = Schema.Struct({
18
+ maybeSavedBoard: Schema.Option(SavedBoard),
19
19
  })
20
20
  export type Flags = typeof Flags.Type
21
21
 
@@ -24,7 +24,7 @@ export const flags: Effect.Effect<Flags> = Effect.gen(function* () {
24
24
  const json = yield* Effect.fromOption(
25
25
  Option.fromNullishOr(yield* store.get(STORAGE_KEY)),
26
26
  )
27
- const decoded = yield* S.decodeEffect(SavedBoardJsonString)(json)
27
+ const decoded = yield* Schema.decodeEffect(SavedBoardJsonString)(json)
28
28
  return Flags.make({ maybeSavedBoard: Option.some(decoded) })
29
29
  }).pipe(
30
30
  Effect.catch(() =>
@@ -1,18 +1,18 @@
1
- import { Schema as S } from 'effect'
1
+ import { Schema } from 'effect'
2
2
  import { defineMessageUnion } from 'foldkit/message'
3
3
 
4
4
  import { DragAndDrop } from '@foldkit/ui'
5
5
 
6
6
  export const Message = defineMessageUnion({
7
7
  GotDragAndDropMessage: { message: DragAndDrop.Message },
8
- ClickedAddCard: { columnId: S.String },
9
- ChangedNewCardTitle: { value: S.String },
8
+ ClickedAddCard: { columnId: Schema.String },
9
+ ChangedNewCardTitle: { value: Schema.String },
10
10
  SubmittedNewCard: {},
11
11
  CancelledNewCard: {},
12
12
  CompletedGenerateCardId: {
13
- cardId: S.String,
14
- columnId: S.String,
15
- title: S.String,
13
+ cardId: Schema.String,
14
+ columnId: Schema.String,
15
+ title: Schema.String,
16
16
  },
17
17
  CompletedSaveBoard: {},
18
18
  CompletedFocusAddCardInput: {},
@@ -1,23 +1,25 @@
1
- import { Schema as S } from 'effect'
1
+ import { Schema } from 'effect'
2
2
 
3
3
  import { DragAndDrop } from '@foldkit/ui'
4
4
 
5
5
  import { Column } from './domain'
6
6
 
7
- export const SavedBoard = S.Struct({
8
- columns: S.Array(Column.Column),
7
+ export const SavedBoard = Schema.Struct({
8
+ columns: Schema.Array(Column.Column),
9
9
  })
10
10
 
11
11
  export type SavedBoard = typeof SavedBoard.Type
12
12
 
13
- export const SavedBoardJsonString = S.fromJsonString(S.toCodecJson(SavedBoard))
13
+ export const SavedBoardJsonString = Schema.fromJsonString(
14
+ Schema.toCodecJson(SavedBoard),
15
+ )
14
16
 
15
- export const Model = S.Struct({
16
- columns: S.Array(Column.Column),
17
+ export const Model = Schema.Struct({
18
+ columns: Schema.Array(Column.Column),
17
19
  dragAndDrop: DragAndDrop.Model,
18
- maybeNewCardColumnId: S.Option(S.String),
19
- newCardTitle: S.String,
20
- announcement: S.String,
20
+ maybeNewCardColumnId: Schema.Option(Schema.String),
21
+ newCardTitle: Schema.String,
22
+ announcement: Schema.String,
21
23
  })
22
24
 
23
25
  export type Model = typeof Model.Type
@@ -1,4 +1,4 @@
1
- import { Array, Match as M, Option, String, pipe } from 'effect'
1
+ import { Array, Match, Option, String, pipe } from 'effect'
2
2
  import { Update } from 'foldkit'
3
3
  import { evo } from 'foldkit/struct'
4
4
 
@@ -42,9 +42,9 @@ const announceKeyboardDrag = (
42
42
  model: Model,
43
43
  nextDragAndDrop: DragAndDrop.Model,
44
44
  ): string =>
45
- M.value(nextDragAndDrop.dragState).pipe(
46
- M.withReturnType<string>(),
47
- M.tag('KeyboardDragging', nextState => {
45
+ Match.value(nextDragAndDrop.dragState).pipe(
46
+ Match.withReturnType<string>(),
47
+ Match.tag('KeyboardDragging', nextState => {
48
48
  const wasIdle = model.dragAndDrop.dragState._tag === 'Idle'
49
49
  if (wasIdle) {
50
50
  const title = findCardTitle(model.columns, nextState.itemId)
@@ -70,7 +70,7 @@ const announceKeyboardDrag = (
70
70
 
71
71
  return model.announcement
72
72
  }),
73
- M.orElse(() => model.announcement),
73
+ Match.orElse(() => model.announcement),
74
74
  )
75
75
 
76
76
  const screenReaderTextForDrop = (
@@ -3,10 +3,10 @@ import {
3
3
  Crypto,
4
4
  Effect,
5
5
  Layer,
6
- Match as M,
6
+ Match,
7
7
  Number,
8
8
  Option,
9
- Schema as S,
9
+ Schema,
10
10
  } from 'effect'
11
11
  import { Command, ManagedResource, Runtime, type Update } from 'foldkit'
12
12
  import { Document, Html, HtmlBuilder } from 'foldkit/html'
@@ -50,15 +50,15 @@ type EngineService = ManagedResource.ServiceOf<typeof Engine>
50
50
  export const EngineState = defineTaggedUnion({
51
51
  Off: {},
52
52
  Booting: {},
53
- Ready: { engineId: S.String },
54
- Failed: { reason: S.String },
53
+ Ready: { engineId: Schema.String },
54
+ Failed: { reason: Schema.String },
55
55
  })
56
56
  type EngineState = typeof EngineState.Type
57
57
 
58
- export const Model = S.Struct({
58
+ export const Model = Schema.Struct({
59
59
  engine: EngineState,
60
- computeCount: S.Number,
61
- maybeSquareResult: S.Option(S.Number),
60
+ computeCount: Schema.Number,
61
+ maybeSquareResult: Schema.Option(Schema.Number),
62
62
  })
63
63
  export type Model = typeof Model.Type
64
64
 
@@ -67,11 +67,11 @@ export type Model = typeof Model.Type
67
67
  export const Message = defineMessageUnion({
68
68
  ClickedStartEngine: {},
69
69
  ClickedStopEngine: {},
70
- StartedEngine: { engineId: S.String },
70
+ StartedEngine: { engineId: Schema.String },
71
71
  StoppedEngine: {},
72
- FailedStartEngine: { reason: S.String },
72
+ FailedStartEngine: { reason: Schema.String },
73
73
  ClickedCompute: {},
74
- CompletedCompute: { result: S.Number },
74
+ CompletedCompute: { result: Schema.Number },
75
75
  SkippedCompute: {},
76
76
  })
77
77
 
@@ -80,7 +80,7 @@ export type Message = typeof Message.Type
80
80
  // COMMAND
81
81
 
82
82
  export const Compute = Command.define('Compute', {
83
- args: { value: S.Number },
83
+ args: { value: Schema.Number },
84
84
  messages: [Message.CompletedCompute, Message.SkippedCompute],
85
85
  execute: ({ value }) =>
86
86
  Effect.gen(function* () {
@@ -146,13 +146,13 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
146
146
 
147
147
  export const managedResources = ManagedResource.make<Model, Message>()(
148
148
  entry => ({
149
- engine: entry(S.Option(S.Null), {
149
+ engine: entry(Schema.Option(Schema.Null), {
150
150
  resource: Engine,
151
151
  modelToMaybeRequirements: model =>
152
- M.value(model.engine).pipe(
153
- M.tag('Booting', 'Ready', () => Option.some(null)),
154
- M.tag('Off', 'Failed', () => Option.none()),
155
- M.exhaustive,
152
+ Match.value(model.engine).pipe(
153
+ Match.tag('Booting', 'Ready', () => Option.some(null)),
154
+ Match.tag('Off', 'Failed', () => Option.none()),
155
+ Match.exhaustive,
156
156
  ),
157
157
  acquire: () =>
158
158
  Layer.build(engineLayer).pipe(
@@ -225,18 +225,18 @@ const engineControlsView = (
225
225
  engine: EngineState,
226
226
  h: HtmlBuilder<Message>,
227
227
  ): Html => {
228
- const controls = M.value(engine).pipe(
229
- M.tag('Booting', 'Ready', () => ({
228
+ const controls = Match.value(engine).pipe(
229
+ Match.tag('Booting', 'Ready', () => ({
230
230
  label: 'Stop engine',
231
231
  message: Message.ClickedStopEngine(),
232
232
  colorClassName: 'bg-red-500 hover:bg-red-600',
233
233
  })),
234
- M.tag('Off', 'Failed', () => ({
234
+ Match.tag('Off', 'Failed', () => ({
235
235
  label: 'Start engine',
236
236
  message: Message.ClickedStartEngine(),
237
237
  colorClassName: 'bg-green-500 hover:bg-green-600',
238
238
  })),
239
- M.exhaustive,
239
+ Match.exhaustive,
240
240
  )
241
241
 
242
242
  return h.div(
@@ -1,11 +1,11 @@
1
- import { Schema as S } from 'effect'
1
+ import { Schema } from 'effect'
2
2
 
3
- export const Location = S.Struct({
4
- id: S.String,
5
- name: S.String,
6
- region: S.String,
7
- lng: S.Number,
8
- lat: S.Number,
3
+ export const Location = Schema.Struct({
4
+ id: Schema.String,
5
+ name: Schema.String,
6
+ region: Schema.String,
7
+ lng: Schema.Number,
8
+ lat: Schema.Number,
9
9
  })
10
10
  export type Location = typeof Location.Type
11
11
 
@@ -6,7 +6,7 @@ import {
6
6
  Function,
7
7
  Option,
8
8
  Queue,
9
- Schema as S,
9
+ Schema,
10
10
  Stream,
11
11
  String,
12
12
  } from 'effect'
@@ -34,32 +34,32 @@ const GEOLOCATION_TIMEOUT_MS = 10_000
34
34
 
35
35
  // MODEL
36
36
 
37
- const Bounds = S.Struct({
38
- west: S.Number,
39
- south: S.Number,
40
- east: S.Number,
41
- north: S.Number,
37
+ const Bounds = Schema.Struct({
38
+ west: Schema.Number,
39
+ south: Schema.Number,
40
+ east: Schema.Number,
41
+ north: Schema.Number,
42
42
  })
43
43
  type Bounds = typeof Bounds.Type
44
44
 
45
- const LngLat = S.Struct({ lng: S.Number, lat: S.Number })
45
+ const LngLat = Schema.Struct({ lng: Schema.Number, lat: Schema.Number })
46
46
  type LngLat = typeof LngLat.Type
47
47
 
48
48
  export const GeolocateState = defineTaggedUnion({
49
49
  Idle: {},
50
50
  Locating: {},
51
- Failed: { reason: S.String },
51
+ Failed: { reason: Schema.String },
52
52
  })
53
53
  export type GeolocateState = typeof GeolocateState.Type
54
54
 
55
- export const Model = S.Struct({
56
- locations: S.Array(Location),
57
- searchQuery: S.String,
58
- maybeMapHostId: S.Option(S.String),
59
- maybeMapError: S.Option(S.String),
60
- maybeBounds: S.Option(Bounds),
61
- maybeSelectedLocationId: S.Option(S.String),
62
- maybeUserLocation: S.Option(LngLat),
55
+ export const Model = Schema.Struct({
56
+ locations: Schema.Array(Location),
57
+ searchQuery: Schema.String,
58
+ maybeMapHostId: Schema.Option(Schema.String),
59
+ maybeMapError: Schema.Option(Schema.String),
60
+ maybeBounds: Schema.Option(Bounds),
61
+ maybeSelectedLocationId: Schema.Option(Schema.String),
62
+ maybeUserLocation: Schema.Option(LngLat),
63
63
  geolocateState: GeolocateState,
64
64
  })
65
65
  export type Model = typeof Model.Type
@@ -67,21 +67,21 @@ export type Model = typeof Model.Type
67
67
  // MESSAGE
68
68
 
69
69
  export const Message = defineMessageUnion({
70
- SucceededMountMap: { hostId: S.String },
71
- FailedMountMap: { reason: S.String },
70
+ SucceededMountMap: { hostId: Schema.String },
71
+ FailedMountMap: { reason: Schema.String },
72
72
  MovedMap: { bounds: Bounds },
73
- ClickedMarker: { locationId: S.String },
74
- ClickedLocation: { locationId: S.String },
75
- UpdatedSearchQuery: { value: S.String },
73
+ ClickedMarker: { locationId: Schema.String },
74
+ ClickedLocation: { locationId: Schema.String },
75
+ UpdatedSearchQuery: { value: Schema.String },
76
76
  ClickedFindMe: {},
77
77
  DismissedGeolocate: {},
78
78
  SucceededGeolocate: {
79
- lng: S.Number,
80
- lat: S.Number,
79
+ lng: Schema.Number,
80
+ lat: Schema.Number,
81
81
  },
82
- FailedGeolocate: { reason: S.String },
82
+ FailedGeolocate: { reason: Schema.String },
83
83
  SucceededFlyTo: {},
84
- FailedFlyTo: { reason: S.String },
84
+ FailedFlyTo: { reason: Schema.String },
85
85
  CompletedFocusSearchInput: {},
86
86
  CompletedLockBodyScroll: {},
87
87
  CompletedUnlockBodyScroll: {},
@@ -115,10 +115,10 @@ const flyToMap = (
115
115
 
116
116
  export const FlyTo = Command.define('FlyTo', {
117
117
  args: {
118
- maybeHostId: S.Option(S.String),
119
- lng: S.Number,
120
- lat: S.Number,
121
- zoom: S.Number,
118
+ maybeHostId: Schema.Option(Schema.String),
119
+ lng: Schema.Number,
120
+ lat: Schema.Number,
121
+ zoom: Schema.Number,
122
122
  },
123
123
  messages: [Message.SucceededFlyTo, Message.FailedFlyTo],
124
124
  execute: ({ maybeHostId, lng, lat, zoom }) =>
@@ -310,7 +310,34 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
310
310
 
311
311
  // MAP MOUNT
312
312
 
313
- const mountMap = (element: Element, hostId: string) =>
313
+ type MountedMap = Readonly<{
314
+ map: MapInstance
315
+ markerElements: ReadonlyArray<HTMLButtonElement>
316
+ }>
317
+
318
+ const applyMapViewState = (
319
+ { map, markerElements }: MountedMap,
320
+ viewState: Mount.ViewState,
321
+ ): Effect.Effect<void> =>
322
+ Effect.sync(() => {
323
+ const isLive = viewState === 'Live'
324
+
325
+ if (isLive) {
326
+ map.keyboard.enable()
327
+ } else {
328
+ map.keyboard.disable()
329
+ }
330
+
331
+ Array.forEach(markerElements, markerElement => {
332
+ markerElement.disabled = !isLive
333
+ })
334
+ })
335
+
336
+ const mountMap = (
337
+ element: Element,
338
+ hostId: string,
339
+ viewStateChanges: Stream.Stream<Mount.ViewState>,
340
+ ) =>
314
341
  Effect.gen(function* () {
315
342
  if (!(element instanceof HTMLElement)) {
316
343
  return Message.FailedMountMap({
@@ -319,7 +346,7 @@ const mountMap = (element: Element, hostId: string) =>
319
346
  }
320
347
 
321
348
  return yield* Effect.gen(function* () {
322
- yield* Effect.acquireRelease(
349
+ const mountedMap = yield* Effect.acquireRelease(
323
350
  Effect.gen(function* () {
324
351
  const maplibre = yield* Effect.tryPromise(() => import('maplibre-gl'))
325
352
  maplibre.setWorkerUrl(maplibreWorkerUrl)
@@ -330,22 +357,33 @@ const mountMap = (element: Element, hostId: string) =>
330
357
  zoom: INITIAL_MAP_ZOOM,
331
358
  })
332
359
 
333
- Array.forEach(featuredLocations, ({ id, lng, lat }) => {
334
- const markerElement = document.createElement('button')
335
- markerElement.setAttribute('data-location-id', id)
336
- markerElement.setAttribute('aria-label', `Marker: ${id}`)
337
- markerElement.className = markerStyle
338
- new maplibre.Marker({ element: markerElement })
339
- .setLngLat([lng, lat])
340
- .addTo(map)
341
- })
360
+ const markerElements = Array.map(
361
+ featuredLocations,
362
+ ({ id, lng, lat }) => {
363
+ const markerElement = document.createElement('button')
364
+ markerElement.setAttribute('data-location-id', id)
365
+ markerElement.setAttribute('aria-label', `Marker: ${id}`)
366
+ markerElement.className = markerStyle
367
+ new maplibre.Marker({ element: markerElement })
368
+ .setLngLat([lng, lat])
369
+ .addTo(map)
370
+ return markerElement
371
+ },
372
+ )
342
373
 
343
374
  setMap(hostId, map)
344
- return map
375
+ return { map, markerElements }
345
376
  }),
346
377
  () => Effect.sync(() => removeMap(hostId)),
347
378
  )
348
379
 
380
+ yield* viewStateChanges.pipe(
381
+ Stream.runForEach(viewState =>
382
+ applyMapViewState(mountedMap, viewState),
383
+ ),
384
+ Effect.forkScoped,
385
+ )
386
+
349
387
  return Message.SucceededMountMap({ hostId })
350
388
  }).pipe(
351
389
  Effect.catch(error =>
@@ -359,9 +397,10 @@ const mountMap = (element: Element, hostId: string) =>
359
397
  })
360
398
 
361
399
  export const MountMap = Mount.define('MountMap', {
362
- args: { hostId: S.String },
400
+ args: { hostId: Schema.String },
363
401
  messages: [Message.SucceededMountMap, Message.FailedMountMap],
364
- execute: ({ element, hostId }) => mountMap(element, hostId),
402
+ execute: ({ element, hostId, viewStateChanges }) =>
403
+ mountMap(element, hostId, viewStateChanges),
365
404
  })
366
405
 
367
406
  // SUBSCRIPTIONS
@@ -428,7 +467,7 @@ const streamMapEvents = (hostId: string) =>
428
467
 
429
468
  export const subscriptions = Subscription.make<Model, Message>()(entry => ({
430
469
  mapEvents: entry(
431
- { maybeMapHostId: S.Option(S.String) },
470
+ { maybeMapHostId: Schema.Option(Schema.String) },
432
471
  {
433
472
  modelToDependencies: model => ({
434
473
  maybeMapHostId: model.maybeMapHostId,