diff options
author | Chocobozzz <chocobozzz@cpy.re> | 2021-05-27 15:59:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-27 15:59:55 +0200 |
commit | 2539932e16129992a2c0889b4ff527c265a8e2c7 (patch) | |
tree | fb5048e63e02a2485eb96d27455f43e4b22e8ae0 /client/src/app/shared/shared-custom-markup | |
parent | eb34ec30e0b57286fc6f85160490d2e973a3b0b1 (diff) | |
download | PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.gz PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.zst PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.zip |
Instance homepage support (#4007)
* Prepare homepage parsers
* Add ability to update instance hompage
* Add ability to set homepage as landing page
* Add homepage preview in admin
* Dynamically update left menu for homepage
* Inject home content in homepage
* Add videos list and channel miniature custom markup
* Remove unused elements in markup service
Diffstat (limited to 'client/src/app/shared/shared-custom-markup')
17 files changed, 496 insertions, 0 deletions
diff --git a/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.html b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.html new file mode 100644 index 000000000..da81006b9 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.html | |||
@@ -0,0 +1,8 @@ | |||
1 | <div *ngIf="channel" class="channel"> | ||
2 | <my-actor-avatar [channel]="channel" size="34"></my-actor-avatar> | ||
3 | |||
4 | <div class="display-name">{{ channel.displayName }}</div> | ||
5 | <div class="username">{{ channel.name }}</div> | ||
6 | |||
7 | <div class="description">{{ channel.description }}</div> | ||
8 | </div> | ||
diff --git a/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.scss b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.scss new file mode 100644 index 000000000..85018afe2 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.scss | |||
@@ -0,0 +1,9 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .channel { | ||
5 | border-radius: 15px; | ||
6 | padding: 10px; | ||
7 | width: min-content; | ||
8 | border: 1px solid pvar(--mainColor); | ||
9 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.ts new file mode 100644 index 000000000..97bb5567e --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/channel-miniature-markup.component.ts | |||
@@ -0,0 +1,26 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { VideoChannel, VideoChannelService } from '../shared-main' | ||
3 | |||
4 | /* | ||
5 | * Markup component that creates a channel miniature only | ||
6 | */ | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-channel-miniature-markup', | ||
10 | templateUrl: 'channel-miniature-markup.component.html', | ||
11 | styleUrls: [ 'channel-miniature-markup.component.scss' ] | ||
12 | }) | ||
13 | export class ChannelMiniatureMarkupComponent implements OnInit { | ||
14 | @Input() name: string | ||
15 | |||
16 | channel: VideoChannel | ||
17 | |||
18 | constructor ( | ||
19 | private channelService: VideoChannelService | ||
20 | ) { } | ||
21 | |||
22 | ngOnInit () { | ||
23 | this.channelService.getVideoChannel(this.name) | ||
24 | .subscribe(channel => this.channel = channel) | ||
25 | } | ||
26 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts new file mode 100644 index 000000000..ffaf15710 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts | |||
@@ -0,0 +1,136 @@ | |||
1 | import { ComponentRef, Injectable } from '@angular/core' | ||
2 | import { MarkdownService } from '@app/core' | ||
3 | import { | ||
4 | ChannelMiniatureMarkupData, | ||
5 | EmbedMarkupData, | ||
6 | PlaylistMiniatureMarkupData, | ||
7 | VideoMiniatureMarkupData, | ||
8 | VideosListMarkupData | ||
9 | } from '@shared/models' | ||
10 | import { ChannelMiniatureMarkupComponent } from './channel-miniature-markup.component' | ||
11 | import { DynamicElementService } from './dynamic-element.service' | ||
12 | import { EmbedMarkupComponent } from './embed-markup.component' | ||
13 | import { PlaylistMiniatureMarkupComponent } from './playlist-miniature-markup.component' | ||
14 | import { VideoMiniatureMarkupComponent } from './video-miniature-markup.component' | ||
15 | import { VideosListMarkupComponent } from './videos-list-markup.component' | ||
16 | |||
17 | type BuilderFunction = (el: HTMLElement) => ComponentRef<any> | ||
18 | |||
19 | @Injectable() | ||
20 | export class CustomMarkupService { | ||
21 | private builders: { [ selector: string ]: BuilderFunction } = { | ||
22 | 'peertube-video-embed': el => this.embedBuilder(el, 'video'), | ||
23 | 'peertube-playlist-embed': el => this.embedBuilder(el, 'playlist'), | ||
24 | 'peertube-video-miniature': el => this.videoMiniatureBuilder(el), | ||
25 | 'peertube-playlist-miniature': el => this.playlistMiniatureBuilder(el), | ||
26 | 'peertube-channel-miniature': el => this.channelMiniatureBuilder(el), | ||
27 | 'peertube-videos-list': el => this.videosListBuilder(el) | ||
28 | } | ||
29 | |||
30 | constructor ( | ||
31 | private dynamicElementService: DynamicElementService, | ||
32 | private markdown: MarkdownService | ||
33 | ) { } | ||
34 | |||
35 | async buildElement (text: string) { | ||
36 | const html = await this.markdown.customPageMarkdownToHTML(text, this.getSupportedTags()) | ||
37 | |||
38 | const rootElement = document.createElement('div') | ||
39 | rootElement.innerHTML = html | ||
40 | |||
41 | for (const selector of this.getSupportedTags()) { | ||
42 | rootElement.querySelectorAll(selector) | ||
43 | .forEach((e: HTMLElement) => { | ||
44 | try { | ||
45 | const component = this.execBuilder(selector, e) | ||
46 | |||
47 | this.dynamicElementService.injectElement(e, component) | ||
48 | } catch (err) { | ||
49 | console.error('Cannot inject component %s.', selector, err) | ||
50 | } | ||
51 | }) | ||
52 | } | ||
53 | |||
54 | return rootElement | ||
55 | } | ||
56 | |||
57 | private getSupportedTags () { | ||
58 | return Object.keys(this.builders) | ||
59 | } | ||
60 | |||
61 | private execBuilder (selector: string, el: HTMLElement) { | ||
62 | return this.builders[selector](el) | ||
63 | } | ||
64 | |||
65 | private embedBuilder (el: HTMLElement, type: 'video' | 'playlist') { | ||
66 | const data = el.dataset as EmbedMarkupData | ||
67 | const component = this.dynamicElementService.createElement(EmbedMarkupComponent) | ||
68 | |||
69 | this.dynamicElementService.setModel(component, { uuid: data.uuid, type }) | ||
70 | |||
71 | return component | ||
72 | } | ||
73 | |||
74 | private videoMiniatureBuilder (el: HTMLElement) { | ||
75 | const data = el.dataset as VideoMiniatureMarkupData | ||
76 | const component = this.dynamicElementService.createElement(VideoMiniatureMarkupComponent) | ||
77 | |||
78 | this.dynamicElementService.setModel(component, { uuid: data.uuid }) | ||
79 | |||
80 | return component | ||
81 | } | ||
82 | |||
83 | private playlistMiniatureBuilder (el: HTMLElement) { | ||
84 | const data = el.dataset as PlaylistMiniatureMarkupData | ||
85 | const component = this.dynamicElementService.createElement(PlaylistMiniatureMarkupComponent) | ||
86 | |||
87 | this.dynamicElementService.setModel(component, { uuid: data.uuid }) | ||
88 | |||
89 | return component | ||
90 | } | ||
91 | |||
92 | private channelMiniatureBuilder (el: HTMLElement) { | ||
93 | const data = el.dataset as ChannelMiniatureMarkupData | ||
94 | const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent) | ||
95 | |||
96 | this.dynamicElementService.setModel(component, { name: data.name }) | ||
97 | |||
98 | return component | ||
99 | } | ||
100 | |||
101 | private videosListBuilder (el: HTMLElement) { | ||
102 | const data = el.dataset as VideosListMarkupData | ||
103 | const component = this.dynamicElementService.createElement(VideosListMarkupComponent) | ||
104 | |||
105 | const model = { | ||
106 | title: data.title, | ||
107 | description: data.description, | ||
108 | sort: data.sort, | ||
109 | categoryOneOf: this.buildArrayNumber(data.categoryOneOf), | ||
110 | languageOneOf: this.buildArrayString(data.languageOneOf), | ||
111 | count: this.buildNumber(data.count) || 10 | ||
112 | } | ||
113 | |||
114 | this.dynamicElementService.setModel(component, model) | ||
115 | |||
116 | return component | ||
117 | } | ||
118 | |||
119 | private buildNumber (value: string) { | ||
120 | if (!value) return undefined | ||
121 | |||
122 | return parseInt(value, 10) | ||
123 | } | ||
124 | |||
125 | private buildArrayNumber (value: string) { | ||
126 | if (!value) return undefined | ||
127 | |||
128 | return value.split(',').map(v => parseInt(v, 10)) | ||
129 | } | ||
130 | |||
131 | private buildArrayString (value: string) { | ||
132 | if (!value) return undefined | ||
133 | |||
134 | return value.split(',') | ||
135 | } | ||
136 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts b/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts new file mode 100644 index 000000000..e967e30ac --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts | |||
@@ -0,0 +1,57 @@ | |||
1 | import { | ||
2 | ApplicationRef, | ||
3 | ComponentFactoryResolver, | ||
4 | ComponentRef, | ||
5 | EmbeddedViewRef, | ||
6 | Injectable, | ||
7 | Injector, | ||
8 | OnChanges, | ||
9 | SimpleChange, | ||
10 | SimpleChanges, | ||
11 | Type | ||
12 | } from '@angular/core' | ||
13 | |||
14 | @Injectable() | ||
15 | export class DynamicElementService { | ||
16 | |||
17 | constructor ( | ||
18 | private injector: Injector, | ||
19 | private applicationRef: ApplicationRef, | ||
20 | private componentFactoryResolver: ComponentFactoryResolver | ||
21 | ) { } | ||
22 | |||
23 | createElement <T> (ofComponent: Type<T>) { | ||
24 | const div = document.createElement('div') | ||
25 | |||
26 | const component = this.componentFactoryResolver.resolveComponentFactory(ofComponent) | ||
27 | .create(this.injector, [], div) | ||
28 | |||
29 | return component | ||
30 | } | ||
31 | |||
32 | injectElement <T> (wrapper: HTMLElement, componentRef: ComponentRef<T>) { | ||
33 | const hostView = componentRef.hostView as EmbeddedViewRef<any> | ||
34 | |||
35 | this.applicationRef.attachView(hostView) | ||
36 | wrapper.appendChild(hostView.rootNodes[0]) | ||
37 | } | ||
38 | |||
39 | setModel <T> (componentRef: ComponentRef<T>, attributes: Partial<T>) { | ||
40 | const changes: SimpleChanges = {} | ||
41 | |||
42 | for (const key of Object.keys(attributes)) { | ||
43 | const previousValue = componentRef.instance[key] | ||
44 | const newValue = attributes[key] | ||
45 | |||
46 | componentRef.instance[key] = newValue | ||
47 | changes[key] = new SimpleChange(previousValue, newValue, previousValue === undefined) | ||
48 | } | ||
49 | |||
50 | const component = componentRef.instance | ||
51 | if (typeof (component as unknown as OnChanges).ngOnChanges === 'function') { | ||
52 | (component as unknown as OnChanges).ngOnChanges(changes) | ||
53 | } | ||
54 | |||
55 | componentRef.changeDetectorRef.detectChanges() | ||
56 | } | ||
57 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/embed-markup.component.ts b/client/src/app/shared/shared-custom-markup/embed-markup.component.ts new file mode 100644 index 000000000..a854d89f6 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/embed-markup.component.ts | |||
@@ -0,0 +1,22 @@ | |||
1 | import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | ||
2 | import { environment } from 'src/environments/environment' | ||
3 | import { Component, ElementRef, Input, OnInit } from '@angular/core' | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-embed-markup', | ||
7 | template: '' | ||
8 | }) | ||
9 | export class EmbedMarkupComponent implements OnInit { | ||
10 | @Input() uuid: string | ||
11 | @Input() type: 'video' | 'playlist' = 'video' | ||
12 | |||
13 | constructor (private el: ElementRef) { } | ||
14 | |||
15 | ngOnInit () { | ||
16 | const link = this.type === 'video' | ||
17 | ? buildVideoLink({ baseUrl: `${environment.originServerUrl}/videos/embed/${this.uuid}` }) | ||
18 | : buildPlaylistLink({ baseUrl: `${environment.originServerUrl}/video-playlists/embed/${this.uuid}` }) | ||
19 | |||
20 | this.el.nativeElement.innerHTML = buildVideoOrPlaylistEmbed(link, this.uuid) | ||
21 | } | ||
22 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/index.ts b/client/src/app/shared/shared-custom-markup/index.ts new file mode 100644 index 000000000..14bde3ea9 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './custom-markup.service' | ||
2 | export * from './dynamic-element.service' | ||
3 | export * from './shared-custom-markup.module' | ||
diff --git a/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.html b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.html new file mode 100644 index 000000000..4e1d1a13f --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.html | |||
@@ -0,0 +1,2 @@ | |||
1 | <my-video-playlist-miniature *ngIf="playlist" [playlist]="playlist"> | ||
2 | </my-video-playlist-miniature> | ||
diff --git a/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.scss b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.scss new file mode 100644 index 000000000..281cef726 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | my-video-playlist-miniature { | ||
5 | display: inline-block; | ||
6 | width: $video-thumbnail-width; | ||
7 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.ts new file mode 100644 index 000000000..7aee450f1 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/playlist-miniature-markup.component.ts | |||
@@ -0,0 +1,38 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { MiniatureDisplayOptions } from '../shared-video-miniature' | ||
3 | import { VideoPlaylist, VideoPlaylistService } from '../shared-video-playlist' | ||
4 | |||
5 | /* | ||
6 | * Markup component that creates a playlist miniature only | ||
7 | */ | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-playlist-miniature-markup', | ||
11 | templateUrl: 'playlist-miniature-markup.component.html', | ||
12 | styleUrls: [ 'playlist-miniature-markup.component.scss' ] | ||
13 | }) | ||
14 | export class PlaylistMiniatureMarkupComponent implements OnInit { | ||
15 | @Input() uuid: string | ||
16 | |||
17 | playlist: VideoPlaylist | ||
18 | |||
19 | displayOptions: MiniatureDisplayOptions = { | ||
20 | date: true, | ||
21 | views: true, | ||
22 | by: true, | ||
23 | avatar: false, | ||
24 | privacyLabel: false, | ||
25 | privacyText: false, | ||
26 | state: false, | ||
27 | blacklistInfo: false | ||
28 | } | ||
29 | |||
30 | constructor ( | ||
31 | private playlistService: VideoPlaylistService | ||
32 | ) { } | ||
33 | |||
34 | ngOnInit () { | ||
35 | this.playlistService.getVideoPlaylist(this.uuid) | ||
36 | .subscribe(playlist => this.playlist = playlist) | ||
37 | } | ||
38 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/shared-custom-markup.module.ts b/client/src/app/shared/shared-custom-markup/shared-custom-markup.module.ts new file mode 100644 index 000000000..4bbb71588 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/shared-custom-markup.module.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | |||
2 | import { CommonModule } from '@angular/common' | ||
3 | import { NgModule } from '@angular/core' | ||
4 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' | ||
5 | import { SharedGlobalIconModule } from '../shared-icons' | ||
6 | import { SharedMainModule } from '../shared-main' | ||
7 | import { SharedVideoMiniatureModule } from '../shared-video-miniature' | ||
8 | import { SharedVideoPlaylistModule } from '../shared-video-playlist' | ||
9 | import { ChannelMiniatureMarkupComponent } from './channel-miniature-markup.component' | ||
10 | import { CustomMarkupService } from './custom-markup.service' | ||
11 | import { DynamicElementService } from './dynamic-element.service' | ||
12 | import { EmbedMarkupComponent } from './embed-markup.component' | ||
13 | import { PlaylistMiniatureMarkupComponent } from './playlist-miniature-markup.component' | ||
14 | import { VideoMiniatureMarkupComponent } from './video-miniature-markup.component' | ||
15 | import { VideosListMarkupComponent } from './videos-list-markup.component' | ||
16 | |||
17 | @NgModule({ | ||
18 | imports: [ | ||
19 | CommonModule, | ||
20 | |||
21 | SharedMainModule, | ||
22 | SharedGlobalIconModule, | ||
23 | SharedVideoMiniatureModule, | ||
24 | SharedVideoPlaylistModule, | ||
25 | SharedActorImageModule | ||
26 | ], | ||
27 | |||
28 | declarations: [ | ||
29 | VideoMiniatureMarkupComponent, | ||
30 | PlaylistMiniatureMarkupComponent, | ||
31 | ChannelMiniatureMarkupComponent, | ||
32 | EmbedMarkupComponent, | ||
33 | VideosListMarkupComponent | ||
34 | ], | ||
35 | |||
36 | exports: [ | ||
37 | VideoMiniatureMarkupComponent, | ||
38 | PlaylistMiniatureMarkupComponent, | ||
39 | ChannelMiniatureMarkupComponent, | ||
40 | VideosListMarkupComponent, | ||
41 | EmbedMarkupComponent | ||
42 | ], | ||
43 | |||
44 | providers: [ | ||
45 | CustomMarkupService, | ||
46 | DynamicElementService | ||
47 | ] | ||
48 | }) | ||
49 | export class SharedCustomMarkupModule { } | ||
diff --git a/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.html b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.html new file mode 100644 index 000000000..9b4930b6d --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.html | |||
@@ -0,0 +1,6 @@ | |||
1 | <my-video-miniature | ||
2 | *ngIf="video" | ||
3 | [video]="video" [user]="getUser()" [displayAsRow]="false" | ||
4 | [displayVideoActions]="false" [displayOptions]="displayOptions" | ||
5 | > | ||
6 | </my-video-miniature> | ||
diff --git a/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.scss b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.scss new file mode 100644 index 000000000..81e265f29 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | my-video-miniature { | ||
5 | display: inline-block; | ||
6 | width: $video-thumbnail-width; | ||
7 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.ts new file mode 100644 index 000000000..79add0c3b --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/video-miniature-markup.component.ts | |||
@@ -0,0 +1,44 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { AuthService } from '@app/core' | ||
3 | import { Video, VideoService } from '../shared-main' | ||
4 | import { MiniatureDisplayOptions } from '../shared-video-miniature' | ||
5 | |||
6 | /* | ||
7 | * Markup component that creates a video miniature only | ||
8 | */ | ||
9 | |||
10 | @Component({ | ||
11 | selector: 'my-video-miniature-markup', | ||
12 | templateUrl: 'video-miniature-markup.component.html', | ||
13 | styleUrls: [ 'video-miniature-markup.component.scss' ] | ||
14 | }) | ||
15 | export class VideoMiniatureMarkupComponent implements OnInit { | ||
16 | @Input() uuid: string | ||
17 | |||
18 | video: Video | ||
19 | |||
20 | displayOptions: MiniatureDisplayOptions = { | ||
21 | date: true, | ||
22 | views: true, | ||
23 | by: true, | ||
24 | avatar: false, | ||
25 | privacyLabel: false, | ||
26 | privacyText: false, | ||
27 | state: false, | ||
28 | blacklistInfo: false | ||
29 | } | ||
30 | |||
31 | constructor ( | ||
32 | private auth: AuthService, | ||
33 | private videoService: VideoService | ||
34 | ) { } | ||
35 | |||
36 | getUser () { | ||
37 | return this.auth.getUser() | ||
38 | } | ||
39 | |||
40 | ngOnInit () { | ||
41 | this.videoService.getVideo({ videoId: this.uuid }) | ||
42 | .subscribe(video => this.video = video) | ||
43 | } | ||
44 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/videos-list-markup.component.html b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.html new file mode 100644 index 000000000..501f35e04 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.html | |||
@@ -0,0 +1,13 @@ | |||
1 | <div class="root"> | ||
2 | <h4 *ngIf="title">{{ title }}</h4> | ||
3 | <div *ngIf="description" class="description">{{ description }}</div> | ||
4 | |||
5 | <div class="videos"> | ||
6 | <my-video-miniature | ||
7 | *ngFor="let video of videos" | ||
8 | [video]="video" [user]="getUser()" [displayAsRow]="false" | ||
9 | [displayVideoActions]="false" [displayOptions]="displayOptions" | ||
10 | > | ||
11 | </my-video-miniature> | ||
12 | </div> | ||
13 | </div> | ||
diff --git a/client/src/app/shared/shared-custom-markup/videos-list-markup.component.scss b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.scss new file mode 100644 index 000000000..dcd931090 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.scss | |||
@@ -0,0 +1,9 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | my-video-miniature { | ||
5 | margin-right: 15px; | ||
6 | display: inline-block; | ||
7 | min-width: $video-thumbnail-width; | ||
8 | max-width: $video-thumbnail-width; | ||
9 | } | ||
diff --git a/client/src/app/shared/shared-custom-markup/videos-list-markup.component.ts b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.ts new file mode 100644 index 000000000..cc25d0a51 --- /dev/null +++ b/client/src/app/shared/shared-custom-markup/videos-list-markup.component.ts | |||
@@ -0,0 +1,60 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { AuthService } from '@app/core' | ||
3 | import { VideoSortField } from '@shared/models' | ||
4 | import { Video, VideoService } from '../shared-main' | ||
5 | import { MiniatureDisplayOptions } from '../shared-video-miniature' | ||
6 | |||
7 | /* | ||
8 | * Markup component list videos depending on criterias | ||
9 | */ | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-videos-list-markup', | ||
13 | templateUrl: 'videos-list-markup.component.html', | ||
14 | styleUrls: [ 'videos-list-markup.component.scss' ] | ||
15 | }) | ||
16 | export class VideosListMarkupComponent implements OnInit { | ||
17 | @Input() title: string | ||
18 | @Input() description: string | ||
19 | @Input() sort = '-publishedAt' | ||
20 | @Input() categoryOneOf: number[] | ||
21 | @Input() languageOneOf: string[] | ||
22 | @Input() count = 10 | ||
23 | |||
24 | videos: Video[] | ||
25 | |||
26 | displayOptions: MiniatureDisplayOptions = { | ||
27 | date: true, | ||
28 | views: true, | ||
29 | by: true, | ||
30 | avatar: false, | ||
31 | privacyLabel: false, | ||
32 | privacyText: false, | ||
33 | state: false, | ||
34 | blacklistInfo: false | ||
35 | } | ||
36 | |||
37 | constructor ( | ||
38 | private auth: AuthService, | ||
39 | private videoService: VideoService | ||
40 | ) { } | ||
41 | |||
42 | getUser () { | ||
43 | return this.auth.getUser() | ||
44 | } | ||
45 | |||
46 | ngOnInit () { | ||
47 | const options = { | ||
48 | videoPagination: { | ||
49 | currentPage: 1, | ||
50 | itemsPerPage: this.count | ||
51 | }, | ||
52 | categoryOneOf: this.categoryOneOf, | ||
53 | languageOneOf: this.languageOneOf, | ||
54 | sort: this.sort as VideoSortField | ||
55 | } | ||
56 | |||
57 | this.videoService.getVideos(options) | ||
58 | .subscribe(({ data }) => this.videos = data) | ||
59 | } | ||
60 | } | ||