Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 4x 5x 4x 17x 5x 5x 5x 3x 2x 7x 7x 7x 4x 4x 4x | import { Data, Duration, Effect, HashMap, Option, Schema } from 'effect'
import { Command, type Update } from 'foldkit'
import { modifyFields } from 'foldkit/struct'
import { Message } from './message'
import { Feedback, type Model } from './model'
type UpdateReturn = Update.Return<Model, Message>
const showFeedback = (
model: Model,
cellId: string,
feedback: Feedback,
): UpdateReturn => ({
model: modifyFields(model, {
feedbackByCellId: HashMap.set(cellId, feedback),
}),
commands: [WaitBeforeHidingCopyFeedback({ cellId, copyId: feedback.copyId })],
})
// UPDATE
export const update = (model: Model, message: Message) =>
Message.match<UpdateReturn>(message, {
ClickedCopy: ({ cellId, text }) => {
const copyId = model.copyCount + 1
return {
model: modifyFields(model, { copyCount: () => copyId }),
commands: [CopyText({ cellId, text, copyId })],
}
},
SucceededCopyText: ({ cellId, copyId }) =>
showFeedback(model, cellId, Feedback.Copied({ copyId })),
FailedCopyText: ({ cellId, copyId }) =>
showFeedback(model, cellId, Feedback.Failed({ copyId })),
// NOTE: a newer copy of the same cell owns the feedback now, so an older wait leaves it alone.
CompletedWaitBeforeHidingCopyFeedback: ({ cellId, copyId }) => ({
model: modifyFields(model, {
feedbackByCellId: feedbackByCellId =>
Option.exists(
HashMap.get(feedbackByCellId, cellId),
feedback => feedback.copyId === copyId,
)
? HashMap.remove(feedbackByCellId, cellId)
: feedbackByCellId,
}),
}),
})
// COMMAND
class ClipboardRefusedError extends Data.TaggedError('ClipboardRefusedError')<{
readonly cause: unknown
}> {}
export const CopyText = Command.define('CopyText', {
args: { cellId: Schema.String, text: Schema.String, copyId: Schema.Int },
messages: [Message.SucceededCopyText, Message.FailedCopyText],
execute: ({ cellId, text, copyId }) =>
Effect.tryPromise({
try: () => navigator.clipboard.writeText(text),
catch: cause => new ClipboardRefusedError({ cause }),
}).pipe(
Effect.as(Message.SucceededCopyText({ cellId, copyId })),
Effect.catch(() =>
Effect.succeed(Message.FailedCopyText({ cellId, copyId })),
),
),
})
const COPY_FEEDBACK_DURATION = Duration.millis(1200)
export const WaitBeforeHidingCopyFeedback = Command.define(
'WaitBeforeHidingCopyFeedback',
{
args: { cellId: Schema.String, copyId: Schema.Int },
messages: [Message.CompletedWaitBeforeHidingCopyFeedback],
execute: ({ cellId, copyId }) =>
Effect.sleep(COPY_FEEDBACK_DURATION).pipe(
Effect.as(
Message.CompletedWaitBeforeHidingCopyFeedback({ cellId, copyId }),
),
),
},
)
|