|
| 1 | +import { ReactiveElement } from '@videojs/element'; |
| 2 | +import { |
| 3 | + bufferingIndicator, |
| 4 | + button, |
| 5 | + buttonGroup, |
| 6 | + controls, |
| 7 | + error, |
| 8 | + icon, |
| 9 | + iconContainer, |
| 10 | + iconFlipped, |
| 11 | + iconState, |
| 12 | + overlay, |
| 13 | + popup, |
| 14 | + root, |
| 15 | + seek, |
| 16 | + slider, |
| 17 | + time, |
| 18 | +} from '@videojs/skins/video/minimal.tailwind'; |
| 19 | +import { cn } from '@videojs/utils/style'; |
| 20 | +import { SkinMixin } from '../../presets/skin-mixin'; |
| 21 | + |
| 22 | +// Side-effect imports: register all custom elements used in the template. |
| 23 | +import '@videojs/icons/element'; |
| 24 | +import '../media/container'; |
| 25 | +import '../ui/buffering-indicator'; |
| 26 | +import '../ui/controls'; |
| 27 | +import '../ui/fullscreen-button'; |
| 28 | +import '../ui/mute-button'; |
| 29 | +import '../ui/pip-button'; |
| 30 | +import '../ui/play-button'; |
| 31 | +import '../ui/playback-rate-button'; |
| 32 | +import '../ui/popover'; |
| 33 | +import '../ui/seek-button'; |
| 34 | +import '../ui/time'; |
| 35 | +import '../ui/time-slider'; |
| 36 | +import '../ui/volume-slider'; |
| 37 | +import { playbackRate } from '@videojs/skins/video/default.tailwind'; |
| 38 | + |
| 39 | +const SEEK_TIME = 10; |
| 40 | + |
| 41 | +function getTemplateHTML() { |
| 42 | + return /*html*/ ` |
| 43 | + <media-container class="${root}"> |
| 44 | + <media-buffering-indicator class="${bufferingIndicator}"> |
| 45 | + <media-icon family="minimal" name="spinner"></media-icon> |
| 46 | + </media-buffering-indicator> |
| 47 | +
|
| 48 | + <div class="${error.root}" role="alertdialog" aria-labelledby="media-error-title" aria-describedby="media-error-description"> |
| 49 | + <div class="${error.dialog}"> |
| 50 | + <div class="${error.content}"> |
| 51 | + <p id="media-error-title" class="${error.title}">Something went wrong.</p> |
| 52 | + <p id="media-error-description">An error occurred while trying to play the video. Please try again.</p> |
| 53 | + </div> |
| 54 | + <div class="${error.actions}"> |
| 55 | + <button type="button" class="${cn(button.base, button.default)}">OK</button> |
| 56 | + </div> |
| 57 | + </div> |
| 58 | + </div> |
| 59 | +
|
| 60 | + <media-controls data-controls="" class="${controls}"> |
| 61 | + <span class="${buttonGroup}"> |
| 62 | + <media-play-button class="${cn(button.base, button.icon, iconState.play.button)}"> |
| 63 | + <media-icon family="minimal" name="restart" class="${cn(icon, iconState.play.restart)}"></media-icon> |
| 64 | + <media-icon family="minimal" name="play" class="${cn(icon, iconState.play.play)}"></media-icon> |
| 65 | + <media-icon family="minimal" name="pause" class="${cn(icon, iconState.play.pause)}"></media-icon> |
| 66 | + </media-play-button> |
| 67 | +
|
| 68 | + <media-seek-button seconds="${-SEEK_TIME}" class="${cn(button.base, button.icon, seek.button)}"> |
| 69 | + <span class="${iconContainer}"> |
| 70 | + <media-icon family="minimal" name="seek" class="${cn(icon, iconFlipped)}"></media-icon> |
| 71 | + <span class="${cn(seek.label, seek.labelBackward)}">${SEEK_TIME}</span> |
| 72 | + </span> |
| 73 | + </media-seek-button> |
| 74 | +
|
| 75 | + <media-seek-button seconds="${SEEK_TIME}" class="${cn(button.base, button.icon, seek.button)}"> |
| 76 | + <span class="${iconContainer}"> |
| 77 | + <media-icon family="minimal" name="seek" class="${icon}"></media-icon> |
| 78 | + <span class="${cn(seek.label, seek.labelForward)}">${SEEK_TIME}</span> |
| 79 | + </span> |
| 80 | + </media-seek-button> |
| 81 | + </span> |
| 82 | +
|
| 83 | + <span class="${time.controls}"> |
| 84 | + <media-time-group class="${time.group}"> |
| 85 | + <media-time type="current" class="${time.current}"></media-time> |
| 86 | + <media-time-separator class="${time.separator}"></media-time-separator> |
| 87 | + <media-time type="duration" class="${time.duration}"></media-time> |
| 88 | + </media-time-group> |
| 89 | +
|
| 90 | + <media-time-slider class="${slider.root}"> |
| 91 | + <media-slider-track class="${slider.track}"> |
| 92 | + <media-slider-fill class="${cn(slider.fill.base, slider.fill.fill)}"></media-slider-fill> |
| 93 | + <media-slider-buffer class="${cn(slider.fill.base, slider.fill.buffer)}"></media-slider-buffer> |
| 94 | + </media-slider-track> |
| 95 | + <media-slider-thumb class="${cn(slider.thumb.base, slider.thumb.interactive)}"></media-slider-thumb> |
| 96 | + </media-time-slider> |
| 97 | + </span> |
| 98 | +
|
| 99 | + <span class="${buttonGroup}"> |
| 100 | + <media-playback-rate-button class="${cn(button.base, button.icon, playbackRate.button)}"> |
| 101 | + </media-playback-rate-button> |
| 102 | +
|
| 103 | + <media-mute-button commandfor="volume-popover" class="${cn(button.base, button.icon, iconState.mute.button)}"> |
| 104 | + <media-icon family="minimal" name="volume-off" class="${cn(icon, iconState.mute.volumeOff)}"></media-icon> |
| 105 | + <media-icon family="minimal" name="volume-low" class="${cn(icon, iconState.mute.volumeLow)}"></media-icon> |
| 106 | + <media-icon family="minimal" name="volume-high" class="${cn(icon, iconState.mute.volumeHigh)}"></media-icon> |
| 107 | + </media-mute-button> |
| 108 | +
|
| 109 | + <media-popover id="volume-popover" open-on-hover delay="200" close-delay="100" side="top" class="${cn(popup.base, popup.volume)}"> |
| 110 | + <media-volume-slider class="${slider.root}" orientation="vertical" thumb-alignment="edge"> |
| 111 | + <media-slider-track class="${slider.track}"> |
| 112 | + <media-slider-fill class="${cn(slider.fill.base, slider.fill.fill)}"></media-slider-fill> |
| 113 | + </media-slider-track> |
| 114 | + <media-slider-thumb class="${slider.thumb.base}"></media-slider-thumb> |
| 115 | + </media-volume-slider> |
| 116 | + </media-popover> |
| 117 | +
|
| 118 | + <!--<button type="button" class="${cn(button.base, button.icon)}" aria-label="Captions"> |
| 119 | + <media-icon family="minimal" name="captions-off" class="${icon}"></media-icon> |
| 120 | + <media-icon family="minimal" name="captions-on" class="${icon}"></media-icon> |
| 121 | + </button>--> |
| 122 | +
|
| 123 | + <media-pip-button class="${cn(button.base, button.icon)}"> |
| 124 | + <media-icon family="minimal" name="pip" class="${icon}"></media-icon> |
| 125 | + </media-pip-button> |
| 126 | +
|
| 127 | + <media-fullscreen-button class="${cn(button.base, button.icon, iconState.fullscreen.button)}"> |
| 128 | + <media-icon family="minimal" name="fullscreen-enter" class="${cn(icon, iconState.fullscreen.enter)}"></media-icon> |
| 129 | + <media-icon family="minimal" name="fullscreen-exit" class="${cn(icon, iconState.fullscreen.exit)}"></media-icon> |
| 130 | + </media-fullscreen-button> |
| 131 | + </span> |
| 132 | + </media-controls> |
| 133 | +
|
| 134 | + <div class="${overlay}"></div> |
| 135 | + </media-container> |
| 136 | + `; |
| 137 | +} |
| 138 | + |
| 139 | +export class MinimalVideoSkinTailwindElement extends SkinMixin(ReactiveElement) { |
| 140 | + static readonly tagName = 'video-minimal-skin'; |
| 141 | + static getTemplateHTML = getTemplateHTML; |
| 142 | +} |
| 143 | + |
| 144 | +customElements.define(MinimalVideoSkinTailwindElement.tagName, MinimalVideoSkinTailwindElement); |
| 145 | + |
| 146 | +declare global { |
| 147 | + interface HTMLElementTagNameMap { |
| 148 | + [MinimalVideoSkinTailwindElement.tagName]: MinimalVideoSkinTailwindElement; |
| 149 | + } |
| 150 | +} |
0 commit comments