diff --git a/pages/devices.php b/pages/devices.php index 360da2a..611dde1 100644 --- a/pages/devices.php +++ b/pages/devices.php @@ -11,7 +11,7 @@ - + diff --git a/theme/assets/css/main.css b/theme/assets/css/main.css index 66efd75..9fbb647 100644 --- a/theme/assets/css/main.css +++ b/theme/assets/css/main.css @@ -4535,3 +4535,428 @@ p:last-child { margin-bottom: 0; } .uc-db-bar--3 { transform: scaleY(.40) !important; } .uc-db-bar--4 { transform: scaleY(.62) !important; } } + +/* ═══════════════════════════════════════════════════════════ + NEVER GOES DARK ANIMATION (.platform-visual.has-ngd) + Sequence (10 s loop): + 0 – 30 % : Connected – dots travel player → cloud, cloud green + 30 – 45 % : Breaking – line turns red, × icon fades in + 45 – 72 % : Offline – × visible, ✓ on player, TV still plays + 72 – 85 % : Reconnect – × fades, dots resume, cloud back to green + 85 – 100% : Connected – steady state before next loop + ═══════════════════════════════════════════════════════════ */ + +/* ── Wrapper overrides ─────────────────────────────────────── */ +.platform-visual.has-ngd { + background: none !important; + border: none !important; + border-radius: 0; + aspect-ratio: unset; + padding: 0; + overflow: visible; + position: relative; + font-size: inherit; +} + +/* ── Stage ─────────────────────────────────────────────────── */ +.ngd-stage { + position: relative; + width: 100%; + max-width: 400px; + aspect-ratio: 4/3; + margin: 0 auto; +} + +/* ── TV ─────────────────────────────────────────────────────── */ +.ngd-tv { + position: absolute; + left: 8px; + top: 18px; + display: flex; + flex-direction: column; + align-items: center; +} +.ngd-tv__body { + width: 160px; + height: 120px; + background: #111; + border: 4px solid #111; + border-radius: 6px 6px 4px 4px; + outline: 1px solid #000; + padding: 3px; + display: flex; + align-items: stretch; + position: relative; + box-shadow: 0 10px 36px rgba(0,0,0,.55); +} +/* HDMI port stub on right side */ +.ngd-tv__port { + position: absolute; + right: -5px; + top: 50px; + width: 8px; + height: 14px; + background: #1a1a1a; + border: 1px solid #000; + border-radius: 2px; +} +.ngd-tv__screen { + width: 100%; + height: 100%; + border-radius: 2px; + position: relative; + overflow: hidden; + background: + repeating-linear-gradient( + 180deg, + transparent, transparent 3px, + rgba(0,0,0,.10) 3px, rgba(0,0,0,.10) 4px + ), + linear-gradient(135deg, #0c1016 0%, #151c28 60%, #0c1016 100%); +} +/* Scanline sweep */ +.ngd-tv__screen::after { + content: ''; + position: absolute; + left: 0; width: 100%; height: 3px; + background: linear-gradient(90deg, transparent, rgba(74,222,128,.22), transparent); + animation: da-scan 4s linear infinite; + pointer-events: none; +} +/* TV feet */ +.ngd-tv__feet { + display: flex; + gap: 50px; + margin-top: 3px; +} +.ngd-tv__foot { + width: 22px; + height: 6px; + background: #181818; + border-radius: 0 0 3px 3px; +} + +/* ── Menu board content (always playing) ───────────────────── */ +.ngd-menu { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + padding: 7px 6px 4px; + gap: 3px; +} +.ngd-menu__hd { + display: flex; + align-items: center; + gap: 5px; + padding-bottom: 4px; + border-bottom: 1px solid rgba(255,200,80,.18); + flex-shrink: 0; +} +.ngd-menu__logo { + width: 9px; height: 9px; + background: #4CAF50; + border-radius: 50%; + flex-shrink: 0; +} +.ngd-menu__ttl { + flex: 1; height: 5px; + background: rgba(255,200,80,.45); + border-radius: 2px; + max-width: 55px; +} +.ngd-menu__cols { + display: flex; + gap: 6px; + flex: 1; +} +.ngd-menu__col { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; +} +.ngd-menu__cat { + height: 4px; + background: rgba(76,175,80,.5); + border-radius: 1px; + margin-bottom: 1px; +} +.ngd-menu__row { + display: flex; + align-items: center; + gap: 3px; + padding: 2px 3px; + border-radius: 2px; + transition: background .3s; +} +.ngd-menu__row--hl { + background: rgba(76,175,80,.14); + animation: ngd-hl-pulse 3.5s ease-in-out infinite; +} +.ngd-menu__name { + flex: 1; height: 4px; + background: rgba(255,255,255,.25); + border-radius: 1px; +} +.ngd-menu__row--hl .ngd-menu__name { + background: rgba(76,175,80,.55); +} +.ngd-menu__price { + width: 16px; height: 4px; + background: rgba(255,200,80,.4); + border-radius: 1px; +} +.ngd-menu__row--hl .ngd-menu__price { + background: rgba(255,200,80,.7); +} +/* Scrolling ticker at bottom */ +.ngd-menu__ticker { + height: 6px; + background: rgba(76,175,80,.12); + border-radius: 1px; + overflow: hidden; + flex-shrink: 0; +} +.ngd-menu__ticker-inner { + width: 250%; + height: 100%; + background: repeating-linear-gradient( + 90deg, + rgba(76,175,80,.5) 0px, rgba(76,175,80,.5) 30px, + transparent 30px, transparent 50px + ); + animation: ngd-ticker 4s linear infinite; +} + +/* ── HDMI bridge ────────────────────────────────────────────── */ +.ngd-hdmi { + position: absolute; + left: 168px; + top: 112px; + width: 14px; + height: 3px; + background: #252525; + border-radius: 1px; +} + +/* ── Player device ──────────────────────────────────────────── */ +.ngd-player { + position: absolute; + left: 182px; + top: 102px; +} +.ngd-player__body { + display: flex; + align-items: center; + gap: 5px; + width: 96px; + height: 28px; + background: #1a1a1a; + border: 1.5px solid #2d2d2d; + border-radius: 4px; + padding: 4px 6px; + box-shadow: 0 4px 16px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.04); + position: relative; +} +.ngd-player__led { + width: 6px; + height: 6px; + border-radius: 50%; + flex-shrink: 0; + background: #4CAF50; + box-shadow: 0 0 6px rgba(76,175,80,.8); + animation: ngd-led 10s ease-in-out infinite; +} +.ngd-player__brand { + flex: 1; + height: 5px; + background: rgba(255,255,255,.07); + border-radius: 2px; +} +.ngd-player__port { + width: 8px; height: 11px; + background: #0d0d0d; + border: 1px solid #222; + border-radius: 1px; + flex-shrink: 0; +} +/* Checkmark badge — visible only during offline phase */ +.ngd-player__check { + position: absolute; + top: -14px; + right: -11px; + width: 24px; height: 24px; + opacity: 0; + transform: scale(0.4); + transform-origin: center; + animation: ngd-check-show 10s ease-in-out infinite; + filter: drop-shadow(0 0 4px rgba(76,175,80,.6)); +} + +/* ── Signal wrap (cloud + vertical line to player) ─────────── */ +.ngd-signal-wrap { + position: absolute; + /* horizontally centred on player: player left=182px, width=96px → centre=230px */ + left: 193px; /* 230 – cloud_half(37px) = 193 */ + top: 8px; + width: 74px; + display: flex; + flex-direction: column; + align-items: center; +} +.ngd-cloud { + width: 74px; + flex-shrink: 0; +} +.ngd-cloud__svg { + width: 100%; + height: auto; + display: block; +} +.ngd-cloud__path { + stroke: #4CAF50; + opacity: .85; + animation: ngd-cloud-color 10s ease-in-out infinite; +} +/* Vertical signal line */ +.ngd-signal-line { + width: 3px; + height: 44px; /* gap from cloud bottom to player top */ + background: rgba(76,175,80,.35); + border-radius: 2px; + position: relative; + overflow: visible; + animation: ngd-line-col 10s ease-in-out infinite; +} +/* Dots container — hidden during break phase */ +.ngd-signal__dots { + position: absolute; + inset: 0; + overflow: hidden; + animation: ngd-dots-vis 10s linear infinite; +} +.ngd-signal__dot { + position: absolute; + left: 50%; + transform: translateX(-50%); + width: 5px; height: 5px; + border-radius: 50%; + background: #4CAF50; + box-shadow: 0 0 5px rgba(76,175,80,.8); + animation: ngd-dot-up 1.8s ease-in-out infinite; +} +.ngd-signal__dot--2 { animation-delay: -0.6s; } +.ngd-signal__dot--3 { animation-delay: -1.2s; } +/* Break × badge — centered on line */ +.ngd-signal__break { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%) scale(0); + width: 18px; height: 18px; + opacity: 0; + animation: ngd-break-show 10s ease-in-out infinite; + filter: drop-shadow(0 0 4px rgba(239,68,68,.5)); +} + +/* ═══════════════════════════════════════════════════════════ + KEYFRAMES (10 s cycle) + ═══════════════════════════════════════════════════════════ */ + +/* Ticker scroll */ +@keyframes ngd-ticker { + from { transform: translateX(0); } + to { transform: translateX(-50%); } +} + +/* Highlighted menu row pulsing */ +@keyframes ngd-hl-pulse { + 0%, 100% { background: rgba(76,175,80,.14); } + 50% { background: rgba(76,175,80,.28); } +} + +/* Player LED: green → amber → red during disconnect → back to green */ +@keyframes ngd-led { + 0%, 29% { background: #4CAF50; box-shadow: 0 0 6px rgba(76,175,80,.8); } + 33% { background: #f59e0b; box-shadow: 0 0 5px rgba(245,158,11,.6); } + 38%, 71% { background: #ef4444; box-shadow: 0 0 4px rgba(239,68,68,.4); } + 75% { background: #4CAF50; box-shadow: 0 0 6px rgba(76,175,80,.8); } + 100% { background: #4CAF50; box-shadow: 0 0 6px rgba(76,175,80,.8); } +} + +/* Cloud stroke: green → red → green */ +@keyframes ngd-cloud-color { + 0%, 29% { stroke: #4CAF50; opacity: .85; } + 36%, 71% { stroke: #ef4444; opacity: 1; } + 76%, 100% { stroke: #4CAF50; opacity: .85; } +} + +/* Signal line colour */ +@keyframes ngd-line-col { + 0%, 29% { background: rgba(76,175,80,.35); } + 36%, 71% { background: rgba(239,68,68,.45); } + 76%, 100% { background: rgba(76,175,80,.35); } +} + +/* Dots container: visible during connected phases only */ +@keyframes ngd-dots-vis { + 0%, 29% { opacity: 1; } + 33% { opacity: 0; } + 71% { opacity: 0; } + 75%, 100% { opacity: 1; } +} + +/* Single dot travelling bottom → top */ +@keyframes ngd-dot-up { + 0% { bottom: 1px; opacity: 0; } + 8% { opacity: 1; } + 85% { opacity: 1; } + 100% { bottom: calc(100% - 5px); opacity: 0; } +} + +/* Break × badge: appears when disconnected */ +@keyframes ngd-break-show { + 0%, 29% { opacity: 0; transform: translate(-50%,-50%) scale(0); } + 38%, 71% { opacity: 1; transform: translate(-50%,-50%) scale(1); } + 76%, 100% { opacity: 0; transform: translate(-50%,-50%) scale(0); } +} + +/* Checkmark: appears when offline, confirming local playback */ +@keyframes ngd-check-show { + 0%, 44% { opacity: 0; transform: scale(0.4); } + 52%, 71% { opacity: 1; transform: scale(1); } + 77%, 100% { opacity: 0; transform: scale(0.4); } +} + +/* ── Responsive ─────────────────────────────────────────────── */ +@media (max-width: 640px) { + .ngd-stage { max-width: 320px; } + /* Scale the fixed-px elements down proportionally */ + .ngd-tv__body { width: 128px; height: 96px; } + .ngd-tv__port { top: 40px; } + .ngd-tv__foot { width: 18px; } + .ngd-hdmi { left: 134px; top: 90px; } + .ngd-player { left: 146px; top: 82px; } + .ngd-player__body { width: 76px; height: 24px; } + .ngd-signal-wrap { left: 154px; width: 60px; } + .ngd-signal-line { height: 36px; } +} + +/* ── Reduced-motion overrides ───────────────────────────────── */ +@media (prefers-reduced-motion: reduce) { + .ngd-tv__screen::after, + .ngd-menu__ticker-inner, + .ngd-menu__row--hl, + .ngd-player__led, + .ngd-signal__dot, + .ngd-signal__dots, + .ngd-signal__break, + .ngd-cloud__path, + .ngd-signal-line, + .ngd-player__check { animation: none !important; } + /* Static fallback states */ + .ngd-player__led { background: #4CAF50; box-shadow: 0 0 5px rgba(76,175,80,.6); } + .ngd-cloud__path { stroke: #4CAF50; opacity: .8; } + .ngd-signal__dots { opacity: 1; } +} diff --git a/theme/blocks/index.php b/theme/blocks/index.php index 48c1d43..34dfc25 100644 --- a/theme/blocks/index.php +++ b/theme/blocks/index.php @@ -553,9 +553,10 @@ add_action( 'init', function () { 'imgUrl' => [ 'type' => 'string', 'default' => '' ], 'imgAlt' => [ 'type' => 'string', 'default' => '' ], 'imgWidth' => [ 'type' => 'number', 'default' => 300 ], - 'deviceAnim' => [ 'type' => 'boolean', 'default' => false ], - 'tvStick' => [ 'type' => 'boolean', 'default' => false ], - 'cameraAnim' => [ 'type' => 'boolean', 'default' => false ], + 'deviceAnim' => [ 'type' => 'boolean', 'default' => false ], + 'tvStick' => [ 'type' => 'boolean', 'default' => false ], + 'cameraAnim' => [ 'type' => 'boolean', 'default' => false ], + 'neverGoesDark'=> [ 'type' => 'boolean', 'default' => false ], ], 'supports' => $block_supports, 'render_callback' => 'oribi_render_platform_row', @@ -1570,6 +1571,86 @@ function oribi_render_platform_row( $a ) { $ts .= ''; $visual_html = $ts; $visual_cls = 'platform-visual has-tv-stick'; + } elseif ( ! empty( $a['neverGoesDark'] ) ) { + /* ── Never Goes Dark: player + TV + cloud connection/break animation ── */ + $ngd = ''; /* ngd-stage */ + + $visual_html = $ngd; + $visual_cls = 'platform-visual has-ngd'; } elseif ( ! empty( $a['cameraAnim'] ) ) { $ca = '