Heavily customized version of smokesignal - https://whtwnd.com/kayrozen.com/3lpwe4ymowg2t
1<!-- =============================================== -->
2<!-- CSS STYLES REGION -->
3<!-- =============================================== -->
4<style>
5 .event-grid {
6 display: grid;
7 grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
8 gap: 1.5rem;
9 margin: 1rem 0;
10 }
11
12 .event-card {
13 background: rgba(255, 255, 255, 0.05);
14 border-radius: 12px;
15 padding: 1.25rem;
16 border: 1px solid #3a3a3a;
17 height: 100%;
18 transition: transform 0.2s ease, box-shadow 0.2s ease;
19 position: relative;
20 overflow: hidden;
21 cursor: pointer;
22 }
23
24 .event-card:hover {
25 transform: translateY(-5px);
26 box-shadow: 0 10px 20px rgba(0,0,0,0.2);
27 }
28
29 .event-card-link {
30 position: absolute;
31 top: 0;
32 left: 0;
33 right: 0;
34 bottom: 0;
35 z-index: 1;
36 }
37
38 .event-card-content {
39 position: relative;
40 z-index: 2;
41 }
42
43 /* Ensure buttons remain clickable */
44 .event-card .button,
45 .event-card a:not(.event-card-link) {
46 position: relative;
47 z-index: 3;
48 }
49
50 .event-time {
51 color: #888;
52 font-size: 0.75rem;
53 margin-bottom: 0.5rem;
54 font-weight: 500;
55 text-transform: uppercase;
56 letter-spacing: 0.5px;
57 }
58
59 .event-title {
60 color: white;
61 font-size: 1.125rem;
62 font-weight: 600;
63 margin-bottom: 0.75rem;
64 line-height: 1.4;
65 height: 2.8em;
66 overflow: hidden;
67 display: -webkit-box;
68 -webkit-line-clamp: 2;
69 line-clamp: 2;
70 -webkit-box-orient: vertical;
71 }
72
73 .event-title a {
74 color: white;
75 text-decoration: none;
76 transition: color 0.2s ease;
77 }
78
79 .event-title a:hover {
80 color: #7dd87f;
81 }
82
83 .event-organizer {
84 display: flex;
85 align-items: center;
86 margin-bottom: 0.75rem;
87 }
88
89 .organizer-avatar {
90 width: 24px;
91 height: 24px;
92 border-radius: 50%;
93 background: linear-gradient(45deg, #7dd87f, #5a9f63);
94 margin-right: 0.5rem;
95 display: flex;
96 align-items: center;
97 justify-content: center;
98 font-weight: bold;
99 font-size: 0.75rem;
100 color: white;
101 flex-shrink: 0;
102 }
103
104 .organizer-name {
105 color: #ccc;
106 font-size: 0.875rem;
107 white-space: nowrap;
108 overflow: hidden;
109 text-overflow: ellipsis;
110 }
111
112 .event-tags {
113 display: flex;
114 gap: 0.5rem;
115 margin-bottom: 1rem;
116 flex-wrap: wrap;
117 }
118
119 .event-tag {
120 font-size: 0.75rem;
121 padding: 0.25rem 0.5rem;
122 border-radius: 4px;
123 font-weight: 500;
124 text-transform: uppercase;
125 letter-spacing: 0.3px;
126 }
127
128 .tag-inperson { background-color: #2d5a3d; color: #7dd87f; }
129 .tag-virtual { background-color: #2d3d5a; color: #7f9ff8; }
130 .tag-hybrid { background-color: #5a2d5a; color: #d87fd8; }
131 .tag-planned { background-color: #3a3a3a; color: #aaa; }
132 .tag-scheduled { background-color: #2d5a3d; color: #7dd87f; }
133 .tag-cancelled { background-color: #5a2d2d; color: #f87f7f; }
134 .tag-postponed { background-color: #5a4a2d; color: #f8d67f; }
135 .tag-rescheduled { background-color: #2d3d5a; color: #7f9ff8; }
136 .tag-going { background-color: #2d5a3d; color: #7dd87f; }
137 .tag-interested { background-color: #2d3d5a; color: #7f9ff8; }
138 .tag-notgoing { background-color: #5a2d2d; color: #f87f7f; }
139 .tag-organizer { background-color: #5a2d5a; color: #d87fd8; }
140 .tag-legacy { background-color: #5a4a2d; color: #f8d67f; }
141
142 .event-participants {
143 display: flex;
144 align-items: center;
145 color: #aaa;
146 font-size: 0.875rem;
147 margin-bottom: 1rem;
148 }
149
150 .participants-icon {
151 margin-right: 0.5rem;
152 color: #7dd87f;
153 width: 12px;
154 }
155
156 .event-description {
157 color: #aaa;
158 font-size: 0.875rem;
159 margin-bottom: 1rem;
160 line-height: 1.4;
161 height: 2.8em;
162 overflow: hidden;
163 display: -webkit-box;
164 -webkit-line-clamp: 2;
165 line-clamp: 2;
166 -webkit-box-orient: vertical;
167 }
168
169 .event-actions {
170 display: flex;
171 gap: 0.5rem;
172 margin-top: 1rem;
173 padding-top: 1rem;
174 border-top: 1px solid #3a3a3a;
175 }
176
177 .action-btn {
178 flex: 1;
179 background: rgba(125, 216, 127, 0.1);
180 border: 1px solid #7dd87f;
181 color: #7dd87f;
182 border-radius: 6px;
183 padding: 0.5rem;
184 font-size: 0.875rem;
185 transition: all 0.2s ease;
186 text-decoration: none;
187 display: flex;
188 align-items: center;
189 justify-content: center;
190 gap: 0.25rem;
191 }
192
193 .action-btn:hover {
194 background: #7dd87f;
195 color: #1a1a1a;
196 }
197
198 .action-btn.secondary {
199 background: rgba(255, 255, 255, 0.05);
200 border: 1px solid #666;
201 color: #ccc;
202 }
203
204 .action-btn.secondary:hover {
205 background: rgba(255, 255, 255, 0.1);
206 color: white;
207 }
208
209 .event-stats {
210 display: flex;
211 gap: 1rem;
212 margin-bottom: 1rem;
213 font-size: 0.875rem;
214 color: #aaa;
215 }
216
217 .event-stats .stat {
218 display: flex;
219 align-items: center;
220 gap: 0.25rem;
221 }
222
223 .event-stats .stat i {
224 color: #7dd87f;
225 }
226
227 .empty-state {
228 text-align: center;
229 padding: 3rem 1rem;
230 color: #888;
231 }
232
233 .empty-state .icon {
234 font-size: 3rem;
235 margin-bottom: 1rem;
236 color: #555;
237 }
238
239 .empty-state h3 {
240 color: #ccc;
241 margin-bottom: 0.5rem;
242 }
243
244 @media (max-width: 768px) {
245 .event-grid {
246 grid-template-columns: 1fr;
247 gap: 1rem;
248 }
249
250 .event-card {
251 padding: 1rem;
252 }
253
254 .event-actions {
255 flex-direction: column;
256 }
257 }
258</style>
259
260<!-- =============================================== -->
261<!-- EVENT LISTING CONTENT -->
262<!-- =============================================== -->
263
264{% if events %}
265<div class="event-grid">
266 {% for event in events %}
267 <div class="event-card">
268 <a href="{{ base }}{{ event.site_url }}" class="event-card-link" hx-boost="true"></a>
269
270 <div class="event-card-content">
271 <!-- Time and Date -->
272 {% if event.starts_at_human %}
273 <div class="event-time">
274 <i class="fas fa-clock"></i>
275 <time class="dt-start" {% if event.starts_at_machine %}datetime="{{ event.starts_at_machine }}"{% endif %}>
276 {{ event.starts_at_human }}
277 </time>
278 </div>
279 {% endif %}
280
281 <!-- Event Title -->
282 <h3 class="event-title">
283 <a href="{{ base }}{{ event.site_url }}" hx-boost="true">
284 {% autoescape false %}{{ event.name }}{% endautoescape %}
285 </a>
286 </h3>
287
288 <!-- Event Tags -->
289 <div class="event-tags">
290 <!-- Role Tag -->
291 {% if event.role %}
292 <span class="event-tag tag-{{ event.role }}">
293 <i class="
294 {%- if event.role == 'going' -%}fas fa-star
295 {%- elif event.role == 'interested' -%}fas fa-eye
296 {%- elif event.role == 'notgoing' -%}fas fa-ban
297 {%- elif event.role == 'organizer' -%}fas fa-calendar
298 {%- else -%}fas fa-question
299 {%- endif -%}"></i>
300 {%- if event.role == 'going' -%}{{ t("status-going") }}
301 {%- elif event.role == 'interested' -%}{{ t("status-interested") }}
302 {%- elif event.role == 'notgoing' -%}{{ t("status-not-going") }}
303 {%- elif event.role == 'organizer' -%}{{ t("status-organizer") }}
304 {%- else -%}{{ t("status-unknown") }}
305 {%- endif -%}
306 </span>
307 {% endif %}
308
309 <!-- Legacy Tag -->
310 {% if event.collection != "community.lexicon.calendar.event" %}
311 <span class="event-tag tag-legacy">{{ t("status-legacy") }}</span>
312 {% endif %}
313
314 <!-- Status Tag -->
315 {% if event.status == "planned" %}
316 <span class="event-tag tag-planned" title="{{ t('status-planned') }}">
317 <i class="fas fa-calendar-days"></i> {{ t("status-planned") }}
318 </span>
319 {% elif event.status == "scheduled" %}
320 <span class="event-tag tag-scheduled" title="{{ t('status-scheduled') }}">
321 <i class="fas fa-calendar-check"></i> {{ t("status-scheduled") }}
322 </span>
323 {% elif event.status == "rescheduled" %}
324 <span class="event-tag tag-rescheduled" title="{{ t('status-rescheduled') }}">
325 <i class="fas fa-calendar-plus"></i> {{ t("status-rescheduled") }}
326 </span>
327 {% elif event.status == "cancelled" %}
328 <span class="event-tag tag-cancelled" title="{{ t('status-cancelled') }}">
329 <i class="fas fa-calendar-xmark"></i> {{ t("status-cancelled") }}
330 </span>
331 {% elif event.status == "postponed" %}
332 <span class="event-tag tag-postponed" title="{{ t('status-postponed') }}">
333 <i class="fas fa-calendar-minus"></i> {{ t("status-postponed") }}
334 </span>
335 {% endif %}
336
337 <!-- Mode Tag -->
338 {% if event.mode == "inperson" %}
339 <span class="event-tag tag-inperson">
340 <i class="fas fa-users"></i> {{ t("mode-in-person") }}
341 </span>
342 {% elif event.mode == "virtual" %}
343 <span class="event-tag tag-virtual">
344 <i class="fas fa-video"></i> {{ t("mode-virtual") }}
345 </span>
346 {% elif event.mode == "hybrid" %}
347 <span class="event-tag tag-hybrid">
348 <i class="fas fa-globe"></i> {{ t("mode-hybrid") }}
349 </span>
350 {% endif %}
351 </div>
352
353 <!-- Organizer Info -->
354 {% if event.organizer_display_name %}
355 <div class="event-organizer">
356 <div class="organizer-avatar">
357 {{ event.organizer_display_name|first|upper }}
358 </div>
359 <span class="organizer-name">
360 <a href="{{ base }}/{{ event.organizer_did }}" hx-boost="true" style="color: inherit; text-decoration: none;">
361 {{ event.organizer_display_name }}
362 </a>
363 </span>
364 </div>
365 {% endif %}
366
367 <!-- Event Description Preview -->
368 {% if event.description_short %}
369 <div class="event-description">
370 {% autoescape false %}{{ event.description_short }}{% endautoescape %}
371 </div>
372 {% endif %}
373
374 <!-- Location -->
375 {% if event.location %}
376 <div class="event-location" style="color: #aaa; font-size: 0.875rem; margin-bottom: 1rem;">
377 <i class="fas fa-map-marker-alt" style="color: #7dd87f; margin-right: 0.5rem;"></i>
378 {{ event.location }}
379 </div>
380 {% endif %}
381
382 <!-- End Time -->
383 {% if event.ends_at_human %}
384 <div class="event-end-time" style="color: #888; font-size: 0.75rem; margin-bottom: 1rem;">
385 <i class="fas fa-clock" style="margin-right: 0.25rem;"></i>
386 {{ t("ends-at", time=event.ends_at_human) }}
387 </div>
388 {% endif %}
389
390 <!-- Event Statistics -->
391 <div class="event-stats">
392 <div class="stat" title="{{ t('event-count-going', count=event.count_going | default(0)) }}">
393 <i class="fas fa-star"></i>
394 <span>{{ event.count_going | default(0) }}</span>
395 </div>
396 <div class="stat" title="{{ t('event-count-interested', count=event.count_interested | default(0)) }}">
397 <i class="fas fa-eye"></i>
398 <span>{{ event.count_interested | default(0) }}</span>
399 </div>
400 <div class="stat" title="{{ t('event-count-not-going', count=event.count_not_going | default(0)) }}">
401 <i class="fas fa-ban"></i>
402 <span>{{ event.count_not_going | default(0) }}</span>
403 </div>
404 </div>
405
406 <!-- Action Buttons -->
407 <div class="event-actions">
408 <a href="{{ base }}{{ event.site_url }}" class="action-btn" hx-boost="true">
409 <i class="fas fa-eye"></i>
410 {{ t("view-event") }}
411 </a>
412 </div>
413 </div>
414 </div>
415 {% endfor %}
416</div>
417{% else %}
418<div class="empty-state">
419 <div class="icon">
420 <i class="fas fa-calendar-times"></i>
421 </div>
422 <h3>{{ t("no-events-found") }}</h3>
423 <p>{{ t("no-events-description") }}</p>
424</div>
425{% endif %}