Skip to content

Commit bd6d094

Browse files
authored
Merge pull request #6 from StuyPulse/calendar-fixes
Calendar Fixes
2 parents b0b7401 + f47c81d commit bd6d094

File tree

1 file changed

+229
-2
lines changed

1 file changed

+229
-2
lines changed

src/pages/calendar/index.astro

Lines changed: 229 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ import PageSite from "@layouts/PageSite.astro";
44
---
55

66
<PageSite title="Calendar" description="Calendar for Team 694, used for meeting schedules and competitions.">
7+
<div id="eventModal" class="modal">
8+
<div class="modal-content">
9+
<div class="modal-header">
10+
<h2 id="modalTitle"></h2>
11+
<span class="close">&times;</span>
12+
</div>
13+
<div class="modal-body">
14+
<p id="modalTime"></p>
15+
<p id="modalDescription"></p>
16+
<div id="modalActions" class="modal-actions">
17+
<button id="joinZoomButton" class="zoom-btn" style="display: none;">Join Zoom Meeting</button>
18+
</div>
19+
</div>
20+
</div>
21+
</div>
22+
723
<script>
824
// import fullcalendar
925
import { Calendar } from "@fullcalendar/core";
@@ -20,9 +36,93 @@ import PageSite from "@layouts/PageSite.astro";
2036
}) : "empty";
2137
}
2238

