feat: new hotel and genuss

This commit is contained in:
2026-07-24 10:30:02 +00:00
parent 20ba71465f
commit 11b0d20c42
5 changed files with 77 additions and 50 deletions

View File

@@ -215,6 +215,14 @@ DEFAULT_INVITATION_GROUPS = [
AGE_REQUIRED_NAMES = {"Lena", "Finn", "Fin", "Bruno"} AGE_REQUIRED_NAMES = {"Lena", "Finn", "Fin", "Bruno"}
HOTEL_RECOMMENDATIONS = [ HOTEL_RECOMMENDATIONS = [
{
"id": "unico_boutique",
"name": "UNICO Boutique Hotel",
"address": "Frankfurter Straße 70, 65239 Hochheim am Main",
"website_url": "https://www.unicohotel.de/",
"drive_minutes": "5",
"walk_minutes": "20",
},
{ {
"id": "parkhotel_sonnenberg", "id": "parkhotel_sonnenberg",
"name": "Parkhotel Sonnenberg", "name": "Parkhotel Sonnenberg",
@@ -304,7 +312,7 @@ TEXTS = {
"upload_submit": "Foto hochladen", "upload_submit": "Foto hochladen",
"schedule": "Ablauf", "schedule": "Ablauf",
"hotels": "Hotels", "hotels": "Hotels",
"taxi": "Taxi", "taxi": "Genuss",
"location": "Location", "location": "Location",
"gifts": "Geschenke", "gifts": "Geschenke",
"visit_location": "Zur Location-Webseite", "visit_location": "Zur Location-Webseite",
@@ -344,8 +352,9 @@ TEXTS = {
"hotels_text": "Empfehlungen folgen. Bitte frühzeitig buchen.", "hotels_text": "Empfehlungen folgen. Bitte frühzeitig buchen.",
"hotels_intro": "Hier findet ihr Hotels in der Nähe. Bitte bucht frühzeitig und schaut euch die aktuellen Preise direkt auf den Hotel-Webseiten an.", "hotels_intro": "Hier findet ihr Hotels in der Nähe. Bitte bucht frühzeitig und schaut euch die aktuellen Preise direkt auf den Hotel-Webseiten an.",
"hotel_visit_website": "Zur Hotel-Webseite", "hotel_visit_website": "Zur Hotel-Webseite",
"hotel_route_drive": "Route zur Location (Auto)", "hotel_route_from_current": "Route ab aktuellem Standort",
"hotel_route_walk": "Route zur Location (zu Fuß)", "hotel_route_drive": "Route vom Hotel zur Location (Auto)",
"hotel_route_walk": "Route vom Hotel zur Location (zu Fuß)",
"hotel_time_note": "Genaue Fahr- und Gehzeit seht ihr live in Google Maps.", "hotel_time_note": "Genaue Fahr- und Gehzeit seht ihr live in Google Maps.",
"hotel_route_modal_title": "Route zur Location", "hotel_route_modal_title": "Route zur Location",
"hotel_route_modal_close": "Karte schließen", "hotel_route_modal_close": "Karte schließen",
@@ -357,10 +366,10 @@ TEXTS = {
"hotel_hotel_frankenbach_desc": "Zentral in Eltville, gute Anbindung zur Location.", "hotel_hotel_frankenbach_desc": "Zentral in Eltville, gute Anbindung zur Location.",
"hotel_spritzenhaus_desc": "Historisches Haus am Rhein mit modernen Zimmern.", "hotel_spritzenhaus_desc": "Historisches Haus am Rhein mit modernen Zimmern.",
"hotel_kronenschloesschen_desc": "Elegantes Hotel in Hattenheim, nah an den Weinbergen.", "hotel_kronenschloesschen_desc": "Elegantes Hotel in Hattenheim, nah an den Weinbergen.",
"hotel_kloster_eberbach_desc": "Besonderes Ambiente am Kloster mit kurzer Fahrzeit.", "hotel_kloster_eberbach_desc": "Historisches Klosterambiente, umgeben von Weinbergen und Natur.",
"hotel_weinhaus_engel_desc": "Gemütliches Weinhaus-Hotel in Rauenthal.", "hotel_weinhaus_engel_desc": "Gemütliches Weinhaus-Hotel in Rauenthal.",
"taxi_text": "An einem Taxiservice arbeiten wir noch.", "hotel_unico_boutique_desc": "Modernes Boutique-Hotel direkt in Hochheim mit stilvollen Zimmern und kurzer Entfernung zur Location.",
"taxi_sticker_alt": "Bauarbeiter-Sticker: Arbeit in Progress", "taxi_text": "Coming soon",
"gifts_teaser": "Wir würden uns über diese Geschenke sehr freuen...", "gifts_teaser": "Wir würden uns über diese Geschenke sehr freuen...",
"gifts_reveal_button": "Wunsch aufdecken", "gifts_reveal_button": "Wunsch aufdecken",
"gifts_image_alt": "Ein großer Haufen Geldscheine", "gifts_image_alt": "Ein großer Haufen Geldscheine",
@@ -447,7 +456,7 @@ TEXTS = {
"upload_submit": "Upload photo", "upload_submit": "Upload photo",
"schedule": "Schedule", "schedule": "Schedule",
"hotels": "Hotels", "hotels": "Hotels",
"taxi": "Taxi", "taxi": "Culinary Delights",
"location": "Location", "location": "Location",
"gifts": "Gifts", "gifts": "Gifts",
"visit_location": "Visit location website", "visit_location": "Visit location website",
@@ -487,8 +496,9 @@ TEXTS = {
"hotels_text": "Recommendations will follow. Please book early.", "hotels_text": "Recommendations will follow. Please book early.",
"hotels_intro": "Here are hotel options nearby. Please book early and check current rates directly on each hotel website.", "hotels_intro": "Here are hotel options nearby. Please book early and check current rates directly on each hotel website.",
"hotel_visit_website": "Visit hotel website", "hotel_visit_website": "Visit hotel website",
"hotel_route_drive": "Route to location (car)", "hotel_route_from_current": "Route from current location",
"hotel_route_walk": "Route to location (walk)", "hotel_route_drive": "Route from hotel to location (car)",
"hotel_route_walk": "Route from hotel to location (walk)",
"hotel_time_note": "Exact driving and walking times are shown live in Google Maps.", "hotel_time_note": "Exact driving and walking times are shown live in Google Maps.",
"hotel_route_modal_title": "Route to location", "hotel_route_modal_title": "Route to location",
"hotel_route_modal_close": "Close map", "hotel_route_modal_close": "Close map",
@@ -500,10 +510,10 @@ TEXTS = {
"hotel_hotel_frankenbach_desc": "Central in Eltville with good access to the venue.", "hotel_hotel_frankenbach_desc": "Central in Eltville with good access to the venue.",
"hotel_spritzenhaus_desc": "Historic house by the Rhine with modern rooms.", "hotel_spritzenhaus_desc": "Historic house by the Rhine with modern rooms.",
"hotel_kronenschloesschen_desc": "Elegant hotel in Hattenheim near the vineyards.", "hotel_kronenschloesschen_desc": "Elegant hotel in Hattenheim near the vineyards.",
"hotel_kloster_eberbach_desc": "Unique monastery setting with a short drive to the venue.", "hotel_kloster_eberbach_desc": "Historic monastery atmosphere surrounded by vineyards and nature.",
"hotel_weinhaus_engel_desc": "Cozy winehouse hotel in Rauenthal.", "hotel_weinhaus_engel_desc": "Cozy winehouse hotel in Rauenthal.",
"taxi_text": "We are still working on a taxi service.", "hotel_unico_boutique_desc": "Modern boutique hotel in Hochheim with stylish rooms and a short journey to the venue.",
"taxi_sticker_alt": "Construction worker sticker: Work in progress", "taxi_text": "Coming soon",
"gifts_teaser": "We would be very happy to receive these gifts...", "gifts_teaser": "We would be very happy to receive these gifts...",
"gifts_reveal_button": "Reveal wish", "gifts_reveal_button": "Reveal wish",
"gifts_image_alt": "A big pile of cash", "gifts_image_alt": "A big pile of cash",
@@ -678,6 +688,7 @@ def get_hotels_for_page() -> list[dict]:
"walk_route_url": build_google_maps_directions(entry["address"], "walking"), "walk_route_url": build_google_maps_directions(entry["address"], "walking"),
"drive_route_embed_url": build_google_maps_route_embed(entry["address"], "driving"), "drive_route_embed_url": build_google_maps_route_embed(entry["address"], "driving"),
"walk_route_embed_url": build_google_maps_route_embed(entry["address"], "walking"), "walk_route_embed_url": build_google_maps_route_embed(entry["address"], "walking"),
"current_route_url": build_google_maps_destination(entry["address"], "driving"),
} }
) )
return hotels return hotels

View File

@@ -1261,34 +1261,6 @@ body.has-route-modal {
box-shadow: 0 10px 22px rgba(31, 58, 47, 0.24); box-shadow: 0 10px 22px rgba(31, 58, 47, 0.24);
} }
.taxi-coming-soon {
margin: 0.3rem auto 0.9rem;
max-width: min(460px, 100%);
}
.taxi-coming-soon--de {
max-width: min(660px, 100%);
}
.taxi-coming-soon--en {
max-width: min(460px, 100%);
overflow: hidden;
}
.taxi-coming-soon--en .taxi-sticker--en {
width: 156%;
max-width: none;
margin-left: -28%;
}
.taxi-coming-soon img {
display: block;
width: 100%;
height: auto;
object-fit: contain;
filter: drop-shadow(0 10px 22px rgba(31, 58, 47, 0.18));
}
.gift-fun { .gift-fun {
position: relative; position: relative;
overflow: hidden; overflow: hidden;

View File

@@ -45,7 +45,12 @@
</div> </div>
{% elif page == 'hotels' %} {% elif page == 'hotels' %}
<p>{{ t('hotels_intro') }}</p> <p>{{ t('hotels_intro') }}</p>
<div class="hotel-list"> <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 %} {% for hotel in hotels %}
<article class="hotel-card"> <article class="hotel-card">
<h2>{{ hotel.name }}</h2> <h2>{{ hotel.name }}</h2>
@@ -57,6 +62,14 @@
</div> </div>
<div class="hotel-actions"> <div class="hotel-actions">
<a class="btn" href="{{ hotel.website_url }}" target="_blank" rel="noopener">{{ t('hotel_visit_website') }}</a> <a class="btn" href="{{ hotel.website_url }}" target="_blank" rel="noopener">{{ t('hotel_visit_website') }}</a>
<a
class="btn btn-ghost"
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 <a
class="btn btn-ghost" class="btn btn-ghost"
href="{{ hotel.drive_route_url }}" href="{{ hotel.drive_route_url }}"
@@ -77,6 +90,46 @@
</article> </article>
{% endfor %} {% endfor %}
</div> </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" data-route-modal hidden>
<div class="route-modal-backdrop" data-route-close></div> <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') }}"> <section class="route-modal-panel" role="dialog" aria-modal="true" aria-label="{{ t('hotel_route_modal_title') }}">
@@ -133,15 +186,6 @@
})(); })();
</script> </script>
{% elif page == 'taxi' %} {% elif page == 'taxi' %}
<div class="taxi-coming-soon{% if lang == 'en' %} taxi-coming-soon--en{% else %} taxi-coming-soon--de{% endif %}">
<img
src="{{ url_for('static', filename='assets/bauerbeiter-eng-sticker.png' if lang == 'en' else 'assets/bauarbeiter-sticker.png') }}"
class="{% if lang == 'en' %}taxi-sticker--en{% endif %}"
alt="{{ t('taxi_sticker_alt') }}"
loading="lazy"
decoding="async"
>
</div>
<p>{{ t('taxi_text') }}</p> <p>{{ t('taxi_text') }}</p>
{% elif page == 'gifts' %} {% elif page == 'gifts' %}
<section class="gift-fun" data-gift-fun> <section class="gift-fun" data-gift-fun>

Binary file not shown.