You've already forked Atomcms-edit
1037 lines
30 KiB
PHP
Executable File
1037 lines
30 KiB
PHP
Executable File
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
<title>{{ setting('hotel_name') }} - Nitro</title>
|
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Ubuntu+Condensed&display=swap" rel="stylesheet">
|
|
|
|
@vite(['resources/themes/' . setting('theme') . '/css/app.css', 'resources/themes/' . setting('theme') . '/js/app.js'], 'build')
|
|
|
|
<style>
|
|
:root {
|
|
--toolbar__primary__color: {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }};
|
|
--toolbar__hover__color: {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }};
|
|
--toolbar__border__color: {{ setting('toolbar_border_color', setting('button_border_color', '#cf9d15')) }};
|
|
--toolbar__text__color: {{ setting('toolbar_text_color', setting('button_text_color', '#1a1a2e')) }};
|
|
}
|
|
.toolbar { --toolbar__primary__color: var(--toolbar__primary__color); --toolbar__hover__color: var(--toolbar__hover__color); --toolbar__border__color: var(--toolbar__border__color); --toolbar__text__color: var(--toolbar__text__color); }
|
|
--color-primary: {{ setting('color_primary', '#eeb425') }};
|
|
--color-background: {{ setting('color_background', '#1a1a2e') }};
|
|
--button-color: {{ setting('button_primary_color', '#eeb425') }};
|
|
--button-text-color: {{ setting('button_text_color', '#1a1a2e') }};
|
|
--button-secondary-color: {{ setting('button_secondary_color', '#22c55e') }};
|
|
--button-secondary-text-color: {{ setting('button_secondary_text_color', '#ffffff') }};
|
|
--button-secondary-hover-color: {{ setting('button_secondary_hover_color', '#16a34a') }};
|
|
--button-secondary-border-color: {{ setting('button_secondary_border_color', '#16a34a') }};
|
|
--button-danger-color: {{ setting('button_danger_color', '#ef4444') }};
|
|
--button-danger-text-color: {{ setting('button_danger_text_color', '#ffffff') }};
|
|
--button-danger-hover-color: {{ setting('button_danger_hover_color', '#dc2626') }};
|
|
--button-danger-border-color: {{ setting('button_danger_border_color', '#dc2626') }};
|
|
--button-outline-color: {{ setting('button_outline_color', '#eeb425') }};
|
|
--button-outline-text-color: {{ setting('button_outline_text_color', '#1a1a2e') }};
|
|
--button-outline-hover-color: {{ setting('button_outline_hover_color', '#cf9d15') }};
|
|
}
|
|
</style>
|
|
|
|
@if(setting('button_enabled') == '1')
|
|
<style>
|
|
.cms-button {
|
|
background-color: {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} !important;
|
|
background: {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} !important;
|
|
color: {{ setting('toolbar_text_color', setting('button_text_color', '#1a1a2e')) }} !important;
|
|
border: {{ setting('button_border_width', '2') }}px solid {{ setting('toolbar_border_color', setting('button_border_color', '#cf9d15')) }} !important;
|
|
border-radius: {{ setting('button_border_radius', '8') }}px !important;
|
|
transition: {{ setting('button_transition', 'all') }} {{ setting('button_transition_duration', '300') }}ms !important;
|
|
}
|
|
.cms-button:hover {
|
|
background-color: {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} !important;
|
|
background: {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} !important;
|
|
transform: scale({{ setting('button_hover_scale', '1.05') }});
|
|
}
|
|
.toolbar-btn.cms-button {
|
|
padding: 8px !important;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} !important;
|
|
background: {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} !important;
|
|
}
|
|
.toolbar-btn.cms-button svg {
|
|
stroke: {{ setting('toolbar_text_color', setting('button_text_color', '#1a1a2e')) }} !important;
|
|
}
|
|
.toolbar-btn.cms-button:hover {
|
|
background-color: {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} !important;
|
|
background: {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} !important;
|
|
}
|
|
</style>
|
|
@endif
|
|
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Toolbar Container */
|
|
.toolbar {
|
|
position: fixed;
|
|
top: 16px;
|
|
left: 16px;
|
|
z-index: 9999;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
/* Standard Button Style - ALL buttons same size */
|
|
.toolbar-btn {
|
|
width: 40px;
|
|
height: 40px;
|
|
border: 2px solid {{ setting('toolbar_border_color', setting('button_border_color', '#cf9d15')) }};
|
|
border-radius: 6px;
|
|
background: linear-gradient(135deg, {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} 0%, {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} 100%);
|
|
color: {{ setting('toolbar_text_color', setting('button_text_color', '#1a1a2e')) }};
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
transition: transform 0.2s, box-shadow 0.2s;
|
|
}
|
|
|
|
.toolbar-btn:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
/* Radio Bar - Same height as buttons */
|
|
.radio-container {
|
|
width: 40px;
|
|
height: 40px;
|
|
border: 2px solid {{ setting('toolbar_border_color', setting('button_border_color', '#cf9d15')) }};
|
|
border-radius: 6px;
|
|
background: linear-gradient(135deg, {{ setting('toolbar_primary_color', setting('button_primary_color', '#eeb425')) }} 0%, {{ setting('toolbar_hover_color', setting('button_hover_color', '#cf9d15')) }} 100%);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
overflow: hidden;
|
|
transition: width 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.radio-container.expanded {
|
|
width: 320px;
|
|
}
|
|
|
|
.radio-toggle {
|
|
width: 36px;
|
|
height: 36px;
|
|
min-width: 36px;
|
|
border: none;
|
|
background: transparent;
|
|
color: {{ setting('button_text_color', '#1a1a2e') }};
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
}
|
|
|
|
.radio-status-dot {
|
|
position: absolute;
|
|
top: 6px;
|
|
right: 6px;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: #10b981;
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
.radio-status-dot.live {
|
|
background: #ef4444;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.5; }
|
|
}
|
|
|
|
.radio-content {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 0 8px;
|
|
opacity: 0;
|
|
transition: opacity 0.2s;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.radio-container.expanded .radio-content {
|
|
opacity: 1;
|
|
}
|
|
|
|
.radio-divider {
|
|
width: 1px;
|
|
height: 24px;
|
|
background: rgba(26, 26, 46, 0.3);
|
|
}
|
|
|
|
.radio-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.radio-dj-avatar {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 4px;
|
|
border: 1px solid rgba(26, 26, 46, 0.3);
|
|
background: rgba(26, 26, 46, 0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.radio-dj-avatar img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.radio-dj-name {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
color: var(--button-text-color);
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.radio-song {
|
|
font-size: 9px;
|
|
color: var(--button-text-color);
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.radio-control-btn {
|
|
width: 28px;
|
|
height: 28px;
|
|
border: none;
|
|
border-radius: 50%;
|
|
background: #1a1a2e;
|
|
color: var(--color-primary);
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.radio-volume {
|
|
width: 50px;
|
|
height: 4px;
|
|
background: rgba(26, 26, 46, 0.3);
|
|
border-radius: 2px;
|
|
appearance: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.radio-volume::-webkit-slider-thumb {
|
|
appearance: none;
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: #1a1a2e;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.radio-listeners {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 3px;
|
|
color: var(--button-text-color);
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.hidden {
|
|
display: none !important;
|
|
}
|
|
|
|
/* DJ Avatar Popup */
|
|
.dj-popup {
|
|
position: fixed;
|
|
bottom: 100px;
|
|
right: 24px;
|
|
background: linear-gradient(145deg, rgba(20, 20, 30, 0.98) 0%, rgba(10, 10, 20, 0.99) 100%);
|
|
border: 2px solid var(--color-primary);
|
|
border-radius: 16px;
|
|
padding: 20px;
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
|
|
z-index: 10000;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
min-width: 280px;
|
|
transform: translateX(400px);
|
|
opacity: 0;
|
|
transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
}
|
|
|
|
.dj-popup.show {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
|
|
.dj-popup-avatar {
|
|
width: 80px;
|
|
height: 80px;
|
|
border-radius: 50%;
|
|
border: 3px solid var(--color-primary);
|
|
background: var(--color-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 32px;
|
|
box-shadow: 0 8px 24px rgba(238, 180, 37, 0.4);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.dj-popup-avatar img {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.dj-popup-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.dj-popup-label {
|
|
font-size: 11px;
|
|
color: rgba(255, 255, 255, 0.6);
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.dj-popup-name {
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.dj-popup-show {
|
|
font-size: 13px;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.dj-popup-close {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 50%;
|
|
border: none;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
color: rgba(255, 255, 255, 0.6);
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 14px;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.dj-popup-close:hover {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
color: white;
|
|
}
|
|
|
|
.dj-popup-indicator {
|
|
position: absolute;
|
|
top: -4px;
|
|
left: -4px;
|
|
right: -4px;
|
|
bottom: -4px;
|
|
border: 2px solid #10b981;
|
|
border-radius: 18px;
|
|
animation: djPopupPulse 2s infinite;
|
|
pointer-events: none;
|
|
}
|
|
|
|
@keyframes djPopupPulse {
|
|
0%, 100% { opacity: 1; transform: scale(1); }
|
|
50% { opacity: 0.5; transform: scale(1.02); }
|
|
}
|
|
|
|
{{-- Client Loading Overlay --}}
|
|
@if($loginData)
|
|
@php $ic = $loginData['icon_color']; $bg = $loginData['background']; @endphp
|
|
.client-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 10001;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: {{ $bg }};
|
|
transition: opacity 0.6s ease, transform 0.6s ease;
|
|
}
|
|
.client-overlay.hidden {
|
|
opacity: 0;
|
|
transform: scale(1.1);
|
|
pointer-events: none;
|
|
}
|
|
.client-overlay-content {
|
|
text-align: center;
|
|
}
|
|
.client-overlay-icon {
|
|
width: {{ $loginData['icon_size'] }}px;
|
|
height: {{ $loginData['icon_size'] }}px;
|
|
margin: 0 auto 24px;
|
|
background: {{ $ic }};
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 48px;
|
|
color: {{ $loginData['text_color'] }};
|
|
box-shadow: 0 0 40px {{ $ic }}44;
|
|
}
|
|
.client-overlay-letter {
|
|
font-size: 52px;
|
|
font-weight: 800;
|
|
line-height: 1;
|
|
}
|
|
.client-overlay-img {
|
|
width: 80px;
|
|
height: auto;
|
|
object-fit: contain;
|
|
}
|
|
.client-overlay-text {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
color: {{ $loginData['text_color'] }};
|
|
margin-bottom: 16px;
|
|
letter-spacing: 2px;
|
|
}
|
|
.client-overlay-subtitle {
|
|
font-size: 14px;
|
|
color: {{ $loginData['text_color'] }}99;
|
|
margin-bottom: 24px;
|
|
}
|
|
.client-overlay-loader {
|
|
margin: 24px auto 0;
|
|
position: relative;
|
|
}
|
|
@keyframes clientBar {
|
|
0% { left: -40%; }
|
|
100% { left: 100%; }
|
|
}
|
|
@keyframes clientDots {
|
|
0%, 80%, 100% { transform: scale(0); }
|
|
40% { transform: scale(1); }
|
|
}
|
|
@keyframes clientPulseLoad {
|
|
0%, 100% { transform: scale(1); opacity: 0.5; }
|
|
50% { transform: scale(1.3); opacity: 1; }
|
|
}
|
|
@keyframes clientSpinLoad {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
@keyframes clientSkeleton {
|
|
0% { background-position: -200px 0; }
|
|
100% { background-position: calc(200px + 100%) 0; }
|
|
}
|
|
|
|
.client-bar-bar {
|
|
width: 200px;
|
|
height: 4px;
|
|
background: rgba(255,255,255,0.1);
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
.client-bar-bar::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
width: 40%;
|
|
background: {{ $loginData['bar_color'] }};
|
|
border-radius: 4px;
|
|
animation: clientBar 1.2s ease-in-out infinite;
|
|
}
|
|
|
|
.client-bar-dots {
|
|
display: flex;
|
|
gap: 8px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 20px;
|
|
}
|
|
.client-bar-dots span {
|
|
width: 12px;
|
|
height: 12px;
|
|
background: {{ $loginData['bar_color'] }};
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
animation: clientDots 1.4s ease-in-out infinite both;
|
|
}
|
|
.client-bar-dots span:nth-child(1) { animation-delay: -0.32s; }
|
|
.client-bar-dots span:nth-child(2) { animation-delay: -0.16s; }
|
|
.client-bar-dots span:nth-child(3) { animation-delay: 0s; }
|
|
|
|
.client-bar-pulse {
|
|
width: 24px;
|
|
height: 24px;
|
|
margin: 0 auto;
|
|
background: {{ $loginData['bar_color'] }};
|
|
border-radius: 50%;
|
|
animation: clientPulseLoad 1.5s ease-in-out infinite;
|
|
}
|
|
|
|
.client-bar-double {
|
|
width: 200px;
|
|
height: 4px;
|
|
position: relative;
|
|
margin: 0 auto;
|
|
}
|
|
.client-bar-double::before,
|
|
.client-bar-double::after {
|
|
content: '';
|
|
position: absolute;
|
|
height: 4px;
|
|
border-radius: 4px;
|
|
background: {{ $loginData['bar_color'] }}66;
|
|
}
|
|
.client-bar-double::before {
|
|
width: 100%;
|
|
top: 0;
|
|
animation: clientBar 2s ease-in-out infinite;
|
|
}
|
|
.client-bar-double::after {
|
|
width: 60%;
|
|
top: 10px;
|
|
animation: clientBar 2s ease-in-out infinite reverse;
|
|
}
|
|
|
|
.client-bar-spinner {
|
|
width: 30px;
|
|
height: 30px;
|
|
margin: 0 auto;
|
|
border: 3px solid rgba(255,255,255,0.1);
|
|
border-top-color: {{ $loginData['bar_color'] }};
|
|
border-radius: 50%;
|
|
animation: clientSpinLoad 0.8s linear infinite;
|
|
}
|
|
|
|
.client-bar-skeleton {
|
|
width: 200px;
|
|
height: 14px;
|
|
margin: 0 auto;
|
|
background: rgba(255,255,255,0.06);
|
|
border-radius: 8px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
.client-bar-skeleton::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, {{ $loginData['bar_color'] }}33, transparent);
|
|
background-size: 200px 100%;
|
|
animation: clientSkeleton 1.5s ease-in-out infinite;
|
|
}
|
|
|
|
{{-- Animation Effects --}}
|
|
.client-effect-sparkle .client-overlay-icon { animation: clientSparkle 1.5s ease-in-out infinite; }
|
|
@keyframes clientSparkle {
|
|
0%, 100% { transform: scale(1) rotate(0deg); box-shadow: 0 0 20px {{ $ic }}44; }
|
|
50% { transform: scale(1.15) rotate(10deg); box-shadow: 0 0 60px {{ $ic }}88; }
|
|
}
|
|
.client-effect-glow .client-overlay-icon { animation: clientGlow 2s ease-in-out infinite; }
|
|
@keyframes clientGlow {
|
|
0%, 100% { box-shadow: 0 0 20px {{ $ic }}44; }
|
|
50% { box-shadow: 0 0 80px {{ $ic }}cc, 0 0 120px {{ $ic }}66; }
|
|
}
|
|
.client-effect-float .client-overlay-icon { animation: clientFloat 3s ease-in-out infinite; }
|
|
@keyframes clientFloat {
|
|
0%, 100% { transform: translateY(0); }
|
|
50% { transform: translateY(-20px); }
|
|
}
|
|
.client-effect-bounce .client-overlay-icon { animation: clientBounce 1s ease-in-out infinite; }
|
|
@keyframes clientBounce {
|
|
0%, 100% { transform: translateY(0); }
|
|
50% { transform: translateY(-30px); }
|
|
}
|
|
.client-effect-pulse .client-overlay-icon { animation: clientPulse 1.5s ease-in-out infinite; }
|
|
@keyframes clientPulse {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.1); }
|
|
}
|
|
.client-effect-shine .client-overlay-icon { overflow: hidden; position: relative; }
|
|
.client-effect-shine .client-overlay-icon::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: linear-gradient(45deg, transparent 40%, rgba(255,255,255,0.3) 50%, transparent 60%);
|
|
animation: clientShine 2s ease-in-out infinite;
|
|
}
|
|
@keyframes clientShine {
|
|
0% { transform: translateX(-100%) rotate(45deg); }
|
|
100% { transform: translateX(100%) rotate(45deg); }
|
|
}
|
|
.client-effect-heartbeat .client-overlay-icon { animation: clientHeartbeat 1.5s ease-in-out infinite; }
|
|
@keyframes clientHeartbeat {
|
|
0%, 100% { transform: scale(1); }
|
|
15% { transform: scale(1.2); }
|
|
30% { transform: scale(1); }
|
|
45% { transform: scale(1.15); }
|
|
60% { transform: scale(1); }
|
|
}
|
|
.client-effect-rotate .client-overlay-icon { animation: clientRotate 2s linear infinite; }
|
|
@keyframes clientRotate {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
.client-effect-color-cycle .client-overlay-icon { animation: clientColorCycle 3s linear infinite; }
|
|
@keyframes clientColorCycle {
|
|
0% { background: {{ $ic }}; }
|
|
25% { background: #ef4444; }
|
|
50% { background: #22c55e; }
|
|
75% { background: #3b82f6; }
|
|
100% { background: {{ $ic }}; }
|
|
}
|
|
.client-effect-neon-pulse .client-overlay-icon { animation: clientNeonPulse 1.5s ease-in-out infinite; }
|
|
@keyframes clientNeonPulse {
|
|
0%, 100% { box-shadow: 0 0 20px {{ $ic }}, 0 0 40px {{ $ic }}44; }
|
|
50% { box-shadow: 0 0 60px {{ $ic }}, 0 0 100px {{ $ic }}88, 0 0 140px {{ $ic }}44; }
|
|
}
|
|
.client-effect-rainbow .client-overlay-icon { animation: clientRainbow 4s linear infinite; }
|
|
@keyframes clientRainbow {
|
|
0% { filter: hue-rotate(0deg); }
|
|
100% { filter: hue-rotate(360deg); }
|
|
}
|
|
.client-effect-fire .client-overlay-icon { animation: clientFire 0.5s ease-in-out infinite alternate; }
|
|
@keyframes clientFire {
|
|
0% { transform: scale(1); box-shadow: 0 0 30px #ff4500, 0 0 60px #ff8c00; background: #ff4500; }
|
|
100% { transform: scale(1.05); box-shadow: 0 0 50px #ff8c00, 0 0 80px #ff4500; background: #ff6347; }
|
|
}
|
|
.client-effect-glitch .client-overlay-content { animation: clientGlitchText 0.3s ease-in-out infinite alternate; }
|
|
@keyframes clientGlitchText {
|
|
0% { transform: translate(0); }
|
|
25% { transform: translate(-3px, 2px); }
|
|
50% { transform: translate(3px, -2px); }
|
|
75% { transform: translate(-2px, -1px); }
|
|
100% { transform: translate(2px, 1px); }
|
|
}
|
|
.client-effect-pop .client-overlay-icon { animation: clientPop 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; }
|
|
@keyframes clientPop {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.3); }
|
|
}
|
|
@endif
|
|
</style>
|
|
</head>
|
|
|
|
<body class="overflow-hidden" id="nitro-client">
|
|
{{-- Toolbar --}}
|
|
<div class="toolbar">
|
|
{{-- Home Button --}}
|
|
<a href="{{ route('me.show') }}" class="toolbar-btn cms-button" data-turbolinks="false" title="Home">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
|
<polyline points="9 22 9 12 15 12 15 22"></polyline>
|
|
</svg>
|
|
</a>
|
|
|
|
{{-- Reload Button --}}
|
|
<button class="toolbar-btn cms-button" onclick="location.reload()" title="Herladen">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="23 4 23 10 17 10"></polyline>
|
|
<polyline points="1 20 1 14 7 14"></polyline>
|
|
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
{{-- Fullscreen Button --}}
|
|
<button class="toolbar-btn cms-button" onclick="toggleFullscreen()" title="Fullscreen">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
{{-- Online Count Button --}}
|
|
<button class="toolbar-btn cms-button" title="Online gebruikers">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
<circle cx="12" cy="7" r="4"></circle>
|
|
</svg>
|
|
<span id="onlineCount" style="margin-left: 4px; font-size: 11px; font-weight: 700;">0</span>
|
|
</button>
|
|
|
|
|
|
</button>
|
|
|
|
{{-- Radio Player --}}
|
|
<div id="radioContainer" class="radio-container">
|
|
<button class="radio-toggle" onclick="toggleRadioBar()" title="Radio">
|
|
<div class="radio-status-dot" id="radioStatus"></div>
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M9 18V5l12-2v13"></path>
|
|
<circle cx="6" cy="18" r="3"></circle>
|
|
<circle cx="18" cy="16" r="3"></circle>
|
|
</svg>
|
|
</button>
|
|
|
|
<div class="radio-content">
|
|
<div class="radio-divider"></div>
|
|
|
|
<div class="radio-info">
|
|
<div class="radio-dj-avatar" id="radioDjAvatar">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
<circle cx="12" cy="7" r="4"></circle>
|
|
</svg>
|
|
</div>
|
|
<div style="display: flex; flex-direction: column;">
|
|
<span class="radio-dj-name" id="radioDj">{{ __('radio.music') }}</span>
|
|
<span class="radio-song" id="radioSong">{{ __('radio.loading') }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="radio-divider"></div>
|
|
|
|
<button class="radio-control-btn" onclick="toggleRadioPlay()" title="Play/Pause">
|
|
<svg id="playIcon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
|
|
<polygon points="5 3 19 12 5 21 5 3"/>
|
|
</svg>
|
|
<svg id="pauseIcon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor" class="hidden">
|
|
<rect x="6" y="4" width="4" height="16"/>
|
|
<rect x="14" y="4" width="4" height="16"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<div class="radio-divider"></div>
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#1a1a2e" stroke-width="2">
|
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
|
|
</svg>
|
|
<input type="range" class="radio-volume" id="radioVolume" min="0" max="100" value="50" onchange="setRadioVolume(this.value)">
|
|
|
|
<div class="radio-divider"></div>
|
|
|
|
<div class="radio-listeners">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#1a1a2e" stroke-width="2">
|
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
|
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
|
</svg>
|
|
<span id="radioListeners">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Nitro Client --}}
|
|
@php
|
|
$nitroUrl = sprintf('%s/index.html?sso=%s', setting('nitro_path'), $sso);
|
|
$toolbarParams = [];
|
|
// Toolbar with fallback to button colors (don't URL encode - # is valid in URLs)
|
|
$toolbarParams[] = 'toolbar_primary=' . (setting('toolbar_primary_color') ?: setting('button_primary_color', '#eeb425'));
|
|
$toolbarParams[] = 'toolbar_hover=' . (setting('toolbar_hover_color') ?: setting('button_hover_color', '#cf9d15'));
|
|
$toolbarParams[] = 'toolbar_border=' . (setting('toolbar_border_color') ?: setting('button_border_color', '#cf9d15'));
|
|
$toolbarParams[] = 'toolbar_text=' . (setting('toolbar_text_color') ?: setting('button_text_color', '#1a1a2e'));
|
|
if(count($toolbarParams)) $nitroUrl .= '&' . implode('&', $toolbarParams);
|
|
@endphp
|
|
|
|
{{-- Client Loading Overlay --}}
|
|
@if($loginData)
|
|
@php $cmsLogo = setting('cms_logo'); $anim = $loginData['animation']; @endphp
|
|
<div id="clientOverlay" class="client-overlay client-effect-{{ $anim }}">
|
|
<div class="client-overlay-content">
|
|
<div class="client-overlay-icon">
|
|
@if($loginData['show_logo'] && $cmsLogo)
|
|
<img src="{{ $cmsLogo }}" alt="{{ setting('hotel_name') }}" class="client-overlay-img">
|
|
@else
|
|
<span class="client-overlay-letter">{{ substr(setting('hotel_name'), 0, 1) }}</span>
|
|
@endif
|
|
</div>
|
|
@if($loginData['show_name'])
|
|
<div class="client-overlay-text">{{ setting('hotel_name') }}</div>
|
|
@endif
|
|
@if($loginData['custom_text'])
|
|
<div class="client-overlay-subtitle">{{ $loginData['custom_text'] }}</div>
|
|
@endif
|
|
<div class="client-overlay-loader">
|
|
@if($loginData['bar_style'] === 'dots')
|
|
<div class="client-bar-dots"><span></span><span></span><span></span></div>
|
|
@else
|
|
<div class="client-bar-{{ $loginData['bar_style'] }}"></div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function() {
|
|
var overlay = document.getElementById('clientOverlay');
|
|
var iframe = document.getElementById('nitro');
|
|
var startTime = Date.now();
|
|
var hidden = false;
|
|
function hideOverlay() {
|
|
if (!hidden) {
|
|
hidden = true;
|
|
overlay.classList.add('hidden');
|
|
setTimeout(function() { overlay.remove(); }, 700);
|
|
}
|
|
}
|
|
if (iframe) {
|
|
var poll = setInterval(function() {
|
|
try {
|
|
var doc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
if (doc && doc.querySelector('canvas')) {
|
|
clearInterval(poll);
|
|
var elapsed = Date.now() - startTime;
|
|
var minWait = Math.max(0, 3000 - elapsed);
|
|
setTimeout(hideOverlay, minWait);
|
|
}
|
|
} catch(e) {}
|
|
}, 200);
|
|
}
|
|
setTimeout(hideOverlay, 15000);
|
|
})();
|
|
</script>
|
|
@endif
|
|
|
|
<iframe id="nitro" src="about:blank" data-src="{{ $nitroUrl }}"
|
|
class="absolute top-0 left-0 m-0 h-full w-full overflow-hidden border-none p-0"></iframe>
|
|
|
|
<script>
|
|
(function() {
|
|
var iframe = document.getElementById('nitro');
|
|
if (iframe && (!iframe.src || iframe.src === 'about:blank')) {
|
|
setTimeout(function() {
|
|
iframe.src = iframe.getAttribute('data-src');
|
|
}, 500);
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
{{-- Disconnected Message --}}
|
|
<div id="disconnected" class="hidden" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000;">
|
|
<div style="position: absolute; width: 100%; height: 100%; background: rgba(0,0,0,0.7);"></div>
|
|
<div style="position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; gap: 16px;">
|
|
<h2 style="font-size: 24px; color: white;">{{ __('Verbinding verbroken') }}</h2>
|
|
<div style="display: flex; gap: 16px;">
|
|
<button onclick="location.reload()" style="padding: 12px 24px; background: var(--color-primary); border: 2px solid var(--color-primary); border-radius: 6px; color: var(--button-text-color); font-weight: 700; cursor: pointer;">
|
|
{{ __('Herladen') }}
|
|
</button>
|
|
<a href="{{ route('me.show') }}" style="padding: 12px 24px; background: transparent; border: 2px solid var(--color-primary); border-radius: 6px; color: var(--color-primary); text-decoration: none; font-weight: 700;">
|
|
{{ __('Terug') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- DJ Avatar Popup --}}
|
|
@if(setting('radio_show_dj_avatar_popup'))
|
|
<div id="djPopup" class="dj-popup">
|
|
<div class="dj-popup-indicator"></div>
|
|
<button class="dj-popup-close" onclick="hideDjPopup()">✕</button>
|
|
<div class="dj-popup-avatar" id="djPopupAvatar">
|
|
🎵
|
|
</div>
|
|
<div class="dj-popup-info">
|
|
<div class="dj-popup-label">Nu Live</div>
|
|
<div class="dj-popup-name" id="djPopupName">DJ Name</div>
|
|
<div class="dj-popup-show" id="djPopupShow">Show Name</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<audio id="radioAudio" preload="none"></audio>
|
|
|
|
<script>
|
|
// Fullscreen
|
|
function toggleFullscreen() {
|
|
if (document.fullscreenElement) {
|
|
document.exitFullscreen();
|
|
} else {
|
|
document.documentElement.requestFullscreen();
|
|
}
|
|
}
|
|
|
|
// Online count
|
|
function updateOnlineCount() {
|
|
fetch("{{ route('api.online-count') }}")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
document.getElementById('onlineCount').textContent = data.data?.onlineCount || 0;
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
setInterval(updateOnlineCount, 15000);
|
|
updateOnlineCount();
|
|
|
|
// Radio
|
|
let radioPlaying = false;
|
|
let radioStreamUrl = null;
|
|
let radioExpanded = false;
|
|
const radioAudio = document.getElementById('radioAudio');
|
|
|
|
function toggleRadioBar() {
|
|
const container = document.getElementById('radioContainer');
|
|
radioExpanded = !radioExpanded;
|
|
|
|
if (radioExpanded) {
|
|
container.classList.add('expanded');
|
|
if (!radioStreamUrl) loadRadio();
|
|
} else {
|
|
container.classList.remove('expanded');
|
|
}
|
|
}
|
|
|
|
function loadRadio() {
|
|
fetch("{{ route('api.radio.config') }}")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.enabled && data.stream_url) {
|
|
radioStreamUrl = data.stream_url;
|
|
radioAudio.src = radioStreamUrl;
|
|
document.getElementById('radioSong').textContent = 'Gereed';
|
|
|
|
fetch("{{ route('api.settings.radio.auto-play') }}")
|
|
.then(r => r.json())
|
|
.then(settings => {
|
|
if (settings.auto_play) toggleRadioPlay();
|
|
});
|
|
} else {
|
|
document.getElementById('radioSong').textContent = 'Offline';
|
|
}
|
|
})
|
|
.catch(() => {
|
|
document.getElementById('radioSong').textContent = 'Error';
|
|
});
|
|
}
|
|
|
|
function toggleRadioPlay() {
|
|
if (!radioStreamUrl) {
|
|
loadRadio();
|
|
return;
|
|
}
|
|
|
|
const playIcon = document.getElementById('playIcon');
|
|
const pauseIcon = document.getElementById('pauseIcon');
|
|
|
|
if (radioPlaying) {
|
|
radioAudio.pause();
|
|
playIcon.classList.remove('hidden');
|
|
pauseIcon.classList.add('hidden');
|
|
radioPlaying = false;
|
|
} else {
|
|
radioAudio.volume = document.getElementById('radioVolume').value / 100;
|
|
radioAudio.play()
|
|
.then(() => {
|
|
playIcon.classList.add('hidden');
|
|
pauseIcon.classList.remove('hidden');
|
|
radioPlaying = true;
|
|
})
|
|
.catch(() => {
|
|
document.getElementById('radioSong').textContent = 'Fout';
|
|
});
|
|
}
|
|
}
|
|
|
|
function setRadioVolume(val) {
|
|
radioAudio.volume = val / 100;
|
|
localStorage.setItem('radioVol', val);
|
|
}
|
|
|
|
const savedVol = localStorage.getItem('radioVol');
|
|
if (savedVol) {
|
|
document.getElementById('radioVolume').value = savedVol;
|
|
}
|
|
|
|
// Update radio info
|
|
function updateRadioInfo() {
|
|
if (!radioStreamUrl) return;
|
|
|
|
fetch("{{ route('api.radio.config') }}")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
const defaultLook = '{{ setting("radio_default_avatar_figure", "hr-893-45.hd-180-2.ch-210-62.lg-285-62.sh-295-62.ha-1012-62.wa-2007-0") }}';
|
|
const defaultName = '{{ setting("radio_default_dj_name", "Frank") }}';
|
|
const avatarUrl = "{{ setting('avatar_imager') }}" + (data.dj?.look || defaultLook) + '&headonly=1';
|
|
|
|
const avatarEl = document.getElementById('radioDjAvatar');
|
|
if (data.dj?.look) {
|
|
avatarEl.innerHTML = '<img src="' + avatarUrl + '" alt="DJ">';
|
|
} else {
|
|
avatarEl.innerHTML = '<img src="' + avatarUrl + '" alt="' + defaultName + '">';
|
|
}
|
|
|
|
const dj = data.dj ? (typeof data.dj === 'object' ? data.dj.username : data.dj) : defaultName;
|
|
document.getElementById('radioDj').textContent = dj;
|
|
|
|
const status = document.getElementById('radioStatus');
|
|
if (data.dj) {
|
|
status.classList.add('live');
|
|
} else {
|
|
status.classList.remove('live');
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
|
|
fetch("{{ route('api.radio.now-playing') }}")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
const song = data.song || data.title || (data.now_playing?.title) || 'Live';
|
|
document.getElementById('radioSong').textContent = song;
|
|
})
|
|
.catch(() => {});
|
|
|
|
fetch("{{ route('api.radio.listeners') }}")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
document.getElementById('radioListeners').textContent = data.count || '0';
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
setInterval(updateRadioInfo, 10000);
|
|
|
|
// Init
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
loadRadio();
|
|
updateRadioInfo();
|
|
});
|
|
|
|
</script>
|
|
|
|
<script src="{{ asset('assets/js/atom.js') }}"></script>
|
|
</body>
|
|
|
|
</html>
|