UNPKG

@eternalheart/ngx-file-preview

Version:

A powerful Angular file preview component library supporting multiple file formats including images, videos, PDFs, Office documents, text files and more.

482 lines (470 loc) 61.4 kB
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core'; import { CommonModule } from '@angular/common'; import { BasePreviewComponent } from '../base-preview/base-preview.component'; import { PreviewIconComponent } from '../../components/preview-icon/preview-icon.component'; import Hls from 'hls.js'; import { I18nPipe } from "../../i18n"; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; export class VideoPreviewComponent extends BasePreviewComponent { constructor() { super(...arguments); this.isPlaying = false; this.currentTime = 0; this.duration = 0; this.progress = 0; this.volume = 1; this.previousVolume = 1; this.brightness = 100; this.isPiPMode = false; this.isControlsVisible = true; this.showVolumeControl = false; this.showBrightnessControl = false; this.isMuted = false; this.playbackSpeed = 1; this.playbackSpeeds = [0.75, 1, 1.5, 2.0, 3.0, 5.0]; this.showSpeedControl = false; this.isDragging = false; this.onGlobalDrag = (event) => { if (this.isDragging) { const progressBar = this.videoPlayer.nativeElement.parentElement?.querySelector('.progress-bar'); if (progressBar) { const rect = progressBar.getBoundingClientRect(); const pos = Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width)); const video = this.videoPlayer.nativeElement; video.currentTime = pos * video.duration; this.progress = pos * 100; this.cdr.markForCheck(); } } }; this.stopDragging = () => { if (this.isDragging) { this.isDragging = false; // 移除全局事件监听 document.removeEventListener('mousemove', this.onGlobalDrag); document.removeEventListener('mouseup', this.stopDragging); } }; } ngOnInit() { this.startLoading(); this.cdr.markForCheck(); } ngAfterViewInit() { this.setupVideo(); } onVideoLoad() { this.stopLoading(); this.duration = this.videoPlayer.nativeElement.duration; this.cdr.markForCheck(); } setupVideo() { const video = this.videoPlayer.nativeElement; const url = this.file.url; if (this.isHLSVideo(url)) { this.setupHLS(video, url); } else { // 对于普通视频,直接设置 src video.src = url; } } // 播放控制 togglePlay() { const video = this.videoPlayer.nativeElement; if (video.paused) { video.play().then(() => { this.isPlaying = true; this.cdr.markForCheck(); }).catch((error) => { console.error('播放失败:', error); this.isPlaying = false; this.cdr.markForCheck(); }); } else { video.pause(); this.isPlaying = false; this.cdr.markForCheck(); } } isHLSVideo(url) { return url.toLowerCase().includes('.m3u8') || url.includes('application/x-mpegURL') || url.includes('application/vnd.apple.mpegurl'); } // 进度更新 onTimeUpdate() { const video = this.videoPlayer.nativeElement; this.currentTime = video.currentTime; this.progress = (video.currentTime / video.duration) * 100; } adjustVolume(event) { const value = +event.target.value; this.volume = value / 100; this.isMuted = this.volume === 0; if (this.volume > 0) { this.previousVolume = this.volume; } this.videoPlayer.nativeElement.volume = this.volume; this.cdr.markForCheck(); } adjustBrightness(event) { const value = +event.target.value; this.brightness = value; this.videoPlayer.nativeElement.style.filter = `brightness(${this.brightness}%)`; this.cdr.markForCheck(); } // 画中画模式 async togglePip() { if (!document.pictureInPictureElement) { try { await this.videoPlayer.nativeElement.requestPictureInPicture(); this.isPiPMode = true; } catch (error) { console.error('画中画模式不支持:', error); } } else { await document.exitPictureInPicture(); this.isPiPMode = false; } } setupHLS(video, url) { if (Hls.isSupported()) { this.hls = new Hls({ debug: false, enableWorker: true, // 添加一些 HLS 配置以确保更好的兼容性 capLevelToPlayerSize: true, startLevel: -1, abrMaxWithRealBitrate: true }); this.hls.loadSource(url); this.hls.attachMedia(video); this.hls.on(Hls.Events.MANIFEST_PARSED, () => { // 清单解析完成后,尝试播放 video.play().catch(() => { console.log('Autoplay prevented'); }); }); this.hls.on(Hls.Events.ERROR, (event, data) => { if (data.fatal) { console.error('HLS error:', data); } }); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { // Safari 原生支持 video.src = url; } } async handleFileContent(content) { } toggleFullscreen() { const video = this.videoContainer.nativeElement; if (!document.fullscreenElement) { video.requestFullscreen(); } else { document.exitFullscreen(); } } // 控制栏显示/隐藏 showControls() { this.isControlsVisible = true; clearTimeout(this.controlsTimeout); } hideControls() { this.controlsTimeout = setTimeout(() => { if (this.isPlaying) { this.isControlsVisible = false; this.cdr.markForCheck(); } }, 2000); } // 后退15秒 back15s() { this.videoPlayer.nativeElement.currentTime -= 15; } // 前进15秒 forward15s() { this.videoPlayer.nativeElement.currentTime += 15; } ngOnDestroy() { if (this.hls) { this.hls.destroy(); } } // 跳转播放 seek(event) { const progressBar = event.currentTarget; const rect = progressBar.getBoundingClientRect(); const pos = (event.clientX - rect.left) / rect.width; if (pos >= 0 && pos <= 1) { // 确保在有效范围内 const video = this.videoPlayer.nativeElement; video.currentTime = pos * video.duration; this.progress = pos * 100; this.cdr.markForCheck(); } } // 进度条拖动 startDragging(event) { this.isDragging = true; this.seek(event); // 添加全局鼠标事件监听 document.addEventListener('mousemove', this.onGlobalDrag); document.addEventListener('mouseup', this.stopDragging); } // 音量控制 cycleVolume() { if (this.volume > 0) { this.previousVolume = this.volume; this.volume = 0; this.isMuted = true; } else { this.volume = this.previousVolume; this.isMuted = false; } this.videoPlayer.nativeElement.volume = this.volume; this.cdr.markForCheck(); } getVolumeIcon() { if (this.volume === 0) return 'mute'; return 'volume'; } // 亮度控制 cycleBrightness() { const levels = [0, 100, 200]; const currentIndex = levels.indexOf(this.brightness); const nextIndex = (currentIndex + 1) % levels.length; this.brightness = levels[nextIndex]; this.videoPlayer.nativeElement.style.filter = `brightness(${this.brightness}%)`; this.cdr.markForCheck(); } // 倍速控制 toggleSpeedControl() { this.showSpeedControl = !this.showSpeedControl; this.showVolumeControl = false; this.showBrightnessControl = false; this.cdr.markForCheck(); } setPlaybackSpeed(speed) { this.playbackSpeed = speed; this.videoPlayer.nativeElement.playbackRate = speed; this.showSpeedControl = false; this.cdr.markForCheck(); } formatTime(seconds) { if (!seconds) return '00:00:00'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); return [hours, minutes, secs] .map(val => val.toString().padStart(2, '0')) .join(':'); } onVideoEnded() { this.isPlaying = false; this.cdr.markForCheck(); } onVideoPause() { this.isPlaying = false; this.cdr.markForCheck(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VideoPreviewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: VideoPreviewComponent, isStandalone: true, selector: "ngx-video-preview", viewQueries: [{ propertyName: "videoPlayer", first: true, predicate: ["videoPlayer"], descendants: true }, { propertyName: "videoContainer", first: true, predicate: ["videoContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: ` <div class="video-container" #videoContainer [class.pip-mode]="isPiPMode"> <video #videoPlayer (loadeddata)="onVideoLoad()" (timeupdate)="onTimeUpdate()" (ended)="onVideoEnded()" (pause)="onVideoPause()" (click)="togglePlay()"> </video> <div class="controls" [class.visible]="isControlsVisible" (mouseover)="showControls()" (mouseleave)="hideControls()"> <!-- 进度条 --> <div class="progress-bar" (mousedown)="startDragging($event)"> <div class="progress" [style.width.%]="progress"></div> </div> <div class="bottom-controls"> <!-- 左侧控制按钮 --> <div class="left-controls"> <button (click)="togglePlay()"> <preview-icon [name]="isPlaying ? 'pause' : 'play'" [title]="(isPlaying ? 'preview.toolbar.pause' : 'preview.toolbar.play')|i18n"></preview-icon> </button> <button (click)="back15s()"> <preview-icon name="back15s" [title]="'preview.toolbar.back15s'|i18n"></preview-icon> </button> <button (click)="forward15s()"> <preview-icon name="forward15s" [title]="'preview.toolbar.forward15s'|i18n"></preview-icon> </button> <span class="time"> {{ formatTime(currentTime) }} / {{ formatTime(duration) }} </span> </div> <!-- 右侧控制按钮 --> <div class="right-controls"> <!-- 倍速控制 --> <div class="speed-control" (mouseenter)="showSpeedControl = true" (mouseleave)="showSpeedControl = false"> <button> {{ playbackSpeed }}x </button> <div class="speed-options" *ngIf="showSpeedControl"> <button *ngFor="let speed of playbackSpeeds" (click)="setPlaybackSpeed(speed)" [class.active]="playbackSpeed === speed"> {{ speed }}x </button> </div> </div> <!-- 亮度控制 --> <div class="control-group" (mouseenter)="showBrightnessControl = true" (mouseleave)="showBrightnessControl = false"> <button (click)="cycleBrightness()"> <preview-icon [name]="'lightness'"></preview-icon> </button> <div class="slider-container" *ngIf="showBrightnessControl"> <input type="range" min="0" max="200" [value]="brightness" (input)="adjustBrightness($event)"> </div> </div> <!-- 音量控制 --> <div class="control-group" (mouseenter)="showVolumeControl = true" (mouseleave)="showVolumeControl = false"> <button (click)="cycleVolume()"> <preview-icon [name]="getVolumeIcon()"></preview-icon> </button> <div class="slider-container" *ngIf="showVolumeControl"> <input type="range" min="0" max="100" [value]="volume * 100" (input)="adjustVolume($event)"> </div> </div> <button (click)="togglePip()"> <preview-icon name="pip" [title]="'preview.toolbar.pip'|i18n"></preview-icon> </button> <button (click)="toggleFullscreen()"> <preview-icon name="fullscreen" [title]="'preview.toolbar.fullscreen'|i18n"></preview-icon> </button> </div> </div> </div> </div> `, isInline: true, styles: [":root{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #d32029;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(0, 0, 0, .85);--nfp-text-secondary: rgba(0, 0, 0, .65);--nfp-text-disabled: rgba(0, 0, 0, .25);--nfp-bg-container: #ffffff;--nfp-bg-elevated: #fafafa;--nfp-bg-layout: #f0f2f5;--nfp-hover-bg: rgba(0, 0, 0, .04);--nfp-border-color: #d9d9d9;--nfp-split-color: rgba(0, 0, 0, .06);--nfp-scrollbar-bg: #ffffff;--nfp-scrollbar-thumb: #d9d9d9;--nfp-toolbar-bg: #fafafa;--nfp-toolbar-border: #d9d9d9;--nfp-toolbar-hover: rgba(0, 0, 0, .04);--nfp-toolbar-active: #e6f4ff;--nfp-preview-mask: rgba(0, 0, 0, .3);--nfp-preview-loading-bg: rgba(255, 255, 255, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .1);--nfp-theme-transition-duration: .3s}[data-nfp-theme=dark]{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #a61d24;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(255, 255, 255, .85);--nfp-text-secondary: rgba(255, 255, 255, .65);--nfp-text-disabled: rgba(255, 255, 255, .25);--nfp-bg-container: #1a1a1a;--nfp-bg-elevated: #262626;--nfp-bg-layout: #141414;--nfp-hover-bg: rgba(255, 255, 255, .08);--nfp-border-color: #303030;--nfp-split-color: rgba(255, 255, 255, .12);--nfp-scrollbar-bg: #1a1a1a;--nfp-scrollbar-thumb: #404040;--nfp-toolbar-bg: #262626;--nfp-toolbar-border: #303030;--nfp-toolbar-hover: rgba(255, 255, 255, .08);--nfp-toolbar-active: #111b26;--nfp-preview-mask: rgba(0, 0, 0, .65);--nfp-preview-loading-bg: rgba(0, 0, 0, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .4);--nfp-theme-transition-duration: .3s}*{transition:background-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),border-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),color var(--nfp-theme-transition-duration) var(--theme-transition-timing)}.no-transition,.no-transition *{transition:none!important}\n", ":host{display:block;width:100%;height:100%}.video-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--nfp-bg-container);position:relative}video{width:100%;height:100%;object-fit:contain}.controls{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(transparent,var(--nfp-preview-mask));padding:20px;opacity:0;transition:opacity .3s}.controls.visible{opacity:1}.progress-bar{width:100%;height:4px;margin-bottom:8px;background:var(--nfp-toolbar-bg);cursor:pointer;position:relative}.progress-bar .progress{height:100%;background:var(--nfp-primary-color);position:relative}.progress-bar .progress:after{content:\"\";position:absolute;right:-4px;top:-4px;width:12px;height:12px;background:var(--nfp-primary-color);border-radius:50%;transform:scale(0);transition:transform .2s}.progress-bar:hover .progress:after{transform:scale(1.2)}.bottom-controls{display:flex;justify-content:space-between;align-items:center}.left-controls,.right-controls{display:flex;gap:10px;align-items:center}button{background:transparent;border:none;color:#fff;cursor:pointer;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:16px}button:hover{background:#ffffff1a}.time{color:#fff;font-size:14px;font-family:monospace;min-width:120px;display:inline-block}.control-group{position:relative}.control-group .slider-container{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);padding:10px 6px;border-radius:4px;height:100px;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;display:flex;flex-direction:column;align-items:center;box-shadow:1px 1px 10px 1px #0000004d}.control-group .slider-container:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.control-group .slider-container:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.control-group .slider-container input[type=range]{writing-mode:bt-lr;-webkit-appearance:slider-vertical;width:4px;height:100px;padding:0;margin:0;background:var(--nfp-toolbar-hover)}.control-group .slider-container input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-webkit-slider-thumb:hover{transform:scale(1.2)}.control-group .slider-container input[type=range]::-moz-range-thumb{width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-moz-range-thumb:hover{transform:scale(1.2)}.control-group:hover .slider-container{opacity:1;pointer-events:auto}.speed-control{position:relative}.speed-control .speed-options{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);border-radius:4px;padding:6px 0;min-width:100px;display:flex;flex-direction:column-reverse;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;box-shadow:1px 1px 10px 1px #0000004d}.speed-control .speed-options:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.speed-control .speed-options:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.speed-control .speed-options button{width:100%;padding:4px 16px;text-align:left;border-radius:0;color:var(--nfp-text-primary)}.speed-control .speed-options button.active{color:var(--nfp-primary-active)}.speed-control .speed-options button:hover{background:#0000001a}.speed-control:hover .speed-options{opacity:1;pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PreviewIconComponent, selector: "preview-icon", inputs: ["name", "svg", "size", "color", "themeMode", "title", "cursor"] }, { kind: "pipe", type: I18nPipe, name: "i18n" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VideoPreviewComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-video-preview', standalone: true, imports: [CommonModule, PreviewIconComponent, I18nPipe], template: ` <div class="video-container" #videoContainer [class.pip-mode]="isPiPMode"> <video #videoPlayer (loadeddata)="onVideoLoad()" (timeupdate)="onTimeUpdate()" (ended)="onVideoEnded()" (pause)="onVideoPause()" (click)="togglePlay()"> </video> <div class="controls" [class.visible]="isControlsVisible" (mouseover)="showControls()" (mouseleave)="hideControls()"> <!-- 进度条 --> <div class="progress-bar" (mousedown)="startDragging($event)"> <div class="progress" [style.width.%]="progress"></div> </div> <div class="bottom-controls"> <!-- 左侧控制按钮 --> <div class="left-controls"> <button (click)="togglePlay()"> <preview-icon [name]="isPlaying ? 'pause' : 'play'" [title]="(isPlaying ? 'preview.toolbar.pause' : 'preview.toolbar.play')|i18n"></preview-icon> </button> <button (click)="back15s()"> <preview-icon name="back15s" [title]="'preview.toolbar.back15s'|i18n"></preview-icon> </button> <button (click)="forward15s()"> <preview-icon name="forward15s" [title]="'preview.toolbar.forward15s'|i18n"></preview-icon> </button> <span class="time"> {{ formatTime(currentTime) }} / {{ formatTime(duration) }} </span> </div> <!-- 右侧控制按钮 --> <div class="right-controls"> <!-- 倍速控制 --> <div class="speed-control" (mouseenter)="showSpeedControl = true" (mouseleave)="showSpeedControl = false"> <button> {{ playbackSpeed }}x </button> <div class="speed-options" *ngIf="showSpeedControl"> <button *ngFor="let speed of playbackSpeeds" (click)="setPlaybackSpeed(speed)" [class.active]="playbackSpeed === speed"> {{ speed }}x </button> </div> </div> <!-- 亮度控制 --> <div class="control-group" (mouseenter)="showBrightnessControl = true" (mouseleave)="showBrightnessControl = false"> <button (click)="cycleBrightness()"> <preview-icon [name]="'lightness'"></preview-icon> </button> <div class="slider-container" *ngIf="showBrightnessControl"> <input type="range" min="0" max="200" [value]="brightness" (input)="adjustBrightness($event)"> </div> </div> <!-- 音量控制 --> <div class="control-group" (mouseenter)="showVolumeControl = true" (mouseleave)="showVolumeControl = false"> <button (click)="cycleVolume()"> <preview-icon [name]="getVolumeIcon()"></preview-icon> </button> <div class="slider-container" *ngIf="showVolumeControl"> <input type="range" min="0" max="100" [value]="volume * 100" (input)="adjustVolume($event)"> </div> </div> <button (click)="togglePip()"> <preview-icon name="pip" [title]="'preview.toolbar.pip'|i18n"></preview-icon> </button> <button (click)="toggleFullscreen()"> <preview-icon name="fullscreen" [title]="'preview.toolbar.fullscreen'|i18n"></preview-icon> </button> </div> </div> </div> </div> `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":root{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #d32029;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(0, 0, 0, .85);--nfp-text-secondary: rgba(0, 0, 0, .65);--nfp-text-disabled: rgba(0, 0, 0, .25);--nfp-bg-container: #ffffff;--nfp-bg-elevated: #fafafa;--nfp-bg-layout: #f0f2f5;--nfp-hover-bg: rgba(0, 0, 0, .04);--nfp-border-color: #d9d9d9;--nfp-split-color: rgba(0, 0, 0, .06);--nfp-scrollbar-bg: #ffffff;--nfp-scrollbar-thumb: #d9d9d9;--nfp-toolbar-bg: #fafafa;--nfp-toolbar-border: #d9d9d9;--nfp-toolbar-hover: rgba(0, 0, 0, .04);--nfp-toolbar-active: #e6f4ff;--nfp-preview-mask: rgba(0, 0, 0, .3);--nfp-preview-loading-bg: rgba(255, 255, 255, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .1);--nfp-theme-transition-duration: .3s}[data-nfp-theme=dark]{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #a61d24;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(255, 255, 255, .85);--nfp-text-secondary: rgba(255, 255, 255, .65);--nfp-text-disabled: rgba(255, 255, 255, .25);--nfp-bg-container: #1a1a1a;--nfp-bg-elevated: #262626;--nfp-bg-layout: #141414;--nfp-hover-bg: rgba(255, 255, 255, .08);--nfp-border-color: #303030;--nfp-split-color: rgba(255, 255, 255, .12);--nfp-scrollbar-bg: #1a1a1a;--nfp-scrollbar-thumb: #404040;--nfp-toolbar-bg: #262626;--nfp-toolbar-border: #303030;--nfp-toolbar-hover: rgba(255, 255, 255, .08);--nfp-toolbar-active: #111b26;--nfp-preview-mask: rgba(0, 0, 0, .65);--nfp-preview-loading-bg: rgba(0, 0, 0, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .4);--nfp-theme-transition-duration: .3s}*{transition:background-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),border-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),color var(--nfp-theme-transition-duration) var(--theme-transition-timing)}.no-transition,.no-transition *{transition:none!important}\n", ":host{display:block;width:100%;height:100%}.video-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--nfp-bg-container);position:relative}video{width:100%;height:100%;object-fit:contain}.controls{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(transparent,var(--nfp-preview-mask));padding:20px;opacity:0;transition:opacity .3s}.controls.visible{opacity:1}.progress-bar{width:100%;height:4px;margin-bottom:8px;background:var(--nfp-toolbar-bg);cursor:pointer;position:relative}.progress-bar .progress{height:100%;background:var(--nfp-primary-color);position:relative}.progress-bar .progress:after{content:\"\";position:absolute;right:-4px;top:-4px;width:12px;height:12px;background:var(--nfp-primary-color);border-radius:50%;transform:scale(0);transition:transform .2s}.progress-bar:hover .progress:after{transform:scale(1.2)}.bottom-controls{display:flex;justify-content:space-between;align-items:center}.left-controls,.right-controls{display:flex;gap:10px;align-items:center}button{background:transparent;border:none;color:#fff;cursor:pointer;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:16px}button:hover{background:#ffffff1a}.time{color:#fff;font-size:14px;font-family:monospace;min-width:120px;display:inline-block}.control-group{position:relative}.control-group .slider-container{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);padding:10px 6px;border-radius:4px;height:100px;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;display:flex;flex-direction:column;align-items:center;box-shadow:1px 1px 10px 1px #0000004d}.control-group .slider-container:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.control-group .slider-container:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.control-group .slider-container input[type=range]{writing-mode:bt-lr;-webkit-appearance:slider-vertical;width:4px;height:100px;padding:0;margin:0;background:var(--nfp-toolbar-hover)}.control-group .slider-container input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-webkit-slider-thumb:hover{transform:scale(1.2)}.control-group .slider-container input[type=range]::-moz-range-thumb{width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-moz-range-thumb:hover{transform:scale(1.2)}.control-group:hover .slider-container{opacity:1;pointer-events:auto}.speed-control{position:relative}.speed-control .speed-options{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);border-radius:4px;padding:6px 0;min-width:100px;display:flex;flex-direction:column-reverse;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;box-shadow:1px 1px 10px 1px #0000004d}.speed-control .speed-options:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.speed-control .speed-options:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.speed-control .speed-options button{width:100%;padding:4px 16px;text-align:left;border-radius:0;color:var(--nfp-text-primary)}.speed-control .speed-options button.active{color:var(--nfp-primary-active)}.speed-control .speed-options button:hover{background:#0000001a}.speed-control:hover .speed-options{opacity:1;pointer-events:auto}\n"] }] }], propDecorators: { videoPlayer: [{ type: ViewChild, args: ['videoPlayer'] }], videoContainer: [{ type: ViewChild, args: ['videoContainer'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlkZW8tcHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL25neC1maWxlLXByZXZpZXcvc3JjL2xpYi9wcmV2aWV3LXR5cGVzL3ZpZGVvLXByZXZpZXcvdmlkZW8tcHJldmlldy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLHVCQUF1QixFQUN2QixTQUFTLEVBSVQsU0FBUyxFQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUM3QyxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSx3Q0FBd0MsQ0FBQztBQUM1RSxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSxzREFBc0QsQ0FBQztBQUMxRixPQUFPLEdBQUcsTUFBTSxRQUFRLENBQUM7QUFFekIsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLFlBQVksQ0FBQzs7O0FBeUdwQyxNQUFNLE9BQU8scUJBQXNCLFNBQVEsb0JBQW9CO0lBdkcvRDs7UUEyR0UsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixnQkFBVyxHQUFHLENBQUMsQ0FBQztRQUNoQixhQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxtQkFBYyxHQUFHLENBQUMsQ0FBQztRQUNuQixlQUFVLEdBQUcsR0FBRyxDQUFDO1FBQ2pCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFDbEIsc0JBQWlCLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQUMxQiwwQkFBcUIsR0FBRyxLQUFLLENBQUM7UUFFOUIsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNoQixrQkFBYSxHQUFHLENBQUMsQ0FBQztRQUNsQixtQkFBYyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMs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O1FBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDMUIsQ0FBQzsrR0F6U1UscUJBQXFCO21HQUFyQixxQkFBcUIsbVRBbkd0Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErRlQseWhNQWhHUyxZQUFZLGdRQUFFLG9CQUFvQiw4SEFBRSxRQUFROzs0RkFvRzNDLHFCQUFxQjtrQkF2R2pDLFNBQVM7K0JBQ0UsbUJBQW1CLGNBQ2pCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxRQUFRLENBQUMsWUFDN0M7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBK0ZULG1CQUVnQix1QkFBdUIsQ0FBQyxNQUFNOzhCQUdyQixXQUFXO3NCQUFwQyxTQUFTO3VCQUFDLGFBQWE7Z0JBQ0ssY0FBYztzQkFBMUMsU0FBUzt1QkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgVmlld0NoaWxkXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtDb21tb25Nb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge0Jhc2VQcmV2aWV3Q29tcG9uZW50fSBmcm9tICcuLi9iYXNlLXByZXZpZXcvYmFzZS1wcmV2aWV3LmNvbXBvbmVudCc7XG5pbXBvcnQge1ByZXZpZXdJY29uQ29tcG9uZW50fSBmcm9tICcuLi8uLi9jb21wb25lbnRzL3ByZXZpZXctaWNvbi9wcmV2aWV3LWljb24uY29tcG9uZW50JztcbmltcG9ydCBIbHMgZnJvbSAnaGxzLmpzJztcbmltcG9ydCB7RmlsZVJlYWRlclJlc3BvbnNlfSBmcm9tIFwiLi4vLi4vc2VydmljZXNcIjtcbmltcG9ydCB7STE4blBpcGV9IGZyb20gXCIuLi8uLi9pMThuXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC12aWRlby1wcmV2aWV3JyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgUHJldmlld0ljb25Db21wb25lbnQsIEkxOG5QaXBlXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwidmlkZW8tY29udGFpbmVyXCIgI3ZpZGVvQ29udGFpbmVyIFtjbGFzcy5waXAtbW9kZV09XCJpc1BpUE1vZGVcIj5cbiAgICAgIDx2aWRlbyAjdmlkZW9QbGF5ZXJcbiAgICAgICAgICAgICAobG9hZGVkZGF0YSk9XCJvblZpZGVvTG9hZCgpXCJcbiAgICAgICAgICAgICAodGltZXVwZGF0ZSk9XCJvblRpbWVVcGRhdGUoKVwiXG4gICAgICAgICAgICAgKGVuZGVkKT1cIm9uVmlkZW9FbmRlZCgpXCJcbiAgICAgICAgICAgICAocGF1c2UpPVwib25WaWRlb1BhdXNlKClcIlxuICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVQbGF5KClcIj5cbiAgICAgIDwvdmlkZW8+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJjb250cm9sc1wiIFtjbGFzcy52aXNpYmxlXT1cImlzQ29udHJvbHNWaXNpYmxlXCIgKG1vdXNlb3Zlcik9XCJzaG93Q29udHJvbHMoKVwiXG4gICAgICAgICAgIChtb3VzZWxlYXZlKT1cImhpZGVDb250cm9scygpXCI+XG4gICAgICAgIDwhLS0g6L+b5bqm5p2hIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwicHJvZ3Jlc3MtYmFyXCJcbiAgICAgICAgICAgICAobW91c2Vkb3duKT1cInN0YXJ0RHJhZ2dpbmcoJGV2ZW50KVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJwcm9ncmVzc1wiIFtzdHlsZS53aWR0aC4lXT1cInByb2dyZXNzXCI+PC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJib3R0b20tY29udHJvbHNcIj5cbiAgICAgICAgICA8IS0tIOW3puS+p+aOp+WItuaMiemSriAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVmdC1jb250cm9sc1wiPlxuICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwidG9nZ2xlUGxheSgpXCI+XG4gICAgICAgICAgICAgIDxwcmV2aWV3LWljb24gW25hbWVdPVwiaXNQbGF5aW5nID8gJ3BhdXNlJyA6ICdwbGF5J1wiIFt0aXRsZV09XCIoaXNQbGF5aW5nID8gJ3ByZXZpZXcudG9vbGJhci5wYXVzZScgOiAncHJldmlldy50b29sYmFyLnBsYXknKXxpMThuXCI+PC9wcmV2aWV3LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImJhY2sxNXMoKVwiPlxuICAgICAgICAgICAgICA8cHJldmlldy1pY29uIG5hbWU9XCJiYWNrMTVzXCIgW3RpdGxlXT1cIidwcmV2aWV3LnRvb2xiYXIuYmFjazE1cyd8aTE4blwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJmb3J3YXJkMTVzKClcIj5cbiAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBuYW1lPVwiZm9yd2FyZDE1c1wiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLmZvcndhcmQxNXMnfGkxOG5cIj48L3ByZXZpZXctaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0aW1lXCI+XG4gICAgICAgICAgICAgIHt7IGZvcm1hdFRpbWUoY3VycmVudFRpbWUpIH19IC8ge3sgZm9ybWF0VGltZShkdXJhdGlvbikgfX1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0g5Y+z5L6n5o6n5Yi25oyJ6ZKuIC0tPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyaWdodC1jb250cm9sc1wiPlxuICAgICAgICAgICAgPCEtLSDlgI3pgJ/mjqfliLYgLS0+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3BlZWQtY29udHJvbFwiXG4gICAgICAgICAgICAgICAgIChtb3VzZWVudGVyKT1cInNob3dTcGVlZENvbnRyb2wgPSB0cnVlXCJcbiAgICAgICAgICAgICAgICAgKG1vdXNlbGVhdmUpPVwic2hvd1NwZWVkQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24+XG4gICAgICAgICAgICAgICAge3sgcGxheWJhY2tTcGVlZCB9fXhcbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzcGVlZC1vcHRpb25zXCIgKm5nSWY9XCJzaG93U3BlZWRDb250cm9sXCI+XG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAqbmdGb3I9XCJsZXQgc3BlZWQgb2YgcGxheWJhY2tTcGVlZHNcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInNldFBsYXliYWNrU3BlZWQoc3BlZWQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwicGxheWJhY2tTcGVlZCA9PT0gc3BlZWRcIj5cbiAgICAgICAgICAgICAgICAgIHt7IHNwZWVkIH19eFxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8IS0tIOS6ruW6puaOp+WItiAtLT5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb250cm9sLWdyb3VwXCJcbiAgICAgICAgICAgICAgICAgKG1vdXNlZW50ZXIpPVwic2hvd0JyaWdodG5lc3NDb250cm9sID0gdHJ1ZVwiXG4gICAgICAgICAgICAgICAgIChtb3VzZWxlYXZlKT1cInNob3dCcmlnaHRuZXNzQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImN5Y2xlQnJpZ2h0bmVzcygpXCI+XG4gICAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBbbmFtZV09XCInbGlnaHRuZXNzJ1wiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNsaWRlci1jb250YWluZXJcIiAqbmdJZj1cInNob3dCcmlnaHRuZXNzQ29udHJvbFwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwicmFuZ2VcIlxuICAgICAgICAgICAgICAgICAgICAgICBtaW49XCIwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgbWF4PVwiMjAwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgW3ZhbHVlXT1cImJyaWdodG5lc3NcIlxuICAgICAgICAgICAgICAgICAgICAgICAoaW5wdXQpPVwiYWRqdXN0QnJpZ2h0bmVzcygkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDwhLS0g6Z+z6YeP5o6n5Yi2IC0tPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbnRyb2wtZ3JvdXBcIlxuICAgICAgICAgICAgICAgICAobW91c2VlbnRlcik9XCJzaG93Vm9sdW1lQ29udHJvbCA9IHRydWVcIlxuICAgICAgICAgICAgICAgICAobW91c2VsZWF2ZSk9XCJzaG93Vm9sdW1lQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImN5Y2xlVm9sdW1lKClcIj5cbiAgICAgICAgICAgICAgICA8cHJldmlldy1pY29uIFtuYW1lXT1cImdldFZvbHVtZUljb24oKVwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNsaWRlci1jb250YWluZXJcIiAqbmdJZj1cInNob3dWb2x1bWVDb250cm9sXCI+XG4gICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJyYW5nZVwiXG4gICAgICAgICAgICAgICAgICAgICAgIG1pbj1cIjBcIlxuICAgICAgICAgICAgICAgICAgICAgICBtYXg9XCIxMDBcIlxuICAgICAgICAgICAgICAgICAgICAgICBbdmFsdWVdPVwidm9sdW1lICogMTAwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgKGlucHV0KT1cImFkanVzdFZvbHVtZSgkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cInRvZ2dsZVBpcCgpXCI+XG4gICAgICAgICAgICAgIDxwcmV2aWV3LWljb24gbmFtZT1cInBpcFwiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLnBpcCd8aTE4blwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJ0b2dnbGVGdWxsc2NyZWVuKClcIj5cbiAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBuYW1lPVwiZnVsbHNjcmVlblwiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLmZ1bGxzY3JlZW4nfGkxOG5cIj48L3ByZXZpZXctaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZVVybHM6IFtcIi4uLy4uL3N0eWxlcy9fdGhlbWUuc2Nzc1wiLCBcInZpZGVvLXByZXZpZXcuY29tcG9uZW50LnNjc3NcIl0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBWaWRlb1ByZXZpZXdDb21wb25lbnQgZXh0ZW