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 | 1x 128x 1546x 1494x 26x 26x 52x 118x 1x 51x 51x 1x 128x 1686x 663x 128x 77x 51x 1x 1x 256x | import { Option } from 'effect'
import type { Html, HtmlBuilder } from 'foldkit/html'
import { Message } from '@/message'
import { CursorState, type Model } from '@/model'
import { Button } from '@foldkit/ui'
import type { LatLon } from '../../core/domain'
import * as Icon from '../ui/icon'
export type CellTone = 'Live' | 'Stale' | 'Cue'
/**
* One position the readout reports. Each row says where its position comes from and how its
* cells look; the columns (one per coordinate system) are in columns.ts.
*/
export type ReadoutRow = Readonly<{
id: 'Cursor' | 'Cue'
label: string
iconView: (h: HtmlBuilder<Message>) => Html
/** Whether the row applies at all; the cursor row needs a pointer that can hover. */
isAvailable: (model: Model) => boolean
point: (model: Model) => Option.Option<LatLon.LatLon>
tone: (model: Model) => CellTone
actionView: (model: Model, h: HtmlBuilder<Message>) => Html
}>
const cursorRow: ReadoutRow = {
id: 'Cursor',
label: 'Cursor',
iconView: Icon.cross,
isAvailable: model => model.pointer === 'Hover',
point: model =>
CursorState.match(model.cursor, {
Idle: () => Option.none(),
OnMap: ({ point }) => Option.some(point),
OffMap: ({ point }) => Option.some(point),
}),
tone: model => (CursorState.guards.OnMap(model.cursor) ? 'Live' : 'Stale'),
actionView: (_model, h) => h.empty,
}
const clearCueButtonView = (h: HtmlBuilder<Message>): Html =>
Button.view(
{
onClick: Message.ClickedClearCue(),
toView: attributes =>
h.button(
[
...attributes.button,
h.AriaLabel('Clear the cue'),
h.Title('Clear the cue'),
h.Class(
'ml-auto min-h-6 min-w-6 rounded px-1 text-faint outline-hidden hover:text-ink focus-visible:ring-2 focus-visible:ring-focus',
),
],
['×'],
),
},
h,
)
const cueRow: ReadoutRow = {
id: 'Cue',
label: 'Cue',
iconView: Icon.cue,
isAvailable: () => true,
point: model => model.maybeCue,
tone: () => 'Cue',
actionView: (model, h) =>
Option.match(model.maybeCue, {
onNone: () => h.empty,
onSome: () => clearCueButtonView(h),
}),
}
export const rows: ReadonlyArray<ReadoutRow> = [cursorRow, cueRow]
export const availableRows = (model: Model): ReadonlyArray<ReadoutRow> =>
rows.filter(row => row.isAvailable(model))
|