From 98b1f59a8b19375d384424c47c20e5f1a3740f3e Mon Sep 17 00:00:00 2001 From: lenhanphung Date: Mon, 22 Sep 2025 17:20:48 +0700 Subject: [PATCH] feat: customize now indicator arrow to display current time --- src/components/Calendar/Calendar.tsx | 62 ++++++++++++++++++++++ src/components/Calendar/CustomCalendar.css | 22 ++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/components/Calendar/Calendar.tsx b/src/components/Calendar/Calendar.tsx index 794d436..66badf0 100644 --- a/src/components/Calendar/Calendar.tsx +++ b/src/components/Calendar/Calendar.tsx @@ -432,6 +432,56 @@ export default function CalendarApp() { } }} viewDidMount={(arg) => { + // Update now indicator arrow with current time + const updateNowIndicator = () => { + const nowIndicatorArrow = document.querySelector( + ".fc-timegrid-now-indicator-arrow" + ) as HTMLElement; + if (nowIndicatorArrow) { + const now = new Date(); + const timeString = now.toLocaleTimeString(undefined, { + hour: "2-digit", + minute: "2-digit", + hour12: false, + }); + nowIndicatorArrow.setAttribute("data-time", timeString); + } + }; + + // Update immediately and then every minute + updateNowIndicator(); + const timeInterval = setInterval(updateNowIndicator, 60000); + + // Watch for now indicator arrow creation and update immediately + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.nodeType === Node.ELEMENT_NODE) { + const element = node as Element; + if ( + element.classList?.contains( + "fc-timegrid-now-indicator-arrow" + ) || + element.querySelector?.( + ".fc-timegrid-now-indicator-arrow" + ) + ) { + setTimeout(updateNowIndicator, 10); + } + } + }); + }); + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + }); + + // Store interval and observer for cleanup + (arg.el as any).__timeInterval = timeInterval; + (arg.el as any).__timeObserver = observer; + // Add global hover effect for week and day views if ( arg.view.type === "timeGridWeek" || @@ -536,6 +586,18 @@ export default function CalendarApp() { } }} viewWillUnmount={(arg) => { + // Clean up time interval + if ((arg.el as any).__timeInterval) { + clearInterval((arg.el as any).__timeInterval); + delete (arg.el as any).__timeInterval; + } + + // Clean up observer + if ((arg.el as any).__timeObserver) { + (arg.el as any).__timeObserver.disconnect(); + delete (arg.el as any).__timeObserver; + } + // Clean up event listeners to prevent memory leaks const calendarEl = document.querySelector(".fc") as HTMLElement; if (calendarEl) { diff --git a/src/components/Calendar/CustomCalendar.css b/src/components/Calendar/CustomCalendar.css index c950534..4c6bcdb 100644 --- a/src/components/Calendar/CustomCalendar.css +++ b/src/components/Calendar/CustomCalendar.css @@ -1,7 +1,4 @@ /* Custom main calendar view */ -.fc-header-toolbar.fc-toolbar.fc-toolbar-ltr { - /* display: none; */ -} .fc-theme-standard td, .fc-theme-standard th { border: 1px solid #b8c1cc; @@ -148,7 +145,24 @@ th.fc-col-header-cell.fc-day { left: -5px; } .fc .fc-timegrid-now-indicator-arrow { - display: none; + display: block !important; + width: auto; + height: auto; + position: relative; + border: 0; +} + +.fc .fc-timegrid-now-indicator-arrow::before { + content: attr(data-time); + color: #f67e35; + white-space: nowrap; + font-family: Roboto, sans-serif; + font-weight: 600; + position: absolute; + top: -2px; + left: 25px; + font-size: 14px; + letter-spacing: 0.25px; } .fc-day-today .fc-timegrid-now-indicator-container { overflow: unset;