39+
function dayFormat(date: Date | null) {
40+
return date !== null ? date.toLocaleDateString([], {
41+
month: "short",
42+
day: "numeric"
43+
}) : "empty";
44+
}
45+
46+
function showEventModal(event: any) {
47+
const modal = document.getElementById("eventModal");
48+
const modalTitle = document.getElementById("modalTitle");
49+
const modalTime = document.getElementById("modalTime");
50+
const modalDescription = document.getElementById("modalDescription");
51+
const joinZoomButton = document.getElementById("joinZoomButton");
52+
53+
if (!modal || !modalTitle || !modalTime || !modalDescription || !joinZoomButton) return;
54+
55+
modalTitle.textContent = event.title;
56+
57+
const time = timeFormat(event.start) == timeFormat(event.end) ? `All Day` : `${timeFormat(event.start)} - ${timeFormat(event.end)}`;
58+
const day = dayFormat(event.start) == dayFormat(event.end) ? dayFormat(event.start) : `${dayFormat(event.start)} - ${dayFormat(event.end)}`;
59+
modalTime.textContent = `${day}: ${time}`;
60+
61+
const description = event.extendedProps.description || "";
62+
const location = event.extendedProps.location || "";
63+
64+
const zoomRegex = /(https:\/\/[a-z0-9.-]*zoom\.us\/[^\s]+)/i;
65+
const zoomLink = (description.match(zoomRegex) || location.match(zoomRegex) || [])[0];
66+
67+
if (description) {
68+
const cleanDescription = (text: string) => {
69+
let cleaned = text.replace(/<a[^>]*href="[^"]*zoom\.us[^"]*"[^>]*>.*?<\/a>/gi, '');
70+
cleaned = cleaned.replace(/(https:\/\/[a-z0-9.-]*zoom\.us\/[^\s]+)/gi, '');
71+
cleaned = cleaned.replace(/\s+/g, ' ').trim();
72+
return cleaned;
73+
};
74+
75+
const cleanedDescription = cleanDescription(description);
76+
77+
if (cleanedDescription) {
78+
modalDescription.textContent = cleanedDescription;
79+
modalDescription.style.display = "block";
80+
} else {
81+
modalDescription.style.display = "none";
82+
}
83+
} else {
84+
modalDescription.style.display = "none";
85+
}
86+
87+
if (zoomLink) {
88+
joinZoomButton.style.display = "inline-block";
89+
joinZoomButton.onclick = () => {
90+
window.open(zoomLink, "_blank");
91+
closeModal();
92+
};
93+
} else {
94+
joinZoomButton.style.display = "none";
95+
}
96+
97+
modal.style.display = "block";
98+
}
99+
100+
function closeModal() {
101+
const modal = document.getElementById("eventModal");
102+
if (modal) {
103+
modal.style.display = "none";
104+
}
105+
}
106+
23107
document.addEventListener("DOMContentLoaded", function () {
24108
var calendarEl = document.getElementById("calendar");
25109
if (!calendarEl) throw new Error("Calendar element not found");
110+
111+
const modal = document.getElementById("eventModal");
112+
const closeButton = document.querySelector(".close") as HTMLElement;
113+
114+
if (closeButton) {
115+
closeButton.onclick = closeModal // error: Property 'onclick' does not exist on type 'Element'
116+
}
117+
118+
if (modal) {
119+
window.onclick = function(event) {
120+
if (event.target === modal) {
121+
closeModal();
122+
}
123+
};
124+
}
125+
26126
var calendar = new Calendar(calendarEl, {
27127
googleCalendarApiKey: "AIzaSyC8aX6KJLfEyiuSJ76hErHB8voNcoAi4yA",
28128
initialView: window.innerWidth < 768 ? "listWeek" : "dayGridMonth",
@@ -59,16 +159,143 @@ import PageSite from "@layouts/PageSite.astro";
59159
}
60160
],
61161
eventClick: function ({event, jsEvent}) {
62-
alert(`${event.title} (${timeFormat(event.start)} - ${timeFormat(event.end)})`);
162+
// alert(`${event.title} (${timeFormat(event.start)} - ${timeFormat(event.end)})`);
63163

64164
// prevents current tab from navigating
65165
jsEvent.preventDefault();
166+
167+
showEventModal(event);
66168
},
67169
});
68170
calendar.render();
69171
});
70172
</script>
173+
<style>
174+
.modal {
175+
display: none;
176+
position: fixed;
177+
z-index: 1000;
178+
left: 0;
179+
top: 0;
180+
width: 100%;
181+
height: 100%;
182+
overflow: auto;
183+
background-color: rgba(0, 0, 0, 0.5);
184+
animation: fadeIn 0.3s ease-in-out;
185+
}
186+
187+
@keyframes fadeIn {
188+
from { opacity: 0; }
189+
to { opacity: 1; }
190+
}
191+
192+
.modal-content {
193+
background-color: #fefefe;
194+
margin: 10% auto;
195+
padding: 0;
196+
border-radius: 8px;
197+
width: 90%;
198+
max-width: 500px;
199+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
200+
animation: slideIn 0.3s ease-out;
201+
}
202+
203+
@keyframes slideIn {
204+
from {
205+
transform: translateY(-50px);
206+
opacity: 0;
207+
}
208+
to {
209+
transform: translateY(0);
210+
opacity: 1;
211+
}
212+
}
213+
214+
.modal-header {
215+
padding: 20px 20px 10px 20px;
216+
border-bottom: 1px solid #e0e0e0;
217+
display: flex;
218+
justify-content: space-between;
219+
align-items: center;
220+
}
221+
222+
.modal-header h2 {
223+
margin: 0;
224+
color: #333;
225+
font-size: 1.5em;
226+
font-weight: 600;
227+
}
228+
229+
.close {
230+
color: #aaa;
231+
font-size: 28px;
232+
font-weight: bold;
233+
cursor: pointer;
234+
line-height: 1;
235+
transition: color 0.2s ease;
236+
}
237+
238+
.close:hover,
239+
.close:focus {
240+
color: #555;
241+
}
242+
243+
.modal-body {
244+
padding: 20px;
245+
}
246+
247+
.modal-body p {
248+
margin: 0 0 15px 0;
249+
color: #666;
250+
line-height: 1.5;
251+
}
252+
253+
.modal-actions {
254+
margin-top: 20px;
255+
text-align: center;
256+
}
257+
258+
.zoom-btn {
259+
background: linear-gradient(135deg, #2D8CFF, #1E6FDD);
260+
color: white;
261+
border: none;
262+
padding: 12px 24px;
263+
border-radius: 6px;
264+
cursor: pointer;
265+
font-size: 16px;
266+
font-weight: 500;
267+
transition: all 0.2s ease;
268+
box-shadow: 0 2px 8px rgba(45, 140, 255, 0.3);
269+
}
270+
271+
.zoom-btn:hover {
272+
background: linear-gradient(135deg, #1E6FDD, #155ABB);
273+
transform: translateY(-1px);
274+
box-shadow: 0 4px 12px rgba(45, 140, 255, 0.4);
275+
}
276+
277+
.zoom-btn:active {
278+
transform: translateY(0);
279+
}
280+
281+
/* Mobile responsiveness */
282+
@media (max-width: 768px) {
283+
.modal-content {
284+
width: 95%;
285+
margin: 5% auto;
286+
}
287+
288+
.modal-header h2 {
289+
font-size: 1.3em;
290+
}
291+
292+
.modal-body {
293+
padding: 15px;
294+
}
295+
}
296+
</style>
297+
71298
<div class="container">
72299
<div id="calendar"></div>
73300
</div>
74-
</PageSite>
301+
</PageSite>

0 commit comments

Comments
 (0)