Positionen Action Button und DVA Button hinzugefügt
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
<div class="dropdown-menu">
|
||||
{% for s in site_list %}
|
||||
<a class="dropdown-item{% if s == current_site %} active{% endif %}"
|
||||
href="{{ site_dropdown_url_prefix }}{{ s }}">{{ s | capitalize }}</a>
|
||||
href="{{ site_dropdown_url_prefix }}{{ s }}"><i class="ti ti-building me-1"></i>{{ s | capitalize }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -73,6 +73,24 @@
|
||||
color: var(--ccm-primary);
|
||||
}
|
||||
|
||||
/* ─── Dropdown-Hover (grauer Hintergrund) ─── */
|
||||
.dropdown-item:hover,
|
||||
.dropdown-item:focus {
|
||||
background-color: #e9ecef !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
.dropdown-item.active,
|
||||
.dropdown-item:active {
|
||||
background-color: #e9ecef !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
[data-bs-theme="dark"] .dropdown-item:hover,
|
||||
[data-bs-theme="dark"] .dropdown-item:focus,
|
||||
[data-bs-theme="dark"] .dropdown-item.active,
|
||||
[data-bs-theme="dark"] .dropdown-item:active {
|
||||
background-color: #3a3f45 !important;
|
||||
}
|
||||
|
||||
/* ─── Drag-Handle für SortableJS ─── */
|
||||
.drag-handle {
|
||||
cursor: grab;
|
||||
@@ -186,7 +204,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card-Body: Tabs (Playlist | Einstellungen | Medien) -->
|
||||
<!-- Card-Body: Tabs (Playlist | Einstellungen | Aktionen | Digital Voice Agent | Medien) -->
|
||||
<div class="card-body">
|
||||
|
||||
<ul class="nav nav-tabs" data-bs-toggle="tabs" role="tablist">
|
||||
@@ -205,6 +223,11 @@
|
||||
<i class="ti ti-click me-1"></i>Aktionen
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href="#voice-{{ screen }}" class="nav-link" data-bs-toggle="tab" role="tab">
|
||||
<i class="ti ti-robot me-1"></i>Digital Voice Agent
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href="#media-{{ screen }}" class="nav-link" data-bs-toggle="tab" role="tab">
|
||||
<i class="ti ti-upload me-1"></i>Medien
|
||||
@@ -315,6 +338,13 @@
|
||||
<label class="form-check-label">Videos anzeigen</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch mb-4">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="stay_on_first"
|
||||
{% if cfg.stay_on_first %}checked{% endif %}>
|
||||
<label class="form-check-label">Auf erstem Element stehen bleiben (kein Refresh)</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Einstellungen speichern
|
||||
</button>
|
||||
@@ -323,7 +353,7 @@
|
||||
|
||||
<!-- ═══ Tab: Aktionen ═══ -->
|
||||
<div class="tab-pane" id="actions-{{ screen }}" role="tabpanel">
|
||||
<form action="/admin/{{ current_site }}/update/{{ screen }}" method="post">
|
||||
<form action="/admin/{{ current_site }}/update-actions/{{ screen }}" method="post">
|
||||
<h3>Aktions-Button (Player)</h3>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
@@ -348,6 +378,84 @@
|
||||
<option value="redirect" {% if cfg.custom_url_target|default('overlay') == 'redirect' %}selected{% endif %}>Weiterleitung (gleiches Fenster)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Position</label>
|
||||
<select name="custom_url_position" class="form-select">
|
||||
<optgroup label="Oben">
|
||||
<option value="top-left" {% if cfg.custom_url_position|default('top-left') == 'top-left' %}selected{% endif %}>Oben links</option>
|
||||
<option value="top-center" {% if cfg.custom_url_position|default('top-left') == 'top-center' %}selected{% endif %}>Oben mitte</option>
|
||||
<option value="top-right" {% if cfg.custom_url_position|default('top-left') == 'top-right' %}selected{% endif %}>Oben rechts</option>
|
||||
</optgroup>
|
||||
<optgroup label="Mitte">
|
||||
<option value="middle-left" {% if cfg.custom_url_position|default('top-left') == 'middle-left' %}selected{% endif %}>Mitte links</option>
|
||||
<option value="middle-center" {% if cfg.custom_url_position|default('top-left') == 'middle-center' %}selected{% endif %}>Mitte zentriert</option>
|
||||
<option value="middle-right" {% if cfg.custom_url_position|default('top-left') == 'middle-right' %}selected{% endif %}>Mitte rechts</option>
|
||||
</optgroup>
|
||||
<optgroup label="Unten">
|
||||
<option value="bottom-left" {% if cfg.custom_url_position|default('top-left') == 'bottom-left' %}selected{% endif %}>Unten links</option>
|
||||
<option value="bottom-center" {% if cfg.custom_url_position|default('top-left') == 'bottom-center' %}selected{% endif %}>Unten mitte</option>
|
||||
<option value="bottom-right" {% if cfg.custom_url_position|default('top-left') == 'bottom-right' %}selected{% endif %}>Unten rechts</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Einstellungen speichern
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- ═══ Tab: Digital Voice Agent (pro Screen: Enabled, Label, Ziel, Position, Bild) ═══ -->
|
||||
<div class="tab-pane" id="voice-{{ screen }}" role="tabpanel">
|
||||
<form action="/admin/{{ current_site }}/update-voice/{{ screen }}" method="post">
|
||||
<h3>Digital Voice Agent</h3>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="voice_agent_enabled"
|
||||
{% if cfg.voice_agent_enabled %}checked{% endif %}>
|
||||
<label class="form-check-label">Voice Agent anzeigen</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="voice_agent_show_image"
|
||||
{% if cfg.voice_agent_show_image %}checked{% endif %}>
|
||||
<label class="form-check-label">Bild (dva.png) über dem Button anzeigen <span class="badge bg-warning text-dark ms-1">Beta</span></label>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">URL (fest in config.json definiert)</label>
|
||||
<input type="url" class="form-control" value="{{ voice_agent_url|default('') }}" readonly>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Button-Beschriftung</label>
|
||||
<input type="text" name="voice_agent_label" class="form-control"
|
||||
placeholder="z. B. Digitaler Assistent" value="{{ cfg.voice_agent_label|default('Digitaler Assistent') }}" maxlength="50">
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Verhalten bei Klick</label>
|
||||
<select name="voice_agent_target" class="form-select">
|
||||
<option value="overlay" {% if cfg.voice_agent_target|default('overlay') == 'overlay' %}selected{% endif %}>Im Player (iframe mit Zurück-Button)</option>
|
||||
<option value="redirect" {% if cfg.voice_agent_target|default('overlay') == 'redirect' %}selected{% endif %}>Weiterleitung (gleiches Fenster)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Position</label>
|
||||
<select name="voice_agent_position" class="form-select">
|
||||
<optgroup label="Oben">
|
||||
<option value="top-left" {% if cfg.voice_agent_position|default('top-left') == 'top-left' %}selected{% endif %}>Oben links</option>
|
||||
<option value="top-center" {% if cfg.voice_agent_position|default('top-left') == 'top-center' %}selected{% endif %}>Oben mitte</option>
|
||||
<option value="top-right" {% if cfg.voice_agent_position|default('top-left') == 'top-right' %}selected{% endif %}>Oben rechts</option>
|
||||
</optgroup>
|
||||
<optgroup label="Mitte">
|
||||
<option value="middle-left" {% if cfg.voice_agent_position|default('top-left') == 'middle-left' %}selected{% endif %}>Mitte links</option>
|
||||
<option value="middle-center" {% if cfg.voice_agent_position|default('top-left') == 'middle-center' %}selected{% endif %}>Mitte zentriert</option>
|
||||
<option value="middle-right" {% if cfg.voice_agent_position|default('top-left') == 'middle-right' %}selected{% endif %}>Mitte rechts</option>
|
||||
</optgroup>
|
||||
<optgroup label="Unten">
|
||||
<option value="bottom-left" {% if cfg.voice_agent_position|default('top-left') == 'bottom-left' %}selected{% endif %}>Unten links</option>
|
||||
<option value="bottom-center" {% if cfg.voice_agent_position|default('top-left') == 'bottom-center' %}selected{% endif %}>Unten mitte</option>
|
||||
<option value="bottom-right" {% if cfg.voice_agent_position|default('top-left') == 'bottom-right' %}selected{% endif %}>Unten rechts</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Einstellungen speichern
|
||||
</button>
|
||||
|
||||
@@ -77,39 +77,227 @@
|
||||
Wenn der Aktions-Button angeklickt wird, öffnet
|
||||
sich dieser Overlay-Bereich mit Zurück-Button.
|
||||
═══════════════════════════════════════════════════ -->
|
||||
<div id="overlay" style="display:none;position:fixed;inset:0;z-index:99999;background:#fff;">
|
||||
<button onclick="closeOverlay()"
|
||||
style="position:absolute;top:16px;left:16px;z-index:10;
|
||||
padding:8px 16px;background:#DA002D;color:#fff;
|
||||
border:none;border-radius:6px;font-size:1rem;cursor:pointer;">
|
||||
<div id="overlay" style="display:none;position:fixed;inset:0;z-index:99999;background:#000;">
|
||||
<style>
|
||||
/* Zurück-Button-Position: 9 Positionen, dynamisch per openOverlay(pos) gesetzt */
|
||||
#overlay-back.overlay-back-top-left { top: 16px; left: 16px; }
|
||||
#overlay-back.overlay-back-top-center { top: 16px; left: 50%; transform: translateX(-50%); }
|
||||
#overlay-back.overlay-back-top-right { top: 16px; right: 16px; }
|
||||
#overlay-back.overlay-back-middle-left { top: 50%; left: 16px; transform: translateY(-50%); }
|
||||
#overlay-back.overlay-back-middle-center { top: 50%; left: 50%; transform: translate(-50%,-50%); }
|
||||
#overlay-back.overlay-back-middle-right { top: 50%; right: 16px; transform: translateY(-50%); }
|
||||
#overlay-back.overlay-back-bottom-left { bottom: 16px; left: 16px; }
|
||||
#overlay-back.overlay-back-bottom-center { bottom: 16px; left: 50%; transform: translateX(-50%); }
|
||||
#overlay-back.overlay-back-bottom-right { bottom: 16px; right: 16px; }
|
||||
</style>
|
||||
<button id="overlay-back" onclick="closeOverlay()"
|
||||
style="position:absolute;z-index:10;
|
||||
padding:8px 20px;background:#fff;color:#000;
|
||||
border:none;border-radius:20px;font-size:1rem;font-weight:600;
|
||||
cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.08);">
|
||||
← Zurück
|
||||
</button>
|
||||
<iframe id="overlay-iframe" style="width:100%;height:100%;border:none;display:block;"></iframe>
|
||||
</div>
|
||||
|
||||
<!-- ─── Custom-URL-Button (oben links) ─── -->
|
||||
<!-- ─── Custom-URL-Button (Position: 9 Positionen oben/mitte/unten × links/mitte/rechts)
|
||||
Bottom-Positionen weichen automatisch 16px über dem Newsticker-Balken aus ─── -->
|
||||
{% if custom_url and custom_url_enabled %}
|
||||
<style>
|
||||
/* Einheitliches Button-Styling: Weiß, abgerundet, fetter Text (Custom-URL + Voice-Agent) */
|
||||
.btn-pos-{{ screen }} {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
padding: 10px 20px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
.btn-pos-{{ screen }}-top-left { top: 16px; left: 16px; }
|
||||
.btn-pos-{{ screen }}-top-center { top: 16px; left: 50%; transform: translateX(-50%); }
|
||||
.btn-pos-{{ screen }}-top-right { top: 16px; right: 16px; }
|
||||
.btn-pos-{{ screen }}-middle-left { top: 50%; left: 16px; transform: translateY(-50%); }
|
||||
.btn-pos-{{ screen }}-middle-center { top: 50%; left: 50%; transform: translate(-50%,-50%); }
|
||||
.btn-pos-{{ screen }}-middle-right { top: 50%; right: 16px; transform: translateY(-50%); }
|
||||
.btn-pos-{{ screen }}-bottom-left { bottom: {% if newsticker_enabled %}56px{% else %}16px{% endif %}; left: 16px; }
|
||||
.btn-pos-{{ screen }}-bottom-center { bottom: {% if newsticker_enabled %}56px{% else %}16px{% endif %}; left: 50%; transform: translateX(-50%); }
|
||||
.btn-pos-{{ screen }}-bottom-right { bottom: {% if newsticker_enabled %}56px{% else %}16px{% endif %}; right: 16px; }
|
||||
</style>
|
||||
{% if custom_url_target == "redirect" %}
|
||||
<!-- Direkt-Weiterleitung (verlässt den Player) -->
|
||||
<a href="{{ custom_url }}"
|
||||
style="position:fixed;top:16px;left:16px;z-index:9999;
|
||||
padding:10px 20px;background:#DA002D;color:#fff;
|
||||
border:none;border-radius:8px;font-size:1rem;cursor:pointer;
|
||||
text-decoration:none;box-shadow:0 2px 8px rgba(0,0,0,0.3);">
|
||||
class="btn-pos-{{ screen }} btn-pos-{{ screen }}-{{ custom_url_position|default('top-left') }}">
|
||||
{{ custom_url_label or "Info" }}
|
||||
</a>
|
||||
{% else %}
|
||||
<!-- iframe-Overlay (bleibt im Player, Zurück-Button) -->
|
||||
<button onclick='openOverlay({{ custom_url | tojson }})'
|
||||
style="position:fixed;top:16px;left:16px;z-index:9999;
|
||||
padding:10px 20px;background:#DA002D;color:#fff;
|
||||
border:none;border-radius:8px;font-size:1rem;cursor:pointer;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,0.3);">
|
||||
<button onclick='openOverlay({{ custom_url | tojson }}, "{{ custom_url_position|default('top-left') }}")'
|
||||
class="btn-pos-{{ screen }} btn-pos-{{ screen }}-{{ custom_url_position|default('top-left') }}">
|
||||
{{ custom_url_label or "Info" }}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════
|
||||
Voice-Agent-Button (fix positioniert, 9 Positionen)
|
||||
Typewriter-Tagline, optionales DVA-Bild, animierte
|
||||
Balken, Verhalten overlay/redirect. Bottom-Positionen
|
||||
weichen dem Newsticker aus.
|
||||
═══════════════════════════════════════════════════ -->
|
||||
{% if voice_agent_url and voice_agent_enabled %}
|
||||
<style>
|
||||
/* Voice-Agent-Wrap: Fixpositionierter Container, Column-Layout für Bild + Button */
|
||||
.voice-wrap-{{ screen }} {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.voice-pos-{{ screen }} .voice-text-{{ screen }} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
line-height: 1.3;
|
||||
min-width: 160px;
|
||||
}
|
||||
/* Typewriter-Tagline: Mehrsprachig, Buchstabe für Buchstabe, 0,8 s Fade-Out */
|
||||
.voice-pos-{{ screen }} .voice-text-{{ screen }} .voice-tagline-{{ screen }} {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: #888;
|
||||
height: 1.2em;
|
||||
line-height: 1.2em;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.8s ease;
|
||||
}
|
||||
.voice-pos-{{ screen }} .voice-text-{{ screen }} .voice-label-{{ screen }} {
|
||||
display: block;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
}
|
||||
.voice-pos-{{ screen }} .voice-text-{{ screen }} .voice-tagline-{{ screen }} .cursor {
|
||||
display: inline-block;
|
||||
width: 2px;
|
||||
height: 1em;
|
||||
background: #DA002D;
|
||||
margin-left: 2px;
|
||||
animation: voice-blink-{{ screen }} 0.6s step-end infinite;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
@keyframes voice-blink-{{ screen }} {
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
/* Optionales DVA-Bild (dva.png) oberhalb des Buttons, Beta-Feature */
|
||||
.voice-wrap-{{ screen }} .voice-img-{{ screen }} {
|
||||
width: 200px;
|
||||
aspect-ratio: 648 / 596;
|
||||
margin-bottom: 6px;
|
||||
background: url('/static/dva.png') no-repeat center/contain;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* Voice-Agent-Button: Weiß, 20 px Border-Radius, fett – einheitlich mit Aktions-Button */
|
||||
.voice-pos-{{ screen }} {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px 20px;
|
||||
gap: 12px;
|
||||
min-width: 280px;
|
||||
height: 56px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
.voice-pos-{{ screen }}:hover {
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
}
|
||||
.voice-pos-{{ screen }} .voice-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
width: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* Animierte Balken (5 Stück): Welle-Effekt mit abgestuften Verzögerungen */
|
||||
.voice-pos-{{ screen }} .voice-icon .bar {
|
||||
width: 3px;
|
||||
border-radius: 2px;
|
||||
background: #DA002D;
|
||||
transform-origin: center bottom;
|
||||
animation: voice-bar-{{ screen }} 0.6s ease-in-out infinite alternate;
|
||||
}
|
||||
.voice-pos-{{ screen }} .voice-icon .bar:nth-child(1) { height: 10px; animation-delay: 0.0s; }
|
||||
.voice-pos-{{ screen }} .voice-icon .bar:nth-child(2) { height: 16px; animation-delay: 0.2s; }
|
||||
.voice-pos-{{ screen }} .voice-icon .bar:nth-child(3) { height: 22px; animation-delay: 0.4s; }
|
||||
.voice-pos-{{ screen }} .voice-icon .bar:nth-child(4) { height: 14px; animation-delay: 0.1s; }
|
||||
.voice-pos-{{ screen }} .voice-icon .bar:nth-child(5) { height: 8px; animation-delay: 0.3s; }
|
||||
@keyframes voice-bar-{{ screen }} {
|
||||
0% { transform: scaleY(0.4); }
|
||||
100% { transform: scaleY(1.2); }
|
||||
}
|
||||
/* Voice-Agent-Positionen: 9 Positionen (oben/mitte/unten × links/mitte/rechts), Bottom weicht Newsticker aus */
|
||||
.voice-wrap-{{ screen }}-top-left { top: 16px; left: 16px; }
|
||||
.voice-wrap-{{ screen }}-top-center { top: 16px; left: 50%; transform: translateX(-50%); }
|
||||
.voice-wrap-{{ screen }}-top-right { top: 16px; right: 16px; }
|
||||
.voice-wrap-{{ screen }}-middle-left { top: 50%; left: 16px; transform: translateY(-50%); }
|
||||
.voice-wrap-{{ screen }}-middle-center { top: 50%; left: 50%; transform: translate(-50%,-50%); }
|
||||
.voice-wrap-{{ screen }}-middle-right { top: 50%; right: 16px; transform: translateY(-50%); }
|
||||
.voice-wrap-{{ screen }}-bottom-left { bottom: calc({% if newsticker_enabled %}56px{% else %}16px{% endif %}); left: 16px; }
|
||||
.voice-wrap-{{ screen }}-bottom-center { bottom: calc({% if newsticker_enabled %}56px{% else %}16px{% endif %}); left: 50%; transform: translateX(-50%); }
|
||||
.voice-wrap-{{ screen }}-bottom-right { bottom: calc({% if newsticker_enabled %}56px{% else %}16px{% endif %}); right: 16px; }
|
||||
</style>
|
||||
<!-- Voice-Agent-Wrap: Fixpositionierter Container mit Button + optionalem Bild -->
|
||||
<div class="voice-wrap-{{ screen }} voice-wrap-{{ screen }}-{{ voice_agent_position|default('top-left') }}">
|
||||
{% if voice_agent_show_image %}<span class="voice-img-{{ screen }}"></span>{% endif %}
|
||||
{% if voice_agent_target == "redirect" %}
|
||||
<a href="{{ voice_agent_url }}"
|
||||
class="voice-pos-{{ screen }}">
|
||||
<span class="voice-icon">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</span>
|
||||
<span class="voice-text-{{ screen }}">
|
||||
<span class="voice-tagline-{{ screen }}" id="voice-tagline-{{ screen }}"></span>
|
||||
<span class="voice-label-{{ screen }}">{{ voice_agent_label or "Digitaler Assistent" }}</span>
|
||||
</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<button onclick='openOverlay({{ voice_agent_url | tojson }}, "{{ voice_agent_position|default('top-left') }}")'
|
||||
class="voice-pos-{{ screen }}">
|
||||
<span class="voice-icon">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</span>
|
||||
<span class="voice-text-{{ screen }}">
|
||||
<span class="voice-tagline-{{ screen }}" id="voice-tagline-{{ screen }}"></span>
|
||||
<span class="voice-label-{{ screen }}">{{ voice_agent_label or "Digitaler Assistent" }}</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- ─── Medien-Elemente (eines ist jeweils sichtbar) ─── -->
|
||||
<img id="image">
|
||||
<video id="video" muted autoplay playsinline></video>
|
||||
@@ -135,11 +323,13 @@
|
||||
|
||||
let playerTimer = null;
|
||||
|
||||
// ─── Custom-URL-Overlay ───
|
||||
function openOverlay(url) {
|
||||
// ─── Custom-URL/Voice-Agent-Overlay (open/close mit Zurück-Button-Position-Tracking) ───
|
||||
function openOverlay(url, pos) {
|
||||
if (playerTimer) clearTimeout(playerTimer);
|
||||
document.getElementById("overlay").style.display = "block";
|
||||
document.getElementById("overlay-iframe").src = url;
|
||||
var backBtn = document.getElementById("overlay-back");
|
||||
backBtn.className = "overlay-back-" + (pos || "top-left");
|
||||
}
|
||||
|
||||
function closeOverlay() {
|
||||
@@ -162,8 +352,10 @@ updateClock();
|
||||
const normalFiles = {{ normal_files | tojson }};
|
||||
const prioFiles = {{ prio_files | tojson }};
|
||||
const interval = {{ interval }} * 1000;
|
||||
const screen = "{{ screen }}";
|
||||
const site = "{{ site }}";
|
||||
const stayOnFirst = {{ "true" if stay_on_first else "false" }};
|
||||
const screen = "{{ screen }}";
|
||||
const site = "{{ site }}";
|
||||
// stayOnFirst: Player bleibt auf erstem Element (kein Timer/Advance)
|
||||
|
||||
// ─── Player-Status ───
|
||||
let normalIndex = 0;
|
||||
@@ -270,7 +462,7 @@ function playNext() {
|
||||
iframe.style.height = `100vh`;
|
||||
iframe.style.transform = `translate(-50%, -50%)`;
|
||||
}
|
||||
playerTimer = setTimeout(playNext, interval);
|
||||
if (!stayOnFirst) playerTimer = setTimeout(playNext, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -279,7 +471,7 @@ function playNext() {
|
||||
if (isVideo(item)) {
|
||||
vid.style.display = "block";
|
||||
vid.src = src;
|
||||
vid.onended = playNext;
|
||||
vid.onended = stayOnFirst ? null : playNext;
|
||||
vid.play();
|
||||
} else if (isHtml(item)) {
|
||||
iframe.style.display = "block";
|
||||
@@ -312,6 +504,51 @@ async function checkForUpdates() {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Voice-Agent-Tagline Typewriter ───
|
||||
// Wechselt mehrsprachige Sätze, Buchstabe für Buchstabe, 2,5 s Pause, 0,8 s Fade-Out
|
||||
(function() {
|
||||
const el = document.getElementById('voice-tagline-{{ screen }}');
|
||||
if (!el) return;
|
||||
const phrases = [
|
||||
"Always ready to help",
|
||||
"How can I assist you?",
|
||||
"Questions? Just ask.",
|
||||
"Wie kann ich helfen?",
|
||||
"Ich bin für Sie da",
|
||||
"Sprechen Sie mich einfach an",
|
||||
"Comment puis-je vous aider?",
|
||||
"¿En qué puedo ayudarle?",
|
||||
"Come posso aiutarti?",
|
||||
"I'm here for you",
|
||||
"Let me know what you need"
|
||||
];
|
||||
let idx = 0, charIdx = 0, fading = false;
|
||||
function type() {
|
||||
if (fading) {
|
||||
el.style.opacity = '0';
|
||||
fading = false;
|
||||
setTimeout(function() {
|
||||
el.textContent = '';
|
||||
el.style.opacity = '1';
|
||||
setTimeout(type, 200);
|
||||
}, 800);
|
||||
return;
|
||||
}
|
||||
const phrase = phrases[idx % phrases.length];
|
||||
if (charIdx < phrase.length) {
|
||||
el.textContent = phrase.slice(0, charIdx + 1);
|
||||
charIdx++;
|
||||
setTimeout(type, 50 + Math.random() * 30);
|
||||
} else {
|
||||
charIdx = 0;
|
||||
idx++;
|
||||
fading = true;
|
||||
setTimeout(type, 2500);
|
||||
}
|
||||
}
|
||||
type();
|
||||
})();
|
||||
|
||||
// ─── Start ───
|
||||
playNext();
|
||||
setInterval(checkForUpdates, 5000);
|
||||
|
||||
Reference in New Issue
Block a user