new feat übersetzer und faq
This commit is contained in:
@@ -7,62 +7,82 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600;700&family=Source+Sans+3:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css', v='20260321a') }}" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css', v='20260724v') }}" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<a class="brand" href="{{ url_for('welcome') if guest_name else url_for('landing') }}">{{ t('brand') }}</a>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<form method="post" action="{{ url_for('set_lang', code='de') }}">
|
||||
<button class="btn btn-ghost" type="submit">DE</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('set_lang', code='en') }}">
|
||||
<button class="btn btn-ghost" type="submit">EN</button>
|
||||
</form>
|
||||
{% if guest_name %}
|
||||
<div
|
||||
class="toolbar-timer"
|
||||
data-countdown-target="{{ wedding_countdown_iso }}"
|
||||
data-countdown-started="{{ t('countdown_started') }}"
|
||||
>
|
||||
<div class="toolbar {{ 'toolbar-authenticated' if guest_name else 'toolbar-login' }}">
|
||||
<div class="toolbar-row toolbar-row-top">
|
||||
<form method="post" action="{{ url_for('set_lang', code='de') }}">
|
||||
<button class="btn btn-ghost" type="submit">DE</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('set_lang', code='en') }}">
|
||||
<button class="btn btn-ghost" type="submit">EN</button>
|
||||
</form>
|
||||
{% if guest_name %}
|
||||
<button
|
||||
class="btn btn-ghost toolbar-nav-btn toolbar-timer-btn"
|
||||
class="btn btn-ghost toolbar-nav-btn toolbar-translate-btn"
|
||||
type="button"
|
||||
aria-label="{{ t('countdown_button_label') }}"
|
||||
title="{{ t('countdown_button_label') }}"
|
||||
data-countdown-toggle
|
||||
aria-expanded="false"
|
||||
aria-label="{{ t('translator') }}"
|
||||
title="{{ t('translator') }}"
|
||||
data-translator-open
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path d="M15 2H9v2h6V2zm-3 4a8 8 0 1 0 8 8 8 8 0 0 0-8-8zm3.4 11.4L11 13V8h2v4.2l3.8 3.8z" />
|
||||
<path d="M12 5.5A8.4 8.4 0 0 0 6.5 3.4 8.6 8.6 0 0 0 2 4.7v14.1a.75.75 0 0 0 1.02.7A8.1 8.1 0 0 1 6.5 18.6a7.1 7.1 0 0 1 4.98 2 .75.75 0 0 0 1.04 0 7.1 7.1 0 0 1 4.98-2 8.1 8.1 0 0 1 3.48.9.75.75 0 0 0 1.02-.7V4.7a8.6 8.6 0 0 0-4.5-1.3A8.4 8.4 0 0 0 12 5.5zm-1 12.9a8.7 8.7 0 0 0-4.5-1.3 9.6 9.6 0 0 0-3 .5V5.7a7.4 7.4 0 0 1 3-.8A6.9 6.9 0 0 1 11 6.7zm9.5-.8a9.6 9.6 0 0 0-3-.5 8.7 8.7 0 0 0-4.5 1.3V6.7a6.9 6.9 0 0 1 4.5-1.8 7.4 7.4 0 0 1 3 .8z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="toolbar-timer-popover" data-countdown-popover hidden>
|
||||
<p class="toolbar-timer-label">{{ t('countdown_until') }}</p>
|
||||
<div class="toolbar-timer-grid" data-countdown-grid>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-days>0</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_days') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-hours>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_hours') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-minutes>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_minutes') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-seconds>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_seconds') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="toolbar-timer-subline" data-countdown-subline>{{ t('countdown_subline') }}</p>
|
||||
</div>
|
||||
<a class="btn btn-ghost toolbar-nav-btn toolbar-faq-btn" href="{{ url_for('faq') }}" aria-label="{{ t('faq') }}" title="{{ t('faq') }}">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path d="M12 2a10 10 0 1 0 10 10A10.01 10.01 0 0 0 12 2zm.15 16.25a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25zm1.75-7.05-.75.48a1.36 1.36 0 0 0-.65 1.17v.4h-2v-.4a3.34 3.34 0 0 1 1.58-2.85l.75-.48a1.75 1.75 0 1 0-2.68-1.48h-2a3.75 3.75 0 1 1 5.75 3.16z" />
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="toolbar-session-actions">
|
||||
{% if guest_name %}
|
||||
<div class="toolbar-row toolbar-row-bottom">
|
||||
<div
|
||||
class="toolbar-timer"
|
||||
data-countdown-target="{{ wedding_countdown_iso }}"
|
||||
data-countdown-started="{{ t('countdown_started') }}"
|
||||
>
|
||||
<button
|
||||
class="btn btn-ghost toolbar-nav-btn toolbar-timer-btn"
|
||||
type="button"
|
||||
aria-label="{{ t('countdown_button_label') }}"
|
||||
title="{{ t('countdown_button_label') }}"
|
||||
data-countdown-toggle
|
||||
aria-expanded="false"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path d="M15 2H9v2h6V2zm-3 4a8 8 0 1 0 8 8 8 8 0 0 0-8-8zm3.4 11.4L11 13V8h2v4.2l3.8 3.8z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="toolbar-timer-popover" data-countdown-popover hidden>
|
||||
<p class="toolbar-timer-label">{{ t('countdown_until') }}</p>
|
||||
<div class="toolbar-timer-grid" data-countdown-grid>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-days>0</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_days') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-hours>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_hours') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-minutes>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_minutes') }}</span>
|
||||
</div>
|
||||
<div class="toolbar-timer-unit">
|
||||
<span class="toolbar-timer-value" data-countdown-seconds>00</span>
|
||||
<span class="toolbar-timer-unit-label">{{ t('countdown_seconds') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="toolbar-timer-subline" data-countdown-subline>{{ t('countdown_subline') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-ghost toolbar-nav-btn" href="{{ url_for('guest_area') }}" aria-label="{{ t('dashboard') }}" title="{{ t('dashboard') }}">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path d="M3 3h8v8H3V3zm10 0h8v5h-8V3zM3 13h5v8H3v-8zm7 0h11v8H10v-8z" />
|
||||
@@ -76,6 +96,50 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% if guest_name %}
|
||||
<dialog
|
||||
class="translator-dialog"
|
||||
data-translator-dialog
|
||||
data-source-lang="{{ 'de' if lang == 'de' else 'en' }}"
|
||||
aria-labelledby="translator-title"
|
||||
>
|
||||
<div class="translator-sheet">
|
||||
<div class="translator-head">
|
||||
<div>
|
||||
<h2 id="translator-title">{{ t('translator') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="translator-direction" aria-label="{{ t('translator_direction') }}">
|
||||
<span data-translator-source>{{ t('language_german') if lang == 'de' else t('language_english') }}</span>
|
||||
<button class="translator-swap" type="button" data-translator-swap aria-label="{{ t('translator_swap') }}">⇄</button>
|
||||
<span data-translator-target>{{ t('language_english') if lang == 'de' else t('language_german') }}</span>
|
||||
</div>
|
||||
|
||||
<label class="translator-label" for="translator-text">{{ t('translator_input_label') }}</label>
|
||||
<textarea
|
||||
id="translator-text"
|
||||
class="translator-input"
|
||||
rows="4"
|
||||
maxlength="500"
|
||||
placeholder="{{ t('translator_placeholder') }}"
|
||||
data-translator-input
|
||||
></textarea>
|
||||
|
||||
<div class="translator-quick-list" aria-label="{{ t('translator_quick_phrases') }}">
|
||||
<button type="button" data-translator-phrase data-de="Schön, dich kennenzulernen." data-en="Nice to meet you.">{{ t('translator_phrase_meet') }}</button>
|
||||
<button type="button" data-translator-phrase data-de="Möchtest du etwas trinken?" data-en="Would you like something to drink?">{{ t('translator_phrase_drink') }}</button>
|
||||
<button type="button" data-translator-phrase data-de="Wo ist die Toilette?" data-en="Where is the restroom?">{{ t('translator_phrase_restroom') }}</button>
|
||||
</div>
|
||||
|
||||
<p class="translator-privacy">{{ t('translator_privacy') }}</p>
|
||||
<button class="btn translator-submit" type="button" data-translator-submit disabled>
|
||||
{{ t('translator_submit') }} <span aria-hidden="true">↗</span>
|
||||
</button>
|
||||
</div>
|
||||
</dialog>
|
||||
{% endif %}
|
||||
|
||||
<main class="container">
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
@@ -95,5 +159,6 @@
|
||||
</footer>
|
||||
<script src="{{ url_for('static', filename='dashboard-transition.js', v='20260303a') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='countdown.js', v='20260303c') }}" defer></script>
|
||||
<script src="{{ url_for('static', filename='translator.js', v='20260724b') }}" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -169,6 +169,23 @@
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="legal-section" id="deepl-translation">
|
||||
<h2>Translation with DeepL</h2>
|
||||
<p>
|
||||
The protected guest area provides an optional link to the external translation service DeepL, operated by DeepL
|
||||
SE, Maarweg 165, 50825 Cologne, Germany. No connection to DeepL is established merely by opening this website.
|
||||
</p>
|
||||
<p>
|
||||
Only after you click “Translate with DeepL” will the text you entered and technical connection data, such as your
|
||||
IP address, be transmitted directly from your browser to DeepL. The text is not sent to or stored by our web
|
||||
server. Please do not enter names, contact details, confidential information, or other personal data.
|
||||
</p>
|
||||
<p>
|
||||
After the link is opened, DeepL's privacy policy and terms apply:
|
||||
<a href="https://www.deepl.com/privacy" target="_blank" rel="noopener noreferrer">DeepL privacy policy</a>.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="legal-section" id="photo-upload">
|
||||
<h2>Photo Uploads</h2>
|
||||
<p>
|
||||
@@ -384,6 +401,25 @@
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="legal-section" id="deepl-uebersetzung">
|
||||
<h2>Übersetzung mit DeepL</h2>
|
||||
<p>
|
||||
Im geschützten Gästebereich wird eine optionale Weiterleitung zum externen Übersetzungsdienst DeepL angeboten.
|
||||
Anbieter ist die DeepL SE, Maarweg 165, 50825 Köln. Allein durch das Öffnen dieser Website wird noch keine
|
||||
Verbindung zu DeepL hergestellt.
|
||||
</p>
|
||||
<p>
|
||||
Erst wenn Sie „Mit DeepL übersetzen“ anklicken, werden der von Ihnen eingegebene Text und technische
|
||||
Verbindungsdaten, beispielsweise Ihre IP-Adresse, direkt durch Ihren Browser an DeepL übermittelt. Der Text wird
|
||||
nicht an unseren Webserver gesendet oder dort gespeichert. Bitte geben Sie keine Namen, Kontaktdaten,
|
||||
vertraulichen Informationen oder sonstigen personenbezogenen Daten ein.
|
||||
</p>
|
||||
<p>
|
||||
Nach dem Öffnen des Links gelten die Datenschutzbestimmungen und Nutzungsbedingungen von DeepL:
|
||||
<a href="https://www.deepl.com/privacy" target="_blank" rel="noopener noreferrer">Datenschutz bei DeepL</a>.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="legal-section" id="foto-upload">
|
||||
<h2>Upload von Fotos durch Nutzer</h2>
|
||||
<p>
|
||||
|
||||
24
backend/templates/faq.html
Normal file
24
backend/templates/faq.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="card faq-card">
|
||||
<h1>{{ t('faq') }}</h1>
|
||||
<p class="faq-intro">{{ t('faq_intro') }}</p>
|
||||
|
||||
<div class="faq-list">
|
||||
{% for question_key, answer_key in faq_items %}
|
||||
<details class="faq-item">
|
||||
<summary>
|
||||
<span>{{ t(question_key) }}</span>
|
||||
<span class="faq-toggle" aria-hidden="true"></span>
|
||||
</summary>
|
||||
<div class="faq-answer">
|
||||
<p>{{ t(answer_key) }}</p>
|
||||
</div>
|
||||
</details>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a class="btn btn-ghost faq-tour-restart" href="{{ url_for('welcome', tour=1) }}">{{ t('tour_restart') }}</a>
|
||||
</section>
|
||||
<script src="{{ url_for('static', filename='faq.js', v='20260724a') }}" defer></script>
|
||||
{% endblock %}
|
||||
@@ -63,7 +63,7 @@
|
||||
<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"
|
||||
class="btn btn-ghost route-location-btn"
|
||||
href="{{ hotel.current_route_url }}"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
@@ -199,6 +199,7 @@
|
||||
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>
|
||||
@@ -318,7 +319,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 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>
|
||||
|
||||
@@ -11,4 +11,87 @@
|
||||
</div>
|
||||
</section>
|
||||
<p class="hero-hint-below">{{ welcome_hint }}</p>
|
||||
|
||||
{% if show_onboarding %}
|
||||
<dialog
|
||||
class="onboarding-dialog"
|
||||
data-onboarding-dialog
|
||||
data-complete-url="{{ url_for('complete_onboarding') }}"
|
||||
data-progress-template="{{ t('tour_progress') }}"
|
||||
aria-labelledby="onboarding-title"
|
||||
>
|
||||
<div class="onboarding-shell">
|
||||
<div class="onboarding-progress" aria-hidden="true">
|
||||
{% for _ in range(6) %}<span data-onboarding-dot></span>{% endfor %}
|
||||
</div>
|
||||
<p class="onboarding-step-label" data-onboarding-progress></p>
|
||||
<h2 id="onboarding-title">{{ t('tour_title') }}</h2>
|
||||
|
||||
<div class="onboarding-slides">
|
||||
<section class="onboarding-slide" data-onboarding-slide>
|
||||
<span class="onboarding-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path d="M3 3h8v8H3V3zm10 0h8v5h-8V3zM3 13h5v8H3v-8zm7 0h11v8H10v-8z" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>{{ t('tour_dashboard_title') }}</h3>
|
||||
<p>{{ t('tour_dashboard_text') }}</p>
|
||||
</section>
|
||||
<section class="onboarding-slide" data-onboarding-slide hidden>
|
||||
<span class="onboarding-icon" aria-hidden="true">✓</span>
|
||||
<h3>{{ t('tour_rsvp_title') }}</h3>
|
||||
<p>{{ t('tour_rsvp_text') }}</p>
|
||||
</section>
|
||||
<section class="onboarding-slide" data-onboarding-slide hidden>
|
||||
<span class="onboarding-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path d="M9 4 7.6 6H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-3.6L15 4H9zm3 4.2A4.8 4.8 0 1 1 7.2 13 4.8 4.8 0 0 1 12 8.2zm0 2A2.8 2.8 0 1 0 14.8 13 2.8 2.8 0 0 0 12 10.2z" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>{{ t('tour_photos_title') }}</h3>
|
||||
<p>{{ t('tour_photos_text') }}</p>
|
||||
</section>
|
||||
<section class="onboarding-slide" data-onboarding-slide hidden>
|
||||
<span class="onboarding-icon onboarding-icon-route" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<circle cx="11" cy="13" r="7.5" />
|
||||
<circle cx="11" cy="13" r="3.5" />
|
||||
<path d="M20.5 3.5 11 13M17 7l.2-3.6M17 7l3.6-.2" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>{{ t('tour_routes_title') }}</h3>
|
||||
<p>{{ t('tour_routes_text') }}</p>
|
||||
</section>
|
||||
<section class="onboarding-slide" data-onboarding-slide hidden>
|
||||
<span class="onboarding-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path d="M12 5.5A8.4 8.4 0 0 0 6.5 3.4 8.6 8.6 0 0 0 2 4.7v14.1a.75.75 0 0 0 1.02.7A8.1 8.1 0 0 1 6.5 18.6a7.1 7.1 0 0 1 4.98 2 .75.75 0 0 0 1.04 0 7.1 7.1 0 0 1 4.98-2 8.1 8.1 0 0 1 3.48.9.75.75 0 0 0 1.02-.7V4.7a8.6 8.6 0 0 0-4.5-1.3A8.4 8.4 0 0 0 12 5.5zm-1 12.9a8.7 8.7 0 0 0-4.5-1.3 9.6 9.6 0 0 0-3 .5V5.7a7.4 7.4 0 0 1 3-.8A6.9 6.9 0 0 1 11 6.7zm9.5-.8a9.6 9.6 0 0 0-3-.5 8.7 8.7 0 0 0-4.5 1.3V6.7a6.9 6.9 0 0 1 4.5-1.8 7.4 7.4 0 0 1 3 .8z" />
|
||||
</svg>
|
||||
</span>
|
||||
<h3>{{ t('tour_translator_title') }}</h3>
|
||||
<p>{{ t('tour_translator_text') }}</p>
|
||||
</section>
|
||||
<section class="onboarding-slide" data-onboarding-slide hidden>
|
||||
<span class="onboarding-icon" aria-hidden="true">?</span>
|
||||
<h3>{{ t('tour_faq_title') }}</h3>
|
||||
<p>{{ t('tour_faq_text') }}</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="onboarding-actions">
|
||||
<div>
|
||||
<button class="btn btn-ghost" type="button" data-onboarding-back hidden>{{ t('tour_back') }}</button>
|
||||
<button
|
||||
class="btn"
|
||||
type="button"
|
||||
data-onboarding-next
|
||||
data-next-label="{{ t('tour_next') }}"
|
||||
data-finish-label="{{ t('tour_finish') }}"
|
||||
>{{ t('tour_next') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
{% endif %}
|
||||
<script src="{{ url_for('static', filename='onboarding.js', v='20260724a') }}" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user