CalendarBuilt revision v17.10.0 React TopicsHuman supportBring a missing role, layout, or state, or a rendering against the standard, to the session working on kit. Name the package and the entry. CalendarOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let part = (row, span, at) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-part", Int.toString(at))
let parts = count =>
ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-column-parts", Int.toString(count))
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let hourHeight = "var(--kit-hour-height)"
let keyCollection = KitReact.Roles.Row.Unsaved([KitReact.Words.Text("This booking will move when you are back online.")])
let item = (~key, ~name, ~span, ~kind, ~room=?, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../record/"),
span,
kind,
standings,
standingWords,
room,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../layout-calendar/#layout-calendar"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.week(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-scope-form-group", kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-scope"},
controlProps: {id: "calendar-scope"},
controlValue: "oakmere",
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
Filter({
id: "calendar-room-filter",
name: "Room",
applied: [KitReact.Words.Text("Main Hall")],
clear: {href: "?week=this&hall=oakmere&payment=overdue&catering=kitchen"},
control: <KitReact.Roles.FormGroup
id="calendar-scope-room-form-group"
kind=Select
label={React.string("Room")}
labelProps={{htmlFor: "calendar-scope-room"}}
controlProps={{id: "calendar-scope-room"}}
controlValue="main-hall"
options=[
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
{label: React.string("Memorial Room"), value: "memorial-room", props: {}},
]
/>,
}),
Filter({
id: "calendar-booking-filter",
name: "Booking",
control: <KitReact.Roles.FormGroup
id="calendar-scope-booking-form-group"
kind=Select
label={React.string("Booking")}
labelProps={{htmlFor: "calendar-scope-booking"}}
controlProps={{id: "calendar-scope-booking"}}
controlValue="all"
options=[
{label: React.string("Any booking"), value: "all", props: {}},
{label: React.string("Regular"), value: "regular", props: {}},
{label: React.string("One-off"), value: "one-off", props: {}},
]
/>,
}),
Filter({
id: "calendar-status-filter",
name: "Status",
control: <KitReact.Roles.FormGroup
id="calendar-scope-status-form-group"
kind=Select
label={React.string("Status")}
labelProps={{htmlFor: "calendar-scope-status"}}
controlProps={{id: "calendar-scope-status"}}
controlValue="all"
options=[
{label: React.string("Any status"), value: "all", props: {}},
{label: React.string("Confirmed"), value: "confirmed", props: {}},
{label: React.string("Provisional"), value: "provisional", props: {}},
]
/>,
}),
Filter({
id: "calendar-hirer-kind-filter",
name: "Hirer kind",
control: <KitReact.Roles.FormGroup
id="calendar-scope-hirer-kind-form-group"
kind=Select
label={React.string("Hirer kind")}
labelProps={{htmlFor: "calendar-scope-hirer-kind"}}
controlProps={{id: "calendar-scope-hirer-kind"}}
controlValue="all"
options=[
{label: React.string("Any hirer"), value: "all", props: {}},
{label: React.string("School"), value: "school", props: {}},
{label: React.string("Club"), value: "club", props: {}},
{label: React.string("Private"), value: "private", props: {}},
]
/>,
}),
Filter({
id: "calendar-payment-filter",
name: "Payment",
applied: [KitReact.Words.Text("Overdue")],
clear: {href: "?week=this&hall=oakmere&room=main-hall&catering=kitchen"},
control: <KitReact.Roles.FormGroup
id="calendar-scope-payment-form-group"
kind=Select
label={React.string("Payment")}
labelProps={{htmlFor: "calendar-scope-payment"}}
controlProps={{id: "calendar-scope-payment"}}
controlValue="overdue"
options=[
{label: React.string("Any payment"), value: "all", props: {}},
{label: React.string("Paid"), value: "paid", props: {}},
{label: React.string("Due"), value: "due", props: {}},
{label: React.string("Overdue"), value: "overdue", props: {}},
]
/>,
}),
Filter({
id: "calendar-setup-filter",
name: "Setup",
control: <KitReact.Roles.FormGroup
id="calendar-scope-setup-form-group"
kind=Select
label={React.string("Setup")}
labelProps={{htmlFor: "calendar-scope-setup"}}
controlProps={{id: "calendar-scope-setup"}}
controlValue="all"
options=[
{label: React.string("Any setup"), value: "all", props: {}},
{label: React.string("Theatre"), value: "theatre", props: {}},
{label: React.string("Cabaret"), value: "cabaret", props: {}},
{label: React.string("Boardroom"), value: "boardroom", props: {}},
]
/>,
}),
Filter({
id: "calendar-catering-filter",
name: "Catering",
applied: [KitReact.Words.Text("Kitchen")],
clear: {href: "?week=this&hall=oakmere&room=main-hall&payment=overdue"},
control: <KitReact.Roles.FormGroup
id="calendar-scope-catering-form-group"
kind=Select
label={React.string("Catering")}
labelProps={{htmlFor: "calendar-scope-catering"}}
controlProps={{id: "calendar-scope-catering"}}
controlValue="kitchen"
options=[
{label: React.string("Any catering"), value: "all", props: {}},
{label: React.string("Kitchen"), value: "kitchen", props: {}},
{label: React.string("None"), value: "none", props: {}},
]
/>,
}),
Filter({
id: "calendar-access-filter",
name: "Access",
control: <KitReact.Roles.FormGroup
id="calendar-scope-access-form-group"
kind=Select
label={React.string("Access")}
labelProps={{htmlFor: "calendar-scope-access"}}
controlProps={{id: "calendar-scope-access"}}
controlValue="all"
options=[
{label: React.string("Any access"), value: "all", props: {}},
{label: React.string("Step-free"), value: "step-free", props: {}},
{label: React.string("Parking"), value: "parking", props: {}},
]
/>,
}),
Filter({
id: "calendar-deposit-filter",
name: "Deposit",
control: <KitReact.Roles.FormGroup
id="calendar-scope-deposit-form-group"
kind=Select
label={React.string("Deposit")}
labelProps={{htmlFor: "calendar-scope-deposit"}}
controlProps={{id: "calendar-scope-deposit"}}
controlValue="all"
options=[
{label: React.string("Any deposit"), value: "all", props: {}},
{label: React.string("Held"), value: "held", props: {}},
{label: React.string("Returned"), value: "returned", props: {}},
]
/>,
}),
More({
id: "calendar-more-filters",
count: {reader: Specimen_Reader.reader, count: 0, counts: "filters", forms: {one: "filter"}},
filters: [
{id: "calendar-room-filter", name: "Room", applied: [KitReact.Words.Text("Main Hall")], clear: {href: "?week=this&hall=oakmere&payment=overdue&catering=kitchen"}},
{id: "calendar-booking-filter", name: "Booking"},
{id: "calendar-status-filter", name: "Status"},
{id: "calendar-hirer-kind-filter", name: "Hirer kind"},
{id: "calendar-payment-filter", name: "Payment", applied: [KitReact.Words.Text("Overdue")], clear: {href: "?week=this&hall=oakmere&room=main-hall&catering=kitchen"}},
{id: "calendar-setup-filter", name: "Setup"},
{id: "calendar-catering-filter", name: "Catering", applied: [KitReact.Words.Text("Kitchen")], clear: {href: "?week=this&hall=oakmere&room=main-hall&payment=overdue"}},
{id: "calendar-access-filter", name: "Access"},
{id: "calendar-deposit-filter", name: "Deposit"},
],
}),
]
filtersCount={reader: Specimen_Reader.reader, count: 3, counts: "filters", forms: {one: "filter"}}
clearFilters={href: "?week=this&hall=oakmere"}
view={<KitReact.Roles.FormGroup id="calendar-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [newBooking], statusLines: [{children: React.string("New bookings wait for the hall manager to approve them.")}]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
head(19),
head(20),
]
hours=[
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Board meeting")}
href="../../record/"
span={span(14, "09:00", "10:00")}
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(2, 1)}}
/>
<Calendar.Block
name={React.string("Community lunch")}
href="../../record/"
span={span(14, "13:00", "13:29")}
kind="Booking"
props={{ariaLabel: "Community lunch, 13:00–13:29", style: sized(6, 1, `calc(${hourHeight} * 29 / 60)`)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <>
<Calendar.Block
name={React.string("School booking for Oakmere Hall")}
href="../../record/"
span={span(15, "09:00", "11:00")}
kind="Booking"
props={{ariaLabel: "School booking for Oakmere Hall, 09:00–11:00", style: placement(2, 2)}}
/>
<Calendar.Block
name={React.string("Room check")}
href="../../record/"
span={span(15, "13:00", "13:30")}
kind="Inspection"
props={{ariaLabel: "Room check, 13:00–13:30", style: sized(6, 1, `calc(${hourHeight} / 2)`)}}
/>
<Calendar.Block
name={React.string("Key handover")}
href="../../record/"
span={span(15, "15:00", "15:20")}
kind="Booking"
props={{ariaLabel: "Key handover, 15:00–15:20", style: sized(8, 1, `calc(${hourHeight} / 3)`)}}
/>
<Calendar.FoldedRun
span={span(15, "16:00", "16:35")}
count={[KitReact.Words.Text("3 inspections")]}
href="day-one-column/"
props={{style: sized(9, 1, `calc(${hourHeight} * 7 / 12)`)}}
/>
<Calendar.CurrentTime
props={{
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
`calc(3.5 * ${hourHeight})`,
),
}}
/>
</>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Block
name={React.string("Parish council")}
href="../../record/"
span={span(16, "11:00", "12:00")}
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(4, 1)}}
/>
<Calendar.Block
name={React.string("Meter reading")}
href="../../record/"
span={span(16, "13:00", "13:05")}
kind="Inspection"
props={{ariaLabel: "Meter reading, 13:00–13:05", style: sized(6, 1, `calc(${hourHeight} / 12)`)}}
/>
</>,
props: {},
},
{key: "2025-04-17", children: React.null, props: {}},
{
key: "2025-04-18",
children: <>
<Calendar.Block
name={React.string("Wedding reception")}
href="../../record/"
span={span(18, "12:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: part(5, 3, 1)}}
/>
<Calendar.Block
name={React.string("Hire request")}
href="../../record/"
span={span(18, "11:00", "13:00")}
kind="Requested"
standings=[Uncovered]
standingWords=["Cover needed"]
props={{ariaLabel: "Hire request, 11:00–13:00, Cover needed", style: part(4, 2, 2)}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-19",
children: <>
<Calendar.Block
name={React.string("Yoga class")}
href="../../record/"
span={span(19, "10:00", "12:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–12:00", style: placement(3, 2)}}
/>
<Calendar.Block
name={React.string("Piano lesson")}
href="../../record/"
span={span(19, "14:00", "14:30")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Piano lesson, 14:00–14:30, Cancelled", style: sized(7, 1, `calc(${hourHeight} / 2)`)}}
/>
<Calendar.Block
name={React.string("Key collection")}
href="../../record/"
span={span(19, "15:00", "15:30")}
kind="Booking"
standings=[Uncovered]
standingWords=["Cover needed"]
standing=keyCollection
props={{ariaLabel: "Key collection, 15:00–15:30, Cover needed, This booking will move when you are back online", style: sized(8, 1, `calc(${hourHeight} / 2)`)}}
/>
</>,
props: {},
},
{
key: "2025-04-20",
children: <Calendar.Block
name={React.string("Summer term choir")}
href="../../record/"
span={span(20, "10:00", "12:00")}
kind="Booking"
standings=[Preparation, Uncovered]
standingWords=["Season not confirmed", "Cover needed"]
props={{ariaLabel: "Summer term choir, 10:00–12:00, Season not confirmed, Cover needed", style: placement(3, 2)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-4812",
~name="Board meeting",
~span=span(14, "09:00", "10:00"),
~kind="Meeting",
),
item(
~key="bk-4813",
~name="Community lunch",
~span=span(14, "13:00", "13:29"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-4820",
~name="School booking for Oakmere Hall",
~span=span(15, "09:00", "11:00"),
~kind="Booking",
),
item(
~key="bk-4821",
~name="Room check",
~span=span(15, "13:00", "13:30"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-4822",
~name="Key handover",
~span=span(15, "15:00", "15:20"),
~kind="Booking",
~room="Meeting Room",
),
item(
~key="bk-4823",
~name="Room check",
~span=span(15, "16:00", "16:15"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-4825",
~name="Fire door check",
~span=span(15, "16:15", "16:30"),
~kind="Inspection",
~room="Meeting Room",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
item(
~key="bk-4824",
~name="Meter reading",
~span=span(15, "16:30", "16:35"),
~kind="Inspection",
~room="Meeting Room",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-4830",
~name="Parish council",
~span=span(16, "11:00", "12:00"),
~kind="Meeting",
),
item(
~key="in-4831",
~name="Meter reading",
~span=span(16, "13:00", "13:05"),
~kind="Inspection",
~room="Meeting Room",
),
]
/>
<Calendar.Day
day={day(17)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
day={day(18)}
items=[
item(
~key="bk-4861",
~name="Hire request",
~span=span(18, "11:00", "13:00"),
~kind="Requested",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
item(
~key="bk-4841",
~name="Wedding reception",
~span=span(18, "12:00", "15:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(19)}
items=[
item(
~key="bk-4850",
~name="Yoga class",
~span=span(19, "10:00", "12:00"),
~kind="Booking",
),
item(
~key="bk-4851",
~name="Piano lesson",
~span=span(19, "14:00", "14:30"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
{
...item(
~key="bk-4852",
~name="Key collection",
~span=span(19, "15:00", "15:30"),
~kind="Booking",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
standing: keyCollection,
},
]
/>
<Calendar.Day
day={day(20)}
items=[
item(
~key="bk-4871",
~name="Summer term choir",
~span=span(20, "10:00", "12:00"),
~kind="Booking",
~standings=[Preparation, Uncovered],
~standingWords=["Season not confirmed", "Cover needed"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, long-hoursOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let offsetSized = (row, span, offset, size) =>
ReactDOM.Style.unsafeAddProp(sized(row, span, size), "--kit-calendar-block-offset", offset)
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-long-hours"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-long-hours-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 20}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-long-hours-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-long-hours-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-long-hours-scope"},
controlProps: {id: "calendar-long-hours-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-long-hours-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-long-hours-room"},
controlProps: {id: "calendar-long-hours-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-long-hours-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-long-hours-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
head(19),
head(20),
]
hours=[
hour(7),
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
hour(18),
hour(19),
hour(20),
hour(21),
hour(22),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span(14, "09:30", "11:30")}
kind="Booking"
props={{ariaLabel: "Toddler group, 09:30–11:30",
style: offsetSized(
3,
3,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 2)`,
),
}}
/>
<Calendar.Block
name={React.string("Badminton club")}
href="../../../record/"
span={span(14, "19:00", "21:00")}
kind="Booking"
props={{ariaLabel: "Badminton club, 19:00–21:00", style: placement(13, 2)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <>
<Calendar.Block
name={React.string("Art class")}
href="../../../record/"
span={span(15, "10:00", "12:00")}
kind="Booking"
props={{ariaLabel: "Art class, 10:00–12:00", style: placement(4, 2)}}
/>
<Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span(15, "18:30", "20:00")}
kind="Booking"
props={{ariaLabel: "Choir rehearsal, 18:30–20:00",
style: offsetSized(
12,
2,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 1.5)`,
),
}}
/>
<Calendar.CurrentTime
props={{
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
`calc(7.5 * ${hourHeight})`,
),
}}
/>
</>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Block
name={React.string("Lunch club")}
href="../../../record/"
span={span(16, "13:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Lunch club, 13:00–15:00", style: placement(7, 2)}}
/>
<Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span={span(16, "19:30", "21:30")}
kind="Meeting"
props={{ariaLabel: "Parish council, 19:30–21:30",
style: offsetSized(
13,
3,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 2)`,
),
}}
/>
</>,
props: {},
},
{
key: "2025-04-17",
children: <Calendar.Block
name={React.string("Brownies")}
href="../../../record/"
span={span(17, "17:30", "19:00")}
kind="Booking"
props={{ariaLabel: "Brownies, 17:30–19:00",
style: offsetSized(
11,
2,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 1.5)`,
),
}}
/>,
props: {},
},
{
key: "2025-04-18",
children: <>
<Calendar.Block
name={React.string("Hall inspection")}
href="../../../record/"
span={span(18, "09:00", "10:00")}
kind="Inspection"
props={{ariaLabel: "Hall inspection, 09:00–10:00", style: placement(3, 1)}}
/>
<Calendar.Block
name={React.string("Quiz night")}
href="../../../record/"
span={span(18, "20:00", "22:00")}
kind="Booking"
props={{ariaLabel: "Quiz night, 20:00–22:00", style: placement(14, 2)}}
/>
</>,
props: {},
},
{
key: "2025-04-19",
children: <Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span={span(19, "11:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Wedding reception, 11:00–15:00", style: placement(5, 4)}}
/>,
props: {},
},
{
key: "2025-04-20",
children: <>
<Calendar.Block
name={React.string("Morning service")}
href="../../../record/"
span={span(20, "08:00", "09:30")}
kind="Booking"
props={{ariaLabel: "Morning service, 08:00–09:30", style: sized(2, 2, `calc(${hourHeight} * 1.5)`)}}
/>
<Calendar.Block
name={React.string("Birthday party")}
href="../../../record/"
span={span(20, "16:00", "18:00")}
kind="Booking"
props={{ariaLabel: "Birthday party, 16:00–18:00", style: placement(10, 2)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6101",
~name="Toddler group",
~span=span(14, "09:30", "11:30"),
~kind="Booking",
),
item(
~key="bk-6102",
~name="Badminton club",
~span=span(14, "19:00", "21:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-6103",
~name="Art class",
~span=span(15, "10:00", "12:00"),
~kind="Booking",
),
item(
~key="bk-6104",
~name="Choir rehearsal",
~span=span(15, "18:30", "20:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-6105",
~name="Lunch club",
~span=span(16, "13:00", "15:00"),
~kind="Booking",
),
item(
~key="bk-6106",
~name="Parish council",
~span=span(16, "19:30", "21:30"),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-6107",
~name="Brownies",
~span=span(17, "17:30", "19:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(18)}
items=[
item(
~key="bk-6108",
~name="Hall inspection",
~span=span(18, "09:00", "10:00"),
~kind="Inspection",
~room="Main Hall",
),
item(
~key="bk-6109",
~name="Quiz night",
~span=span(18, "20:00", "22:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(19)}
items=[
item(
~key="bk-6110",
~name="Wedding reception",
~span=span(19, "11:00", "15:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(20)}
items=[
item(
~key="bk-6111",
~name="Morning service",
~span=span(20, "08:00", "09:30"),
~kind="Booking",
),
item(
~key="bk-6112",
~name="Birthday party",
~span=span(20, "16:00", "18:00"),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, early-nowOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let offsetSized = (row, span, offset, size) =>
ReactDOM.Style.unsafeAddProp(sized(row, span, size), "--kit-calendar-block-offset", offset)
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-early-now"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-early-now-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 20}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-early-now-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-early-now-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-early-now-scope"},
controlProps: {id: "calendar-early-now-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-early-now-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-early-now-room"},
controlProps: {id: "calendar-early-now-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-early-now-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-early-now-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
head(19),
head(20),
]
hours=[
hour(7),
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
hour(18),
hour(19),
hour(20),
hour(21),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Slimming group")}
href="../../../record/"
span={span(14, "09:30", "11:00")}
kind="Booking"
props={{ariaLabel: "Slimming group, 09:30–11:00",
style: offsetSized(
3,
2,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 1.5)`,
),
}}
/>
<Calendar.Block
name={React.string("Youth club")}
href="../../../record/"
span={span(14, "18:00", "20:00")}
kind="Booking"
props={{ariaLabel: "Youth club, 18:00–20:00", style: placement(12, 2)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <>
<Calendar.Block
name={React.string("Baby clinic")}
href="../../../record/"
span={span(15, "09:00", "12:00")}
kind="Booking"
props={{ariaLabel: "Baby clinic, 09:00–12:00", style: placement(3, 3)}}
/>
<Calendar.Block
name={React.string("Table tennis")}
href="../../../record/"
span={span(15, "19:00", "20:30")}
kind="Booking"
props={{ariaLabel: "Table tennis, 19:00–20:30", style: sized(13, 2, `calc(${hourHeight} * 1.5)`)}}
/>
</>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Block
name={React.string("Coffee morning")}
href="../../../record/"
span={span(16, "10:00", "11:30")}
kind="Booking"
props={{ariaLabel: "Coffee morning, 10:00–11:30", style: sized(4, 2, `calc(${hourHeight} * 1.5)`)}}
/>
<Calendar.Block
name={React.string("Trustees meeting")}
href="../../../record/"
span={span(16, "14:00", "15:30")}
kind="Meeting"
props={{ariaLabel: "Trustees meeting, 14:00–15:30", style: sized(8, 2, `calc(${hourHeight} * 1.5)`)}}
/>
<Calendar.CurrentTime
props={{
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
`calc(2.25 * ${hourHeight})`,
),
}}
/>
</>,
props: {},
},
{
key: "2025-04-17",
children: <Calendar.Block
name={React.string("Craft club")}
href="../../../record/"
span={span(17, "13:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Craft club, 13:00–15:00", style: placement(7, 2)}}
/>,
props: {},
},
{
key: "2025-04-18",
children: <>
<Calendar.Block
name={React.string("Hall deep clean")}
href="../../../record/"
span={span(18, "08:00", "09:00")}
kind="Inspection"
props={{ariaLabel: "Hall deep clean, 08:00–09:00", style: placement(2, 1)}}
/>
<Calendar.Block
name={React.string("Film night")}
href="../../../record/"
span={span(18, "19:00", "21:00")}
kind="Booking"
props={{ariaLabel: "Film night, 19:00–21:00", style: placement(13, 2)}}
/>
</>,
props: {},
},
{
key: "2025-04-19",
children: <Calendar.Block
name={React.string("Christening party")}
href="../../../record/"
span={span(19, "12:00", "16:00")}
kind="Booking"
props={{ariaLabel: "Christening party, 12:00–16:00", style: placement(6, 4)}}
/>,
props: {},
},
{
key: "2025-04-20",
children: <Calendar.Block
name={React.string("Art exhibition")}
href="../../../record/"
span={span(20, "11:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Art exhibition, 11:00–15:00", style: placement(5, 4)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6201",
~name="Slimming group",
~span=span(14, "09:30", "11:00"),
~kind="Booking",
),
item(
~key="bk-6202",
~name="Youth club",
~span=span(14, "18:00", "20:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-6203",
~name="Baby clinic",
~span=span(15, "09:00", "12:00"),
~kind="Booking",
),
item(
~key="bk-6204",
~name="Table tennis",
~span=span(15, "19:00", "20:30"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-6205",
~name="Coffee morning",
~span=span(16, "10:00", "11:30"),
~kind="Booking",
),
item(
~key="bk-6206",
~name="Trustees meeting",
~span=span(16, "14:00", "15:30"),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-6207",
~name="Craft club",
~span=span(17, "13:00", "15:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(18)}
items=[
item(
~key="bk-6208",
~name="Hall deep clean",
~span=span(18, "08:00", "09:00"),
~kind="Inspection",
~room="Main Hall",
),
item(
~key="bk-6209",
~name="Film night",
~span=span(18, "19:00", "21:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(19)}
items=[
item(
~key="bk-6210",
~name="Christening party",
~span=span(19, "12:00", "16:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(20)}
items=[
item(
~key="bk-6211",
~name="Art exhibition",
~span=span(20, "11:00", "15:00"),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, bandsOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let band = (name, first, last, stack): DeskGrid.band => {
name: React.string(name),
href: Some("../../../record/"),
first,
last,
stack,
props: {},
}
let placement = (row, span) => ({gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let bandRow = (key, name): Calendar.bandRow => {
key,
name: React.string(name),
href: Some("../../../record/"),
state: None,
props: {},
}
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
let nothing = <p> {React.string("Nothing booked")} </p>
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-bands"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-bands-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 18}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-bands-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-bands-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-bands-scope"},
controlProps: {id: "calendar-bands-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-bands-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-bands-room"},
controlProps: {id: "calendar-bands-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-bands-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-bands-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
]
bands=[
band("Hall closed for rewiring", 2, 4, 1),
band("Spring fair", 5, 5, 1),
band("Oakmere Primary School summer fair rehearsal", 5, 5, 2),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span={span(14, "09:00", "10:00")}
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(1, 1)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(15, "11:00", "12:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 11:00–12:00", style: placement(3, 1)}}
/>,
props: {},
},
{key: "2025-04-16", children: React.null, props: {}},
{key: "2025-04-17", children: React.null, props: {}},
{
key: "2025-04-18",
children: <>
<Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span(18, "10:00", "11:30")}
kind="Booking"
props={{ariaLabel: "Choir rehearsal, 10:00–11:30", style: sized(2, 2, "calc(var(--kit-hour-height) * 1.5)")}}
/>
<Calendar.Block
name={React.string("Hall handover")}
href="../../../record/"
span={span(18, "13:00", "14:00")}
kind="Booking"
props={{ariaLabel: "Hall handover, 13:00–14:00", style: placement(5, 1)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5901",
~name="Board meeting",
~span=span(14, "09:00", "10:00"),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(15)}
bands=[bandRow("cl-118", "Hall closed for rewiring")]
items=[
item(
~key="bk-5902",
~name="Yoga class",
~span=span(15, "11:00", "12:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
bands=[bandRow("cl-118", "Hall closed for rewiring")]
empty=nothing
/>
<Calendar.Day
day={day(17)}
bands=[bandRow("cl-118", "Hall closed for rewiring")]
empty=nothing
/>
<Calendar.Day
day={day(18)}
bands=[
bandRow("bk-5905", "Spring fair"),
bandRow("bk-5906", "Oakmere Primary School summer fair rehearsal"),
]
items=[
item(
~key="bk-5903",
~name="Choir rehearsal",
~span=span(18, "10:00", "11:30"),
~kind="Booking",
),
item(
~key="bk-5904",
~name="Hall handover",
~span=span(18, "13:00", "14:00"),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, partial-day-closureOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span) => ({gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-partial-day-closure"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-closure-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-partial-day-closure-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-closure-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-closure-scope"},
controlProps: {id: "calendar-closure-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-closure-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-closure-room"},
controlProps: {id: "calendar-closure-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-partial-day-closure-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-partial-day-closure-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Closure
name={React.string("Hall closed for floor cleaning")}
href="../../../record/"
props={{style: placement(4, 2)}}
/>
<Calendar.Block
name={React.string("Community lunch")}
href="../../../record/"
span={span(14, "13:00", "14:00")}
kind="Booking"
props={{ariaLabel: "Community lunch, 13:00–14:00", style: placement(5, 1)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(15, "10:00", "11:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Closure
name={React.string("Meeting Room closed for rewiring")}
href="../../../record/"
props={{style: sized(2, 2, "calc(var(--kit-hour-height) * 1.5)")}}
nameProps={{draggable: true}}
/>
<Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span={span(16, "11:00", "12:00")}
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(3, 1)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="cl-131",
~name="Hall closed for floor cleaning",
~span=span(14, "12:00", "14:00"),
~kind="Closure",
),
item(
~key="bk-6101",
~name="Community lunch",
~span=span(14, "13:00", "14:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-6102",
~name="Yoga class",
~span=span(15, "10:00", "11:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="cl-132",
~name="Meeting Room closed for rewiring",
~span=span(16, "10:00", "11:30"),
~kind="Closure",
),
item(
~key="bk-6103",
~name="Parish council",
~span=span(16, "11:00", "12:00"),
~kind="Meeting",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, closure-under-blockOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span, at) =>
ReactDOM.Style.unsafeAddProp(({gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t), "--kit-calendar-block-part", Int.toString(at))
let sized = (style, size) => ReactDOM.Style.unsafeAddProp(style, "--kit-calendar-block-size", size)
let offset = (style, inset) => ReactDOM.Style.unsafeAddProp(style, "--kit-calendar-block-offset", inset)
let parts = count => ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-column-parts", Int.toString(count))
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-closure-under-block"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-closure-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 18}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-closure-under-block-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-closure-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-closure-scope"},
controlProps: {id: "calendar-closure-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-closure-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-closure-room"},
controlProps: {id: "calendar-closure-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-closure-under-block-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-closure-under-block-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
]
hours=[
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
hour(18),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Closure
name={React.string("Floor repair")}
href="../../../record/"
props={{style: placement(4, 1, 2)->offset("calc(var(--kit-hour-height) / 2)")->sized("calc(var(--kit-hour-height) / 2)")}}
/>
<Calendar.Block
name={React.string("Teen jazz")}
href="../../../record/"
span={span(14, "16:00", "17:00")}
kind="Class"
props={{ariaLabel: "Teen jazz, 16:00–17:00", style: placement(4, 1, 1)}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-15",
children: <>
<Calendar.Closure
name={React.string("Fire drill")}
href="../../../record/"
props={{style: placement(2, 1, 2)->sized("calc(var(--kit-hour-height) / 4)")}}
/>
<Calendar.Block
name={React.string("Junior ballet")}
href="../../../record/"
span={span(15, "14:00", "14:30")}
kind="Class"
props={{ariaLabel: "Junior ballet, 14:00–14:30", style: placement(2, 1, 1)->sized("calc(var(--kit-hour-height) / 2)")}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-16",
children: <>
<Calendar.Closure
name={React.string("Sound system check")}
href="../../../record/"
props={{style: placement(1, 2, 2)->offset("calc(var(--kit-hour-height) / 2)")->sized("var(--kit-hour-height)")}}
/>
<Calendar.Block
name={React.string("Adult contemporary")}
href="../../../record/"
span={span(16, "13:00", "15:00")}
kind="Class"
props={{ariaLabel: "Adult contemporary, 13:00–15:00", style: placement(1, 2, 1)}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-17",
children: <>
<Calendar.Closure
name={React.string("Heating maintenance")}
href="../../../record/"
props={{style: placement(4, 2, 2)}}
/>
<Calendar.Block
name={React.string("Ballroom")}
href="../../../record/"
span={span(17, "15:30", "16:30")}
kind="Class"
props={{ariaLabel: "Ballroom, 15:30–16:30", style: placement(3, 2, 1)->offset("calc(var(--kit-hour-height) / 2)")->sized("var(--kit-hour-height)")}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-18",
children: <>
<Calendar.Closure
name={React.string("Mirror cleaning")}
href="../../../record/"
props={{style: placement(2, 1, 3)->offset("calc(var(--kit-hour-height) / 2)")->sized("calc(var(--kit-hour-height) / 2)")}}
/>
<Calendar.Block
name={React.string("Hip hop")}
href="../../../record/"
span={span(18, "14:00", "15:00")}
kind="Class"
props={{ariaLabel: "Hip hop, 14:00–15:00", style: placement(2, 1, 1)}}
/>
<Calendar.Block
name={React.string("Tap")}
href="../../../record/"
span={span(18, "14:30", "15:30")}
kind="Class"
props={{ariaLabel: "Tap, 14:30–15:30", style: placement(2, 2, 2)->offset("calc(var(--kit-hour-height) / 2)")->sized("var(--kit-hour-height)")}}
/>
</>,
props: {style: parts(3)},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(~key="bk-7101", ~name="Teen jazz", ~span=span(14, "16:00", "17:00"), ~kind="Class"),
item(~key="cl-171", ~name="Floor repair", ~span=span(14, "16:30", "17:00"), ~kind="Closure"),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(~key="cl-172", ~name="Fire drill", ~span=span(15, "14:00", "14:15"), ~kind="Closure"),
item(~key="bk-7102", ~name="Junior ballet", ~span=span(15, "14:00", "14:30"), ~kind="Class"),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(~key="bk-7103", ~name="Adult contemporary", ~span=span(16, "13:00", "15:00"), ~kind="Class"),
item(~key="cl-173", ~name="Sound system check", ~span=span(16, "13:30", "14:30"), ~kind="Closure"),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(~key="bk-7104", ~name="Ballroom", ~span=span(17, "15:30", "16:30"), ~kind="Class"),
item(~key="cl-174", ~name="Heating maintenance", ~span=span(17, "16:00", "18:00"), ~kind="Closure"),
]
/>
<Calendar.Day
day={day(18)}
items=[
item(~key="bk-7105", ~name="Hip hop", ~span=span(18, "14:00", "15:00"), ~kind="Class"),
item(~key="cl-175", ~name="Mirror cleaning", ~span=span(18, "14:30", "15:00"), ~kind="Closure"),
item(~key="bk-7106", ~name="Tap", ~span=span(18, "14:30", "15:30"), ~kind="Class"),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, whole-day-closureOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let band = (name, first, last, stack): DeskGrid.band => {
name: React.string(name),
href: Some("../../../record/"),
first,
last,
stack,
props: {},
}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let offsetSized = (row, span, offset, size) =>
ReactDOM.Style.unsafeAddProp(sized(row, span, size), "--kit-calendar-block-offset", offset)
let hourHeight = "var(--kit-hour-height)"
let bandRow = (key, name): Calendar.bandRow => {
key,
name: React.string(name),
href: Some("../../../record/"),
state: None,
props: {},
}
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-whole-day-closure"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 20}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-whole-day-closure-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-scope"},
controlProps: {id: "calendar-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-scope-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-scope-room"},
controlProps: {id: "calendar-scope-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-whole-day-closure-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-whole-day-closure-view", value: "week", options: Two({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
head(19),
head(20),
]
bands=[
band("Hall closed for rewiring", 4, 4, 1),
band("Hall closed for resurfacing", 6, 6, 1),
]
hours=[
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span={span(14, "09:00", "10:00")}
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(15, "10:00", "11:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(3, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span={span(16, "11:00", "12:00")}
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(4, 1)}}
/>,
props: {},
},
{
key: "2025-04-17",
children: <>
<Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span(17, "09:30", "11:00")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Toddler group, 09:30–11:00, Cancelled",
style: offsetSized(
2,
2,
`calc(${hourHeight} / 2)`,
`calc(${hourHeight} * 1.5)`,
),
}}
/>
<Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span(17, "14:00", "15:30")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Choir rehearsal, 14:00–15:30, Cancelled", style: sized(7, 2, `calc(${hourHeight} * 1.5)`)}}
/>
</>,
props: {},
},
{
key: "2025-04-18",
children: <Calendar.Block
name={React.string("Wedding rehearsal")}
href="../../../record/"
span={span(18, "12:00", "13:00")}
kind="Booking"
props={{ariaLabel: "Wedding rehearsal, 12:00–13:00", style: placement(5, 1)}}
/>,
props: {},
},
{
key: "2025-04-19",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(19, "10:00", "11:00")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Yoga class, 10:00–11:00, Cancelled", style: placement(3, 1)}}
/>,
props: {},
},
{
key: "2025-04-20",
children: <Calendar.Block
name={React.string("Sunday service")}
href="../../../record/"
span={span(20, "10:00", "11:30")}
kind="Booking"
props={{ariaLabel: "Sunday service, 10:00–11:30", style: sized(3, 2, `calc(${hourHeight} * 1.5)`)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6001",
~name="Board meeting",
~span=span(14, "09:00", "10:00"),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-6002",
~name="Yoga class",
~span=span(15, "10:00", "11:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-6003",
~name="Parish council",
~span=span(16, "11:00", "12:00"),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
bands=[bandRow("cl-124", "Hall closed for rewiring")]
items=[
item(
~key="bk-6004",
~name="Toddler group",
~span=span(17, "09:30", "11:00"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
item(
~key="bk-6005",
~name="Choir rehearsal",
~span=span(17, "14:00", "15:30"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
]
/>
<Calendar.Day
day={day(18)}
items=[
item(
~key="bk-6006",
~name="Wedding rehearsal",
~span=span(18, "12:00", "13:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(19)}
bands=[bandRow("cl-125", "Hall closed for resurfacing")]
items=[
item(
~key="bk-6007",
~name="Yoga class",
~span=span(19, "10:00", "11:00"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
]
/>
<Calendar.Day
day={day(20)}
items=[
item(
~key="bk-6008",
~name="Sunday service",
~span=span(20, "10:00", "11:30"),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, overlapOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let part = (row, span, at) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-part", Int.toString(at))
let parts = count =>
ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-column-parts", Int.toString(count))
let hourHeight = "var(--kit-hour-height)"
let band = (name, stack): DeskGrid.band => {
name: React.string(name),
href: Some("../../../record/"),
first: 1,
last: 1,
stack,
props: {},
}
let bandRow = (key, name): Calendar.bandRow => {
key,
name: React.string(name),
href: Some("../../../record/"),
state: None,
props: {},
}
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-overlap"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-overlap-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-overlap-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-overlap-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-overlap-scope"},
controlProps: {id: "calendar-overlap-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-overlap-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-overlap-room"},
controlProps: {id: "calendar-overlap-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-overlap-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-overlap-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
]
bands=[band("Open day", 1), band("Meeting Room decorated", 2)]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(14, "10:00", "11:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>
<Calendar.Folded
name={React.string("3 items")}
href="../day-rooms/"
props={{ariaLabel: "3 items, 11:00–12:00", style: placement(3, 1)}}
/>
<Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span={span(14, "12:00", "15:00")}
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: placement(4, 3)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(15, "10:00", "11:00")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span(16, "09:00", "11:00")}
kind="Booking"
props={{ariaLabel: "Toddler group, 09:00–11:00", style: part(1, 2, 1)}}
/>
<Calendar.Block
name={React.string("Fire inspection")}
href="../../../record/"
span={span(16, "09:30", "10:30")}
kind="Inspection"
props={{ariaLabel: "Fire inspection, 09:30–10:30",
style: ReactDOM.Style.unsafeAddProp(
ReactDOM.Style.unsafeAddProp(
part(1, 2, 2),
"--kit-calendar-block-offset",
`calc(${hourHeight} / 2)`,
),
"--kit-calendar-block-size",
hourHeight,
),
}}
/>
</>,
props: {style: parts(2)},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
bands=[bandRow("ev-207", "Open day"), bandRow("wk-311", "Meeting Room decorated")]
items=[
item(
~key="bk-6201",
~name="Yoga class",
~span=span(14, "10:00", "11:00"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6202",
~name="Hire request",
~span=span(14, "11:00", "12:00"),
~kind="Requested",
),
item(
~key="bk-6203",
~name="Parish council",
~span=span(14, "11:00", "12:00"),
~kind="Meeting",
~room="Meeting Room",
),
item(
~key="bk-6204",
~name="Community lunch",
~span=span(14, "11:30", "12:00"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6205",
~name="Wedding reception",
~span=span(14, "12:00", "15:00"),
~kind="Booking",
~room="Main Hall",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-6206",
~name="Yoga class",
~span=span(15, "10:00", "11:00"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-6207",
~name="Toddler group",
~span=span(16, "09:00", "11:00"),
~kind="Booking",
),
item(
~key="bk-6208",
~name="Fire inspection",
~span=span(16, "09:30", "10:30"),
~kind="Inspection",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, contiguous-runOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let row = (row): ReactDOM.Style.t => {gridRow: `${Int.toString(row)} / span 1`}
let placement = (line, size) =>
ReactDOM.Style.unsafeAddProp(row(line), "--kit-calendar-block-size", size)
let offsetPlacement = (line, offset, size) =>
ReactDOM.Style.unsafeAddProp(placement(line, size), "--kit-calendar-block-offset", offset)
let hourHeight = "var(--kit-hour-height)"
let nothing = <p> {React.string("Nothing booked")} </p>
let column = (key): DeskGrid.column => {key, children: React.null, props: {}}
let item = (~key, ~name, ~span, ~kind, ~room): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: Some(room),
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-contiguous-run"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-contiguous-run-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 20}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-contiguous-run-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-contiguous-run-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-contiguous-run-scope"},
controlProps: {id: "calendar-contiguous-run-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-contiguous-run-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-contiguous-run-room"},
controlProps: {id: "calendar-contiguous-run-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{label: React.string("Meeting Room"), value: "meeting-room", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-contiguous-run-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-contiguous-run-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
head(19),
head(20),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.FoldedRun
span={span(14, "09:00", "09:20")}
count={[KitReact.Words.Text("2 bookings")]}
href="../day-one-column/"
props={{style: placement(1, "calc(var(--kit-hour-height) / 3)")}}
/>
<Calendar.FoldedRun
span={span(14, "10:00", "10:35")}
count={[KitReact.Words.Text("3 room inspections")]}
href="../day-one-column/"
props={{style: placement(2, "calc(var(--kit-hour-height) * 7 / 12)")}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <>
<Calendar.Block
name={React.string("Yoga")}
href="../../../record/"
span={span(15, "09:00", "09:15")}
kind="Booking"
props={{ariaLabel: "Yoga, 09:00–09:15", style: placement(1, `calc(${hourHeight} / 4)`)}}
/>
<Calendar.Block
name={React.string("Singing")}
href="../../../record/"
span={span(15, "09:45", "10:00")}
kind="Booking"
props={{ariaLabel: "Singing, 09:45–10:00",
style: offsetPlacement(1, `calc(${hourHeight} * 3 / 4)`, `calc(${hourHeight} / 4)`),
}}
/>
</>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.FoldedRun
span={span(16, "09:00", "09:45")}
count={[KitReact.Words.Text("3 bookings")]}
href="../day-one-column/"
props={{style: placement(1, `calc(${hourHeight} * 3 / 4)`)}}
/>,
props: {},
},
{
key: "2025-04-17",
children: <Calendar.FoldedRun
span={span(17, "09:00", "10:00")}
count={[KitReact.Words.Text("4 inspections")]}
href="../day-one-column/"
props={{style: row(1)}}
/>,
props: {},
},
{
key: "2025-04-18",
children: <Calendar.FoldedRun
span={span(18, "09:00", "09:30")}
count={[KitReact.Words.Text("2 inspections")]}
href="../day-one-column/"
props={{style: placement(1, `calc(${hourHeight} / 2)`)}}
/>,
props: {},
},
column("2025-04-19"),
column("2025-04-20"),
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-7101",
~name="Chair stack",
~span=span(14, "09:00", "09:10"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-7102",
~name="Trolley store",
~span=span(14, "09:10", "09:20"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-7103",
~name="Room check",
~span=span(14, "10:00", "10:10"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7104",
~name="Fire door check",
~span=span(14, "10:10", "10:20"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7105",
~name="Meter reading",
~span=span(14, "10:20", "10:35"),
~kind="Inspection",
~room="Meeting Room",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-7201",
~name="Yoga",
~span=span(15, "09:00", "09:15"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-7203",
~name="Singing",
~span=span(15, "09:45", "10:00"),
~kind="Booking",
~room="Main Hall",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-7301",
~name="Yoga",
~span=span(16, "09:00", "09:15"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-7302",
~name="Judo",
~span=span(16, "09:15", "09:30"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-7303",
~name="Singing",
~span=span(16, "09:30", "09:45"),
~kind="Booking",
~room="Main Hall",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-7401",
~name="Ramp check",
~span=span(17, "09:00", "09:15"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7402",
~name="Door widths",
~span=span(17, "09:15", "09:30"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7403",
~name="Hearing loop test",
~span=span(17, "09:30", "09:45"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7404",
~name="Signage check",
~span=span(17, "09:45", "10:00"),
~kind="Inspection",
~room="Meeting Room",
),
]
/>
<Calendar.Day
day={day(18)}
items=[
item(
~key="bk-7501",
~name="Gate check",
~span=span(18, "09:00", "09:10"),
~kind="Inspection",
~room="Meeting Room",
),
item(
~key="bk-7502",
~name="Lift check",
~span=span(18, "09:20", "09:30"),
~kind="Inspection",
~room="Meeting Room",
),
]
/>
<Calendar.Day day={day(19)} empty=nothing />
<Calendar.Day day={day(20)} empty=nothing />
</Calendar.Days>
</>}
/>
</>
Calendar, cancelledOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let offsetSized = (row, span, offset, size) =>
ReactDOM.Style.unsafeAddProp(sized(row, span, size), "--kit-calendar-block-offset", offset)
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-cancelled"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-cancelled-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-cancelled-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-cancelled-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-cancelled-scope"},
controlProps: {id: "calendar-cancelled-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-cancelled-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-cancelled-room"},
controlProps: {id: "calendar-cancelled-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-cancelled-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-cancelled-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-14", 14),
head("2025-04-15", 15),
head("2025-04-16", 16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span("2025-04-14T08:30:00Z", "2025-04-14T10:00:00Z")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Toddler group, 09:30–11:00, Cancelled",
style: offsetSized(1, 2, `calc(${hourHeight} / 2)`, `calc(${hourHeight} * 1.5)`),
}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z")}
kind="Booking"
standings=[Cancelled]
standingWords=["Cancelled"]
props={{ariaLabel: "Choir rehearsal, 12:00–13:00, Cancelled", style: placement(4, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5101",
~name="Toddler group",
~span=span("2025-04-14T08:30:00Z", "2025-04-14T10:00:00Z"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5102",
~name="Yoga class",
~span=span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5103",
~name="Choir rehearsal",
~span=span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, uncoveredOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let part = (row, span, at) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-part", Int.toString(at))
let parts = count =>
ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-column-parts", Int.toString(count))
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-uncovered"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-uncovered-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-uncovered-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-uncovered-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-uncovered-scope"},
controlProps: {id: "calendar-uncovered-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-uncovered-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-uncovered-room"},
controlProps: {id: "calendar-uncovered-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-uncovered-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-uncovered-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-14", 14),
head("2025-04-15", 15),
head("2025-04-16", 16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T09:00:00Z")}
kind="Booking"
standings=[Uncovered]
standingWords=["Cover needed"]
props={{ariaLabel: "Toddler group, 09:00–10:00, Cover needed", style: part(1, 1, 1)}}
/>
<Calendar.Block
name={React.string("Story time")}
href="../../../record/"
span={span("2025-04-14T08:30:00Z", "2025-04-14T09:00:00Z")}
kind="Booking"
standings=[Uncovered]
standingWords=["Cover needed"]
props={{ariaLabel: "Story time, 09:30–10:00, Cover needed",
style: ReactDOM.Style.unsafeAddProp(
ReactDOM.Style.unsafeAddProp(
part(1, 1, 2),
"--kit-calendar-block-offset",
`calc(${hourHeight} / 2)`,
),
"--kit-calendar-block-size",
`calc(${hourHeight} / 2)`,
),
}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Community lunch")}
href="../../../record/"
span={span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z")}
kind="Booking"
standings=[Uncovered]
standingWords=["Cover needed"]
props={{ariaLabel: "Community lunch, 12:00–13:00, Cover needed", style: placement(4, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5301",
~name="Toddler group",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T09:00:00Z"),
~kind="Booking",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
item(
~key="bk-5304",
~name="Story time",
~span=span("2025-04-14T08:30:00Z", "2025-04-14T09:00:00Z"),
~kind="Booking",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5302",
~name="Yoga class",
~span=span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5303",
~name="Community lunch",
~span=span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z"),
~kind="Booking",
~standings=[Uncovered],
~standingWords=["Cover needed"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, clashingOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let part = (row, span, at) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-part", Int.toString(at))
let parts = count =>
ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-column-parts", Int.toString(count))
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-clashing"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-clashing-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-clashing-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-clashing-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-clashing-scope"},
controlProps: {id: "calendar-clashing-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-clashing-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-clashing-room"},
controlProps: {id: "calendar-clashing-room"},
controlValue: "main-hall",
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-clashing-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-clashing-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-14", 14),
head("2025-04-15", 15),
head("2025-04-16", 16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T09:00:00Z")}
kind="Booking"
standings=[Clashing]
standingWords=["Time conflict"]
props={{ariaLabel: "Toddler group, 09:00–10:00, Time conflict", style: part(1, 1, 1)}}
/>
<Calendar.Block
name={React.string("Hall inspection")}
href="../../../record/"
span={span("2025-04-14T08:30:00Z", "2025-04-14T09:00:00Z")}
kind="Inspection"
standings=[Clashing]
standingWords=["Time conflict"]
props={{ariaLabel: "Hall inspection, 09:30–10:00, Time conflict",
style: ReactDOM.Style.unsafeAddProp(
ReactDOM.Style.unsafeAddProp(
part(1, 1, 2),
"--kit-calendar-block-offset",
`calc(${hourHeight} / 2)`,
),
"--kit-calendar-block-size",
`calc(${hourHeight} / 2)`,
),
}}
/>
</>,
props: {style: parts(2)},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span={span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z")}
kind="Meeting in 2 rooms"
standings=[Clashing]
standingWords=["Time conflict"]
props={{ariaLabel: "Parish council, 12:00–13:00, Time conflict", style: placement(4, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5501",
~name="Toddler group",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T09:00:00Z"),
~kind="Booking",
~standings=[Clashing],
~standingWords=["Time conflict"],
),
item(
~key="bk-5502",
~name="Hall inspection",
~span=span("2025-04-14T08:30:00Z", "2025-04-14T09:00:00Z"),
~kind="Inspection",
~standings=[Clashing],
~standingWords=["Time conflict"],
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5503",
~name="Yoga class",
~span=span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5504",
~name="Parish council",
~span=span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z"),
~kind="Meeting in 2 rooms",
~standings=[Clashing],
~standingWords=["Time conflict"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, coveredOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-covered"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-covered-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-covered-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-covered-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-covered-scope"},
controlProps: {id: "calendar-covered-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-covered-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-covered-room"},
controlProps: {id: "calendar-covered-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-covered-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-covered-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-14", 14),
head("2025-04-15", 15),
head("2025-04-16", 16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T09:30:00Z")}
kind="Booking"
standings=[Covered]
standingWords=["Cover arranged"]
props={{ariaLabel: "Toddler group, 09:00–10:30, Cover arranged", style: sized(1, 2, `calc(${hourHeight} * 1.5)`)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Community lunch")}
href="../../../record/"
span={span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z")}
kind="Booking"
standings=[Covered]
standingWords=["Cover arranged"]
props={{ariaLabel: "Community lunch, 12:00–13:00, Cover arranged", style: placement(4, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5201",
~name="Toddler group",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T09:30:00Z"),
~kind="Booking",
~standings=[Covered],
~standingWords=["Cover arranged"],
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5202",
~name="Yoga class",
~span=span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5203",
~name="Community lunch",
~span=span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z"),
~kind="Booking",
~standings=[Covered],
~standingWords=["Cover arranged"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, preparationOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let hourHeight = "var(--kit-hour-height)"
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-preparation"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-preparation-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-preparation-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-preparation-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-preparation-scope"},
controlProps: {id: "calendar-preparation-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-preparation-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-preparation-room"},
controlProps: {id: "calendar-preparation-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-preparation-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-preparation-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-14", 14),
head("2025-04-15", 15),
head("2025-04-16", 16),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Summer term yoga")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T09:30:00Z")}
kind="Booking"
standings=[Preparation]
standingWords=["Season not confirmed"]
props={{ariaLabel: "Summer term yoga, 09:00–10:30, Season not confirmed", style: sized(1, 2, `calc(${hourHeight} * 1.5)`)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Summer term toddler group")}
href="../../../record/"
span={span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z")}
kind="Booking"
standings=[Preparation, Uncovered]
standingWords=["Season not confirmed", "Cover needed"]
props={{ariaLabel: "Summer term toddler group, 12:00–13:00, Season not confirmed, Cover needed", style: placement(4, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5401",
~name="Summer term yoga",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T09:30:00Z"),
~kind="Booking",
~standings=[Preparation],
~standingWords=["Season not confirmed"],
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5402",
~name="Yoga class",
~span=span("2025-04-15T09:00:00Z", "2025-04-15T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5403",
~name="Summer term toddler group",
~span=span("2025-04-16T11:00:00Z", "2025-04-16T12:00:00Z"),
~kind="Booking",
~standings=[Preparation, Uncovered],
~standingWords=["Season not confirmed", "Cover needed"],
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, day-roomsOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let hours = [
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
let room = (key, name): DeskGrid.head => {
key,
column: Room(name),
props: {},
}
let band = (name, first, last, stack): DeskGrid.band => {
name: React.string(name),
href: Some("../../../record/"),
first,
last,
stack,
props: {},
}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let halfHour = row =>
placement(row, 1)
->ReactDOM.Style.unsafeAddProp("--kit-calendar-block-offset", "calc(var(--kit-hour-height) / 2)")
->ReactDOM.Style.unsafeAddProp("--kit-calendar-block-size", "calc(var(--kit-hour-height) / 2)")
let currentTime: DeskGrid.currentTime = {
props: {
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
"calc(3.5 * var(--kit-hour-height))",
),
},
}
let bandRow = (key, name): Calendar.bandRow => {
key,
name: React.string(name),
href: Some("../../../record/"),
state: None,
props: {},
}
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
let view = id =>
<KitReact.Roles.FormGroup
id={id ++ "-form-group"}
label={React.string("View")}
kind={KitReact.Roles.SegmentedControl.controlSet({name: id, value: "day", options: Three({value: "day", content: React.string("Day")}, {value: "week", content: React.string("Week")}, {value: "month", content: React.string("Month")})})}
/>
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-day-rooms"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-day-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: day(14),
today: {label: "Today", props: {}},
previous: {label: "Previous day", href: "?day=previous", props: {rel: "prev"}},
next: {label: "Next day", href: "?day=next", props: {rel: "next"}},
date: {group: {id: "calendar-day-rooms-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-day-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-day-scope"},
controlProps: {id: "calendar-day-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-day-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-day-room"},
controlProps: {id: "calendar-day-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
{
label: React.string("Meeting Room"),
value: "meeting-room",
props: {},
},
],
}),
]
view={view("calendar-day-view")}
actions={content: [newBooking]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
room("unassigned", "No room yet"),
room("main-hall", "Main Hall"),
room("meeting-room", "Meeting Room"),
room("memorial-room", "Memorial Room"),
]
bands=[band("Open day", 1, 4, 1), band("Meeting Room decorated", 3, 3, 2)]
hours
currentTime
columns=[
{
key: "unassigned",
children: <Calendar.Block
name={React.string("Hire request")}
href="../../../record/"
span={span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z")}
kind="Requested"
props={{ariaLabel: "Hire request, 11:00–12:00", style: placement(3, 1)}}
/>,
props: {},
},
{
key: "main-hall",
children: <>
<Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-14T09:00:00Z", "2025-04-14T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>
<Calendar.Block
name={React.string("Community lunch")}
href="../../../record/"
span={span("2025-04-14T10:30:00Z", "2025-04-14T11:00:00Z")}
kind="Booking"
props={{ariaLabel: "Community lunch, 11:30–12:00", style: halfHour(3)}}
/>
<Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span={span("2025-04-14T11:00:00Z", "2025-04-14T14:00:00Z")}
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: placement(4, 3)}}
/>
</>,
props: {},
},
{
key: "meeting-room",
children: <Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span={span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z")}
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(3, 1)}}
/>,
props: {},
},
{key: "memorial-room", children: React.null, props: {}},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
bands=[bandRow("ev-207", "Open day"), bandRow("wk-311", "Meeting Room decorated")]
items=[
item(
~key="bk-6301",
~name="Yoga class",
~span=span("2025-04-14T09:00:00Z", "2025-04-14T10:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6302",
~name="Hire request",
~span=span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z"),
~kind="Requested",
),
item(
~key="bk-6303",
~name="Parish council",
~span=span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z"),
~kind="Meeting",
~room="Meeting Room",
),
item(
~key="bk-6304",
~name="Community lunch",
~span=span("2025-04-14T10:30:00Z", "2025-04-14T11:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6305",
~name="Wedding reception",
~span=span("2025-04-14T11:00:00Z", "2025-04-14T14:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, day-one-columnOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let currentTime: DeskGrid.currentTime = {
props: {
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
"calc(3.5 * var(--kit-hour-height))",
),
},
}
let hours = [
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
let view = id =>
<KitReact.Roles.FormGroup
id={id ++ "-form-group"}
label={React.string("View")}
kind={KitReact.Roles.SegmentedControl.controlSet({name: id, value: "day", options: Three({value: "day", content: React.string("Day")}, {value: "week", content: React.string("Week")}, {value: "month", content: React.string("Month")})})}
/>
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-day-one-column"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-day-one-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Memorial Hall calendar controls"}}
range={
days: day(14),
today: {label: "Today", props: {}},
previous: {label: "Previous day", href: "?day=previous", props: {rel: "prev"}},
next: {label: "Next day", href: "?day=next", props: {rel: "next"}},
date: {group: {id: "calendar-day-one-column-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-day-one-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-day-one-scope"},
controlProps: {id: "calendar-day-one-scope"},
options: [
{label: React.string("Memorial Hall"), value: "memorial", props: {}},
],
}),
FormGroup({id: "calendar-day-one-kind-form-group",
kind: Select,
label: React.string("Kind"),
labelProps: {htmlFor: "calendar-day-one-kind"},
controlProps: {id: "calendar-day-one-kind"},
options: [
{label: React.string("All kinds"), value: "all", props: {}},
{label: React.string("Bookings"), value: "booking", props: {}},
],
}),
]
view={view("calendar-day-one-view")}
actions={content: [newBooking]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[{key: "2025-04-14", column: Day(day(14)), props: {}}]
hours
currentTime
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Art class")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Art class, 09:00–11:00", style: placement(1, 2)}}
/>
<Calendar.Block
name={React.string("Whist drive")}
href="../../../record/"
span={span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z")}
kind="Booking"
props={{ariaLabel: "Whist drive, 13:00–15:00", style: placement(5, 2)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6401",
~name="Art class",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z"),
~kind="Booking",
),
item(
~key="bk-6402",
~name="Whist drive",
~span=span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z"),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, monthOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module MonthCell = Calendar.MonthCell
let reader = Specimen_Reader.reader
let on = (month, day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month, day})
let day = day => on(4, day)
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let booking = (name, start, standings): MonthCell.item => {
name,
href: "../../../record/",
start: KitReact.Time.timeOfDay(reader, Date.fromString(start)),
standings,
props: {},
}
let item = (~key, ~name, ~span, ~kind, ~room=?, ~standings=[], ~standingWords=[]): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
room,
state: None,
props: {},
}
let weekdays =
[
("monday", "Mon"),
("tuesday", "Tue"),
("wednesday", "Wed"),
("thursday", "Thu"),
("friday", "Fri"),
("saturday", "Sat"),
("sunday", "Sun"),
]->Array.map(((key, day)): Calendar.MonthGrid.head => {
key,
heading: <strong> {React.string(day)} </strong>,
props: {},
})
let number = date => KitReact.Time.dayNumber(reader, {year: 2025, month: 4, day: date})
let outside = (month, date) =>
<MonthCell key={`${Int.toString(month)}-${Int.toString(date)}`} day={KitReact.Time.shortDate(reader, {year: 2025, month, day: date})} />
let plain = (date, month) =>
<MonthCell
key={Int.toString(date)}
day={number(date)}
new={`New booking on ${Int.toString(date)} ${month} 2025`}
/>
let one = (date, month, name, start) =>
<MonthCell
key={Int.toString(date)}
day={number(date)}
items=[booking(name, start, [])]
new={`New booking on ${Int.toString(date)} ${month} 2025`}
/>
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-month"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-month-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.month(reader, ~year=2025, ~month=4),
today: {label: "Today", props: {}},
previous: {label: "Previous month", href: "?month=previous", props: {rel: "prev"}},
next: {label: "Next month", href: "?month=next", props: {rel: "next"}},
date: {group: {id: "calendar-month-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 1})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 1}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-month-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-month-scope"},
controlProps: {id: "calendar-month-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-month-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-month-room"},
controlProps: {id: "calendar-month-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-month-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-month-view", value: "month", options: Three({value: "month", content: React.string("Month")}, {value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<Calendar.MonthGrid subjectRegion columns=7 columnHeads=weekdays>
<>
{outside(3, 31)}
{one(1, "April", "Toddler group", "2025-04-01T08:30:00Z")}
<MonthCell key="2" day={number(2)} />
{one(3, "April", "Parish council", "2025-04-03T18:00:00Z")}
{plain(4, "April")}
{one(5, "April", "Birthday party", "2025-04-05T13:00:00Z")}
{plain(6, "April")}
{plain(7, "April")}
{one(8, "April", "Toddler group", "2025-04-08T08:30:00Z")}
{plain(9, "April")}
{one(10, "April", "Yoga class", "2025-04-10T09:00:00Z")}
{plain(11, "April")}
{one(12, "April", "Wedding reception", "2025-04-12T11:00:00Z")}
{plain(13, "April")}
<MonthCell
key="14"
day={number(14)}
bands=[
{key: "ev-207", name: React.string("Open day"), href: "../../../record/", props: {}},
{
key: "wk-311",
name: React.string("Meeting Room decorated"),
href: "../../../record/",
props: {},
},
]
items=[booking("Yoga class", "2025-04-14T09:00:00Z", [])]
folded={{name: React.string("4 more"), href: "../day-rooms/", props: {}}}
/>
<MonthCell
key="15"
day={number(15)}
bands=[
{
key: "cl-118",
name: React.string("Hall closed for rewiring"),
href: "../../../record/",
props: {},
},
]
items=[booking("Key handover", "2025-04-15T14:00:00Z", [])]
new="New booking on 15 April 2025"
/>
<MonthCell
key="16"
day={number(16)}
items=[
booking("Parish council", "2025-04-16T10:00:00Z", []),
booking("Choir rehearsal", "2025-04-16T17:00:00Z", [Cancelled]),
]
new="New booking on 16 April 2025"
/>
{plain(17, "April")}
{plain(18, "April")}
{one(19, "April", "Birthday party", "2025-04-19T13:00:00Z")}
{plain(20, "April")}
{plain(21, "April")}
{one(22, "April", "Toddler group", "2025-04-22T08:30:00Z")}
{plain(23, "April")}
{one(24, "April", "Yoga class", "2025-04-24T09:00:00Z")}
{plain(25, "April")}
{one(26, "April", "Village fair planning", "2025-04-26T09:00:00Z")}
{plain(27, "April")}
{plain(28, "April")}
{one(29, "April", "Toddler group", "2025-04-29T08:30:00Z")}
{plain(30, "April")}
{outside(5, 1)}
{outside(5, 2)}
{outside(5, 3)}
{outside(5, 4)}
</>
</Calendar.MonthGrid>
<Calendar.Days subjectRegion>
<Calendar.Day
key="2025-04-01"
day={day(1)}
items=[
item(
~key="bk-6501",
~name="Toddler group",
~span=span("2025-04-01T08:30:00Z", "2025-04-01T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-02"
day={day(2)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-03"
day={day(3)}
items=[
item(
~key="bk-6502",
~name="Parish council",
~span=span("2025-04-03T18:00:00Z", "2025-04-03T19:30:00Z"),
~kind="Meeting",
),
]
/>
<Calendar.Day
key="2025-04-04"
day={day(4)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-05"
day={day(5)}
items=[
item(
~key="bk-6503",
~name="Birthday party",
~span=span("2025-04-05T13:00:00Z", "2025-04-05T15:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-06"
day={day(6)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-07"
day={day(7)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-08"
day={day(8)}
items=[
item(
~key="bk-6504",
~name="Toddler group",
~span=span("2025-04-08T08:30:00Z", "2025-04-08T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-09"
day={day(9)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-10"
day={day(10)}
items=[
item(
~key="bk-6505",
~name="Yoga class",
~span=span("2025-04-10T09:00:00Z", "2025-04-10T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-11"
day={day(11)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-12"
day={day(12)}
items=[
item(
~key="bk-6506",
~name="Wedding reception",
~span=span("2025-04-12T11:00:00Z", "2025-04-12T14:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-13"
day={day(13)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-14"
day={day(14)}
bands=[
{
key: "ev-207",
name: React.string("Open day"),
href: Some("../../../record/"),
state: None,
props: {},
},
{
key: "wk-311",
name: React.string("Meeting Room decorated"),
href: Some("../../../record/"),
state: None,
props: {},
},
]
items=[
item(
~key="bk-6507",
~name="Yoga class",
~span=span("2025-04-14T09:00:00Z", "2025-04-14T10:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6508",
~name="Hire request",
~span=span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z"),
~kind="Requested",
),
item(
~key="bk-6509",
~name="Parish council",
~span=span("2025-04-14T10:00:00Z", "2025-04-14T11:00:00Z"),
~kind="Meeting",
~room="Meeting Room",
),
item(
~key="bk-6510",
~name="Community lunch",
~span=span("2025-04-14T10:30:00Z", "2025-04-14T11:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
item(
~key="bk-6511",
~name="Wedding reception",
~span=span("2025-04-14T11:00:00Z", "2025-04-14T14:00:00Z"),
~kind="Booking",
~room="Main Hall",
),
]
/>
<Calendar.Day
key="2025-04-15"
day={day(15)}
bands=[
{
key: "cl-118",
name: React.string("Hall closed for rewiring"),
href: Some("../../../record/"),
state: None,
props: {},
},
]
items=[
item(
~key="bk-6512",
~name="Key handover",
~span=span("2025-04-15T14:00:00Z", "2025-04-15T14:20:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-16"
day={day(16)}
items=[
item(
~key="bk-6513",
~name="Parish council",
~span=span("2025-04-16T10:00:00Z", "2025-04-16T11:30:00Z"),
~kind="Meeting",
),
item(
~key="bk-6514",
~name="Choir rehearsal",
~span=span("2025-04-16T17:00:00Z", "2025-04-16T19:00:00Z"),
~kind="Booking",
~standings=[Cancelled],
~standingWords=["Cancelled"],
),
]
/>
<Calendar.Day
key="2025-04-17"
day={day(17)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-18"
day={day(18)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-19"
day={day(19)}
items=[
item(
~key="bk-6515",
~name="Birthday party",
~span=span("2025-04-19T13:00:00Z", "2025-04-19T15:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-20"
day={day(20)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-21"
day={day(21)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-22"
day={day(22)}
items=[
item(
~key="bk-6516",
~name="Toddler group",
~span=span("2025-04-22T08:30:00Z", "2025-04-22T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-23"
day={day(23)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-24"
day={day(24)}
items=[
item(
~key="bk-6517",
~name="Yoga class",
~span=span("2025-04-24T09:00:00Z", "2025-04-24T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-25"
day={day(25)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-26"
day={day(26)}
items=[
item(
~key="bk-6518",
~name="Village fair planning",
~span=span("2025-04-26T09:00:00Z", "2025-04-26T10:30:00Z"),
~kind="Meeting",
),
]
/>
<Calendar.Day
key="2025-04-27"
day={day(27)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-28"
day={day(28)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
key="2025-04-29"
day={day(29)}
items=[
item(
~key="bk-6519",
~name="Toddler group",
~span=span("2025-04-29T08:30:00Z", "2025-04-29T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day
key="2025-04-30"
day={day(30)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
</Calendar.Days>
</>}
/>
</>
Calendar, emptyOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let day = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let head = (on): DeskGrid.head => {key: Int.toString(on), column: Day(day(on)), props: {}}
let column = (key): DeskGrid.column => {key, children: React.null, props: {}}
let nothing = <p> {React.string("Nothing booked")} </p>
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-empty"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=Some(Empty({words: [KitReact.Words.Text("Nothing booked this week. Bookings show here once they're made.")]}))
scopeId="kit-calendar-empty-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 16}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-empty-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-empty-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-empty-scope"},
controlProps: {id: "calendar-empty-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-empty-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-empty-room"},
controlProps: {id: "calendar-empty-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-empty-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-empty-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
]
hours=[
hour(7),
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
hour(18),
hour(19),
hour(20),
]
columns=[column("2025-04-14"), {...column("2025-04-15"), children: <Calendar.CurrentTime props={{style: ReactDOM.Style.unsafeAddProp({}, "--kit-calendar-now-offset", "calc(11.5 * var(--kit-hour-height))")}} />}, column("2025-04-16")]
/>
<Calendar.Days subjectRegion>
<Calendar.Day day={day(14)} empty=nothing />
<Calendar.Day day={day(15)} empty=nothing />
<Calendar.Day day={day(16)} empty=nothing />
</Calendar.Days>
</>}
/>
</>
Calendar, movingOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let hours = [
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
]
let day = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let head = (on): DeskGrid.head => {key: Int.toString(on), column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~href="../../../record/", ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some(href),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-moving"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-moving-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 17}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-moving-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-moving-scope-form-group", kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-moving-scope"},
controlProps: {id: "calendar-moving-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-moving-room-form-group", kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-moving-room"},
controlProps: {id: "calendar-moving-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-moving-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-moving-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [newBooking]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
]
hours
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z"))
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/calendar-item/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z"))
kind="Booking"
moving=true
props={{ariaLabel: "Yoga class, 10:00–12:00", draggable: true, style: placement(3, 2)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z"))
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(4, 1)}}
/>,
props: {},
},
{
key: "2025-04-17",
children: <Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z"))
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: placement(5, 3)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5701",
~name="Board meeting",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5702",
~name="Yoga class",
~href="../../../record/calendar-item/",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5703",
~name="Parish council",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-5704",
~name="Wedding reception",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z")),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, acceptingOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let hours = [
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
]
let day = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let head = (on): DeskGrid.head => {key: Int.toString(on), column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~href="../../../record/", ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some(href),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-accepting"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-accepting-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 17}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-accepting-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-accepting-scope-form-group", kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-accepting-scope"},
controlProps: {id: "calendar-accepting-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-accepting-room-form-group", kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-accepting-room"},
controlProps: {id: "calendar-accepting-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-accepting-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-accepting-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [newBooking]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
]
hours
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z"))
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(2, 1)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/calendar-item/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z"))
kind="Booking"
moving=true
props={{ariaLabel: "Yoga class, 10:00–12:00", draggable: true, style: placement(3, 2)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z"))
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(4, 1)}}
/>,
props: {},
},
{
key: "2025-04-17",
children: <>
<Calendar.DropTarget
preview={{
name: React.string("Yoga class"),
span: KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T09:00Z"), ~end=Date.fromString("2025-04-17T11:00Z")),
kind: "Booking",
}}
standing=Accepting
props={{style: placement(3, 2)}}
/>
<Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z"))
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: placement(5, 3)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5601",
~name="Board meeting",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5602",
~name="Yoga class",
~href="../../../record/calendar-item/",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5603",
~name="Parish council",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-5604",
~name="Wedding reception",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z")),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, refusedOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let newBooking =
Calendar.PrimaryAction({children: React.string("New booking")})
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let hours = [
hour(8),
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
hour(15),
hour(16),
hour(17),
]
let day = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let head = (on): DeskGrid.head => {key: Int.toString(on), column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let yoga = (span): Calendar.preview => {
name: React.string("Yoga class"),
span,
kind: "Booking",
}
let item = (~key, ~href="../../../record/", ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some(href),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-refused"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-refused-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 17}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-refused-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-refused-scope-form-group", kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-refused-scope"},
controlProps: {id: "calendar-refused-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-refused-room-form-group", kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-refused-room"},
controlProps: {id: "calendar-refused-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-refused-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-refused-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [newBooking]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
]
hours
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z"))
kind="Meeting"
props={{ariaLabel: "Board meeting, 09:00–10:00", style: placement(2, 1)}}
/>
<Calendar.DropTarget
preview={yoga(KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T14:00Z"), ~end=Date.fromString("2025-04-14T16:00Z")))}
standing=Refused
reason=?Some({content: React.string("Oakmere Hall is kept for the lunch club then"), side: Trailing})
props={{style: placement(8, 2)}}
/>
</>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/calendar-item/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z"))
kind="Booking"
moving=true
props={{ariaLabel: "Yoga class, 10:00–12:00", draggable: true, style: placement(3, 2)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <>
<Calendar.Block
name={React.string("Parish council")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z"))
kind="Meeting"
props={{ariaLabel: "Parish council, 11:00–12:00", style: placement(4, 1)}}
/>
<Calendar.DropTarget
preview={yoga(KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T12:00Z"), ~end=Date.fromString("2025-04-16T13:00Z")))}
standing=Refused
reason=?Some({content: React.string("Oakmere Hall is closed for floor cleaning then"), side: Below})
props={{style: placement(6, 1)}}
/>
</>,
props: {},
},
{
key: "2025-04-17",
children: <>
<Calendar.DropTarget
preview={yoga(KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T09:00Z"), ~end=Date.fromString("2025-04-17T11:00Z")))}
standing=Refused
reason=?Some({content: <>{React.string("Oakmere Hall closes at ")}<time dateTime="10:00">{React.string("10:00")}</time>{React.string(" on Thursdays")}</>, side: Leading})
props={{style: placement(3, 2)}}
/>
<Calendar.Block
name={React.string("Wedding reception")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z"))
kind="Booking"
props={{ariaLabel: "Wedding reception, 12:00–15:00", style: placement(5, 3)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-5801",
~name="Board meeting",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T09:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-5802",
~name="Yoga class",
~href="../../../record/calendar-item/",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T09:00Z"), ~end=Date.fromString("2025-04-15T11:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-5803",
~name="Parish council",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T10:00Z"), ~end=Date.fromString("2025-04-16T11:00Z")),
~kind="Meeting",
),
]
/>
<Calendar.Day
day={day(17)}
items=[
item(
~key="bk-5804",
~name="Wedding reception",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-17T11:00Z"), ~end=Date.fromString("2025-04-17T14:00Z")),
~kind="Booking",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Open the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
@module({from: "kit/react/locales/en.json", with: {type_: "json"}})
external en: KitReact.Locale.t = "default"
let reader = KitReact.Reader.make(~locale=en, ~zone="Europe/London")
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let day = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let head = (on): DeskGrid.head => {key: Int.toString(on), column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-toolbar-form"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-toolbar-form-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
toolbarFormProps=?{Some(({}: JsxDOM.domProps))}
range={
days: KitReact.Time.week(reader, {year: 2025, month: 4, day: 14}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-toolbar-form-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: reader, value: Day(KitReact.Time.day(reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(reader, {year: 2025, month: 4, day: 14}), direction: Either})}, formProps: {}},
}
scope=[
FormGroup({id: "calendar-toolbar-form-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-toolbar-form-scope"},
controlProps: {id: "calendar-toolbar-form-scope", name: "hall"},
controlValue: "oakmere",
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-toolbar-form-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-toolbar-form-room"},
controlProps: {id: "calendar-toolbar-form-room", name: "room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-toolbar-form-view" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[head(13), head(14), head(15), head(16), head(17), head(18), head(19)]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{key: "2025-04-13", children: React.null, props: {}},
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Hall hire")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T10:00Z"))
kind="Booking"
props={{ariaLabel: "Hall hire, 9:00–11:00 AM", style: placement(1, 2)}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T10:00Z"), ~end=Date.fromString("2025-04-15T11:00Z"))
kind="Booking"
props={{ariaLabel: "Yoga class, 11:00 AM–12:00 PM", style: placement(3, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Committee meeting")}
href="../../../record/"
span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T12:00Z"), ~end=Date.fromString("2025-04-16T13:00Z"))
kind="Booking"
props={{ariaLabel: "Committee meeting, 1:00–2:00 PM", style: placement(5, 1)}}
/>,
props: {},
},
{key: "2025-04-17", children: React.null, props: {}},
{key: "2025-04-18", children: React.null, props: {}},
{key: "2025-04-19", children: React.null, props: {}},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(13)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-7101",
~name="Hall hire",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-14T08:00Z"), ~end=Date.fromString("2025-04-14T10:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(15)}
items=[
item(
~key="bk-7102",
~name="Yoga class",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-15T10:00Z"), ~end=Date.fromString("2025-04-15T11:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(16)}
items=[
item(
~key="bk-7103",
~name="Committee meeting",
~span=KitReact.Time.interval(reader, ~start=Date.fromString("2025-04-16T12:00Z"), ~end=Date.fromString("2025-04-16T13:00Z")),
~kind="Booking",
),
]
/>
<Calendar.Day
day={day(17)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
day={day(18)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
<Calendar.Day
day={day(19)}
empty={<p> {React.string("Nothing booked")} </p>}
/>
</Calendar.Days>
</>}
/>
</>
Calendar, at-placeOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = KitReact.Reader.atPlace(Specimen_Reader.reader, ~zone="America/New_York")
let date = (on): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day: on})
let range = KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 20})
let span = (~place=?, start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish), ~place?)
let yoga = span("2025-04-14T13:00Z", "2025-04-14T14:00Z")
let pilates = span("2025-04-16T15:00Z", "2025-04-16T16:00Z")
let supplierCall = span("2025-04-17T14:00Z", "2025-04-17T15:00Z", ~place="Europe/London")
let danceRehearsal = span("2025-04-19T19:00Z", "2025-04-19T20:00Z")
let hour = (on): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour: on, minute: 0}), props: {}}
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(date(on)), column: Day(date(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let column = (on, children): DeskGrid.column => {
key: KitReact.Time.datetime(date(on)),
children,
props: {},
}
let block = (~name, ~ariaLabel, ~span, ~kind, ~row) =>
<Calendar.Block
name={React.string(name)} href="../../../record/" span kind props={{ariaLabel, style: placement(row, 1)}}
/>
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-at-place"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-at-place-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: range,
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-at-place-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-at-place-scope-form-group",
kind: Select,
label: React.string("Studio"),
labelProps: {htmlFor: "calendar-at-place-scope"},
controlProps: {id: "calendar-at-place-scope"},
options: [
{label: React.string("All studios"), value: "all", props: {}},
{label: React.string("Riverside Studio"), value: "riverside", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-at-place-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-at-place-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[head(14), head(15), head(16), head(17), head(18), head(19), head(20)]
hours=[hour(8), hour(9), hour(10), hour(11), hour(12), hour(13), hour(14), hour(15), hour(16), hour(17)]
columns=[
column(14, block(~name="Yoga class", ~ariaLabel="Yoga class, 09:00–10:00", ~span=yoga, ~kind="Booking", ~row=2)),
column(15, React.null),
column(16, block(~name="Pilates", ~ariaLabel="Pilates, 11:00–12:00", ~span=pilates, ~kind="Booking", ~row=4)),
column(17, block(~name="Supplier call", ~ariaLabel="Supplier call, 15:00–16:00 UK Time", ~span=supplierCall, ~kind="Call", ~row=3)),
column(18, React.null),
column(19, block(~name="Dance rehearsal", ~ariaLabel="Dance rehearsal, 15:00–16:00", ~span=danceRehearsal, ~kind="Booking", ~row=8)),
column(20, React.null),
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day day={date(14)} items=[item(~key="yoga-class", ~name="Yoga class", ~span=yoga, ~kind="Booking")] />
<Calendar.Day day={date(15)} empty={<p> {React.string("Nothing booked")} </p>} />
<Calendar.Day day={date(16)} items=[item(~key="pilates", ~name="Pilates", ~span=pilates, ~kind="Booking")] />
<Calendar.Day day={date(17)} items=[item(~key="supplier-call", ~name="Supplier call", ~span=supplierCall, ~kind="Call")] />
<Calendar.Day day={date(18)} empty={<p> {React.string("Nothing booked")} </p>} />
<Calendar.Day day={date(19)} items=[item(~key="dance-rehearsal", ~name="Dance rehearsal", ~span=danceRehearsal, ~kind="Booking")] />
<Calendar.Day day={date(20)} empty={<p> {React.string("Nothing booked")} </p>} />
</Calendar.Days>
</>}
/>
</>
Calendar, steppingOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, on): DeskGrid.head => {key, column: Day(day(on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let column = (key): DeskGrid.column => {key, children: React.null, props: {}}
let nothing = <p> {React.string("Nothing booked")} </p>
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-stepping"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-stepping-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 21}, ~last={year: 2025, month: 4, day: 25}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "../stepped/", props: {rel: "next"}},
date: {group: {id: "calendar-stepping-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader, value: Day(day(21)), today: day(14), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-stepping-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-stepping-scope"},
controlProps: {id: "calendar-stepping-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-stepping-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-stepping-room"},
controlProps: {id: "calendar-stepping-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-stepping-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-stepping-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-21", 21),
head("2025-04-22", 22),
head("2025-04-23", 23),
head("2025-04-24", 24),
head("2025-04-25", 25),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
column("2025-04-21"),
{
key: "2025-04-22",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-22T09:00:00Z", "2025-04-22T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
column("2025-04-23"),
{
key: "2025-04-24",
children: <Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span("2025-04-24T11:00:00Z", "2025-04-24T12:00:00Z")}
kind="Booking"
props={{ariaLabel: "Choir rehearsal, 12:00–13:00", style: placement(4, 1)}}
/>,
props: {},
},
column("2025-04-25"),
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day day={day(21)} empty=nothing />
<Calendar.Day
day={day(22)}
items=[
item(
~key="bk-5201",
~name="Yoga class",
~span=span("2025-04-22T09:00:00Z", "2025-04-22T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day day={day(23)} empty=nothing />
<Calendar.Day
day={day(24)}
items=[
item(
~key="bk-5202",
~name="Choir rehearsal",
~span=span("2025-04-24T11:00:00Z", "2025-04-24T12:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day day={day(25)} empty=nothing />
</Calendar.Days>
</>}
/>
</>
Calendar, steppedOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (month, day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let head = (key, month, on): DeskGrid.head => {key, column: Day(day(month, on)), props: {}}
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let column = (key): DeskGrid.column => {key, children: React.null, props: {}}
let nothing = <p> {React.string("Nothing booked")} </p>
let item = (~key, ~name, ~span, ~kind): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room: None,
state: None,
props: {},
}
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-stepped"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-stepped-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(reader, ~first={year: 2025, month: 4, day: 28}, ~last={year: 2025, month: 5, day: 2}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "../stepping/", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-stepped-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader, value: Day(day(4, 28)), today: day(4, 14), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-stepped-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-stepped-scope"},
controlProps: {id: "calendar-stepped-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-stepped-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-stepped-room"},
controlProps: {id: "calendar-stepped-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-stepped-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-stepped-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head("2025-04-28", 4, 28),
head("2025-04-29", 4, 29),
head("2025-04-30", 4, 30),
head("2025-05-01", 5, 1),
head("2025-05-02", 5, 2),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
column("2025-04-28"),
{
key: "2025-04-29",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span("2025-04-29T09:00:00Z", "2025-04-29T10:00:00Z")}
kind="Booking"
props={{ariaLabel: "Yoga class, 10:00–11:00", style: placement(2, 1)}}
/>,
props: {},
},
column("2025-04-30"),
{
key: "2025-05-01",
children: <Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span("2025-05-01T11:00:00Z", "2025-05-01T12:00:00Z")}
kind="Booking"
props={{ariaLabel: "Choir rehearsal, 12:00–13:00", style: placement(4, 1)}}
/>,
props: {},
},
column("2025-05-02"),
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day day={day(4, 28)} empty=nothing />
<Calendar.Day
day={day(4, 29)}
items=[
item(
~key="bk-5301",
~name="Yoga class",
~span=span("2025-04-29T09:00:00Z", "2025-04-29T10:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day day={day(4, 30)} empty=nothing />
<Calendar.Day
day={day(5, 1)}
items=[
item(
~key="bk-5302",
~name="Choir rehearsal",
~span=span("2025-05-01T11:00:00Z", "2025-05-01T12:00:00Z"),
~kind="Booking",
),
]
/>
<Calendar.Day day={day(5, 2)} empty=nothing />
</Calendar.Days>
</>}
/>
</>
Calendar, saved-behindOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(Specimen_Reader.reader, {hour, minute: 0}), props: {}}
let day = day => KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day})
let span = (on, start, end) =>
KitReact.Time.interval(
Specimen_Reader.reader,
~start=Date.fromString(`2025-04-${Int.toString(on)}T${start}:00+01:00`),
~end=Date.fromString(`2025-04-${Int.toString(on)}T${end}:00+01:00`),
)
let head = (on): DeskGrid.head => {key: KitReact.Time.datetime(day(on)), column: DeskGrid.Day(day(on)), props: {}}
let band = (name, on, standing): DeskGrid.band => {
name: React.string(name),
href: Some("../../../record/"),
first: on,
last: on,
stack: 1,
standing,
props: {},
}
let placement = (row, span) => ({gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t)
let sized = (row, span, size) =>
ReactDOM.Style.unsafeAddProp(placement(row, span), "--kit-calendar-block-size", size)
let offset = (row, span, size, by) =>
ReactDOM.Style.unsafeAddProp(sized(row, span, size), "--kit-calendar-block-offset", by)
let words = text => [KitReact.Words.Text(text)]
let failed = text => KitReact.Roles.Row.Failed({words: words(text), tryAgain: {}})
let conflict = (text, label) => KitReact.Roles.Row.Conflict({words: words(text), label, action: {}})
let processing = text => KitReact.Roles.Row.Processing(words(text))
let unsaved = text => KitReact.Roles.Row.Unsaved(words(text))
let bandRow = (key, name, standing): Calendar.bandRow => {
key,
name: React.string(name),
href: Some("../../../record/"),
state: None,
standing,
props: {},
}
let item = (~key, ~name, ~span, ~kind, ~standings=[], ~standingWords=[], ~standing): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings,
standingWords,
standing,
room: None,
state: None,
props: {},
}
let boardMeeting = failed("This meeting was not moved: the connection dropped before it saved.")
let yogaClass = conflict("Maya Patel moved this booking to 11:00 while you were moving it to 10:00.", "Move it to 10:00")
let choirRehearsal = processing("Moving this booking…")
let toddlerGroup = unsaved("This booking will move when you are back online.")
let hallHandover = failed("This booking was not moved: the Main Hall is booked then.")
let springFair = failed("The spring fair was not moved: the connection dropped before it saved.")
let openDay = conflict("Maya Patel moved the open day to Tuesday while you were moving it to Wednesday.", "Move it to Wednesday")
let craftMarket = processing("Moving the craft market…")
let trainingDay = unsaved("The training day will move when you are back online.")
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-saved-behind"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-saved-behind-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Calendar controls"}}
range={
days: KitReact.Time.dayRange(Specimen_Reader.reader, ~first={year: 2025, month: 4, day: 14}, ~last={year: 2025, month: 4, day: 18}),
today: {label: "Today", props: {}},
previous: {label: "Previous week", href: "?week=previous", props: {rel: "prev"}},
next: {label: "Next week", href: "?week=next", props: {rel: "next"}},
date: {group: {id: "calendar-saved-behind-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-saved-behind-scope-form-group",
kind: Select,
label: React.string("Hall"),
labelProps: {htmlFor: "calendar-saved-behind-scope"},
controlProps: {id: "calendar-saved-behind-scope"},
options: [
{label: React.string("All halls"), value: "all", props: {}},
{label: React.string("Oakmere Hall"), value: "oakmere", props: {}},
],
}),
FormGroup({id: "calendar-saved-behind-room-form-group",
kind: Select,
label: React.string("Room"),
labelProps: {htmlFor: "calendar-saved-behind-room"},
controlProps: {id: "calendar-saved-behind-room"},
options: [
{label: React.string("All rooms"), value: "all", props: {}},
{label: React.string("Main Hall"), value: "main-hall", props: {}},
],
}),
]
view={<KitReact.Roles.FormGroup id="calendar-saved-behind-view-form-group" label={React.string("View")} kind={KitReact.Roles.SegmentedControl.controlSet({name: "calendar-saved-behind-view", value: "week", options: Three({value: "week", content: React.string("Week")}, {value: "day", content: React.string("Day")}, {value: "month", content: React.string("Month")})})} />}
actions={content: [PrimaryAction({children: React.string("New booking")})]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[
head(14),
head(15),
head(16),
head(17),
head(18),
]
bands=[
band("Spring fair", 1, springFair),
band("Open day", 2, openDay),
band("Craft market", 3, craftMarket),
band("Staff training day", 4, trainingDay),
]
hours=[
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
]
columns=[
{
key: "2025-04-14",
children: <Calendar.Block
name={React.string("Board meeting")}
href="../../../record/"
span={span(14, "09:00", "09:30")}
kind="Meeting"
standing=boardMeeting
props={{ariaLabel: "Board meeting, 09:00–09:30, This meeting was not moved", style: sized(1, 1, "calc(var(--kit-hour-height) / 2)")}}
/>,
props: {},
},
{
key: "2025-04-15",
children: <Calendar.Block
name={React.string("Yoga class")}
href="../../../record/"
span={span(15, "11:00", "12:00")}
kind="Booking"
standing=yogaClass
props={{ariaLabel: "Yoga class, 11:00–12:00, Maya Patel moved this booking", style: placement(3, 1)}}
/>,
props: {},
},
{
key: "2025-04-16",
children: <Calendar.Block
name={React.string("Choir rehearsal")}
href="../../../record/"
span={span(16, "10:00", "11:30")}
kind="Booking"
standing=choirRehearsal
props={{ariaLabel: "Choir rehearsal, 10:00–11:30, Moving this booking", style: sized(2, 2, "calc(var(--kit-hour-height) * 1.5)")}}
/>,
props: {},
},
{
key: "2025-04-17",
children: <Calendar.Block
name={React.string("Toddler group")}
href="../../../record/"
span={span(17, "09:30", "11:00")}
kind="Booking"
standing=toddlerGroup
props={{ariaLabel: "Toddler group, 09:30–11:00, This booking will move when you are back online", style: offset(1, 2, "calc(var(--kit-hour-height) * 1.5)", "calc(var(--kit-hour-height) / 2)")}}
/>,
props: {},
},
{
key: "2025-04-18",
children: <Calendar.Block
name={React.string("Hall handover")}
href="../../../record/"
span={span(18, "13:00", "14:00")}
kind="Booking"
standings=[Uncovered]
standingWords=["Cover needed"]
standing=hallHandover
props={{ariaLabel: "Hall handover, 13:00–14:00, Cover needed, This booking was not moved", style: placement(5, 1)}}
/>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
bands=[bandRow("ev-301", "Spring fair", springFair)]
items=[item(~key="bk-5901", ~name="Board meeting", ~span=span(14, "09:00", "09:30"), ~kind="Meeting", ~standing=boardMeeting)]
/>
<Calendar.Day
day={day(15)}
bands=[bandRow("ev-302", "Open day", openDay)]
items=[item(~key="bk-5902", ~name="Yoga class", ~span=span(15, "11:00", "12:00"), ~kind="Booking", ~standing=yogaClass)]
/>
<Calendar.Day
day={day(16)}
bands=[bandRow("ev-303", "Craft market", craftMarket)]
items=[item(~key="bk-5903", ~name="Choir rehearsal", ~span=span(16, "10:00", "11:30"), ~kind="Booking", ~standing=choirRehearsal)]
/>
<Calendar.Day
day={day(17)}
bands=[bandRow("ev-304", "Staff training day", trainingDay)]
items=[item(~key="bk-5904", ~name="Toddler group", ~span=span(17, "09:30", "11:00"), ~kind="Booking", ~standing=toddlerGroup)]
/>
<Calendar.Day
day={day(18)}
items=[item(~key="bk-5905", ~name="Hall handover", ~span=span(18, "13:00", "14:00"), ~kind="Booking", ~standings=[Uncovered], ~standingWords=["Cover needed"], ~standing=hallHandover)]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, kindsOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let currentTime: DeskGrid.currentTime = {
props: {
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
"calc(3.5 * var(--kit-hour-height))",
),
},
}
let hours = [
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~name, ~span, ~kind, ~room=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
props: {},
}
let view = id =>
<KitReact.Roles.FormGroup
id={id ++ "-form-group"}
label={React.string("View")}
kind={KitReact.Roles.SegmentedControl.controlSet({name: id, value: "day", options: Three({value: "day", content: React.string("Day")}, {value: "week", content: React.string("Week")}, {value: "month", content: React.string("Month")})})}
/>
let newClass =
Calendar.SplitAction(KitReact.Roles.SplitAction.Primary.role({
id: "calendar-kinds-new",
label: "Other kinds",
variants: [
{
items: [
KitReact.Menu.Item({name: "New private lesson"}),
KitReact.Menu.Item({name: "New rental"}),
],
},
],
children: React.string("New class"),
}))
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-kinds"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-kinds-filters"
filtersLabel="Filters"
toolbarProps={{ariaLabel: "Studio calendar controls"}}
range={
days: day(14),
today: {label: "Today", props: {}},
previous: {label: "Previous day", href: "?day=previous", props: {rel: "prev"}},
next: {label: "Next day", href: "?day=next", props: {rel: "next"}},
date: {group: {id: "calendar-kinds-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-kinds-scope-form-group",
kind: Select,
label: React.string("Studio"),
labelProps: {htmlFor: "calendar-kinds-scope"},
controlProps: {id: "calendar-kinds-scope"},
options: [
{label: React.string("Studio one"), value: "one", props: {}},
],
}),
FormGroup({id: "calendar-kinds-kind-form-group",
kind: Select,
label: React.string("Kind"),
labelProps: {htmlFor: "calendar-kinds-kind"},
controlProps: {id: "calendar-kinds-kind"},
options: [
{label: React.string("All kinds"), value: "all", props: {}},
{label: React.string("Classes"), value: "class", props: {}},
{label: React.string("Private lessons"), value: "private-lesson", props: {}},
{label: React.string("Rentals"), value: "rental", props: {}},
],
}),
]
view={view("calendar-kinds-view")}
actions={content: [newClass]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[{key: "2025-04-14", column: Day(day(14)), props: {}}]
hours
currentTime
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Beginners ballet")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z")}
kind="Class"
props={{ariaLabel: "Beginners ballet, 09:00–11:00", style: placement(1, 2)}}
/>
<Calendar.Block
name={React.string("Studio hire")}
href="../../../record/"
span={span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z")}
kind="Rental"
props={{ariaLabel: "Studio hire, 13:00–15:00", style: placement(5, 2)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6401",
~name="Beginners ballet",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z"),
~kind="Class",
),
item(
~key="bk-6402",
~name="Studio hire",
~span=span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z"),
~kind="Rental",
),
]
/>
</Calendar.Days>
</>}
/>
</>
Calendar, kinds-inertOpen the whole page Sourcemodule Calendar = KitReact.Layouts.Calendar
module DeskGrid = Calendar.DeskGrid
let reader = Specimen_Reader.reader
let day = (day): KitReact.Time.t => KitReact.Time.day(reader, {year: 2025, month: 4, day})
let span = (start, finish) =>
KitReact.Time.interval(reader, ~start=Date.fromString(start), ~end=Date.fromString(finish))
let hour = (hour): DeskGrid.hour => {time: KitReact.Time.clock(reader, {hour, minute: 0}), props: {}}
let currentTime: DeskGrid.currentTime = {
props: {
style: ReactDOM.Style.unsafeAddProp(
{},
"--kit-calendar-now-offset",
"calc(3.5 * var(--kit-hour-height))",
),
},
}
let hours = [
hour(9),
hour(10),
hour(11),
hour(12),
hour(13),
hour(14),
]
let placement = (row, span) => (
{gridRow: `${Int.toString(row)} / span ${Int.toString(span)}`}: ReactDOM.Style.t
)
let item = (~key, ~name, ~span, ~kind, ~room=?, ~actions=?, ~standing=?): Calendar.itemRow => {
key,
name,
href: Some("../../../record/"),
span,
kind,
standings: [],
standingWords: [],
room,
state: None,
?actions,
?standing,
props: {},
}
let view = id =>
<KitReact.Roles.FormGroup
id={id ++ "-form-group"}
label={React.string("View")}
kind={KitReact.Roles.SegmentedControl.controlSet({name: id, value: "day", options: Three({value: "day", content: React.string("Day")}, {value: "week", content: React.string("Week")}, {value: "month", content: React.string("Month")})})}
/>
let newClass =
Calendar.SplitAction(KitReact.Roles.SplitAction.Primary.role({
id: "calendar-kinds-inert-new",
label: "Other kinds",
variants: [
{
items: [
KitReact.Menu.Item({name: "New private lesson"}),
KitReact.Menu.Item({name: "New rental"}),
],
},
],
state: Inert({id: "calendar-kinds-inert-new-main", words: [KitReact.Words.Text("Adding waits until this term's rooms are set.")]}),
children: React.string("New class"),
}))
@react.component
let make = (~owner: string, ~print: Specimen_Print.t) =>
<>
<a href="../../layout-calendar/#layout-calendar-kinds-inert"> {React.string(owner)} </a>
<KitReact.Layouts.Calendar
printIdentity={print.identity} printSubject={print.subject} printStanding={print.standing} printTenant=?print.tenant
density=KitReact.Density.Desk
subjectState=None
scopeId="kit-calendar-kinds-inert-filters"
filtersLabel="Filters"
filtersControlState={Inert({id: "calendar-kinds-inert-filters-control", words: [KitReact.Words.Text("Filters wait until the studios are set.")]})}
toolbarProps={{ariaLabel: "Studio calendar controls"}}
range={
days: day(14),
today: {label: "Today", state: Inert({id: "calendar-kinds-inert-today", words: [KitReact.Words.Text("Today is outside this term.")]}), props: {}},
previous: {label: "Previous day", href: "?day=previous", inert: true, props: {rel: "prev"}},
next: {label: "Next day", href: "?day=next", inert: true, props: {rel: "next"}},
date: {group: {id: "calendar-kinds-inert-date", label: React.string("Go to a date"), kind: KitReact.Roles.DateField.control({name: "date", reader: Specimen_Reader.reader, value: Day(KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14})), today: KitReact.Time.day(Specimen_Reader.reader, {year: 2025, month: 4, day: 14}), direction: Either})}},
}
scope=[
FormGroup({id: "calendar-kinds-inert-scope-form-group",
kind: Select,
label: React.string("Studio"),
labelProps: {htmlFor: "calendar-kinds-inert-scope"},
controlProps: {id: "calendar-kinds-inert-scope"},
options: [
{label: React.string("Studio one"), value: "one", props: {}},
],
}),
FormGroup({id: "calendar-kinds-inert-kind-form-group",
kind: Select,
label: React.string("Kind"),
labelProps: {htmlFor: "calendar-kinds-inert-kind"},
controlProps: {id: "calendar-kinds-inert-kind"},
options: [
{label: React.string("All kinds"), value: "all", props: {}},
{label: React.string("Classes"), value: "class", props: {}},
{label: React.string("Private lessons"), value: "private-lesson", props: {}},
{label: React.string("Rentals"), value: "rental", props: {}},
],
}),
]
view={view("calendar-kinds-inert-view")}
actions={content: [newClass]}
content={subjectRegion => <>
<DeskGrid subjectRegion
columnHeads=[{key: "2025-04-14", column: Day(day(14)), props: {}}]
hours
currentTime
columns=[
{
key: "2025-04-14",
children: <>
<Calendar.Block
name={React.string("Beginners ballet")}
href="../../../record/"
span={span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z")}
kind="Class"
props={{ariaLabel: "Beginners ballet, 09:00–11:00", style: placement(1, 2)}}
/>
<Calendar.Block
name={React.string("Studio hire")}
href="../../../record/"
span={span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z")}
kind="Rental"
props={{ariaLabel: "Studio hire, 13:00–15:00", style: placement(5, 2)}}
/>
</>,
props: {},
},
]
/>
<Calendar.Days subjectRegion>
<Calendar.Day
day={day(14)}
items=[
item(
~key="bk-6401",
~name="Beginners ballet",
~span=span("2025-04-14T08:00:00Z", "2025-04-14T10:00:00Z"),
~kind="Class",
~actions={content: [SubtleAction({children: React.string("Open this class"), state: KitReact.ActionState.Inert({id: "calendar-kinds-inert-open", words: [KitReact.Words.Text("Open this class once you are back online.")]})})]},
),
item(
~key="bk-6402",
~name="Studio hire",
~span=span("2025-04-14T12:00:00Z", "2025-04-14T14:00:00Z"),
~kind="Rental",
~standing=Failed({words: [KitReact.Words.Text("This rental was not reinstated: the connection dropped before it saved.")], tryAgain: {}, tryAgainState: Inert({id: "calendar-kinds-inert-try-again", words: [KitReact.Words.Text("Try again once you are back online.")]})}),
),
]
/>
</Calendar.Days>
</>}
/>
</>
|