--- /dev/null
+<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>
--- /dev/null
+@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;
+ }
+}
--- /dev/null
+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)
+ }
+}
</div>
- <div class="video-info-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>
+ <my-video-description [video]="video"></my-video-description>
<div class="video-attributes mb-3">
<div class="video-attribute">
@use '_bootstrap-variables';
@use '_miniature' as *;
-$player-factor: math.div(16, 9);
-$video-info-margin-left: 44px;
-
@function getPlayerHeight ($width) {
- @return calc(#{$width} / #{$player-factor});
+ @return calc(#{$width} / #{$video-watch-player-factor});
}
@function getPlayerWidth ($height) {
- @return calc(#{$height} * #{$player-factor});
+ @return calc(#{$height} * #{$video-watch-player-factor});
}
@mixin playlist-below-player {
}
}
- .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 {
- @include margin-left($video-info-margin-left);
+ @include margin-left($video-watch-info-margin-left);
}
.video-attributes .video-attribute {
margin-top: 10px;
}
}
-
- .video-info-description {
- font-size: 14px !important;
- }
}
}
AuthService,
AuthUser,
ConfirmService,
- MarkdownService,
MetaService,
Notifier,
PeerTubeSocket,
private serverService: ServerService,
private restExtractor: RestExtractor,
private notifier: Notifier,
- private markdownService: MarkdownService,
private zone: NgZone,
private redirectService: RedirectService,
private videoCaptionService: VideoCaptionService,
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 () {
this.videoDownloadModal.show(this.video, this.videoCaptions)
}
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 () {
this.supportModal.show()
}
})
}
- 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 () {
this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes`
}
this.buildPlayer(urlOptions)
.catch(err => console.error('Cannot build the player', err))
- this.setVideoDescriptionHTML()
this.setVideoLikesBarTooltipText()
this.setOpenGraphTags()
import { RecommendationsModule } from './recommendations/recommendations.module'
import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive'
import { VideoAvatarChannelComponent } from './video-avatar-channel.component'
+import { VideoDescriptionComponent } from './video-description.component'
import { VideoRateComponent } from './video-rate.component'
import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
import { VideoWatchRoutingModule } from './video-watch-routing.module'
VideoWatchComponent,
VideoWatchPlaylistComponent,
VideoRateComponent,
+ VideoDescriptionComponent,
VideoCommentsComponent,
VideoCommentAddComponent,
$focus-box-shadow-form: 0 0 0 .2rem;
+$video-watch-player-factor: math.div(16, 9);
+$video-watch-info-margin-left: 44px;
+
/*** map theme ***/
// pass variables into a sass map,