This commit is contained in:
2026-03-05 21:45:40 +00:00
parent 39c80a0253
commit 146a9bda99
16 changed files with 956 additions and 24 deletions

View File

@@ -10,18 +10,188 @@
</h1>
{% if page == 'schedule' %}
<p>{{ t('schedule_text') }}</p>
<p>{{ t('schedule_intro') }}</p>
<div class="schedule-timeline">
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/ankunft.png') }}'); --schedule-card-position: center 18%;">
<p class="schedule-time">15:00</p>
<h2>{{ t('schedule_arrival_title') }}</h2>
<p>{{ t('schedule_arrival_text') }}</p>
</article>
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/trauzermonie.png') }}'); --schedule-card-position: center 25%;">
<p class="schedule-time">15:30</p>
<h2>{{ t('schedule_ceremony_title') }}</h2>
<p>{{ t('schedule_ceremony_text') }}</p>
</article>
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/sektempfang.png') }}'); --schedule-card-position: center 32%;">
<p class="schedule-time">16:00</p>
<h2>{{ t('schedule_reception_title') }}</h2>
<p>{{ t('schedule_reception_text') }}</p>
</article>
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/buffet.png') }}'); --schedule-card-position: center 40%;">
<p class="schedule-time">18:00</p>
<h2>{{ t('schedule_buffet_title') }}</h2>
<p>{{ t('schedule_buffet_text') }}</p>
</article>
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/kuchen.png') }}'); --schedule-card-position: center 48%;">
<p class="schedule-time">22:00</p>
<h2>{{ t('schedule_cake_title') }}</h2>
<p>{{ t('schedule_cake_text') }}</p>
</article>
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/party.png') }}'); --schedule-card-position: center 56%;">
<p class="schedule-time">{{ t('schedule_afterwards_time') }}</p>
<h2>{{ t('schedule_party_title') }}</h2>
<p>{{ t('schedule_party_text') }}</p>
</article>
</div>
{% elif page == 'hotels' %}
<p>{{ t('hotels_text') }}</p>
<p>{{ t('hotels_intro') }}</p>
<div class="hotel-list">
{% for hotel in hotels %}
<article class="hotel-card">
<h2>{{ hotel.name }}</h2>
<p class="hotel-address">{{ hotel.address }}</p>
<p>{{ hotel.description }}</p>
<div class="hotel-badges">
<span>{{ hotel.drive_badge }}</span>
<span>{{ hotel.walk_badge }}</span>
</div>
<div class="hotel-actions">
<a class="btn" href="{{ hotel.website_url }}" target="_blank" rel="noopener">{{ t('hotel_visit_website') }}</a>
<a
class="btn btn-ghost"
href="{{ hotel.drive_route_url }}"
target="_blank"
rel="noopener"
data-route-popup
data-route-src="{{ hotel.drive_route_embed_url }}"
>{{ t('hotel_route_drive') }}</a>
<a
class="btn btn-ghost"
href="{{ hotel.walk_route_url }}"
target="_blank"
rel="noopener"
data-route-popup
data-route-src="{{ hotel.walk_route_embed_url }}"
>{{ t('hotel_route_walk') }}</a>
</div>
</article>
{% endfor %}
</div>
<div class="route-modal" data-route-modal hidden>
<div class="route-modal-backdrop" data-route-close></div>
<section class="route-modal-panel" role="dialog" aria-modal="true" aria-label="{{ t('hotel_route_modal_title') }}">
<header class="route-modal-head">
<h2>{{ t('hotel_route_modal_title') }}</h2>
<button class="btn btn-ghost route-modal-close" type="button" data-route-close>{{ t('hotel_route_modal_close') }}</button>
</header>
<div class="route-modal-body">
<iframe title="{{ t('hotel_route_modal_title') }}" loading="lazy" referrerpolicy="no-referrer-when-downgrade" allowfullscreen data-route-frame></iframe>
<div class="route-map-actions">
<a class="btn route-open-btn" href="#" target="_blank" rel="noopener" data-route-open-external>{{ t('hotel_route_open_maps') }}</a>
</div>
</div>
</section>
</div>
<script>
(() => {
const modal = document.querySelector("[data-route-modal]");
if (!modal) return;
const frame = modal.querySelector("[data-route-frame]");
const externalLink = modal.querySelector("[data-route-open-external]");
const closeNodes = modal.querySelectorAll("[data-route-close]");
const triggerNodes = document.querySelectorAll("[data-route-popup][data-route-src]");
if (!frame || !externalLink || triggerNodes.length === 0) return;
const closeModal = () => {
modal.hidden = true;
document.body.classList.remove("has-route-modal");
frame.src = "";
};
triggerNodes.forEach((node) => {
node.addEventListener("click", (event) => {
event.preventDefault();
const src = node.getAttribute("data-route-src");
const href = node.getAttribute("href");
if (!src) return;
frame.src = src;
externalLink.href = href || "#";
modal.hidden = false;
document.body.classList.add("has-route-modal");
});
});
closeNodes.forEach((node) => {
node.addEventListener("click", closeModal);
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && !modal.hidden) {
closeModal();
}
});
})();
</script>
{% elif page == 'taxi' %}
<div class="taxi-coming-soon">
<img
src="{{ url_for('static', filename='assets/bauarbeiter-sticker.png') }}"
alt="{{ t('taxi_sticker_alt') }}"
loading="lazy"
decoding="async"
>
</div>
<p>{{ t('taxi_text') }}</p>
{% elif page == 'gifts' %}
<p>{{ t('gifts_text') }}</p>
<section class="gift-fun" data-gift-fun>
<p class="gift-lead">{{ t('gifts_teaser') }}</p>
<button class="btn gift-reveal-btn" type="button" data-gift-reveal>{{ t('gifts_reveal_button') }}</button>
<div class="gift-reveal" hidden data-gift-reveal-panel>
<div class="gift-image-wrap">
<img
src="{{ url_for('static', filename='assets/money-pile.svg') }}"
alt="{{ t('gifts_image_alt') }}"
loading="lazy"
decoding="async"
>
</div>
<p class="gift-caption">{{ t('gifts_caption') }}</p>
<p>{{ t('gifts_text') }}</p>
<div class="money-rain" aria-hidden="true">
<span class="bill" style="--idx: 1;"></span>
<span class="bill" style="--idx: 2;"></span>
<span class="bill" style="--idx: 3;"></span>
<span class="bill" style="--idx: 4;"></span>
<span class="bill" style="--idx: 5;"></span>
<span class="bill" style="--idx: 6;"></span>
<span class="bill" style="--idx: 7;"></span>
<span class="bill" style="--idx: 8;"></span>
<span class="bill" style="--idx: 9;"></span>
<span class="bill" style="--idx: 10;"></span>
<span class="bill" style="--idx: 11;"></span>
<span class="bill" style="--idx: 12;"></span>
</div>
</div>
</section>
<script>
(() => {
const root = document.querySelector("[data-gift-fun]");
if (!root) return;
const button = root.querySelector("[data-gift-reveal]");
const panel = root.querySelector("[data-gift-reveal-panel]");
if (!button || !panel) return;
button.addEventListener("click", () => {
panel.hidden = false;
panel.classList.add("is-active");
button.setAttribute("disabled", "disabled");
}, { once: true });
})();
</script>
{% elif page == 'location' %}
<p><strong>{{ location_name }}</strong></p>
<p>{{ location_address }}</p>
<h2>{{ t('location_story_title') }}</h2>
<p>{{ t('location_story_text') }}</p>
<div class="map-wrap map-consent" data-map-consent>
<p>{{ t('maps_privacy_notice') }}</p>
<button
class="map-preview"
type="button"
@@ -34,6 +204,7 @@
</button>
<div class="map-embed-target" data-map-embed-target></div>
<div class="location-actions">
<a class="btn btn-ghost" href="{{ location_route_url }}" target="_blank" rel="noopener" data-location-route-live>{{ t('route_from_current') }}</a>
<a class="btn" href="{{ location_website_url }}" target="_blank" rel="noopener">{{ t('visit_location') }}</a>
</div>
</div>
@@ -46,6 +217,8 @@
const previewButton = wrapper.querySelector(".map-preview");
const target = wrapper.querySelector("[data-map-embed-target]");
const src = {{ google_maps_embed_url|tojson }};
const destination = {{ location_address|tojson }};
const liveRouteLink = wrapper.querySelector("[data-location-route-live]");
let loaded = false;
const loadMap = () => {
@@ -66,6 +239,38 @@
loadButtons.forEach((button) => {
button.addEventListener("click", loadMap);
});
if (liveRouteLink) {
liveRouteLink.addEventListener("click", (event) => {
event.preventDefault();
const fallback = liveRouteLink.getAttribute("href");
const openFallback = () => {
if (fallback) {
window.open(fallback, "_blank", "noopener");
}
};
if (!navigator.geolocation) {
openFallback();
return;
}
navigator.geolocation.getCurrentPosition(
({ coords }) => {
const origin = `${coords.latitude},${coords.longitude}`;
const query = new URLSearchParams({
api: "1",
origin,
destination,
travelmode: "driving",
});
window.open(`https://www.google.com/maps/dir/?${query.toString()}`, "_blank", "noopener");
},
() => openFallback(),
{ enableHighAccuracy: true, timeout: 4500, maximumAge: 120000 }
);
});
}
})();
</script>
{% endif %}

