Skip to content

Commit 8c42553

Browse files
author
Nap Joseph Calub
committed
feat: format events
1 parent 5c8dd55 commit 8c42553

2 files changed

Lines changed: 78 additions & 59 deletions

File tree

_includes/layouts/events.vto

Lines changed: 77 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ layout: layouts/base.vto
4747
<div class="flex justify-center mb-8">
4848
<div class="flex gap-2">
4949
<template x-for="(yearData, idx) in yearNavigation" :key="idx">
50-
<button
50+
<button
5151
x-show="yearData.show"
5252
@click="navigateToYear(yearData.year)"
5353
class="px-4 py-2 bg-white text-gray-800 rounded-lg hover:bg-gray-100 transition-colors font-semibold"
@@ -58,24 +58,29 @@ layout: layouts/base.vto
5858
</div>
5959
6060
{{# Organization Filter #}}
61-
<div class="mb-8">
61+
<div class="mb-8" x-cloak>
6262
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
6363
<label class="text-white font-semibold">Filter by Organization:</label>
6464
<div class="flex flex-wrap gap-2">
6565
{{ for org of organizations.sort((a, b) => a.name.localeCompare(b.name)) }}
66-
<button
67-
@click="toggleOrganization('{{ org.id }}')"
68-
:class="selectedOrgs.includes('{{ org.id }}') ? 'bg-blue-600 text-white' : 'bg-white text-gray-800'"
69-
class="px-3 py-1 rounded-lg transition-colors text-sm hover:opacity-90"
70-
x-show="hasEventsInYear('{{ org.id }}')"
71-
>
72-
{{ org.name }}
73-
</button>
66+
{{# Check if org has events in any year #}}
67+
{{ set hasEvents = events.some(e => e.by === org.id) }}
68+
{{ if hasEvents }}
69+
<button
70+
@click="toggleOrganization('{{ org.id }}')"
71+
:class="selectedOrgs.includes('{{ org.id }}') ? 'bg-blue-600 text-white' : 'bg-white text-gray-800'"
72+
class="px-3 py-1 rounded-lg transition-colors text-sm hover:opacity-90"
73+
x-show="hasEventsInYear('{{ org.id }}')"
74+
>
75+
{{ org.name }}
76+
</button>
77+
{{ /if }}
7478
{{ /for }}
7579
<button
7680
x-show="selectedOrgs.length > 0"
7781
@click="clearFilters()"
78-
class="px-3 py-1 bg-red-600 text-white rounded-lg transition-colors text-sm hover:bg-red-700"
82+
class="px-3 py-1 bg-red-600 text-white rounded-lg transition-colors text-sm hover:bg-red-700 hidden"
83+
:class="{'hidden': selectedOrgs.length === 0}"
7984
>
8085
Clear All
8186
</button>
@@ -91,18 +96,18 @@ layout: layouts/base.vto
9196
{{ set daysInMonth = new Date(year, monthIndex + 1, 0).getDate() }}
9297
{{ set firstDayRaw = new Date(year, monthIndex, 1).getDay() }}
9398
{{ set firstDay = (firstDayRaw + 6) % 7 }}{{# Convert Sunday=0 to Monday=0 #}}
94-
95-
<div
96-
class="bg-white rounded-lg shadow-md overflow-hidden month-card"
99+
100+
<div
101+
class="bg-white rounded-lg shadow-md overflow-hidden month-card flex flex-col"
97102
data-year="{{ year }}"
98103
data-month="{{ monthIndex }}"
99104
x-show="currentYear === {{ year }}"
100105
>
101-
<div class="bg-gray-800 text-white px-4 py-3">
106+
<div class="bg-gray-800 text-white px-4 py-3 relative">
102107
<h2 class="text-xl font-semibold">{{ monthName }}</h2>
103108
</div>
104109
105-
<div class="p-4">
110+
<div class="p-4 bg-white flex-1">
106111
<div class="grid grid-cols-8 gap-1 text-xs">
107112
{{# Week day headers #}}
108113
<div></div>
@@ -111,17 +116,17 @@ layout: layouts/base.vto
111116
{{ /for }}
112117
113118
{{# Generate calendar with proper week structure #}}
114-
119+
115120
{{# Calculate total weeks needed #}}
116121
{{ set totalDays = firstDay + daysInMonth }}
117122
{{ set totalWeeks = Math.ceil(totalDays / 7) }}
118-
123+
119124
{{# Generate each week row #}}
120125
{{ for weekIndex of [...Array(totalWeeks).keys()] }}
121126
{{# Calculate first day of this week row #}}
122127
{{ set weekStartDay = weekIndex * 7 - firstDay + 1 }}
123128
{{ set weekEndDay = Math.min(weekStartDay + 6, daysInMonth) }}
124-
129+
125130
{{# Add week number for this row #}}
126131
{{ if weekStartDay <= daysInMonth }}
127132
{{# Get the Monday date for this week row to calculate correct ISO week #}}
@@ -143,11 +148,11 @@ layout: layouts/base.vto
143148
{{ else }}
144149
<div></div>
145150
{{ /if }}
146-
151+
147152
{{# Generate 7 day cells for this week #}}
148153
{{ for dayIndex of [...Array(7).keys()] }}
149154
{{ set day = weekIndex * 7 + dayIndex - firstDay + 1 }}
150-
155+
151156
{{ if day < 1 || day > daysInMonth }}
152157
{{# Empty cell for days outside the month #}}
153158
<div></div>
@@ -159,33 +164,33 @@ layout: layouts/base.vto
159164
const endDate = e.end_date ? (typeof e.end_date === 'string' ? e.end_date : e.end_date.toISOString().split('T')[0]) : startDate;
160165
return startDate <= dateStr && endDate >= dateStr;
161166
}) }}
162-
167+
163168
{{ set eventOrgs = dayEvents.map(e => `'${e.by}'`) }}
164169
{{ set eventOrgsStr = eventOrgs.length > 0 ? `[${eventOrgs.join(',')}]` : '[]' }}
165-
170+
166171
<div class="relative calendar-cell" data-date="{{ dateStr }}">
167172
{{ if dayEvents.length > 0 }}
168173
<button
169174
type="button"
170175
@click="showEventModal({{ year }}, {{ monthIndex }}, {{ day }}, $event)"
171176
class="event-day w-full text-center p-1 rounded font-semibold cursor-pointer transition-colors bg-blue-100 text-blue-900 hover:bg-blue-200"
172-
:class="isPastDate({{ year }}, {{ monthIndex }}, {{ day }})
173-
? 'bg-gray-100 text-gray-500 hover:bg-gray-200'
177+
:class="isPastDate({{ year }}, {{ monthIndex }}, {{ day }})
178+
? 'bg-gray-100 text-gray-500 hover:bg-gray-200'
174179
: 'bg-blue-100 text-blue-900 hover:bg-blue-200'"
175180
x-show="shouldShowEvents({{ eventOrgsStr }})"
176181
data-events='{{ JSON.stringify(dayEvents) }}'
177182
>
178183
{{ day }}
179184
</button>
180-
<div
185+
<div
181186
x-show="!shouldShowEvents({{ eventOrgsStr }})"
182187
class="calendar-day text-center p-1 rounded text-gray-700"
183188
:class="isPastDate({{ year }}, {{ monthIndex }}, {{ day }}) ? 'text-gray-400' : 'text-gray-700'"
184189
>
185190
{{ day }}
186191
</div>
187192
{{ else }}
188-
<div
193+
<div
189194
class="calendar-day text-center p-1 rounded text-gray-700"
190195
:class="isPastDate({{ year }}, {{ monthIndex }}, {{ day }}) ? 'text-gray-400' : 'text-gray-700'"
191196
>
@@ -208,7 +213,7 @@ layout: layouts/base.vto
208213
<h2 class="text-2xl font-bold text-white mb-6">
209214
<span x-text="currentYear === new Date().getFullYear() ? 'Upcoming Events' : 'Events'"></span>
210215
</h2>
211-
216+
212217
<div class="space-y-4">
213218
{{# Sort events by start_date #}}
214219
{{ set sortedEvents = events.sort((a, b) => {
@@ -223,8 +228,8 @@ layout: layouts/base.vto
223228
{{ set eventDay = parseInt(startDateStr.substring(8, 10)) }}
224229
{{ set eventWeek = getISOWeek(startDateStr) }}
225230
{{ set org = organizations.find(o => o.id === event.by) }}
226-
227-
<div
231+
232+
<div
228233
class="event-card bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow"
229234
x-show="shouldShowEvent('{{ event.by }}', {{ eventYear }}, '{{ startDateStr }}')"
230235
data-event-org="{{ event.by }}"
@@ -263,11 +268,15 @@ layout: layouts/base.vto
263268
{{ set endMonth = parseInt(endDateStr.substring(5, 7)) - 1 }}
264269
{{ set endDay = parseInt(endDateStr.substring(8, 10)) }}
265270
{{ set endYear = parseInt(endDateStr.substring(0, 4)) }}
266-
{{ shortMonthNames[eventMonth] }} {{ eventDay }} -
267-
{{ if eventYear !== endYear }}
268-
{{ shortMonthNames[endMonth] }} {{ endDay }}, {{ endYear }}
271+
{{ if eventMonth === endMonth && eventYear === endYear }}
272+
{{# Same month and year #}}
273+
{{ monthNames[eventMonth] }} {{ eventDay }}-{{ endDay }}, {{ eventYear }}
274+
{{ else if eventYear === endYear }}
275+
{{# Different months, same year #}}
276+
{{ monthNames[eventMonth] }} {{ eventDay }} - {{ monthNames[endMonth] }} {{ endDay }}, {{ eventYear }}
269277
{{ else }}
270-
{{ shortMonthNames[endMonth] }} {{ endDay }}, {{ eventYear }}
278+
{{# Different years #}}
279+
{{ monthNames[eventMonth] }} {{ eventDay }}, {{ eventYear }} - {{ monthNames[endMonth] }} {{ endDay }}, {{ endYear }}
271280
{{ /if }}
272281
{{ /if }}
273282
</p>
@@ -285,7 +294,7 @@ layout: layouts/base.vto
285294
{{# Event Modal - Must be inside x-data scope #}}
286295
<div id="eventModal" class="fixed inset-0 z-50" x-show="modalOpen" x-cloak>
287296
<div class="fixed inset-0 bg-black bg-opacity-50" @click="closeModal()"></div>
288-
297+
289298
<div class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto mx-4">
290299
<div class="sticky top-0 bg-white border-b px-6 py-4 flex justify-between items-center">
291300
<h2 class="text-xl font-semibold text-gray-900" x-text="modalTitle"></h2>
@@ -332,7 +341,7 @@ function eventsPage() {
332341
}))) }},
333342
organizations: {{ JSON.stringify(organizations) }},
334343
eventYears: {{ JSON.stringify(eventYears) }},
335-
344+
336345
init() {
337346
// Read URL parameters for filters
338347
const params = new URLSearchParams(window.location.search);
@@ -345,35 +354,35 @@ function eventsPage() {
345354
this.currentYear = parseInt(year);
346355
}
347356
},
348-
357+
349358
get yearNavigation() {
350359
const currentIdx = this.eventYears.indexOf(this.currentYear);
351360
const nav = [];
352-
361+
353362
if (currentIdx > 0) {
354363
nav.push({
355364
show: true,
356365
year: this.eventYears[currentIdx - 1],
357366
label: `${this.eventYears[currentIdx - 1]}`
358367
});
359368
}
360-
369+
361370
if (currentIdx < this.eventYears.length - 1) {
362371
nav.push({
363372
show: true,
364373
year: this.eventYears[currentIdx + 1],
365374
label: `${this.eventYears[currentIdx + 1]}`
366375
});
367376
}
368-
377+
369378
return nav;
370379
},
371-
380+
372381
navigateToYear(year) {
373382
this.currentYear = year;
374383
this.updateURL();
375384
},
376-
385+
377386
toggleOrganization(orgId) {
378387
const idx = this.selectedOrgs.indexOf(orgId);
379388
if (idx > -1) {
@@ -383,12 +392,12 @@ function eventsPage() {
383392
}
384393
this.updateURL();
385394
},
386-
395+
387396
clearFilters() {
388397
this.selectedOrgs = [];
389398
this.updateURL();
390399
},
391-
400+
392401
updateURL() {
393402
const params = new URLSearchParams();
394403
if (this.selectedOrgs.length > 0) {
@@ -400,19 +409,19 @@ function eventsPage() {
400409
const url = params.toString() ? `?${params.toString()}` : window.location.pathname;
401410
window.history.replaceState({}, '', url);
402411
},
403-
412+
404413
hasEventsInYear(orgId) {
405-
return this.events.some(e =>
406-
e.by === orgId &&
414+
return this.events.some(e =>
415+
e.by === orgId &&
407416
parseInt(e.start_date.substring(0, 4)) === this.currentYear
408417
);
409418
},
410-
419+
411420
shouldShowEvents(eventOrgs) {
412421
if (this.selectedOrgs.length === 0) return true;
413422
return eventOrgs.some(org => this.selectedOrgs.includes(org));
414423
},
415-
424+
416425
shouldShowEvent(orgId, eventYear, startDate) {
417426
if (eventYear !== this.currentYear) return false;
418427
if (this.selectedOrgs.length === 0) {
@@ -427,33 +436,33 @@ function eventsPage() {
427436
}
428437
return this.selectedOrgs.includes(orgId);
429438
},
430-
439+
431440
isPastDate(year, month, day) {
432441
if (year !== new Date().getFullYear()) return false;
433442
const today = new Date();
434443
today.setHours(0, 0, 0, 0);
435444
const date = new Date(year, month, day);
436445
return date < today;
437446
},
438-
447+
439448
getEventsForDate(dateStr) {
440449
return this.events.filter(event => {
441450
const startDate = event.start_date;
442451
const endDate = event.end_date || startDate;
443-
452+
444453
// Apply organization filter
445454
if (this.selectedOrgs.length > 0 && !this.selectedOrgs.includes(event.by)) {
446455
return false;
447456
}
448-
457+
449458
return startDate <= dateStr && endDate >= dateStr;
450459
});
451460
},
452-
461+
453462
showEventModal(year, month, day, evt) {
454463
const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
455464
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
456-
465+
457466
// Get events from the button's data attribute or fetch them
458467
const button = evt ? evt.currentTarget : null;
459468
let events = [];
@@ -462,7 +471,7 @@ function eventsPage() {
462471
} else {
463472
events = this.getEventsForDate(dateStr);
464473
}
465-
474+
466475
this.modalTitle = `${monthNames[month]} ${day}, ${year}`;
467476
this.modalEvents = events.map(e => {
468477
const org = this.organizations.find(o => o.id === e.by);
@@ -474,7 +483,7 @@ function eventsPage() {
474483
this.modalOpen = true;
475484
document.body.style.overflow = 'hidden';
476485
},
477-
486+
478487
closeModal() {
479488
this.modalOpen = false;
480489
document.body.style.overflow = '';
@@ -485,4 +494,14 @@ function eventsPage() {
485494
486495
<style>
487496
[x-cloak] { display: none !important; }
488-
</style>
497+
498+
/* Hide elements before Alpine loads */
499+
[x-show] {
500+
display: none;
501+
}
502+
503+
/* Show elements once Alpine is ready */
504+
[x-data] [x-show] {
505+
display: revert;
506+
}
507+
</style>

tags_result.page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const navbar = {
1212
],
1313
};
1414

15-
export default function* ({ search }) {
15+
export default function*({ search }) {
1616
// Generate a page for each tag
1717
for (const tag of search.values("tags")) {
1818
yield {

0 commit comments

Comments
 (0)