From 207bdbc6ceb9421d419032ed892280490f4fd9f3 Mon Sep 17 00:00:00 2001 From: Arne Schauf Date: Sat, 18 Apr 2026 18:30:13 +0200 Subject: [PATCH] Enhance event card layouts, timeline styles, and add template tests --- core/static/css/theme/base.css | 4 + core/static/css/timeline.css | 91 ++++++++++++++++----- core/templates/core/event_history_page.html | 45 ++++------ core/templates/core/event_index_page.html | 37 ++++----- core/tests.py | 65 +++++++++++++++ 5 files changed, 171 insertions(+), 71 deletions(-) create mode 100644 core/tests.py diff --git a/core/static/css/theme/base.css b/core/static/css/theme/base.css index bd1b8d1..eaa23cb 100644 --- a/core/static/css/theme/base.css +++ b/core/static/css/theme/base.css @@ -66,6 +66,10 @@ a:hover::after { width: 100%; } +a.btn::after { + display: none; +} + /* Form controls */ .form-control:focus { border-color: var(--bs-primary); diff --git a/core/static/css/timeline.css b/core/static/css/timeline.css index d321710..7ee3ada 100644 --- a/core/static/css/timeline.css +++ b/core/static/css/timeline.css @@ -1,7 +1,7 @@ /* Timeline styling */ .timeline { position: relative; - padding: 0; + padding: 20px 0; list-style: none; } @@ -12,17 +12,18 @@ bottom: 0; left: 40px; width: 4px; - background-color: var(--bs-primary); + background: linear-gradient(to bottom, var(--bs-primary) 0%, rgba(var(--bs-primary-rgb), 0.2) 100%); + border-radius: 2px; } .timeline-item { position: relative; - margin-bottom: 50px; + margin-bottom: 60px; } .timeline-badge { position: absolute; - top: 0; + top: 10px; left: 40px; width: 60px; height: 60px; @@ -36,61 +37,111 @@ flex-direction: column; align-items: center; justify-content: center; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); padding: 5px; + border: 4px solid #fff; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.timeline-item:hover .timeline-badge { + transform: scale(1.1); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); } .timeline-badge-day { - font-size: 1.25rem; + font-size: 1.3rem; font-weight: bold; line-height: 1; } .timeline-badge-month { - font-size: 0.8rem; + font-size: 0.85rem; text-transform: uppercase; line-height: 1; + font-weight: 600; } .timeline-month-header { position: relative; - margin-bottom: 30px; + margin-bottom: 40px; list-style: none; } .timeline-month-header h3 { position: relative; - padding-left: 60px; - border-bottom: 2px solid var(--bs-primary); - padding-bottom: 10px; + padding-left: 85px; + border-bottom: 2px solid rgba(var(--bs-primary-rgb), 0.2); + padding-bottom: 12px; + font-weight: 700; + color: var(--bs-primary); + display: inline-block; } .timeline-panel { position: relative; - width: calc(100% - 90px); + width: calc(100% - 100px); float: right; - border-radius: 8px; + border-radius: 12px; + transition: transform 0.3s ease, box-shadow 0.3s ease; + border: 1px solid rgba(0,0,0,0.05) !important; +} + +.timeline-panel:hover { + transform: translateY(-5px); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1) !important; } .timeline-panel:before { content: ''; position: absolute; - top: 26px; - left: -15px; - border-top: 15px solid transparent; - border-right: 15px solid #fff; - border-bottom: 15px solid transparent; + top: 24px; + left: -12px; + border-top: 12px solid transparent; + border-right: 12px solid #fff; + border-bottom: 12px solid transparent; + filter: drop-shadow(-2px 0 2px rgba(0,0,0,0.03)); } .timeline-date { display: block; margin-bottom: 10px; - font-weight: bold; + font-weight: 600; color: var(--bs-primary); } +.timeline-panel .card-title a { + transition: color 0.2s ease; +} + +.timeline-panel .card-title a:hover { + color: var(--bs-primary) !important; +} + @media (max-width: 767px) { + .timeline:before { + left: 30px; + } + .timeline-badge { - margin-left: 0; + left: 30px; + width: 50px; + height: 50px; + margin-left: -25px; + } + + .timeline-badge-day { + font-size: 1.1rem; + } + + .timeline-badge-month { + font-size: 0.75rem; + } + + .timeline-panel { + width: calc(100% - 70px); + } + + .timeline-month-header h3 { + padding-left: 65px; } } diff --git a/core/templates/core/event_history_page.html b/core/templates/core/event_history_page.html index 70d794e..5620445 100644 --- a/core/templates/core/event_history_page.html +++ b/core/templates/core/event_history_page.html @@ -20,24 +20,24 @@ {{ event.value.start_date|date:"b" }}
-
+
- {{ event.value.start_date|date:"SHORT_DATE_FORMAT" }}{% if event.value.end_date %} - {{ event.value.end_date|date:"SHORT_DATE_FORMAT" }}{% endif %} + {{ event.value.start_date|date:"SHORT_DATE_FORMAT" }}{% if event.value.end_date %} - {{ event.value.end_date|date:"SHORT_DATE_FORMAT" }}{% endif %}
{{ event.value.start_date|date:"F Y" }}
-
-

+
+

{% if event.type == 'page' %} - {{ event.value.title }} + {{ event.value.title }} {% else %} {{ event.value.title }} {% endif %} - {% if event.value.subtitle %}
{{ event.value.subtitle }}{% endif %} + {% if event.value.subtitle %}
{{ event.value.subtitle }}{% endif %}

