Add live video countdown
parent
a5dec99e4b
commit
04fd77c1be
|
|
@ -951,7 +951,8 @@
|
|||
"@types/chart.js": {
|
||||
"version": "2.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.7.tgz",
|
||||
"integrity": "sha512-T+oRIWLPu6cXWYSTwihkeZLKk5V4U4O09Uqx4padQto1XVH7YafX4Z4YV1OIWnKbkqMn/4Cuj9ZwWcG6fnKK3A=="
|
||||
"integrity": "sha512-T+oRIWLPu6cXWYSTwihkeZLKk5V4U4O09Uqx4padQto1XVH7YafX4Z4YV1OIWnKbkqMn/4Cuj9ZwWcG6fnKK3A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jasmine": {
|
||||
"version": "2.8.15",
|
||||
|
|
@ -5997,6 +5998,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"luxon": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.22.0.tgz",
|
||||
"integrity": "sha512-3sLvlfbFo+AxVEY3IqxymbumtnlgBwjDExxK60W3d+trrUzErNAz/PfvPT+mva+vEUrdIodeCOs7fB6zHtRSrw=="
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz",
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@
|
|||
"@angular/material": "^7.2.1",
|
||||
"@angular/platform-browser": "~7.2.0",
|
||||
"@angular/platform-browser-dynamic": "~7.2.0",
|
||||
"@angular/router": "~7.2.0",
|
||||
"@angular/router": "~7.2.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"chartjs-plugin-datalabels": "^0.7.0",
|
||||
"core-js": "^2.5.4",
|
||||
"hammerjs": "^2.0.8",
|
||||
"luxon": "^1.22.0",
|
||||
"rxjs": "~6.3.3",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "~0.8.26"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { AddTransactionPageComponent } from './components/add-transaction-page/a
|
|||
import { MissionaryFormPageComponent } from './components/missionary-form-page/missionary-form-page.component';
|
||||
import { ContributorYearlyReportComponent } from './components/contributor-yearly-report/contributor-yearly-report.component';
|
||||
import { ContributorAllReportsComponent } from './components/contributor-all-reports/contributor-all-reports.component';
|
||||
import { LiveStreamComponent } from './components/live-stream/live-stream.component';
|
||||
|
||||
const routes =
|
||||
[
|
||||
|
|
@ -75,6 +76,10 @@ const routes =
|
|||
path: 'camp',
|
||||
component: CampPageComponent
|
||||
},
|
||||
{
|
||||
path: 'live',
|
||||
component: LiveStreamComponent
|
||||
},
|
||||
{
|
||||
path: 'transactions/add',
|
||||
component: AddTransactionPageComponent
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ import { MissionaryFormPageComponent } from './components/missionary-form-page/m
|
|||
import { MissionarySupportService } from './services/missionary-support-service';
|
||||
import { ContributorYearlyReportComponent } from './components/contributor-yearly-report/contributor-yearly-report.component';
|
||||
import { ContributorAllReportsComponent } from './components/contributor-all-reports/contributor-all-reports.component';
|
||||
import { LiveStreamComponent } from './components/live-stream/live-stream.component';
|
||||
|
||||
|
||||
|
||||
|
|
@ -123,7 +124,8 @@ import { ContributorAllReportsComponent } from './components/contributor-all-rep
|
|||
AddTransactionPopupComponent,
|
||||
MissionaryFormPageComponent,
|
||||
ContributorYearlyReportComponent,
|
||||
ContributorAllReportsComponent
|
||||
ContributorAllReportsComponent,
|
||||
LiveStreamComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
import { DateTime } from "luxon";
|
||||
|
||||
export class Countdown {
|
||||
public days: number = 0;
|
||||
public hours: number = 0;
|
||||
public minutes: number = 0;
|
||||
public seconds: number = 0;
|
||||
public liveDates: Date[] = [
|
||||
DateTime.fromObject({year: 2020, month: 3, day: 22, hour: 10, zone: 'America/Denver'}),
|
||||
DateTime.fromObject({year: 2020, month: 3, day: 22, hour: 11, zone: 'America/Denver'}),
|
||||
DateTime.fromObject({year: 2020, month: 3, day: 22, hour: 19, zone: 'America/Denver'})
|
||||
];
|
||||
public showButton: boolean;
|
||||
public showCounter: boolean = true;
|
||||
|
||||
public dateDisplay: string;
|
||||
public dateDisplaySmall: string;
|
||||
|
||||
public get daysDisplay(): string {
|
||||
return this.formatDisplay(this.days);
|
||||
}
|
||||
|
||||
public get daysText(): string {
|
||||
return this.days === 1 ? 'day ' : 'days';
|
||||
}
|
||||
|
||||
public get hoursDisplay(): string {
|
||||
return this.formatDisplay(this.hours);
|
||||
}
|
||||
|
||||
public get hoursText(): string {
|
||||
return this.hours === 1 ? 'hr ' : 'hrs';
|
||||
}
|
||||
|
||||
public get minutesDisplay(): string {
|
||||
return this.formatDisplay(this.minutes);
|
||||
}
|
||||
|
||||
public get minutesText(): string {
|
||||
return this.minutes === 1 ? 'min ' : 'mins';
|
||||
}
|
||||
|
||||
public get secondsDisplay(): string {
|
||||
return this.formatDisplay(this.seconds);
|
||||
}
|
||||
|
||||
public get secondsText(): string {
|
||||
return this.seconds === 1 ? 'sec ' : 'secs';
|
||||
}
|
||||
|
||||
private clock;
|
||||
|
||||
constructor() {
|
||||
if (this.liveDates.length == 0) return;
|
||||
this.liveDates.sort((a, b) => {
|
||||
if (a < b) return -1;
|
||||
if (a === b) return 0;
|
||||
return 1;
|
||||
});
|
||||
this.updateClock();
|
||||
this.startClock();
|
||||
}
|
||||
|
||||
private resetToZero() {
|
||||
this.days = 0;
|
||||
this.hours = 0;
|
||||
this.minutes = 0;
|
||||
this.seconds = 0;
|
||||
}
|
||||
|
||||
private updateClock() {
|
||||
this.showCounter = true;
|
||||
var now = DateTime.local();
|
||||
var nearestPast = this.getNearestPastDate(now);
|
||||
if (nearestPast) {
|
||||
var pastDiff = now.diff(nearestPast, ['minutes']);
|
||||
if (pastDiff.minutes < 45) {
|
||||
this.showButton = true;
|
||||
this.dateDisplay = nearestPast.toLocaleString(DateTime.DATETIME_HUGE);
|
||||
this.dateDisplaySmall = nearestPast.toLocaleString(DateTime.DATETIME_MED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.showButton = false;
|
||||
var nearestFuture = this.getNearestFutureDate(now);
|
||||
if (!nearestFuture) {
|
||||
this.stopClock();
|
||||
this.resetToZero();
|
||||
this.showCounter = false;
|
||||
this.dateDisplay = '';
|
||||
this.dateDisplaySmall = '';
|
||||
return;
|
||||
}
|
||||
var minDiff = nearestFuture.diff(now, ['minutes']);
|
||||
if (minDiff.minutes <= 10) {
|
||||
this.showButton = true;
|
||||
}
|
||||
|
||||
var hourDiff = nearestFuture.diff(now, ['hours']);
|
||||
if (hourDiff.hours >= 48) {
|
||||
this.showCounter = false;
|
||||
this.dateDisplay = '';
|
||||
this.dateDisplaySmall = '';
|
||||
return;
|
||||
}
|
||||
|
||||
var diff = nearestFuture.diff(now, ['days', 'hours', 'minutes', 'seconds']);
|
||||
this.days = diff.days;
|
||||
this.hours = diff.hours;
|
||||
this.minutes = diff.minutes;
|
||||
this.seconds = Math.floor(diff.seconds);
|
||||
this.dateDisplay = nearestFuture.toLocaleString(DateTime.DATETIME_HUGE);
|
||||
this.dateDisplaySmall = nearestFuture.toLocaleString(DateTime.DATETIME_MED)
|
||||
}
|
||||
|
||||
private startClock() {
|
||||
this.clock = setInterval(this.updateClock.bind(this), 1000);
|
||||
}
|
||||
|
||||
private stopClock() {
|
||||
clearInterval(this.clock);
|
||||
}
|
||||
|
||||
private getNearestPastDate(now: DateTime): DateTime {
|
||||
if (this.liveDates.length === 0) return null;
|
||||
var now = now || DateTime.local();
|
||||
var nearestIndex = this.liveDates.findIndex(d => d > now);
|
||||
if (nearestIndex === 0) return null;
|
||||
if (nearestIndex === -1) return this.liveDates[this.liveDates.length - 1];
|
||||
return this.liveDates[nearestIndex - 1];
|
||||
}
|
||||
|
||||
private getNearestFutureDate(now: DateTime): DateTime {
|
||||
if (this.liveDates.length === 0) return null;
|
||||
var now = now || DateTime.local();
|
||||
var nearest = this.liveDates.find(d => d > now);
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private formatDisplay(val: number): string {
|
||||
if (val <= 0) {
|
||||
return '00';
|
||||
}
|
||||
if (val < 10) {
|
||||
return '0' + val.toString();
|
||||
}
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,117 @@ img.full {
|
|||
bottom: 10%;
|
||||
}
|
||||
|
||||
#live-stream-container {
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
right: 0;
|
||||
bottom: 20%;
|
||||
}
|
||||
|
||||
#title > .live {
|
||||
display: inline-block;
|
||||
background-color: red;
|
||||
color: white;
|
||||
padding: 0px 7px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#live-date {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#live-stream-container > #title {
|
||||
font-size: 25pt;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
font-family: Franklin Gothic Medium,Franklin Gothic,ITC Franklin Gothic,Arial,sans-serif;
|
||||
}
|
||||
|
||||
#countdown-container {
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
margin-top: 7px;
|
||||
display: inline-block;
|
||||
font-size: 30pt;
|
||||
font-weight: bold;
|
||||
border-radius: 10px;
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
padding: 15px 20px;
|
||||
-webkit-box-shadow: inset 0px 0px 20px -15px rgba(0,0,0,1);
|
||||
-moz-box-shadow: inset 0px 0px 20px -15px rgba(0,0,0,1);
|
||||
box-shadow: inset 0px 0px 20px -15px rgba(0,0,0,1);
|
||||
border: 1px solid green;
|
||||
font-family: Consolas,monaco,monospace;
|
||||
}
|
||||
|
||||
/*Button*/
|
||||
#countdown-container.show-button {
|
||||
background-color:#2dabf9;
|
||||
color:#ffffff;
|
||||
text-shadow:0px 1px 0px #263666;
|
||||
}
|
||||
#countdown-container.show-button:hover {
|
||||
background-color:#0688fa;
|
||||
}
|
||||
#countdown-container.show-button:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
/*End Button*/
|
||||
|
||||
#countdown-container .text {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.opacity-zero {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#live-button {
|
||||
position: absolute;
|
||||
font-size: 25pt;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media(max-width:900px){
|
||||
#live-stream-container > #title {
|
||||
font-size: 15pt;
|
||||
}
|
||||
#countdown-container {
|
||||
font-size: 20pt;
|
||||
}
|
||||
}
|
||||
|
||||
.display-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media(max-width:600px){
|
||||
#live-stream-container {
|
||||
left: 5%;
|
||||
right: 5%;
|
||||
bottom: 5%
|
||||
}
|
||||
#live-stream-container > #title {
|
||||
font-size: 11pt;
|
||||
}
|
||||
#countdown-container {
|
||||
font-size: 13pt;
|
||||
}
|
||||
.display-none-sm {
|
||||
display: none;
|
||||
}
|
||||
.display-sm {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#action-button {
|
||||
font-size: 16pt;
|
||||
max-width: 100%;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,35 @@
|
|||
<img id="background-image" src="assets/images/home-images/tiny/sunset_b.jpg" alt="background image" width="100%">
|
||||
|
||||
<div id="filler">
|
||||
<div id="live-stream-container" *ngIf="countdown.showCounter">
|
||||
<div id="title">
|
||||
<span class="live">LIVE</span>
|
||||
<span *ngIf="!countdown.showButton"> SERMON STARTS IN</span>
|
||||
<span *ngIf="countdown.showButton"> SERMON STREAMING NOW</span>
|
||||
</div>
|
||||
<a id="countdown-container" routerLink="/live" [class.show-button]="countdown.showButton" >
|
||||
<div id="live-button" [class.opacity-zero]="!countdown.showButton">
|
||||
<i ofbicon class="mr-10" >live_tv</i>
|
||||
Click to Watch Now
|
||||
</div>
|
||||
<div [class.opacity-zero]="countdown.showButton">
|
||||
<span class="number">{{countdown.daysDisplay}}</span>
|
||||
<span class="text"> {{countdown.daysText}}</span>
|
||||
<span class="number"> {{countdown.hoursDisplay}}</span>
|
||||
<span class="text"> {{countdown.hoursText}}</span>
|
||||
<span class="number"> {{countdown.minutesDisplay}}</span>
|
||||
<span class="text"> {{countdown.minutesText}}</span>
|
||||
<span class="number"> {{countdown.secondsDisplay}}</span>
|
||||
<span class="text"> {{countdown.secondsText}}</span>
|
||||
</div>
|
||||
</a>
|
||||
<div id="live-date" class="display-none-sm">
|
||||
{{countdown.dateDisplay}}
|
||||
</div>
|
||||
<div id="live-date" class="display-sm">
|
||||
{{countdown.dateDisplaySmall}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="call-to-action-container" *ngIf="showCallToAction">
|
||||
<button id="action-button" routerLink="/camp" mat-raised-button color="accent"><i ofbicon class="mr-10">info_outline</i>2019 Youth Camp</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Component, HostListener } from '@angular/core';
|
|||
import { MatDialog, MatDialogConfig } from '@angular/material';
|
||||
import { VideoPopupComponent } from '../popups/video-popup/video-popup.component';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { Countdown } from './countdown';
|
||||
|
||||
@Component({
|
||||
selector: 'home-component',
|
||||
|
|
@ -47,9 +48,13 @@ export class HomeComponent {
|
|||
return true;
|
||||
}
|
||||
|
||||
public countdown: Countdown;
|
||||
public liveDates: Date[] = [];
|
||||
|
||||
constructor(private dialog: MatDialog)
|
||||
{
|
||||
|
||||
this.countdown = new Countdown();
|
||||
this.liveDates = [];
|
||||
}
|
||||
|
||||
@HostListener('window:scroll', ['$event'])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
.video-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 56.25%;
|
||||
}
|
||||
.video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<secondary-page-component [hideSideBarOnMobile]="true" >
|
||||
<div mainContent class="mapWrapper">
|
||||
<div class="video-container">
|
||||
<iframe class="video" src="https://www.youtube-nocookie.com/embed/dAxhAF9ZzbA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div sideBar ofbFadeInOnScroll>
|
||||
|
||||
</div>
|
||||
</secondary-page-component>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LiveStreamComponent } from './live-stream.component';
|
||||
|
||||
describe('LiveStreamComponent', () => {
|
||||
let component: LiveStreamComponent;
|
||||
let fixture: ComponentFixture<LiveStreamComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ LiveStreamComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LiveStreamComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { BibleVerseService } from './../../services/bible-verse.service';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'live-stream-component',
|
||||
templateUrl: './live-stream.component.html',
|
||||
styleUrls: ['./live-stream.component.css']
|
||||
})
|
||||
export class LiveStreamComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 48 KiB |
Loading…
Reference in New Issue