View File

@@ -23,4 +23,28 @@
</form>
</section>
</div>
<aside class="login-privacy-banner" data-login-privacy-banner>
<p class="login-privacy-title">{{ t('login_privacy_title') }}</p>
<p class="login-privacy-text">
{{ t('login_privacy_text') }}
<a href="{{ url_for('datenschutz') }}">{{ t('privacy') }}</a>
</p>
<button class="btn login-privacy-btn" type="button" data-login-privacy-accept>{{ t('login_privacy_accept') }}</button>
</aside>
<script>
(() => {
const banner = document.querySelector("[data-login-privacy-banner]");
const acceptBtn = document.querySelector("[data-login-privacy-accept]");
if (!banner || !acceptBtn) return;
const storageKey = "login_privacy_banner_v1_ack";
if (localStorage.getItem(storageKey) === "1") {
banner.hidden = true;
return;
}
acceptBtn.addEventListener("click", () => {
localStorage.setItem(storageKey, "1");
banner.hidden = true;
});
})();
</script>
{% endblock %}

View File

@@ -5,9 +5,10 @@
{% if wedding_date %}
<p class="hero-kicker">{{ wedding_date }}</p>
{% endif %}
<h1>{{ t('hero_headline') }}</h1>
<p>{{ t('hero_text') }}</p>
<h1>{{ welcome_headline or t('hero_headline') }}</h1>
<p>{{ welcome_text or t('hero_text') }}</p>
<a class="btn hero-cta" href="{{ url_for('guest_area') }}">{{ t('to_guest_area') }}</a>
</div>
</section>
<p class="hero-hint-below">{{ welcome_hint }}</p>
{% endblock %}