Create a dedicated component for video description

This commit is contained in:
Chocobozzz 2021-06-29 17:15:05 +02:00
parent 6ea59f4154
commit b0c43e36db
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 161 additions and 117 deletions

View File

@ -0,0 +1,19 @@
<div class="video-info-description">
<div
class="video-info-description-html"
[innerHTML]="videoHTMLDescription"
(timestampClicked)="onTimestampClicked($event)"
timestampRouteTransformer
></div>
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
<ng-container i18n>Show more</ng-container>
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-down"></span>
<my-small-loader class="description-loading" [loading]="descriptionLoading"></my-small-loader>
</div>
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
<ng-container i18n>Show less</ng-container>
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-up"></span>
</div>
</div>

View File

@ -0,0 +1,46 @@
@use '_variables' as *;
@use '_mixins' as *;
.video-info-description {
@include margin-left($video-watch-info-margin-left);
@include margin-right(0);
margin-top: 20px;
margin-bottom: 20px;
font-size: 15px;
.video-info-description-html {
@include peertube-word-wrap;
::ng-deep a {
text-decoration: none;
}
}
.glyphicon,
.description-loading {
@include margin-left(3px);
}
.description-loading {
display: inline-block;
}
.video-info-description-more {
cursor: pointer;
font-weight: $font-semibold;
color: pvar(--greyForegroundColor);
font-size: 14px;
.glyphicon {
position: relative;
top: 2px;
}
}
}
@media screen and (max-width: 450px) {
.video-info-description {
font-size: 14px !important;
}
}

View File

@ -0,0 +1,87 @@
import { Component, EventEmitter, Inject, Input, LOCALE_ID, OnChanges, Output } from '@angular/core'
import { MarkdownService, Notifier } from '@app/core'
import { VideoDetails, VideoService } from '@app/shared/shared-main'
@Component({
selector: 'my-video-description',
templateUrl: './video-description.component.html',
styleUrls: [ './video-description.component.scss' ]
})
export class VideoDescriptionComponent implements OnChanges {
@Input() video: VideoDetails
@Output() timestampClicked = new EventEmitter<number>()
descriptionLoading = false
completeDescriptionShown = false
completeVideoDescription: string
shortVideoDescription: string
videoHTMLDescription = ''
constructor (
private videoService: VideoService,
private notifier: Notifier,
private markdownService: MarkdownService,
@Inject(LOCALE_ID) private localeId: string
) { }
ngOnChanges () {
this.descriptionLoading = false
this.completeDescriptionShown = false
this.completeVideoDescription = undefined
this.setVideoDescriptionHTML()
}
showMoreDescription () {
if (this.completeVideoDescription === undefined) {
return this.loadCompleteDescription()
}
this.updateVideoDescription(this.completeVideoDescription)
this.completeDescriptionShown = true
}
showLessDescription () {
this.updateVideoDescription(this.shortVideoDescription)
this.completeDescriptionShown = false
}
loadCompleteDescription () {
this.descriptionLoading = true
this.videoService.loadCompleteDescription(this.video.descriptionPath)
.subscribe(
description => {
this.completeDescriptionShown = true
this.descriptionLoading = false
this.shortVideoDescription = this.video.description
this.completeVideoDescription = description
this.updateVideoDescription(this.completeVideoDescription)
},
error => {
this.descriptionLoading = false
this.notifier.error(error.message)
}
)
}
onTimestampClicked (timestamp: number) {
this.timestampClicked.emit(timestamp)
}
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()
.catch(err => console.error(err))
}
private async setVideoDescriptionHTML () {
const html = await this.markdownService.textMarkdownToHTML(this.video.description)
this.videoHTMLDescription = this.markdownService.processVideoTimestamps(html)
}
}

View File

@ -186,25 +186,7 @@
</div> </div>
<div class="video-info-description"> <my-video-description [video]="video"></my-video-description>
<div
class="video-info-description-html"
[innerHTML]="videoHTMLDescription"
(timestampClicked)="handleTimestampClicked($event)"
timestampRouteTransformer
></div>
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
<ng-container i18n>Show more</ng-container>
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-down"></span>
<my-small-loader class="description-loading" [loading]="descriptionLoading"></my-small-loader>
</div>
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
<ng-container i18n>Show less</ng-container>
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-up"></span>
</div>
</div>
<div class="video-attributes mb-3"> <div class="video-attributes mb-3">
<div class="video-attribute"> <div class="video-attribute">

View File

