diff --git a/package-lock.json b/package-lock.json
index be2a30ec..3aef1850 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,10 +13,7 @@
"@emotion/react": "^11.14.0",
"@emotion/server": "^11.11.0",
"@fontsource-variable/inter": "^5.2.8",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/react": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
+ "@fullcalendar/react": "7.0.0-rc.1",
"@react-router/node": "^7.14.1",
"@rjsf/chakra-ui": "^6.4.2",
"@rjsf/core": "^6.4.2",
@@ -33,8 +30,9 @@
"react-dom": "^19.2.4",
"react-icons": "^5.6.0",
"react-router": "^7.14.1",
- "rrule": "^2.8.1",
+ "rrule-temporal": "^1.5.2",
"smol-toml": "^1.6.1",
+ "temporal-polyfill": "^0.3.2",
"timezones-ical-library": "^2.1.3"
},
"devDependencies": {
@@ -1752,54 +1750,38 @@
"url": "https://github.com/sponsors/ayuhito"
}
},
- "node_modules/@fullcalendar/core": {
- "version": "6.1.20",
- "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz",
- "integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==",
- "license": "MIT",
- "dependencies": {
- "preact": "~10.12.1"
- }
- },
- "node_modules/@fullcalendar/daygrid": {
- "version": "6.1.20",
- "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz",
- "integrity": "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==",
+ "node_modules/@full-ui/headless-calendar": {
+ "version": "7.0.0-rc.1",
+ "resolved": "https://registry.npmjs.org/@full-ui/headless-calendar/-/headless-calendar-7.0.0-rc.1.tgz",
+ "integrity": "sha512-JoecyBKMyF0OhpfH2wHAE3eSwTbK183CS+RkaB0KLXA7nS2Tf+obBGVz+kWsil9Ov0x41F7d96S27TnzvaO/UQ==",
"license": "MIT",
"peerDependencies": {
- "@fullcalendar/core": "~6.1.20"
+ "temporal-polyfill": "^0.3.2"
}
},
- "node_modules/@fullcalendar/interaction": {
- "version": "6.1.20",
- "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.20.tgz",
- "integrity": "sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==",
+ "node_modules/@fullcalendar/core": {
+ "version": "7.0.0-rc.1",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-7.0.0-rc.1.tgz",
+ "integrity": "sha512-ke+z94EGR747DwXd6pgYxQhAQ/xjEEARjj6Nx4e3Y9s6L9PFNcdLNMxQr6QPRcgdQ2ipaWDREnPenH3tcak2qQ==",
"license": "MIT",
"peerDependencies": {
- "@fullcalendar/core": "~6.1.20"
+ "@full-ui/headless-calendar": "7.0.0-rc.1",
+ "temporal-polyfill": "^0.3.2"
}
},
"node_modules/@fullcalendar/react": {
- "version": "6.1.20",
- "resolved": "https://registry.npmjs.org/@fullcalendar/react/-/react-6.1.20.tgz",
- "integrity": "sha512-1w0pZtceaUdfAnxMSCGHCQalhi+mR1jOe76sXzyAXpcPz/Lf0zHSdcGK/U2XpZlnQgQtBZW+d+QBnnzVQKCxAA==",
- "license": "MIT",
- "peerDependencies": {
- "@fullcalendar/core": "~6.1.20",
- "react": "^16.7.0 || ^17 || ^18 || ^19",
- "react-dom": "^16.7.0 || ^17 || ^18 || ^19"
- }
- },
- "node_modules/@fullcalendar/timegrid": {
- "version": "6.1.20",
- "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.20.tgz",
- "integrity": "sha512-4H+/MWbz3ntA50lrPif+7TsvMeX3R1GSYjiLULz0+zEJ7/Yfd9pupZmAwUs/PBpA6aAcFmeRr0laWfcz1a9V1A==",
+ "version": "7.0.0-rc.1",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/react/-/react-7.0.0-rc.1.tgz",
+ "integrity": "sha512-/oMniktNyhuyfrVklN4QRKjvfMFR2kAqYeThFVjb8nfdF9EolN23ZkYnV2RU9n56KFg/zPOy2f0pdIDzn0kR3w==",
"license": "MIT",
"dependencies": {
- "@fullcalendar/daygrid": "~6.1.20"
+ "@full-ui/headless-calendar": "7.0.0-rc.1",
+ "@fullcalendar/core": "7.0.0-rc.1"
},
"peerDependencies": {
- "@fullcalendar/core": "~6.1.20"
+ "react": "^16.7.0 || ^17 || ^18 || ^19",
+ "react-dom": "^16.7.0 || ^17 || ^18 || ^19",
+ "temporal-polyfill": "^0.3.2"
}
},
"node_modules/@humanfs/core": {
@@ -1918,6 +1900,18 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@js-temporal/polyfill": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@js-temporal/polyfill/-/polyfill-0.5.1.tgz",
+ "integrity": "sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==",
+ "license": "ISC",
+ "dependencies": {
+ "jsbi": "^4.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@mjackson/node-fetch-server": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz",
@@ -6222,6 +6216,12 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
+ "node_modules/jsbi": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.2.tgz",
+ "integrity": "sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==",
+ "license": "Apache-2.0"
+ },
"node_modules/jsdom": {
"version": "29.0.2",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.2.tgz",
@@ -7221,16 +7221,6 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
- "node_modules/preact": {
- "version": "10.12.1",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
- "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- }
- },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -7613,13 +7603,13 @@
"fsevents": "~2.3.2"
}
},
- "node_modules/rrule": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.8.1.tgz",
- "integrity": "sha512-hM3dHSBMeaJ0Ktp7W38BJZ7O1zOgaFEsn41PDk+yHoEtfLV+PoJt9E9xAlZiWgf/iqEqionN0ebHFZIDAp+iGw==",
- "license": "BSD-3-Clause",
+ "node_modules/rrule-temporal": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/rrule-temporal/-/rrule-temporal-1.5.2.tgz",
+ "integrity": "sha512-I5rAiZfRlMh0vuG23HrGBMLZOSiQO7H1Uq8l9qyfA6oTD5j+UMRwpRs4aVU4XdaFhgN1p3K+cHelG8KvLTTm+g==",
+ "license": "MIT",
"dependencies": {
- "tslib": "^2.4.0"
+ "@js-temporal/polyfill": "^0.5.1"
}
},
"node_modules/run-parallel": {
@@ -7820,6 +7810,21 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/temporal-polyfill": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.2.tgz",
+ "integrity": "sha512-TzHthD/heRK947GNiSu3Y5gSPpeUDH34+LESnfsq8bqpFhsB79HFBX8+Z834IVX68P3EUyRPZK5bL/1fh437Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "temporal-spec": "0.3.1"
+ }
+ },
+ "node_modules/temporal-spec": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.1.tgz",
+ "integrity": "sha512-B4TUhezh9knfSIMwt7RVggApDRJZo73uZdj8AacL2mZ8RP5KtLianh2MXxL06GN9ESYiIsiuoLQhgVfwe55Yhw==",
+ "license": "ISC"
+ },
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
diff --git a/package.json b/package.json
index c9cd205e..96e62a7e 100644
--- a/package.json
+++ b/package.json
@@ -10,10 +10,7 @@
"@emotion/react": "^11.14.0",
"@emotion/server": "^11.11.0",
"@fontsource-variable/inter": "^5.2.8",
- "@fullcalendar/core": "^6.1.20",
- "@fullcalendar/interaction": "^6.1.20",
- "@fullcalendar/react": "^6.1.20",
- "@fullcalendar/timegrid": "^6.1.20",
+ "@fullcalendar/react": "7.0.0-rc.1",
"@react-router/node": "^7.14.1",
"@rjsf/chakra-ui": "^6.4.2",
"@rjsf/core": "^6.4.2",
@@ -30,8 +27,9 @@
"react-dom": "^19.2.4",
"react-icons": "^5.6.0",
"react-router": "^7.14.1",
- "rrule": "^2.8.1",
+ "rrule-temporal": "^1.5.2",
"smol-toml": "^1.6.1",
+ "temporal-polyfill": "^0.3.2",
"timezones-ical-library": "^2.1.3"
},
"scripts": {
diff --git a/src/components/Calendar.css b/src/components/Calendar.css
deleted file mode 100644
index b69ae34c..00000000
--- a/src/components/Calendar.css
+++ /dev/null
@@ -1,67 +0,0 @@
-.fc .fc-scrollgrid,
-.fc .fc-scrollgrid-section > td,
-.fc .fc-timegrid-axis {
- border-color: transparent;
-}
-
-.fc .fc-timegrid-slot {
- border-color: var(--chakra-colors-border-emphasized);
- border-width: 1.5px;
- border-left-color: transparent;
-}
-
-.fc td,
-.fc th {
- border-color: var(--chakra-colors-border-emphasized);
- border-width: 1.5px;
-}
-
-.fc .fc-scrollgrid-section > th:nth-child(1),
-.fc .fc-col-header-cell:last-child {
- border-right-color: transparent;
-}
-
-.fc .fc-scrollgrid-section-sticky > * {
- background: transparent;
-}
-
-.fc .fc-col-header-cell .fc-scrollgrid-sync-inner {
- background: var(--chakra-colors-bg);
-}
-
-.fc .fc-timegrid-event-harness-inset .fc-timegrid-event {
- box-shadow: var(--chakra-colors-bg) 0px 0px 0px 1.5px;
-}
-
-.fc .fc-scroller-harness {
- overflow: visible;
-}
-
-.fc .fc-timegrid-slot-label {
- border: none;
-}
-
-.fc .fc-timegrid-slot-label-frame {
- position: relative;
-}
-
-.fc .fc-timegrid-slot-label-cushion {
- font-size: 0.75rem;
- line-height: 1.3;
- opacity: 0.7;
- position: absolute;
- top: -1.25rem;
- right: 0.25rem;
-}
-
-.fc .fc-timegrid-event {
- border-radius: 0;
- border-width: 0;
- padding-left: 0.25rem;
-}
-
-.fc .fc-col-header-cell-cushion {
- font-size: 0.8rem;
- letter-spacing: 0.05rem;
- text-transform: uppercase;
-}
diff --git a/src/components/Calendar.module.css b/src/components/Calendar.module.css
new file mode 100644
index 00000000..6643900a
--- /dev/null
+++ b/src/components/Calendar.module.css
@@ -0,0 +1,116 @@
+:global(:root) {
+ /* primary */
+ --fc-monarch-primary: rgb(65 95 145);
+ --fc-monarch-primary-foreground: rgb(255 255 255);
+ --fc-monarch-primary-over: #526e9c;
+ --fc-monarch-primary-down: #647ea7;
+
+ /* secondary */
+ --fc-monarch-secondary: rgb(214 227 255);
+ --fc-monarch-secondary-foreground: rgb(40 71 119);
+ --fc-monarch-secondary-over: #c9d6f2;
+ --fc-monarch-secondary-down: #bdc9e5;
+
+ /* tertiary */
+ --fc-monarch-tertiary: rgb(133 93 140);
+ --fc-monarch-tertiary-foreground: rgb(255 255 255);
+ --fc-monarch-tertiary-over: #916c97;
+ --fc-monarch-tertiary-down: #9d7ca2;
+
+ /* calendar content */
+ --fc-monarch-event: var(--fc-monarch-primary);
+ --fc-monarch-event-contrast: var(--fc-monarch-primary-foreground);
+ --fc-monarch-highlight: #d6e3ff4d;
+ --fc-monarch-now: rgb(186 26 26);
+
+ /* controls */
+ --fc-monarch-selected: rgb(86 95 113);
+ --fc-monarch-selected-foreground: rgb(255 255 255);
+ --fc-monarch-selected-over: #656e7e;
+ --fc-monarch-selected-down: #757d8c;
+ --fc-monarch-outline: #6687ff;
+
+ /* popover */
+ --fc-monarch-popover: var(--fc-monarch-background);
+
+ /* neutral backgrounds */
+ --fc-monarch-background: var(--chakra-colors-bg);
+ --fc-monarch-faint: var(--chakra-colors-bg-subtle);
+ --fc-monarch-muted: var(--chakra-colors-bg-muted);
+ --fc-monarch-strong: var(--chakra-colors-bg-emphasized);
+ --fc-monarch-stronger: var(--chakra-colors-bg-solid);
+ --fc-monarch-strongest: var(--chakra-colors-bg-focus-ring);
+
+ /* neutral foregrounds */
+ --fc-monarch-foreground: var(--chakra-colors-fg);
+ --fc-monarch-faint-foreground: var(--chakra-colors-fg-subtle);
+ --fc-monarch-muted-foreground: var(--chakra-colors-fg-muted);
+
+ /* neutral borders */
+ --fc-monarch-border: var(--chakra-colors-border-emphasized);
+ --fc-monarch-strong-border: var(--chakra-colors-border-inverted);
+}
+
+@media not print {
+ :global(.dark) {
+ /* primary */
+ --fc-monarch-primary: rgb(170 199 255);
+ --fc-monarch-primary-foreground: rgb(10 48 95);
+ --fc-monarch-primary-over: #b2cdff;
+ --fc-monarch-primary-down: #bbd2ff;
+
+ /* secondary */
+ --fc-monarch-secondary: rgb(40 71 119);
+ --fc-monarch-secondary-foreground: rgb(214 227 255);
+ --fc-monarch-secondary-over: #32507e;
+ --fc-monarch-secondary-down: #3c5885;
+
+ /* tertiary */
+ --fc-monarch-tertiary: rgb(221 188 224);
+ --fc-monarch-tertiary-foreground: rgb(63 40 68);
+ --fc-monarch-tertiary-over: #e0c3e3;
+ --fc-monarch-tertiary-down: #e4c9e6;
+
+ /* calendar content */
+ --fc-monarch-event: var(--fc-monarch-primary);
+ --fc-monarch-event-contrast: var(--fc-monarch-primary-foreground);
+ --fc-monarch-highlight: #2847774d;
+ --fc-monarch-now: rgb(255 180 171);
+
+ /* controls */
+ --fc-monarch-selected: rgb(190 198 220);
+ --fc-monarch-selected-foreground: rgb(40 49 65);
+ --fc-monarch-selected-over: #c4cce0;
+ --fc-monarch-selected-down: #cbd1e3;
+
+ /* popover */
+ --fc-monarch-popover: rgb(17 19 24);
+ --fc-monarch-popover-foreground: rgb(226 226 233);
+ }
+}
+
+/* THIS ONE */
+.fc-slot-header-inner {
+ line-height: 0.1rem;
+ padding-block: 0.2rem;
+ opacity: 0.7;
+ font-size: 0.75rem;
+}
+
+.fc-day-header-inner {
+ font-size: 0.8rem;
+ letter-spacing: 0.05rem;
+}
+
+.fc-event {
+ cursor: pointer;
+}
+
+.fc-event-inner {
+ padding-top: 0.25rem;
+ padding-inline-start: 0.5rem;
+}
+
+.fc-event-inner > * {
+ padding-block: 0rem;
+}
diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx
index e19c9183..72ffa416 100644
--- a/src/components/Calendar.tsx
+++ b/src/components/Calendar.tsx
@@ -1,19 +1,24 @@
import { useContext, useMemo } from "react";
-import { Box, Circle, Float, Text } from "@chakra-ui/react";
+import { Circle, Float, Text } from "@chakra-ui/react";
import { Tooltip } from "./ui/tooltip";
-import FullCalendar from "@fullcalendar/react";
-import type { EventContentArg, EventApi } from "@fullcalendar/core";
-import timeGridPlugin from "@fullcalendar/timegrid";
-import interactionPlugin from "@fullcalendar/interaction";
+import FullCalendar, {
+ type EventDisplayInfo,
+ type EventApi,
+} from "@fullcalendar/react";
+import themePlugin from "@fullcalendar/react/themes/monarch";
+import timeGridPlugin from "@fullcalendar/react/timegrid";
+import interactionPlugin from "@fullcalendar/react/interaction";
import type { Activity } from "../lib/activity";
import { CustomActivity, Timeslot } from "../lib/activity";
import { Slot } from "../lib/dates";
import { HydrantContext } from "../lib/hydrant";
-import "./Calendar.css";
+import "@fullcalendar/react/skeleton.css";
+import "@fullcalendar/react/themes/monarch/theme.css";
+import styles from "./Calendar.module.css";
// Threshold at which to display a distance warning, in feet (650 meters)
const DISTANCE_WARNING_THRESHOLD = 2112;
@@ -21,6 +26,9 @@ const DISTANCE_WARNING_THRESHOLD = 2112;
// Walking speed, in ft/s (~3 mph)
const WALKING_SPEED = 4.4;
+// User's timezone (for converting between Date and Temporal.PlainDateTime)
+const USER_TZ = Temporal.Now.timeZoneId();
+
/**
* Calendar showing all the activities, including the buttons on top that
* change the schedule option selected.
@@ -71,7 +79,14 @@ export function Calendar() {
if (!beforeEvent.start || !beforeEvent.room) {
continue;
}
- if (thisEvent.start.getTime() != beforeEvent.end.getTime()) {
+ if (
+ Temporal.Instant.compare(
+ thisEvent.start.toTemporalInstant(),
+ Temporal.PlainDateTime.from(beforeEvent.end)
+ .toZonedDateTime(USER_TZ)
+ .toInstant(),
+ ) !== 0
+ ) {
continue;
}
@@ -100,59 +115,60 @@ export function Calendar() {
return undefined;
};
- const renderEvent = ({ event }: EventContentArg) => {
+ const renderEvent = ({
+ event,
+ titleClass,
+ timeClass,
+ isNarrow,
+ isShort,
+ }: EventDisplayInfo) => {
+ const room = event.extendedProps.room as string | undefined;
+ const activity = event.extendedProps.activity as Activity;
+ const distanceWarning = getDistanceWarning(event);
+ const smallText = isNarrow || isShort;
+
const TitleText = () => (
{event.title}
);
- const room = event.extendedProps.room as string | undefined;
- const activity = event.extendedProps.activity as Activity;
- const distanceWarning = getDistanceWarning(event);
+ const RoomText = () => (
+
+ {room}
+
+ );
return (
<>
-
- {!(activity instanceof CustomActivity) ? (
-
- {TitleText()}
-
- ) : (
-
- )}
- {event.extendedProps.roomClarification ? (
-
- {room}
-
- ) : (
- {room}
- )}
-
+ {!(activity instanceof CustomActivity) ? (
+
+ {TitleText()}
+
+ ) : (
+
+ )}
+ {event.extendedProps.roomClarification ? (
+
+ {RoomText()}
+
+ ) : (
+
+ )}
{distanceWarning ? (
-
+
!
@@ -175,12 +194,15 @@ export function Calendar() {
return (
{
// extendedProps: non-standard props of {@link Event.eventInputs}
@@ -188,23 +210,32 @@ export function Calendar() {
}}
headerToolbar={false}
height="auto"
- // a date that is, conveniently enough, a monday
- initialDate="2001-01-01"
- slotDuration="00:30:00"
- slotLabelFormat={({ date }) => {
- const { hour } = date;
+ eventShortHeight={30}
+ initialDate={(() => {
+ const now = Temporal.Now.plainDateISO();
+ return now.subtract({ days: now.dayOfWeek - 1 }).toString();
+ })()}
+ slotDuration={Temporal.Duration.from({ minutes: 30 })}
+ slotHeaderContent={({ time }) => {
+ const milliseconds = time?.milliseconds ?? 0;
+ const hour = Temporal.Duration.from({ milliseconds }).total({
+ unit: "hour",
+ });
return hour === 12
? "noon"
: hour < 12
? `${hour.toString()} AM`
: `${(hour - 12).toString()} PM`;
}}
+ slotHeaderInnerClass={styles["fc-slot-header-inner"]}
+ dayHeaderContent={({ text }) => text.toLocaleUpperCase()}
+ dayHeaderInnerClass={styles["fc-day-header-inner"]}
slotMinTime={
- events.some((e) => (e.start as Date).getHours() < 8)
- ? "06:00:00"
- : "08:00:00"
+ events.some((e) => Temporal.PlainDateTime.from(e.start).hour < 8)
+ ? Temporal.Duration.from({ hours: 6 })
+ : Temporal.Duration.from({ hours: 8 })
}
- slotMaxTime="22:00:00"
+ slotMaxTime={Temporal.Duration.from({ hours: 22 })}
weekends={false}
selectable={viewedActivity instanceof CustomActivity}
select={(e) => {
@@ -212,8 +243,18 @@ export function Calendar() {
state.addTimeslot(
viewedActivity,
Timeslot.fromStartEnd(
- Slot.fromStartDate(e.start),
- Slot.fromStartDate(e.end),
+ Slot.fromStartDate(
+ e.start
+ .toTemporalInstant()
+ .toZonedDateTimeISO(USER_TZ)
+ .toPlainDateTime(),
+ ),
+ Slot.fromStartDate(
+ e.end
+ .toTemporalInstant()
+ .toZonedDateTimeISO(USER_TZ)
+ .toPlainDateTime(),
+ ),
),
);
}
diff --git a/src/components/SelectedActivities.tsx b/src/components/SelectedActivities.tsx
index f37cf528..a1b20893 100644
--- a/src/components/SelectedActivities.tsx
+++ b/src/components/SelectedActivities.tsx
@@ -12,12 +12,19 @@ export function ColorButton(
props: ComponentPropsWithoutRef<"button"> & { color: string },
) {
const { children, color, style, ...otherProps } = props;
+ const contractColor = textColor(color);
return (