@@ -45,38 +45,27 @@ {% image event.value.image max-250x250 class="img-fluid rounded" %} {% endif %}
-
-
- {{ event.value.start_date }}{% if event.value.end_date %} - {{ event.value.end_date }}{% endif %} -
- -

- {% if event.value.location_name %}{{ event.value.location_name }}
{% endif %} - {% if event.value.location_city %}{{ event.value.location_city }}{% endif %} +

+ {% if event.value.location_name or event.value.location_city %} +

+ {% if event.value.location_name %}{{ event.value.location_name }}
{% endif %} + {% if event.value.location_city %}{{ event.value.location_city }}{% endif %}

+ {% endif %}
-
+
{% if event.type == 'manual' %} {% if event.value.flyer.url %} -

- Programm herunterladen -

+ Programm herunterladen {% endif %} {% if event.value.additional_info_target.url %} -

- - {{ event.value.additional_info_btn_label }} -

+ {{ event.value.additional_info_btn_label }} {% endif %} {% elif event.type == 'page' %} {% if event.value.flyer %} -

- Programm herunterladen -

+ Programm herunterladen {% endif %} -

- Details anzeigen -

+ Details anzeigen {% endif %}
diff --git a/core/templates/core/event_index_page.html b/core/templates/core/event_index_page.html index b81c875..7bc575d 100644 --- a/core/templates/core/event_index_page.html +++ b/core/templates/core/event_index_page.html @@ -23,50 +23,41 @@ {% if event.is_partner_event %}
Partner Event
{% endif %} -
+
- {{ event.start_date|date:"SHORT_DATE_FORMAT" }}{% if event.end_date %} - {{ event.end_date|date:"SHORT_DATE_FORMAT" }}{% endif %} + {{ event.start_date|date:"SHORT_DATE_FORMAT" }}{% if event.end_date %} - {{ event.end_date|date:"SHORT_DATE_FORMAT" }}{% endif %}
-
-

{{ event.title }} - {% if event.subtitle %}
{{ event.subtitle }}{% endif %}

+
+

{{ event.title }} + {% if event.subtitle %}
{{ event.subtitle }}{% endif %}

{% if event.img1_img %} {% image event.img1_img max-250x250 class="img-fluid rounded" %} {% endif %}
-
-
- {{ event.start_date }}{% if event.end_date %} - {{ event.end_date }}{% endif %} -
+
{% if event.location_name %} -

- {{ event.location_name }}
- {% if event.location_street %}{{ event.location_street }}
{% endif %} - {% if event.location_city %}{{ event.location_city }}{% endif %} +

+ {{ event.location_name }}
+ {% if event.location_street %}{{ event.location_street }}
{% endif %} + {% if event.location_city %}{{ event.location_city }}{% endif %}

{% endif %}
-
+
{% if event.is_registration_active %} -

- Zur Anmeldung -

+ Zur Anmeldung {% endif %} {% if event.flyer.url %} -

- Programm herunterladen -

+ Programm herunterladen {% endif %} -

- Mehr Informationen -

+ Mehr Informationen
diff --git a/core/tests.py b/core/tests.py new file mode 100644 index 0000000..72ac4cd --- /dev/null +++ b/core/tests.py @@ -0,0 +1,65 @@ +from datetime import date, timedelta + +from django.test import TestCase +from wagtail.models import Page, Site + +from core.models import EventIndexPage, EventPage, HomePage + + +class EventIndexPageTemplateTests(TestCase): + @classmethod + def setUpTestData(cls): + default_site = Site.objects.filter(is_default_site=True).first() + if default_site: + cls.home_page = default_site.root_page.specific + default_site.hostname = 'testserver' + default_site.site_name = 'Test site' + default_site.save() + else: + root_page = Page.get_first_root_node() + cls.home_page = HomePage(title='Home', slug='home') + root_page.add_child(instance=cls.home_page) + cls.home_page.save_revision().publish() + Site.objects.create( + hostname='testserver', + root_page=cls.home_page, + is_default_site=True, + site_name='Test site', + ) + + cls.index_page = EventIndexPage(title='Events', slug='events-overview') + cls.home_page.add_child(instance=cls.index_page) + cls.index_page.save_revision().publish() + + def test_event_index_page_renders_enhanced_timeline_layout(self): + event_page = EventPage( + title='Spring Academy', + slug='spring-academy', + subtitle='Music and masterclasses', + start_date=date.today() + timedelta(days=14), + end_date=date.today() + timedelta(days=16), + location_name='Konzerthaus', + location_street='Street 1', + location_city='10115 Berlin', + show_in_event_calendar=True, + is_partner_event=True, + registration_start_date=date.today(), + ) + self.index_page.add_child(instance=event_page) + event_page.save_revision().publish() + + response = self.client.get(self.index_page.url) + + self.assertContains(response, 'event-index-timeline') + self.assertContains(response, 'timeline-page-hero') + self.assertContains(response, 'event-timeline-card') + self.assertContains(response, 'event-timeline-placeholder') + self.assertContains(response, 'Partner Event') + self.assertContains(response, 'Zur Anmeldung') + self.assertContains(response, 'Konzerthaus') + + def test_event_index_page_shows_empty_state_without_events(self): + response = self.client.get(self.index_page.url) + + self.assertContains(response, 'timeline-empty-state') + self.assertContains(response, 'Zurzeit sind keine Veranstaltungen geplant.')