-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
24954f2
commit 3b6f2a7
Showing
15 changed files
with
771 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
:host { | ||
box-sizing: border-box; | ||
position: relative; | ||
display: inline-block; | ||
width: 100%; | ||
font-family: Helvetica, Arial, sans-serif; | ||
} | ||
|
||
:host([hidden]) { | ||
display: none !important; | ||
} | ||
|
||
theoplayer-ui { | ||
font-family: Helvetica, Arial, sans-serif; | ||
width: 100%; | ||
--theoplayer-loading-delay: 0.1s; | ||
} | ||
|
||
:host(:fullscreen), | ||
:host(:fullscreen) theoplayer-ui { | ||
width: 100% !important; | ||
height: 100% !important; | ||
} | ||
|
||
theoplayer-menu::part(heading) { | ||
display: none !important; | ||
} | ||
|
||
[part='title'] { | ||
user-select: none; | ||
color: var(--theoplayer-text-color, #fff); | ||
text-shadow: 0 0 4px rgba(0, 0, 0, 0.75); | ||
padding: var(--theoplayer-control-padding, 10px); | ||
|
||
/* Vertically center any text */ | ||
font-size: var(--theoplayer-text-font-size, 14px); | ||
line-height: var(--theoplayer-text-content-height, var(--theoplayer-control-height, 24px)); | ||
} | ||
|
||
:host(:not([has-title])) [part='title'] { | ||
display: none; | ||
} | ||
|
||
[part='centered-chrome'] * { | ||
--theoplayer-control-height: 48px; | ||
} | ||
|
||
[part='middle-chrome'] { | ||
position: relative; | ||
display: flex; | ||
flex-flow: column nowrap; | ||
/* Align to bottom for Chromecast display */ | ||
justify-content: flex-end; | ||
flex-grow: 1; | ||
pointer-events: none; | ||
} | ||
|
||
[part='bottom-chrome'] { | ||
position: relative; | ||
display: flex; | ||
flex-flow: column nowrap; | ||
align-items: stretch; | ||
} | ||
|
||
/* | ||
* On mobile, put a backdrop color on the entire player when showing controls. | ||
*/ | ||
:host([mobile]) theoplayer-ui { | ||
--theoplayer-control-backdrop-background: rgba(0, 0, 0, 0.5); | ||
} | ||
|
||
/* | ||
* On desktop, put a soft gradient behind the top and bottom control bars. | ||
*/ | ||
:host { | ||
/* | ||
* Smooth transparent-to-black gradient from Chrome's <video> controls. | ||
* See: https://bugs.chromium.org/p/chromium/issues/detail?id=1404684 | ||
*/ | ||
/* prettier-ignore */ | ||
--theoplayer-control-background-gradient-stops: rgba(0, 0, 0, 0) 0%, | ||
rgba(0, 0, 0, 0.01) 8.1%, | ||
rgba(0, 0, 0, 0.037) 15.5%, | ||
rgba(0, 0, 0, 0.078) 22.5%, | ||
rgba(0, 0, 0, 0.131) 29%, | ||
rgba(0, 0, 0, 0.195) 35.3%, | ||
rgba(0, 0, 0, 0.264) 41.2%, | ||
rgba(0, 0, 0, 0.337) 47.1%, | ||
rgba(0, 0, 0, 0.413) 52.9%, | ||
rgba(0, 0, 0, 0.486) 58.8%, | ||
rgba(0, 0, 0, 0.555) 64.7%, | ||
rgba(0, 0, 0, 0.619) 71%, | ||
rgba(0, 0, 0, 0.672) 77.5%, | ||
rgba(0, 0, 0, 0.713) 84.5%, | ||
rgba(0, 0, 0, 0.74) 91.9%, | ||
rgba(0, 0, 0, 0.75) 100%; | ||
} | ||
|
||
:host(:not([mobile])) [part='top-chrome']::before, | ||
:host(:not([mobile])) [part='bottom-chrome']::before { | ||
content: ''; | ||
display: block; | ||
position: absolute; | ||
inset: 0; | ||
z-index: -1; | ||
pointer-events: none; | ||
} | ||
|
||
:host(:not([mobile])) [part='top-chrome']::before { | ||
background: linear-gradient(to top, var(--theoplayer-control-background-gradient-stops)); | ||
} | ||
|
||
:host(:not([mobile])) [part='bottom-chrome']::before { | ||
background: linear-gradient(to bottom, var(--theoplayer-control-background-gradient-stops)); | ||
} | ||
|
||
.theoplayer-spacer { | ||
flex-grow: 1; | ||
} | ||
|
||
theoplayer-time-range { | ||
--theoplayer-control-height: 12px; | ||
--theoplayer-range-track-pointer-background: rgba(255, 255, 255, 0.5); | ||
} | ||
|
||
/* | ||
* Mobile-only and mobile-hidden elements | ||
*/ | ||
:host([mobile]) [mobile-hidden], | ||
:host(:not([mobile])) [mobile-only] { | ||
display: none !important; | ||
} | ||
|
||
/* | ||
* Live-only and live-hidden elements | ||
*/ | ||
:host(:not([stream-type='vod'])) [live-hidden], | ||
:host(:not([stream-type='vod'])) theoplayer-control-bar ::slotted([live-hidden]), | ||
:host([stream-type='vod']) [live-only], | ||
:host([stream-type='vod']) theoplayer-control-bar ::slotted([live-only]) { | ||
display: none !important; | ||
} | ||
|
||
/* | ||
* Ad-only and ad-hidden elements | ||
*/ | ||
theoplayer-ui[playing-ad] [ad-hidden], | ||
theoplayer-ui:not([playing-ad]) [ad-only] { | ||
display: none !important; | ||
} | ||
|
||
/* | ||
* Hide all controls before first play, except for the center play button | ||
*/ | ||
theoplayer-ui:not([has-first-play]) theoplayer-control-bar, | ||
theoplayer-ui:not([has-first-play]) [part='centered-chrome'] :not(theoplayer-play-button) { | ||
display: none !important; | ||
} | ||
|
||
/* | ||
* Hide center play button on desktop after first play | ||
*/ | ||
:host(:not([mobile])) theoplayer-ui[has-first-play] [part='centered-chrome'] theoplayer-play-button { | ||
display: none !important; | ||
} | ||
|
||
theoplayer-volume-range { | ||
--theoplayer-range-padding-left: 0; | ||
} | ||
|
||
theoplayer-mute-button + theoplayer-volume-range { | ||
width: 0; | ||
overflow: hidden; | ||
--theoplayer-range-padding-right: 0; | ||
|
||
/* Set the internal width so it reveals, not grows */ | ||
--theoplayer-range-track-width: 70px; | ||
transition: width 0.2s ease-in; | ||
} | ||
|
||
/* Expand volume control in all relevant states */ | ||
theoplayer-mute-button:hover + theoplayer-volume-range, | ||
theoplayer-mute-button:focus + theoplayer-volume-range, | ||
theoplayer-mute-button + theoplayer-volume-range:hover, | ||
theoplayer-mute-button + theoplayer-volume-range:focus { | ||
width: 70px; | ||
} | ||
|
||
/* IE doesn't support :focus-within, so keep these separate (and use a polyfill?) */ | ||
theoplayer-mute-button:focus-within + theoplayer-volume-range, | ||
theoplayer-mute-button + theoplayer-volume-range:focus-within { | ||
width: 70px; | ||
} | ||
|
||
/* Reduce space between live button and remaining time display */ | ||
theoplayer-live-button + theoplayer-time-display { | ||
padding-left: 0; | ||
} | ||
|
||
/* Hide remaining time display when playing at live edge */ | ||
theoplayer-live-button[live] + theoplayer-time-display { | ||
display: none !important; | ||
} | ||
|
||
p { | ||
color: var(--theoplayer-text-color, #fff); | ||
font-size: var(--theoplayer-text-font-size, 20px); | ||
} | ||
|
||
#loading-announcement { | ||
display: none; | ||
} | ||
|
||
#offline-announcement { | ||
display: none; | ||
} | ||
|
||
#announcement { | ||
display: none; | ||
} | ||
|
||
theolive-bad-network-button { | ||
display: var(--theolive-bad-network-button-display, none); | ||
} | ||
|
||
theoplayer-settings-menu-button { | ||
display: var(--theolive-quality-button-display, flex); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<theoplayer-ui> | ||
<theolive-logo no-auto-hide slot="top-chrome" part="logo"></theolive-logo> | ||
<p id="loading-announcement" no-auto-hide slot="centered-chrome"><slot name="loading-announcement">Loading...</slot></p> | ||
<p id="offline-announcement" no-auto-hide slot="centered-chrome"><slot name="offline-announcement">The live stream hasn't started yet</slot></p> | ||
<p id="announcement" no-auto-hide slot="centered-chrome"></p> | ||
<theolive-watermark no-auto-hide slot="centered-chrome" part="watermark"></theolive-watermark> | ||
<theoplayer-loading-indicator slot="centered-loading" no-auto-hide part="loading-indicator"></theoplayer-loading-indicator> | ||
<div slot="centered-chrome" part="centered-chrome"> | ||
<theoplayer-play-button part="center-play-button"></theoplayer-play-button> | ||
</div> | ||
<div part="bottom-chrome"> | ||
<theoplayer-control-bar> | ||
<theoplayer-play-button mobile-hidden part="play-button"></theoplayer-play-button> | ||
<theoplayer-mute-button part="mute-button"></theoplayer-mute-button> | ||
<theoplayer-volume-range mobile-hidden part="volume-range"></theoplayer-volume-range> | ||
<theoplayer-live-button ad-hidden live-only part="live-button"></theoplayer-live-button> | ||
<span class="theoplayer-spacer"></span> | ||
<theoplayer-settings-menu-button ad-hidden menu="all-quality-menu" part="quality-button"></theoplayer-settings-menu-button> | ||
<theolive-bad-network-button ad-hidden menu="quality-menu" part="theolive-bad-network-button"></theolive-bad-network-button> | ||
<theoplayer-fullscreen-button part="fullscreen-button"></theoplayer-fullscreen-button> | ||
</theoplayer-control-bar> | ||
</div> | ||
<theoplayer-menu id="quality-menu" slot="menu" menu-close-on-input hidden> | ||
<theolive-bad-network-menu></theolive-bad-network-menu> | ||
</theoplayer-menu> | ||
<theoplayer-menu id="all-quality-menu" slot="menu" menu-close-on-input hidden> | ||
<theoplayer-quality-radio-group></theoplayer-quality-radio-group> | ||
</theoplayer-menu> | ||
<theoplayer-error-display slot="error" part="error-display"></theoplayer-error-display> | ||
</theoplayer-ui> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import "./components/theolive/Logo"; | ||
import "./components/theolive/quality/BadNetworkModeButton"; | ||
import "./components/theolive/quality/BadNetworkModeMenu"; | ||
import css from './THEOliveUI.css' | ||
import html from './THEOliveUI.html'; | ||
import type {ErrorEvent, PlayerConfiguration} from "theoplayer/chromeless"; | ||
import {DefaultUI} from "./DefaultUI"; | ||
import {READY_EVENT} from "./events/ReadyEvent"; | ||
import {ErrorDisplay, PlayButton} from "./components"; | ||
|
||
const template = document.createElement('template'); | ||
template.innerHTML = `<style>${css}</style>${html}`; | ||
|
||
export class THEOLiveUI extends DefaultUI { | ||
private readonly _loading: HTMLParagraphElement; | ||
private readonly _offline: HTMLParagraphElement; | ||
private readonly _announcement: HTMLParagraphElement; | ||
private readonly _errorDisplay: ErrorDisplay; | ||
private readonly _playButton: PlayButton; | ||
private readonly _root: HTMLElement; | ||
|
||
constructor(configuration: PlayerConfiguration = {}) { | ||
super(configuration); | ||
this._loading = this._shadowRoot.querySelector<HTMLParagraphElement>("#loading-announcement")!; | ||
this._offline = this._shadowRoot.querySelector<HTMLParagraphElement>("#offline-announcement")!; | ||
this._announcement = this._shadowRoot.querySelector<HTMLParagraphElement>("#announcement")!; | ||
this._errorDisplay = this._shadowRoot.querySelector<ErrorDisplay>("theoplayer-error-display")!; | ||
this._playButton = this._shadowRoot.querySelector<PlayButton>("theoplayer-play-button")!; | ||
this._root = this._shadowRoot.querySelector<HTMLElement>('theoplayer-ui')! | ||
|
||
this._ui.addEventListener(READY_EVENT, this.onReady); | ||
} | ||
|
||
protected initShadowRoot(): ShadowRoot { | ||
const shadowRoot = this.attachShadow({mode: 'open', delegatesFocus: true}); | ||
shadowRoot.appendChild(template.content.cloneNode(true)); | ||
return shadowRoot; | ||
} | ||
|
||
private readonly onReady = () => { | ||
this._ui.removeEventListener(READY_EVENT, this.onReady); | ||
const player = this.player; | ||
if (player) { | ||
player.theoLive?.addEventListener('publicationloadstart', this.onLoadChannelStart); | ||
player.theoLive?.addEventListener('publicationoffline', this.onChannelOffline); | ||
player.theoLive?.addEventListener('publicationloaded', this.onChannelLoaded); | ||
player.addEventListener('error', this.onError); | ||
} | ||
} | ||
|
||
private onLoadChannelStart = () => { | ||
this.showMessage_('loading', undefined); | ||
}; | ||
|
||
private onChannelOffline = () => { | ||
this.showMessage_('offline', undefined); | ||
}; | ||
|
||
private onChannelLoaded = () => { | ||
this.hidePlayerError(); | ||
this.hideMessage_(); | ||
} | ||
|
||
private onError = (e: ErrorEvent) => { | ||
const errorCode = e.errorObject.code | ||
if (errorCode < 13_000 || errorCode >= 14_000) { | ||
this.showMessage_('offline', undefined); | ||
return; | ||
} | ||
this.stopHidingPlayerError(); | ||
this.hideMessage_(); | ||
}; | ||
|
||
private hidePlayerError(): void { | ||
this._root.removeAttribute('has-error'); | ||
this._errorDisplay.style.display = "none"; | ||
} | ||
|
||
private stopHidingPlayerError(): void { | ||
this._root.setAttribute('has-error', ''); | ||
this._errorDisplay.style.display = "flex"; | ||
} | ||
|
||
private hidePlayerPlayButton_(): void { | ||
this._playButton.style.display = "none"; | ||
} | ||
|
||
private stopHidingPlayerPlayButton(): void { | ||
this._playButton.style.display = "inline-flex"; | ||
} | ||
|
||
private showMessage_(type: 'offline' | 'loading' | 'announcement', text: string | undefined): void { | ||
this.hidePlayerError(); | ||
this._loading.style.display = 'none'; | ||
this._offline.style.display = 'none'; | ||
this._announcement.style.display = 'none'; | ||
if (type === 'loading') { | ||
this._loading.style.display = 'block'; | ||
} else if (type === 'offline') { | ||
this._offline.style.display = 'block'; | ||
} else { | ||
this._announcement.textContent = text ?? ''; | ||
this._announcement.style.display = 'block'; | ||
} | ||
this.hidePlayerPlayButton_(); | ||
} | ||
|
||
private hideMessage_(): void { | ||
this._loading.style.display = 'none'; | ||
this._offline.style.display = 'none'; | ||
this._announcement.style.display = 'none'; | ||
this.stopHidingPlayerPlayButton(); | ||
} | ||
} | ||
|
||
customElements.define('theo-live-default-ui', THEOLiveUI); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.