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.
- package/dist/commands/create.js +9 -7
- package/dist/templates/base/FOLDKIT.md +22 -6
- package/dist/templates/examples/api-cache/src/data.ts +14 -14
- package/dist/templates/examples/api-cache/src/main.ts +42 -39
- package/dist/templates/examples/auth/src/command.ts +3 -3
- package/dist/templates/examples/auth/src/domain/session.ts +8 -6
- package/dist/templates/examples/auth/src/main.ts +11 -11
- package/dist/templates/examples/auth/src/message.ts +3 -3
- package/dist/templates/examples/auth/src/model.ts +2 -2
- package/dist/templates/examples/auth/src/page/loggedIn/index.ts +1 -1
- package/dist/templates/examples/auth/src/page/loggedIn/view.ts +3 -3
- package/dist/templates/examples/auth/src/page/loggedOut/index.ts +1 -1
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +9 -17
- package/dist/templates/examples/auth/src/page/loggedOut/update.ts +4 -6
- package/dist/templates/examples/auth/src/page/loggedOut/view.ts +3 -3
- package/dist/templates/examples/auth/src/route.ts +2 -2
- package/dist/templates/examples/auth/src/update.ts +37 -40
- package/dist/templates/examples/auth/src/view.ts +6 -6
- package/dist/templates/examples/canvas-art/src/main.ts +22 -30
- package/dist/templates/examples/charting/src/command.ts +3 -3
- package/dist/templates/examples/charting/src/domain.ts +53 -48
- package/dist/templates/examples/charting/src/echarts.ts +6 -6
- package/dist/templates/examples/charting/src/githubApi.ts +33 -34
- package/dist/templates/examples/charting/src/http.ts +7 -7
- package/dist/templates/examples/charting/src/message.ts +6 -6
- package/dist/templates/examples/charting/src/model.ts +6 -6
- package/dist/templates/examples/charting/src/npmApi.ts +19 -15
- package/dist/templates/examples/charting/src/subscription.ts +5 -5
- package/dist/templates/examples/charting/src/telemetry.test.ts +18 -12
- package/dist/templates/examples/charting/src/telemetry.ts +11 -18
- package/dist/templates/examples/charting/src/update.ts +17 -23
- package/dist/templates/examples/charting/src/view/chart.ts +2 -2
- package/dist/templates/examples/counter/src/main.ts +2 -2
- package/dist/templates/examples/counters/src/counter.ts +2 -2
- package/dist/templates/examples/counters/src/main.ts +8 -8
- package/dist/templates/examples/embedding/src/main.ts +10 -7
- package/dist/templates/examples/form/src/main.ts +18 -14
- package/dist/templates/examples/generative-art/src/command.ts +7 -2
- package/dist/templates/examples/generative-art/src/message.ts +14 -14
- package/dist/templates/examples/generative-art/src/model.ts +21 -21
- package/dist/templates/examples/generative-art/src/update.ts +15 -17
- package/dist/templates/examples/interrupting-commands/src/main.ts +30 -27
- package/dist/templates/examples/job-application/src/domain/proficiencyLevel.ts +2 -2
- package/dist/templates/examples/job-application/src/domain/pronounOption.ts +2 -2
- package/dist/templates/examples/job-application/src/domain/step.ts +11 -11
- package/dist/templates/examples/job-application/src/main.ts +5 -5
- package/dist/templates/examples/job-application/src/message.ts +2 -2
- package/dist/templates/examples/job-application/src/model.ts +5 -5
- package/dist/templates/examples/job-application/src/step/attachments.ts +32 -34
- package/dist/templates/examples/job-application/src/step/coverLetter.ts +4 -4
- package/dist/templates/examples/job-application/src/step/education/education.ts +11 -14
- package/dist/templates/examples/job-application/src/step/education/entry.ts +21 -22
- package/dist/templates/examples/job-application/src/step/personalInfo.ts +44 -54
- package/dist/templates/examples/job-application/src/step/skills/entry.ts +12 -14
- package/dist/templates/examples/job-application/src/step/skills/skills.ts +11 -14
- package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +43 -45
- package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +11 -14
- package/dist/templates/examples/job-application/src/update.ts +17 -17
- package/dist/templates/examples/job-application/src/view/attachments.ts +5 -5
- package/dist/templates/examples/job-application/src/view/datePicker.ts +3 -3
- package/dist/templates/examples/job-application/src/view/field.ts +5 -5
- package/dist/templates/examples/job-application/src/view/index.ts +28 -22
- package/dist/templates/examples/kanban/src/command.ts +4 -4
- package/dist/templates/examples/kanban/src/domain/card.ts +6 -6
- package/dist/templates/examples/kanban/src/domain/column.ts +9 -9
- package/dist/templates/examples/kanban/src/main.ts +4 -4
- package/dist/templates/examples/kanban/src/message.ts +6 -6
- package/dist/templates/examples/kanban/src/model.ts +11 -9
- package/dist/templates/examples/kanban/src/update.ts +5 -5
- package/dist/templates/examples/managed-resource-layer/src/main.ts +20 -20
- package/dist/templates/examples/map/src/locations.ts +7 -7
- package/dist/templates/examples/map/src/main.ts +83 -44
- package/dist/templates/examples/map/src/mount.test.ts +127 -0
- package/dist/templates/examples/pixel-art/src/command.ts +12 -5
- package/dist/templates/examples/pixel-art/src/main.ts +4 -4
- package/dist/templates/examples/pixel-art/src/message.ts +7 -7
- package/dist/templates/examples/pixel-art/src/model.ts +34 -29
- package/dist/templates/examples/pixel-art/src/subscription.ts +2 -2
- package/dist/templates/examples/pixel-art/src/update.ts +79 -86
- package/dist/templates/examples/query-sync/src/main.ts +106 -102
- package/dist/templates/examples/route-transitions/src/data.ts +6 -6
- package/dist/templates/examples/route-transitions/src/main.ts +23 -29
- package/dist/templates/examples/route-transitions/src/route.ts +3 -3
- package/dist/templates/examples/routing/src/fileTree.ts +10 -8
- package/dist/templates/examples/routing/src/main.ts +23 -21
- package/dist/templates/examples/routing/src/page/people.ts +14 -22
- package/dist/templates/examples/routing/src/route.ts +7 -7
- package/dist/templates/examples/shopping-cart/src/main.ts +30 -31
- package/dist/templates/examples/shopping-cart/src/page/products.ts +10 -10
- package/dist/templates/examples/shopping-cart/src/route.ts +6 -4
- package/dist/templates/examples/slow-warnings/src/main.ts +35 -43
- package/dist/templates/examples/snake/src/domain/snake.ts +2 -2
- package/dist/templates/examples/snake/src/main.ts +39 -47
- package/dist/templates/examples/ssg/src/main.ts +5 -5
- package/dist/templates/examples/ssg/src/route.ts +2 -2
- package/dist/templates/examples/ssr/src/cookie.ts +3 -3
- package/dist/templates/examples/ssr/src/main.ts +10 -10
- package/dist/templates/examples/state-machine/src/main.ts +55 -53
- package/dist/templates/examples/state-machine/src/view.ts +7 -7
- package/dist/templates/examples/stopwatch/src/main.ts +10 -10
- package/dist/templates/examples/todo/src/main.ts +41 -34
- package/dist/templates/examples/ui-showcase/src/main.ts +54 -42
- package/dist/templates/examples/ui-showcase/src/scene.test.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/init.ts +1 -2
- package/dist/templates/examples/ui-showcase/src/ui/message.ts +17 -18
- package/dist/templates/examples/ui-showcase/src/ui/model.ts +47 -44
- package/dist/templates/examples/ui-showcase/src/ui/subscriptions.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/toast.ts +4 -4
- package/dist/templates/examples/ui-showcase/src/ui/update.ts +287 -298
- package/dist/templates/examples/ui-showcase/src/ui/view/animation.ts +2 -2
- package/dist/templates/examples/ui-showcase/src/ui/view/button.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/calendar.ts +4 -4
- package/dist/templates/examples/ui-showcase/src/ui/view/checkbox.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/combobox.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/datePicker.ts +4 -4
- package/dist/templates/examples/ui-showcase/src/ui/view/dialog.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/disclosure.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/dragAndDrop.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/fieldset.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/fileDrop.ts +6 -6
- package/dist/templates/examples/ui-showcase/src/ui/view/hoverIntent.ts +9 -20
- package/dist/templates/examples/ui-showcase/src/ui/view/input.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/listbox.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/menu.ts +15 -15
- package/dist/templates/examples/ui-showcase/src/ui/view/popover.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/radioGroup.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/select.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/slider.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/switch.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/tabs.ts +7 -7
- package/dist/templates/examples/ui-showcase/src/ui/view/textarea.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/toast.ts +8 -8
- package/dist/templates/examples/ui-showcase/src/ui/view/tooltip.ts +1 -1
- package/dist/templates/examples/ui-showcase/src/ui/view/virtualList.ts +7 -7
- package/dist/templates/examples/view-transitions/src/artwork.ts +7 -7
- package/dist/templates/examples/view-transitions/src/main.ts +6 -6
- package/dist/templates/examples/view-transitions/src/route.ts +3 -3
- package/dist/templates/examples/weather/src/main.ts +42 -42
- package/dist/templates/examples/weather/src/story.test.ts +5 -5
- package/dist/templates/examples/web-components/src/main.ts +16 -16
- package/dist/templates/examples/websocket-chat/src/main.ts +30 -30
- package/dist/templates/release.json +13 -13
- package/dist/templates/rendering/ssg/src/main.ts +5 -5
- package/dist/templates/rendering/ssg/src/route.ts +2 -2
- package/dist/templates/rendering/ssr/server/main.ts +15 -15
- package/dist/templates/rendering/ssr/src/cookie.ts +3 -3
- package/dist/templates/rendering/ssr/src/main.ts +10 -10
- package/dist/utils/packages.js +17 -0
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Schema
|
|
1
|
+
import { Schema, pipe } from 'effect'
|
|
2
2
|
import { Route } from 'foldkit'
|
|
3
3
|
import { defineRouteUnion, literal } from 'foldkit/route'
|
|
4
4
|
|
|
5
5
|
export const AppRoute = defineRouteUnion({
|
|
6
6
|
Home: {},
|
|
7
7
|
About: {},
|
|
8
|
-
NotFound: { path:
|
|
8
|
+
NotFound: { path: Schema.String },
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
export type AppRoute = typeof AppRoute.Type
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Number
|
|
1
|
+
import { Number, Option, Record, pipe } from 'effect'
|
|
2
2
|
import { Cookies } from 'effect/unstable/http'
|
|
3
3
|
|
|
4
4
|
export const COUNT_COOKIE = 'foldkit-ssr-count'
|
|
@@ -7,7 +7,7 @@ export const readCountCookie = (cookieHeader: string): number =>
|
|
|
7
7
|
pipe(
|
|
8
8
|
Cookies.parseHeader(cookieHeader),
|
|
9
9
|
Record.get(COUNT_COOKIE),
|
|
10
|
-
Option.flatMap(
|
|
11
|
-
Option.filter(Number.isSafeInteger),
|
|
10
|
+
Option.flatMap(Number.parse),
|
|
11
|
+
Option.filter(globalThis.Number.isSafeInteger),
|
|
12
12
|
Option.getOrElse(() => 0),
|
|
13
13
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Schema
|
|
1
|
+
import { Effect, Schema } from 'effect'
|
|
2
2
|
import { Command, Runtime, type Update } from 'foldkit'
|
|
3
3
|
import { type Document, type Html, type HtmlBuilder } from 'foldkit/html'
|
|
4
4
|
import { defineMessageUnion } from 'foldkit/message'
|
|
@@ -10,19 +10,19 @@ import { COUNT_COOKIE } from './cookie'
|
|
|
10
10
|
|
|
11
11
|
// MODEL
|
|
12
12
|
|
|
13
|
-
export const Model =
|
|
14
|
-
count:
|
|
15
|
-
renderedAt:
|
|
16
|
-
renderedOn:
|
|
13
|
+
export const Model = Schema.Struct({
|
|
14
|
+
count: Schema.Number,
|
|
15
|
+
renderedAt: Schema.String,
|
|
16
|
+
renderedOn: Schema.Literals(['Server', 'Client']),
|
|
17
17
|
})
|
|
18
18
|
export type Model = typeof Model.Type
|
|
19
19
|
|
|
20
20
|
// FLAGS
|
|
21
21
|
|
|
22
|
-
export const Flags =
|
|
23
|
-
initialCount:
|
|
24
|
-
renderedAt:
|
|
25
|
-
renderedOn:
|
|
22
|
+
export const Flags = Schema.Struct({
|
|
23
|
+
initialCount: Schema.Number,
|
|
24
|
+
renderedAt: Schema.String,
|
|
25
|
+
renderedOn: Schema.Literals(['Server', 'Client']),
|
|
26
26
|
})
|
|
27
27
|
export type Flags = typeof Flags.Type
|
|
28
28
|
|
|
@@ -62,7 +62,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
62
62
|
const COUNT_COOKIE_MAX_AGE_SECONDS = 31536000
|
|
63
63
|
|
|
64
64
|
export const PersistCount = Command.define('PersistCount', {
|
|
65
|
-
args: { count:
|
|
65
|
+
args: { count: Schema.Number },
|
|
66
66
|
messages: [Message.CompletedPersistCount],
|
|
67
67
|
execute: ({ count }) =>
|
|
68
68
|
Effect.try(() => {
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
Array,
|
|
3
3
|
Duration,
|
|
4
4
|
Effect,
|
|
5
|
-
Match
|
|
5
|
+
Match,
|
|
6
6
|
Number,
|
|
7
7
|
Option,
|
|
8
|
-
Schema
|
|
8
|
+
Schema,
|
|
9
9
|
String,
|
|
10
10
|
flow,
|
|
11
11
|
pipe,
|
|
@@ -21,9 +21,9 @@ import { RadioGroup } from '@foldkit/ui'
|
|
|
21
21
|
|
|
22
22
|
// MODEL
|
|
23
23
|
|
|
24
|
-
export const Discount =
|
|
25
|
-
code:
|
|
26
|
-
percentOff:
|
|
24
|
+
export const Discount = Schema.Struct({
|
|
25
|
+
code: Schema.String,
|
|
26
|
+
percentOff: Schema.Number,
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
export const Promo = defineTaggedUnion({
|
|
@@ -33,31 +33,34 @@ export const Promo = defineTaggedUnion({
|
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
export const CheckoutState = defineTaggedUnion({
|
|
36
|
-
Cart: { isShippingRequired:
|
|
37
|
-
Shipping: { isShippingRequired:
|
|
36
|
+
Cart: { isShippingRequired: Schema.Boolean },
|
|
37
|
+
Shipping: { isShippingRequired: Schema.Boolean },
|
|
38
38
|
Payment: {
|
|
39
|
-
isPaymentMethodSelected:
|
|
40
|
-
isShippingRequired:
|
|
39
|
+
isPaymentMethodSelected: Schema.Boolean,
|
|
40
|
+
isShippingRequired: Schema.Boolean,
|
|
41
41
|
},
|
|
42
42
|
Review: {
|
|
43
|
-
isPaymentMethodSelected:
|
|
44
|
-
isShippingRequired:
|
|
45
|
-
isTermsAccepted:
|
|
43
|
+
isPaymentMethodSelected: Schema.Boolean,
|
|
44
|
+
isShippingRequired: Schema.Boolean,
|
|
45
|
+
isTermsAccepted: Schema.Boolean,
|
|
46
46
|
promo: Promo,
|
|
47
|
-
promoCodeInput:
|
|
47
|
+
promoCodeInput: Schema.String,
|
|
48
|
+
},
|
|
49
|
+
Placing: {
|
|
50
|
+
isShippingRequired: Schema.Boolean,
|
|
51
|
+
maybeDiscount: Schema.Option(Discount),
|
|
48
52
|
},
|
|
49
|
-
Placing: { isShippingRequired: S.Boolean, maybeDiscount: S.Option(Discount) },
|
|
50
53
|
Confirmed: {
|
|
51
|
-
isShippingRequired:
|
|
52
|
-
maybeDiscount:
|
|
53
|
-
orderId:
|
|
54
|
+
isShippingRequired: Schema.Boolean,
|
|
55
|
+
maybeDiscount: Schema.Option(Discount),
|
|
56
|
+
orderId: Schema.String,
|
|
54
57
|
},
|
|
55
|
-
Cancelled: { isShippingRequired:
|
|
58
|
+
Cancelled: { isShippingRequired: Schema.Boolean },
|
|
56
59
|
})
|
|
57
60
|
|
|
58
|
-
export const TransitionLogEntry =
|
|
59
|
-
id:
|
|
60
|
-
summary:
|
|
61
|
+
export const TransitionLogEntry = Schema.Struct({
|
|
62
|
+
id: Schema.Number,
|
|
63
|
+
summary: Schema.String,
|
|
61
64
|
})
|
|
62
65
|
export type TransitionLogEntry = typeof TransitionLogEntry.Type
|
|
63
66
|
|
|
@@ -76,11 +79,11 @@ export const editionName = (isShippingRequired: boolean): string =>
|
|
|
76
79
|
|
|
77
80
|
export const EditionRadioGroup = RadioGroup.create()
|
|
78
81
|
|
|
79
|
-
export const Model =
|
|
82
|
+
export const Model = Schema.Struct({
|
|
80
83
|
checkout: CheckoutState,
|
|
81
84
|
editionRadioGroup: RadioGroup.Model,
|
|
82
|
-
transitionLog:
|
|
83
|
-
nextTransitionLogId:
|
|
85
|
+
transitionLog: Schema.Array(TransitionLogEntry),
|
|
86
|
+
nextTransitionLogId: Schema.Number,
|
|
84
87
|
})
|
|
85
88
|
export type Model = typeof Model.Type
|
|
86
89
|
|
|
@@ -92,13 +95,13 @@ export const Message = defineMessageUnion({
|
|
|
92
95
|
ClickedCancel: {},
|
|
93
96
|
ClickedPlaceOrder: {},
|
|
94
97
|
ClickedStartOver: {},
|
|
95
|
-
ToggledPaymentMethod: { isSelected:
|
|
96
|
-
SelectedEdition: { isShippingRequired:
|
|
98
|
+
ToggledPaymentMethod: { isSelected: Schema.Boolean },
|
|
99
|
+
SelectedEdition: { isShippingRequired: Schema.Boolean },
|
|
97
100
|
GotEditionRadioGroupMessage: { message: RadioGroup.Message },
|
|
98
|
-
ToggledTermsAccepted: { isAccepted:
|
|
99
|
-
UpdatedPromoCode: { value:
|
|
101
|
+
ToggledTermsAccepted: { isAccepted: Schema.Boolean },
|
|
102
|
+
UpdatedPromoCode: { value: Schema.String },
|
|
100
103
|
SubmittedPromoCode: {},
|
|
101
|
-
SucceededPlaceOrder: { orderId:
|
|
104
|
+
SucceededPlaceOrder: { orderId: Schema.String },
|
|
102
105
|
})
|
|
103
106
|
|
|
104
107
|
export type Message = typeof Message.Type
|
|
@@ -108,7 +111,7 @@ export type Message = typeof Message.Type
|
|
|
108
111
|
const PLACE_ORDER_DELAY = Duration.seconds(1)
|
|
109
112
|
|
|
110
113
|
export const PlaceOrder = Command.define('PlaceOrder', {
|
|
111
|
-
args: { isShippingRequired:
|
|
114
|
+
args: { isShippingRequired: Schema.Boolean },
|
|
112
115
|
messages: [Message.SucceededPlaceOrder],
|
|
113
116
|
execute: ({ isShippingRequired }) =>
|
|
114
117
|
Effect.gen(function* () {
|
|
@@ -129,9 +132,9 @@ const PROMO_DISCOUNTS: ReadonlyArray<typeof Discount.Type> = [
|
|
|
129
132
|
export const promoToMaybeDiscount = (
|
|
130
133
|
promo: typeof Promo.Type,
|
|
131
134
|
): Option.Option<typeof Discount.Type> =>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
Match.value(promo).pipe(
|
|
136
|
+
Match.tags({ AppliedPromo: appliedPromo => appliedPromo.discount }),
|
|
137
|
+
Match.option,
|
|
135
138
|
)
|
|
136
139
|
|
|
137
140
|
export const isReviewReady = (
|
|
@@ -352,8 +355,8 @@ export const TRANSITION_LOG_LIMIT = 20
|
|
|
352
355
|
const resultToTransitionSummary = (
|
|
353
356
|
result: Machine.TransitionResult<typeof CheckoutState.Type, Message>,
|
|
354
357
|
): string =>
|
|
355
|
-
|
|
356
|
-
|
|
358
|
+
Match.value(result).pipe(
|
|
359
|
+
Match.tagsExhaustive({
|
|
357
360
|
Transitioned: ({ from, messageTag, target }) =>
|
|
358
361
|
`${from} -> ${target} on ${messageTag}`,
|
|
359
362
|
Ignored: ({ messageTag, stateTag }) =>
|
|
@@ -368,8 +371,8 @@ const stepMachine =
|
|
|
368
371
|
|
|
369
372
|
const { state: nextCheckout } = result
|
|
370
373
|
|
|
371
|
-
const transitionCommands =
|
|
372
|
-
|
|
374
|
+
const transitionCommands = Match.value(result).pipe(
|
|
375
|
+
Match.tagsExhaustive({
|
|
373
376
|
Transitioned: ({ commands }) => commands,
|
|
374
377
|
Ignored: () => [],
|
|
375
378
|
}),
|
|
@@ -393,17 +396,16 @@ const stepMachine =
|
|
|
393
396
|
}
|
|
394
397
|
}
|
|
395
398
|
|
|
396
|
-
const foldEditionRadioGroupOutMessage =
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
)
|
|
399
|
+
const foldEditionRadioGroupOutMessage = RadioGroup.OutMessage.match<
|
|
400
|
+
Update.Step<Model, Message>
|
|
401
|
+
>({
|
|
402
|
+
Selected: ({ value }) =>
|
|
403
|
+
stepMachine(
|
|
404
|
+
Message.SelectedEdition({
|
|
405
|
+
isShippingRequired: value === HARDCOVER_EDITION,
|
|
406
|
+
}),
|
|
407
|
+
),
|
|
408
|
+
})
|
|
407
409
|
|
|
408
410
|
const foldEditionRadioGroup = Update.foldChild({
|
|
409
411
|
update: EditionRadioGroup.update,
|
|
@@ -415,12 +417,12 @@ const foldEditionRadioGroup = Update.foldChild({
|
|
|
415
417
|
})
|
|
416
418
|
|
|
417
419
|
export const update = (model: Model, message: Message) =>
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
420
|
+
Match.value(message).pipe(
|
|
421
|
+
Match.withReturnType<UpdateReturn>(),
|
|
422
|
+
Match.tag('GotEditionRadioGroupMessage', ({ message }) =>
|
|
421
423
|
foldEditionRadioGroup(model, message),
|
|
422
424
|
),
|
|
423
|
-
|
|
425
|
+
Match.tag(
|
|
424
426
|
'ClickedContinue',
|
|
425
427
|
'ClickedBack',
|
|
426
428
|
'ClickedCancel',
|
|
@@ -434,5 +436,5 @@ export const update = (model: Model, message: Message) =>
|
|
|
434
436
|
'SucceededPlaceOrder',
|
|
435
437
|
() => stepMachine(message)(model),
|
|
436
438
|
),
|
|
437
|
-
|
|
439
|
+
Match.exhaustive,
|
|
438
440
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clsx } from 'clsx'
|
|
2
|
-
import { Array, Match
|
|
2
|
+
import { Array, Match, Option, pipe } from 'effect'
|
|
3
3
|
import { Document, Html, HtmlBuilder } from 'foldkit/html'
|
|
4
4
|
|
|
5
5
|
import { Button, Checkbox, Input, RadioGroup } from '@foldkit/ui'
|
|
@@ -80,15 +80,15 @@ const progressSteps: ReadonlyArray<string> = [
|
|
|
80
80
|
const stateToMaybeProgressStep = (
|
|
81
81
|
state: typeof CheckoutState.Type,
|
|
82
82
|
): Option.Option<string> =>
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
Match.value(state).pipe(
|
|
84
|
+
Match.tags({
|
|
85
85
|
Cart: () => 'Bag',
|
|
86
86
|
Shipping: () => 'Delivery',
|
|
87
87
|
Payment: () => 'Payment',
|
|
88
88
|
Review: () => 'Review',
|
|
89
89
|
Cancelled: () => 'Bag',
|
|
90
90
|
}),
|
|
91
|
-
|
|
91
|
+
Match.option,
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
const currentProgressIndex = (state: typeof CheckoutState.Type): number =>
|
|
@@ -140,13 +140,13 @@ const orderPricing = (
|
|
|
140
140
|
const stateToMaybeDiscount = (
|
|
141
141
|
state: typeof CheckoutState.Type,
|
|
142
142
|
): Option.Option<typeof Discount.Type> =>
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
Match.value(state).pipe(
|
|
144
|
+
Match.tags({
|
|
145
145
|
Review: reviewState => promoToMaybeDiscount(reviewState.promo),
|
|
146
146
|
Placing: placingState => placingState.maybeDiscount,
|
|
147
147
|
Confirmed: confirmedState => confirmedState.maybeDiscount,
|
|
148
148
|
}),
|
|
149
|
-
|
|
149
|
+
Match.option,
|
|
150
150
|
Option.flatten,
|
|
151
151
|
)
|
|
152
152
|
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
Clock,
|
|
3
3
|
Duration,
|
|
4
4
|
Effect,
|
|
5
|
-
Schema
|
|
5
|
+
Schema,
|
|
6
6
|
Stream,
|
|
7
7
|
String,
|
|
8
8
|
flow,
|
|
@@ -19,10 +19,10 @@ const TICK_INTERVAL_MS = 10
|
|
|
19
19
|
|
|
20
20
|
// MODEL
|
|
21
21
|
|
|
22
|
-
export const Model =
|
|
23
|
-
elapsedMs:
|
|
24
|
-
isRunning:
|
|
25
|
-
startTime:
|
|
22
|
+
export const Model = Schema.Struct({
|
|
23
|
+
elapsedMs: Schema.Number,
|
|
24
|
+
isRunning: Schema.Boolean,
|
|
25
|
+
startTime: Schema.Number,
|
|
26
26
|
})
|
|
27
27
|
export type Model = typeof Model.Type
|
|
28
28
|
|
|
@@ -30,11 +30,11 @@ export type Model = typeof Model.Type
|
|
|
30
30
|
|
|
31
31
|
export const Message = defineMessageUnion({
|
|
32
32
|
ClickedStart: {},
|
|
33
|
-
CompletedDetermineStartTime: { startTime:
|
|
33
|
+
CompletedDetermineStartTime: { startTime: Schema.Number },
|
|
34
34
|
ClickedStop: {},
|
|
35
35
|
ClickedReset: {},
|
|
36
36
|
Ticked: {},
|
|
37
|
-
CompletedDetermineTickTime: { elapsedMs:
|
|
37
|
+
CompletedDetermineTickTime: { elapsedMs: Schema.Number },
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
export type Message = typeof Message.Type
|
|
@@ -42,7 +42,7 @@ export type Message = typeof Message.Type
|
|
|
42
42
|
// COMMAND
|
|
43
43
|
|
|
44
44
|
export const DetermineStartTime = Command.define('DetermineStartTime', {
|
|
45
|
-
args: { elapsedMs:
|
|
45
|
+
args: { elapsedMs: Schema.Number },
|
|
46
46
|
messages: [Message.CompletedDetermineStartTime],
|
|
47
47
|
execute: ({ elapsedMs }) =>
|
|
48
48
|
Effect.gen(function* () {
|
|
@@ -52,7 +52,7 @@ export const DetermineStartTime = Command.define('DetermineStartTime', {
|
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
export const DetermineTickTime = Command.define('DetermineTickTime', {
|
|
55
|
-
args: { startTime:
|
|
55
|
+
args: { startTime: Schema.Number },
|
|
56
56
|
messages: [Message.CompletedDetermineTickTime],
|
|
57
57
|
execute: ({ startTime }) =>
|
|
58
58
|
Effect.gen(function* () {
|
|
@@ -117,7 +117,7 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
|
|
|
117
117
|
|
|
118
118
|
export const subscriptions = Subscription.make<Model, Message>()(entry => ({
|
|
119
119
|
tick: entry(
|
|
120
|
-
{ isRunning:
|
|
120
|
+
{ isRunning: Schema.Boolean },
|
|
121
121
|
{
|
|
122
122
|
modelToDependencies: model => ({ isRunning: model.isRunning }),
|
|
123
123
|
dependenciesToStream: ({ isRunning }) =>
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
Array,
|
|
4
4
|
Clock,
|
|
5
5
|
Effect,
|
|
6
|
-
Match
|
|
6
|
+
Match,
|
|
7
7
|
Option,
|
|
8
8
|
Random,
|
|
9
|
-
Schema
|
|
9
|
+
Schema,
|
|
10
10
|
String,
|
|
11
11
|
} from 'effect'
|
|
12
12
|
import { KeyValueStore } from 'effect/unstable/persistence'
|
|
@@ -25,31 +25,31 @@ const TODOS_STORAGE_KEY = 'todos'
|
|
|
25
25
|
|
|
26
26
|
// MODEL
|
|
27
27
|
|
|
28
|
-
const Todo =
|
|
29
|
-
id:
|
|
30
|
-
text:
|
|
31
|
-
completed:
|
|
32
|
-
createdAt:
|
|
28
|
+
const Todo = Schema.Struct({
|
|
29
|
+
id: Schema.String,
|
|
30
|
+
text: Schema.String,
|
|
31
|
+
completed: Schema.Boolean,
|
|
32
|
+
createdAt: Schema.Number,
|
|
33
33
|
})
|
|
34
34
|
type Todo = typeof Todo.Type
|
|
35
35
|
|
|
36
|
-
const Todos =
|
|
36
|
+
const Todos = Schema.Array(Todo)
|
|
37
37
|
type Todos = typeof Todos.Type
|
|
38
38
|
|
|
39
|
-
const TodosJsonString =
|
|
39
|
+
const TodosJsonString = Schema.fromJsonString(Schema.toCodecJson(Todos))
|
|
40
40
|
|
|
41
|
-
const Filter =
|
|
41
|
+
const Filter = Schema.Literals(['All', 'Active', 'Completed'])
|
|
42
42
|
type Filter = typeof Filter.Type
|
|
43
43
|
|
|
44
44
|
export const EditingState = defineTaggedUnion({
|
|
45
45
|
NotEditing: {},
|
|
46
|
-
Editing: { id:
|
|
46
|
+
Editing: { id: Schema.String, text: Schema.String },
|
|
47
47
|
})
|
|
48
48
|
export type EditingState = typeof EditingState.Type
|
|
49
49
|
|
|
50
|
-
export const Model =
|
|
50
|
+
export const Model = Schema.Struct({
|
|
51
51
|
todos: Todos,
|
|
52
|
-
newTodoText:
|
|
52
|
+
newTodoText: Schema.String,
|
|
53
53
|
filter: Filter,
|
|
54
54
|
editing: EditingState,
|
|
55
55
|
})
|
|
@@ -58,13 +58,17 @@ export type Model = typeof Model.Type
|
|
|
58
58
|
// MESSAGE
|
|
59
59
|
|
|
60
60
|
export const Message = defineMessageUnion({
|
|
61
|
-
UpdatedNewTodo: { text:
|
|
62
|
-
UpdatedEditingTodo: { text:
|
|
61
|
+
UpdatedNewTodo: { text: Schema.String },
|
|
62
|
+
UpdatedEditingTodo: { text: Schema.String },
|
|
63
63
|
AddedTodo: {},
|
|
64
|
-
CompletedGenerateTodo: {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
CompletedGenerateTodo: {
|
|
65
|
+
id: Schema.String,
|
|
66
|
+
timestamp: Schema.Number,
|
|
67
|
+
text: Schema.String,
|
|
68
|
+
},
|
|
69
|
+
DeletedTodo: { id: Schema.String },
|
|
70
|
+
ToggledTodo: { id: Schema.String },
|
|
71
|
+
StartedEditing: { id: Schema.String },
|
|
68
72
|
SavedEdit: {},
|
|
69
73
|
CancelledEdit: {},
|
|
70
74
|
ToggledAll: {},
|
|
@@ -77,8 +81,8 @@ export type Message = typeof Message.Type
|
|
|
77
81
|
|
|
78
82
|
// FLAGS
|
|
79
83
|
|
|
80
|
-
export const Flags =
|
|
81
|
-
todos:
|
|
84
|
+
export const Flags = Schema.Struct({
|
|
85
|
+
todos: Schema.Option(Todos),
|
|
82
86
|
})
|
|
83
87
|
export type Flags = typeof Flags.Type
|
|
84
88
|
|
|
@@ -267,7 +271,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
267
271
|
// COMMAND
|
|
268
272
|
|
|
269
273
|
export const GenerateTodo = Command.define('GenerateTodo', {
|
|
270
|
-
args: { text:
|
|
274
|
+
args: { text: Schema.String },
|
|
271
275
|
messages: [Message.CompletedGenerateTodo],
|
|
272
276
|
execute: ({ text }) =>
|
|
273
277
|
Effect.gen(function* () {
|
|
@@ -285,7 +289,10 @@ export const SaveTodos = Command.define('SaveTodos', {
|
|
|
285
289
|
execute: ({ todos }) =>
|
|
286
290
|
Effect.gen(function* () {
|
|
287
291
|
const store = yield* KeyValueStore.KeyValueStore
|
|
288
|
-
yield* store.set(
|
|
292
|
+
yield* store.set(
|
|
293
|
+
TODOS_STORAGE_KEY,
|
|
294
|
+
Schema.encodeSync(TodosJsonString)(todos),
|
|
295
|
+
)
|
|
289
296
|
return Message.SucceededSaveTodos({ todos })
|
|
290
297
|
}).pipe(
|
|
291
298
|
Effect.catch(() => Effect.succeed(Message.FailedSaveTodos())),
|
|
@@ -541,11 +548,11 @@ const footerView = (
|
|
|
541
548
|
})
|
|
542
549
|
|
|
543
550
|
const filterTodos = (todos: Todos, filter: Filter): Todos =>
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
551
|
+
Match.value(filter).pipe(
|
|
552
|
+
Match.when('All', () => todos),
|
|
553
|
+
Match.when('Active', () => Array.filter(todos, todo => !todo.completed)),
|
|
554
|
+
Match.when('Completed', () => Array.filter(todos, todo => todo.completed)),
|
|
555
|
+
Match.exhaustive,
|
|
549
556
|
)
|
|
550
557
|
|
|
551
558
|
export const view = (model: Model, h: HtmlBuilder<Message>): Document => {
|
|
@@ -615,11 +622,11 @@ export const view = (model: Model, h: HtmlBuilder<Message>): Document => {
|
|
|
615
622
|
h.div(
|
|
616
623
|
[h.Class('text-center text-gray-500 py-8')],
|
|
617
624
|
[
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
625
|
+
Match.value(model.filter).pipe(
|
|
626
|
+
Match.when('All', () => 'No todos yet. Add one above!'),
|
|
627
|
+
Match.when('Active', () => 'No active todos'),
|
|
628
|
+
Match.when('Completed', () => 'No completed todos'),
|
|
629
|
+
Match.exhaustive,
|
|
623
630
|
),
|
|
624
631
|
],
|
|
625
632
|
),
|
|
@@ -649,7 +656,7 @@ export const flags: Effect.Effect<Flags> = Effect.gen(function* () {
|
|
|
649
656
|
Option.fromNullishOr(yield* store.get(TODOS_STORAGE_KEY)),
|
|
650
657
|
)
|
|
651
658
|
|
|
652
|
-
const decodeTodos =
|
|
659
|
+
const decodeTodos = Schema.decodeEffect(TodosJsonString)
|
|
653
660
|
const todos = yield* decodeTodos(todosJson)
|
|
654
661
|
|
|
655
662
|
return { todos: Option.some(todos) }
|