@ -4,15 +4,12 @@
@use '_bootstrap-variables'; @use '_bootstrap-variables';
@use '_miniature' as *; @use '_miniature' as *;
$player-factor: math.div(16, 9);
$video-info-margin-left: 44px;
@function getPlayerHeight ($width) { @function getPlayerHeight ($width) {
@return calc(#{$width} / #{$player-factor}); @return calc(#{$width} / #{$video-watch-player-factor});
} }
@function getPlayerWidth ($height) { @function getPlayerWidth ($height) {
@return calc(#{$height} * #{$player-factor}); @return calc(#{$height} * #{$video-watch-player-factor});
} }
@mixin playlist-below-player { @mixin playlist-below-player {
@ -316,46 +313,8 @@ $video-info-margin-left: 44px;
} }
} }
.video-info-description {
@include margin-left($video-info-margin-left);
@include margin-right(0);
margin-top: 20px;
margin-bottom: 20px;
font-size: 15px;
.video-info-description-html {
@include peertube-word-wrap;
::ng-deep a {
text-decoration: none;
}
}
.glyphicon,
.description-loading {
@include margin-left(3px);
}
.description-loading {
display: inline-block;
}
.video-info-description-more {
cursor: pointer;
font-weight: $font-semibold;
color: pvar(--greyForegroundColor);
font-size: 14px;
.glyphicon {
position: relative;
top: 2px;
}
}
}
.video-attributes { .video-attributes {
@include margin-left($video-info-margin-left); @include margin-left($video-watch-info-margin-left);
} }
.video-attributes .video-attribute { .video-attributes .video-attribute {
@ -555,10 +514,6 @@ my-video-comments {
margin-top: 10px; margin-top: 10px;
} }
} }
.video-info-description {
font-size: 14px !important;
}
} }
} }

View File

@ -8,7 +8,6 @@ import {
AuthService, AuthService,
AuthUser, AuthUser,
ConfirmService, ConfirmService,
MarkdownService,
MetaService, MetaService,
Notifier, Notifier,
PeerTubeSocket, PeerTubeSocket,
@ -139,7 +138,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private serverService: ServerService, private serverService: ServerService,
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private notifier: Notifier, private notifier: Notifier,
private markdownService: MarkdownService,
private zone: NgZone, private zone: NgZone,
private redirectService: RedirectService, private redirectService: RedirectService,
private videoCaptionService: VideoCaptionService, private videoCaptionService: VideoCaptionService,
@ -228,20 +226,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.hotkeysService.remove(this.hotkeys) this.hotkeysService.remove(this.hotkeys)
} }
showMoreDescription () {
if (this.completeVideoDescription === undefined) {
return this.loadCompleteDescription()
}
this.updateVideoDescription(this.completeVideoDescription)
this.completeDescriptionShown = true
}
showLessDescription () {
this.updateVideoDescription(this.shortVideoDescription)
this.completeDescriptionShown = false
}
showDownloadModal () { showDownloadModal () {
this.videoDownloadModal.show(this.video, this.videoCaptions) this.videoDownloadModal.show(this.video, this.videoCaptions)
} }
@ -250,28 +234,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled && !this.video.isLive return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled && !this.video.isLive
} }
loadCompleteDescription () {
this.descriptionLoading = true
this.videoService.loadCompleteDescription(this.video.descriptionPath)
.subscribe(
description => {
this.completeDescriptionShown = true
this.descriptionLoading = false
this.shortVideoDescription = this.video.description
this.completeVideoDescription = description
this.updateVideoDescription(this.completeVideoDescription)
},
error => {
this.descriptionLoading = false
this.notifier.error(error.message)
}
)
}
showSupportModal () { showSupportModal () {
this.supportModal.show() this.supportModal.show()
} }
@ -492,17 +454,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}) })
} }
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()
.catch(err => console.error(err))
}
private async setVideoDescriptionHTML () {
const html = await this.markdownService.textMarkdownToHTML(this.video.description)
this.videoHTMLDescription = this.markdownService.processVideoTimestamps(html)
}
private setVideoLikesBarTooltipText () { private setVideoLikesBarTooltipText () {
this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes` this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes`
} }
@ -552,7 +503,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.buildPlayer(urlOptions) this.buildPlayer(urlOptions)
.catch(err => console.error('Cannot build the player', err)) .catch(err => console.error('Cannot build the player', err))
this.setVideoDescriptionHTML()
this.setVideoLikesBarTooltipText() this.setVideoLikesBarTooltipText()
this.setOpenGraphTags() this.setOpenGraphTags()

View File

@ -19,6 +19,7 @@ import { PlayerStylesComponent } from './player-styles.component'
import { RecommendationsModule } from './recommendations/recommendations.module' import { RecommendationsModule } from './recommendations/recommendations.module'
import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive' import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive'
import { VideoAvatarChannelComponent } from './video-avatar-channel.component' import { VideoAvatarChannelComponent } from './video-avatar-channel.component'
import { VideoDescriptionComponent } from './video-description.component'
import { VideoRateComponent } from './video-rate.component' import { VideoRateComponent } from './video-rate.component'
import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
import { VideoWatchRoutingModule } from './video-watch-routing.module' import { VideoWatchRoutingModule } from './video-watch-routing.module'
@ -47,6 +48,7 @@ import { VideoWatchComponent } from './video-watch.component'
VideoWatchComponent, VideoWatchComponent,
VideoWatchPlaylistComponent, VideoWatchPlaylistComponent,
VideoRateComponent, VideoRateComponent,
VideoDescriptionComponent,
VideoCommentsComponent, VideoCommentsComponent,
VideoCommentAddComponent, VideoCommentAddComponent,

View File

@ -95,6 +95,9 @@ $activated-action-button-color: #000;
$focus-box-shadow-form: 0 0 0 .2rem; $focus-box-shadow-form: 0 0 0 .2rem;
$video-watch-player-factor: math.div(16, 9);
$video-watch-info-margin-left: 44px;
/*** map theme ***/ /*** map theme ***/
// pass variables into a sass map, // pass variables into a sass map,