662 lines
28 KiB
HTML
662 lines
28 KiB
HTML
{% extends 'base.html' %}
|
|
{% block content %}
|
|
<section class="card">
|
|
<h1>
|
|
{% if page == 'schedule' %}{{ t('schedule') }}{% endif %}
|
|
{% if page == 'hotels' %}{{ t('hotels') }}{% endif %}
|
|
{% if page == 'taxi' %}{{ t('taxi') }}{% endif %}
|
|
{% if page == 'location' %}{{ t('location') }}{% endif %}
|
|
{% if page == 'gifts' %}{{ t('gifts') }}{% endif %}
|
|
</h1>
|
|
|
|
{% if page == 'schedule' %}
|
|
<p>{{ t('schedule_intro') }}</p>
|
|
<div class="schedule-timeline">
|
|
<article class="schedule-item" style="--schedule-card-image: url('{{ url_for('static', filename='assets/ankunft.webp') }}'); --schedule-card-position: center 18%;">
|
|
<p class="schedule-time">16: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.webp') }}'); --schedule-card-position: center 25%;">
|
|
<p class="schedule-time">16: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.webp') }}'); --schedule-card-position: center 32%;">
|
|
<p class="schedule-time">{{ t('schedule_reception_time') }}</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.webp') }}'); --schedule-card-position: center 40%;">
|
|
<p class="schedule-time">19: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.webp') }}'); --schedule-card-position: center 48%;">
|
|
<p class="schedule-time">{{ t('schedule_cake_time') }}</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.webp') }}'); --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_intro') }}</p>
|
|
<div
|
|
class="hotel-list"
|
|
data-hotel-routes
|
|
data-route-denied="{{ t('route_location_denied') }}"
|
|
data-route-unavailable="{{ t('route_location_unavailable') }}"
|
|
>
|
|
{% 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 route-location-btn"
|
|
href="{{ hotel.current_route_url }}"
|
|
target="_blank"
|
|
rel="noopener"
|
|
data-hotel-route-live
|
|
data-hotel-destination="{{ hotel.address }}"
|
|
>{{ t('hotel_route_from_current') }}</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>
|
|
<script>
|
|
(() => {
|
|
const wrapper = document.querySelector("[data-hotel-routes]");
|
|
if (!wrapper) return;
|
|
const routeLinks = wrapper.querySelectorAll("[data-hotel-route-live][data-hotel-destination]");
|
|
const deniedMsg = wrapper.dataset.routeDenied || "";
|
|
const unavailableMsg = wrapper.dataset.routeUnavailable || "";
|
|
|
|
routeLinks.forEach((link) => {
|
|
link.addEventListener("click", (event) => {
|
|
event.preventDefault();
|
|
if (!navigator.geolocation) {
|
|
if (unavailableMsg) window.alert(unavailableMsg);
|
|
return;
|
|
}
|
|
|
|
const destination = link.dataset.hotelDestination;
|
|
navigator.geolocation.getCurrentPosition(
|
|
({ coords }) => {
|
|
const query = new URLSearchParams({
|
|
api: "1",
|
|
origin: `${coords.latitude},${coords.longitude}`,
|
|
destination,
|
|
travelmode: "driving",
|
|
});
|
|
window.open(`https://www.google.com/maps/dir/?${query.toString()}`, "_blank", "noopener");
|
|
},
|
|
(geoError) => {
|
|
if (geoError && geoError.code === 1 && deniedMsg) {
|
|
window.alert(deniedMsg);
|
|
return;
|
|
}
|
|
if (unavailableMsg) window.alert(unavailableMsg);
|
|
},
|
|
{ enableHighAccuracy: false, timeout: 10000, maximumAge: 300000 }
|
|
);
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
<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="culinary-page">
|
|
<section
|
|
class="culinary-hero culinary-hero-food"
|
|
style="--culinary-hero-image: url('{{ url_for('static', filename='assets/culinary/Genusseinleitungsbild.png') }}');"
|
|
role="img"
|
|
aria-label="{{ t('culinary_hero_image_alt') }}"
|
|
></section>
|
|
|
|
<div class="culinary-intro-copy">
|
|
<h2>{{ t('culinary_title') }}</h2>
|
|
<p>{{ t('culinary_intro') }}</p>
|
|
</div>
|
|
|
|
<nav class="culinary-jump-nav" aria-label="{{ t('culinary_navigation') }}" data-culinary-switch data-active="menu">
|
|
<span class="culinary-switch-slider" aria-hidden="true"></span>
|
|
<a class="is-active" href="#menu" data-culinary-target="menu">{{ t('culinary_menu') }}</a>
|
|
<a href="#drinks" data-culinary-target="drinks">{{ t('culinary_drinks') }}</a>
|
|
</nav>
|
|
|
|
<section class="culinary-section" id="menu">
|
|
<div class="culinary-section-heading">
|
|
<p class="culinary-eyebrow">{{ t('culinary_menu') }}</p>
|
|
<h2>{{ t('culinary_reception_title') }}</h2>
|
|
<p>{{ t('culinary_reception_text') }}</p>
|
|
</div>
|
|
|
|
<article class="culinary-course culinary-course-starter">
|
|
<img
|
|
class="culinary-course-image"
|
|
src="{{ url_for('static', filename='assets/culinary/Burrata.png') }}"
|
|
alt="{{ t('culinary_starter_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-number" aria-hidden="true">01</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('culinary_starter') }}</p>
|
|
<h3>{{ t('culinary_starter_title') }}</h3>
|
|
<p>{{ t('culinary_starter_text') }}</p>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="culinary-course culinary-course-main">
|
|
<img
|
|
src="{{ url_for('static', filename='assets/culinary/main-course-alternative-v2.png') }}"
|
|
alt="{{ t('culinary_main_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-number" aria-hidden="true">02</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('culinary_main') }}</p>
|
|
<h3>{{ t('culinary_main_title') }}</h3>
|
|
<div class="culinary-menu-grid">
|
|
<div>
|
|
<h4>{{ t('culinary_meat_fish') }}</h4>
|
|
<ul>
|
|
<li>{{ t('culinary_rosemary_chicken') }}</li>
|
|
<li>{{ t('culinary_roastbeef') }}</li>
|
|
<li>{{ t('culinary_seabream') }}</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4>{{ t('culinary_parmesan_wheel') }}</h4>
|
|
<ul><li>{{ t('culinary_linguine') }}</li></ul>
|
|
</div>
|
|
<div>
|
|
<h4>{{ t('culinary_sides') }}</h4>
|
|
<ul>
|
|
<li>{{ t('culinary_rosemary_potatoes') }}</li>
|
|
<li>{{ t('culinary_herb_rice') }}</li>
|
|
<li>{{ t('culinary_grilled_vegetables') }}</li>
|
|
<li>{{ t('culinary_salad') }}</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4>{{ t('culinary_sauces') }}</h4>
|
|
<ul>
|
|
<li>{{ t('culinary_bbq') }}</li>
|
|
<li>{{ t('culinary_sesame_mayo') }}</li>
|
|
<li>{{ t('culinary_red_wine_jus') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="culinary-course culinary-course-dessert">
|
|
<img
|
|
class="culinary-course-image"
|
|
src="{{ url_for('static', filename='assets/culinary/Panacotta.png') }}"
|
|
alt="{{ t('culinary_dessert_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-number" aria-hidden="true">03</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('culinary_dessert') }}</p>
|
|
<h3>{{ t('culinary_dessert_title') }}</h3>
|
|
<div class="culinary-dessert-grid">
|
|
<div>
|
|
<h4>{{ t('culinary_cake') }}</h4>
|
|
<p>{{ t('culinary_cake_text') }}</p>
|
|
</div>
|
|
<div>
|
|
<h4>{{ t('culinary_dessert_variations') }}</h4>
|
|
<ul>
|
|
<li>{{ t('culinary_panna_cotta') }}</li>
|
|
<li>{{ t('culinary_creme_brulee') }}</li>
|
|
<li>{{ t('culinary_pineapple') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
|
|
<section class="culinary-section drinks-section" id="drinks">
|
|
<div class="culinary-section-heading drinks-section-heading">
|
|
<p class="culinary-eyebrow">{{ t('culinary_drinks') }}</p>
|
|
<h2>{{ t('drinks_during_celebration') }}</h2>
|
|
<p>{{ t('drinks_intro') }}</p>
|
|
</div>
|
|
<div class="drinks-course-list">
|
|
<article class="culinary-course drink-course">
|
|
<img
|
|
class="culinary-course-image drink-course-image"
|
|
src="{{ url_for('static', filename='assets/culinary/alkoholfrei.png') }}"
|
|
alt="{{ t('drinks_refreshments_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 48 48" focusable="false">
|
|
<path d="M24 5C19 13 12 20 12 29a12 12 0 0 0 24 0C36 20 29 13 24 5Z" />
|
|
<path d="M18 30a6 6 0 0 0 6 6" />
|
|
<circle cx="35" cy="13" r="5" />
|
|
<path d="m31.5 9.5 7 7M35 8v10M30 13h10" />
|
|
</svg>
|
|
</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('drinks_refreshments') }}</p>
|
|
<h3>{{ t('drinks_non_alcoholic') }}</h3>
|
|
<ul class="drinks-inline-list">
|
|
<li>{{ t('drinks_water') }}</li><li>{{ t('drinks_soft') }}</li><li>{{ t('drinks_juices') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="culinary-course drink-course wine-course">
|
|
<img
|
|
class="culinary-course-image"
|
|
src="{{ url_for('static', filename='assets/culinary/Getränkekarte titel.png') }}"
|
|
alt="{{ t('drinks_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 48 48" focusable="false">
|
|
<path d="M8 8h15l-2 13a6 6 0 0 1-6 5 6 6 0 0 1-6-5L8 8Z" />
|
|
<path d="M15 26v11M10 40h10" />
|
|
<path d="M28 18v20h11V18" />
|
|
<path d="M28 18v-1c0-2 1.5-3.5 3.5-3.5.8-2.5 4.5-2.5 5.3 0 1.3.2 2.2 1.3 2.2 3.5v1H28Z" />
|
|
<path d="M39 22h3c4 0 4 9 0 9h-3M31 23v10M35 23v10" />
|
|
</svg>
|
|
</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('drinks_wine_beer') }}</p>
|
|
<h3>{{ t('drinks_wine_selection') }}</h3>
|
|
<div class="wine-selection-grid">
|
|
<section class="wine-family">
|
|
<h4>{{ t('drinks_white_wine') }}</h4>
|
|
<div class="wine-entry"><p class="wine-estate">Jung Dahlen</p><h5>Einklang Riesling</h5><span class="wine-style">{{ t('drinks_off_dry') }}</span></div>
|
|
<div class="wine-entry"><p class="wine-estate">Domdechant Werner</p><h5>Riesling</h5><span class="wine-style">{{ t('drinks_dry') }}</span></div>
|
|
</section>
|
|
<section class="wine-family">
|
|
<h4>{{ t('drinks_rose_wine') }}</h4>
|
|
<div class="wine-entry"><p class="wine-estate">Jung Dahlen</p><h5>Rosé Sinfonie</h5></div>
|
|
</section>
|
|
<section class="wine-family">
|
|
<h4>{{ t('drinks_red_wine') }}</h4>
|
|
<div class="wine-entry"><p class="wine-estate">Jung Dahlen</p><h5>Pinot Noir</h5></div>
|
|
</section>
|
|
<section class="wine-family">
|
|
<h4>{{ t('drinks_beer') }}</h4>
|
|
<p>{{ t('drinks_beer_selection') }}</p>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="culinary-course drink-course">
|
|
<img
|
|
class="culinary-course-image drink-course-image drink-course-image-bar"
|
|
src="{{ url_for('static', filename='assets/culinary/barclassics.png') }}"
|
|
alt="{{ t('drinks_bar_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 48 48" focusable="false">
|
|
<path d="M7 12h28L21 27Z" />
|
|
<path d="M21 27v11M14 41h14" />
|
|
<path d="m29 12 8-7" />
|
|
<circle cx="36" cy="8" r="4" />
|
|
</svg>
|
|
</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('drinks_aperitif_spirits') }}</p>
|
|
<h3>{{ t('drinks_bar_classics') }}</h3>
|
|
<div class="drink-pair-grid">
|
|
<section><h4>{{ t('drinks_aperitif') }}</h4><ul><li>Aperol Spritz</li><li>Lillet Wildberry</li><li>Hugo</li><li>{{ t('drinks_sparkling_wine') }}</li></ul></section>
|
|
<section><h4>{{ t('drinks_spirits') }}</h4><p>{{ t('drinks_spirits_text') }}</p></section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="culinary-course drink-course evening-bar-course">
|
|
<img
|
|
class="culinary-course-image drink-course-image drink-course-image-cocktails"
|
|
src="{{ url_for('static', filename='assets/culinary/Cocktails.png') }}"
|
|
alt="{{ t('drinks_evening_image_alt') }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<div class="culinary-course-body">
|
|
<div class="culinary-course-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 48 48" focusable="false">
|
|
<path d="M14 9h20l-3 31H17L14 9Z" />
|
|
<path d="M16 19h16M20 23l5-2 2 5-5 2-2-5ZM18 31l5-2 2 5-5 2-2-5Z" />
|
|
<path d="m27 20 11-16" />
|
|
<circle cx="33" cy="12" r="5" />
|
|
<path d="m29.5 8.5 7 7M33 7v10M28 12h10" />
|
|
<circle cx="27" cy="17" r="2" />
|
|
</svg>
|
|
</div>
|
|
<div class="culinary-course-copy">
|
|
<p class="culinary-course-label">{{ t('drinks_evening_bar') }}</p>
|
|
<p class="cocktail-time evening-bar-time">{{ t('drinks_from_22') }}</p>
|
|
<h3>{{ t('drinks_longdrinks_cocktails') }}</h3>
|
|
<div class="evening-drinks-grid">
|
|
<section><h4>{{ t('drinks_longdrinks') }}</h4><ul><li>Gin & Tonic</li><li>Rum & Cola</li><li>Vodka Orange</li><li>Whisky & Cola</li></ul></section>
|
|
<section class="cocktail-panel"><h4>{{ t('drinks_cocktails') }}</h4><ul><li>Mojito Razz</li><li>Sex on the Beach</li><li>Bahama Mama</li></ul></section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<script src="{{ url_for('static', filename='culinary.js', v='20260808a') }}" defer></script>
|
|
{% elif page == 'gifts' %}
|
|
<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"
|
|
>
|
|
<span class="gift-money-label">{{ t('gifts_money_label') }}</span>
|
|
</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' %}
|
|
{% if location_video_url %}
|
|
<div class="location-video-card">
|
|
<video
|
|
class="location-video"
|
|
controls
|
|
preload="metadata"
|
|
playsinline
|
|
poster="{{ url_for('static', filename='assets/location/hochheim.png') }}"
|
|
>
|
|
<source src="{{ location_video_url }}">
|
|
</video>
|
|
</div>
|
|
{% endif %}
|
|
<h2>{{ t('location_story_title') }}</h2>
|
|
<p>{{ t('location_story_text') }}</p>
|
|
<div class="location-slideshow" aria-label="{{ location_name }}">
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/hochheim.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="eager"
|
|
decoding="async"
|
|
style="--slide-index: 0;"
|
|
>
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/draußen.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
style="--slide-index: 1;"
|
|
>
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/trausaal.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
style="--slide-index: 2;"
|
|
>
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/gewölbe.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
style="--slide-index: 3;"
|
|
>
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/thresen.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
style="--slide-index: 4;"
|
|
>
|
|
<img
|
|
class="location-slide"
|
|
src="{{ url_for('static', filename='assets/location/essen1.png') }}"
|
|
alt="{{ location_name }}"
|
|
loading="lazy"
|
|
decoding="async"
|
|
style="--slide-index: 5;"
|
|
>
|
|
</div>
|
|
<p class="location-map-intro">{{ t('location_map_intro') }}</p>
|
|
<div
|
|
class="map-wrap map-consent"
|
|
data-map-consent
|
|
data-route-denied="{{ t('route_location_denied') }}"
|
|
data-route-unavailable="{{ t('route_location_unavailable') }}"
|
|
>
|
|
<button
|
|
class="map-preview"
|
|
type="button"
|
|
data-map-load
|
|
aria-label="{{ t('maps_load_button') }}"
|
|
title="{{ t('maps_load_button') }}"
|
|
style="--map-preview-image: url('{{ url_for('static', filename='assets/location-map-preview.jpeg') }}');"
|
|
>
|
|
<span class="map-preview-overlay">{{ t('maps_load_button') }}</span>
|
|
</button>
|
|
<div class="map-embed-target" data-map-embed-target></div>
|
|
<div class="location-actions">
|
|
<a class="btn btn-ghost route-location-btn" 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>
|
|
|
|
<script>
|
|
(() => {
|
|
const wrapper = document.querySelector("[data-map-consent]");
|
|
if (!wrapper) return;
|
|
const loadButtons = Array.from(wrapper.querySelectorAll("[data-map-load]"));
|
|
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]");
|
|
const deniedMsg = wrapper.dataset.routeDenied || "";
|
|
const unavailableMsg = wrapper.dataset.routeUnavailable || "";
|
|
let loaded = false;
|
|
|
|
const loadMap = () => {
|
|
if (loaded) return;
|
|
const iframe = document.createElement("iframe");
|
|
iframe.src = src;
|
|
iframe.title = {{ location_name|tojson }};
|
|
iframe.loading = "lazy";
|
|
iframe.referrerPolicy = "no-referrer-when-downgrade";
|
|
iframe.allowFullscreen = true;
|
|
target.appendChild(iframe);
|
|
if (previewButton) {
|
|
previewButton.remove();
|
|
}
|
|
loadButtons.forEach((button) => button.remove());
|
|
loaded = true;
|
|
};
|
|
|
|
loadButtons.forEach((button) => {
|
|
button.addEventListener("click", loadMap);
|
|
});
|
|
|
|
if (liveRouteLink) {
|
|
liveRouteLink.addEventListener("click", (event) => {
|
|
event.preventDefault();
|
|
if (!navigator.geolocation) {
|
|
if (unavailableMsg) {
|
|
window.alert(unavailableMsg);
|
|
}
|
|
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");
|
|
},
|
|
(geoError) => {
|
|
if (geoError && geoError.code === 1 && deniedMsg) {
|
|
window.alert(deniedMsg);
|
|
return;
|
|
}
|
|
if (unavailableMsg) {
|
|
window.alert(unavailableMsg);
|
|
}
|
|
},
|
|
{ enableHighAccuracy: true, timeout: 4500, maximumAge: 120000 }
|
|
);
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
{% endif %}
|
|
</section>
|
|
{% endblock %}
|