diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-09 10:31:27 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-09 10:31:27 +0200 |
commit | 61cbafc1f80a33a895b54b15751a42e0d78af231 (patch) | |
tree | 4ecbd18133550053afe0d12441030f8a1c257511 | |
parent | 9105634f16e5dfc66df198f23dbfae77dff2d821 (diff) | |
download | PeerTube-61cbafc1f80a33a895b54b15751a42e0d78af231.tar.gz PeerTube-61cbafc1f80a33a895b54b15751a42e0d78af231.tar.zst PeerTube-61cbafc1f80a33a895b54b15751a42e0d78af231.zip |
Improve channel card custom markup
8 files changed, 166 insertions, 23 deletions
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss index da3751b47..60914ec12 100644 --- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss | |||
@@ -52,19 +52,10 @@ | |||
52 | 52 | ||
53 | .actor-counters { | 53 | .actor-counters { |
54 | @include margin-left(15px); | 54 | @include margin-left(15px); |
55 | @include actor-counters; | ||
55 | 56 | ||
56 | grid-row: 1; | 57 | grid-row: 1; |
57 | grid-column: 3; | 58 | grid-column: 3; |
58 | color: pvar(--greyForegroundColor); | ||
59 | font-size: 16px; | ||
60 | display: flex; | ||
61 | align-items: center; | ||
62 | } | ||
63 | |||
64 | .actor-counters > *:not(:last-child)::after { | ||
65 | content: '•'; | ||
66 | margin: 0 10px; | ||
67 | color: pvar(--mainColor); | ||
68 | } | 59 | } |
69 | 60 | ||
70 | .description-html { | 61 | .description-html { |
@@ -94,6 +85,7 @@ my-subscribe-button { | |||
94 | 85 | ||
95 | my-video-miniature { | 86 | my-video-miniature { |
96 | @include margin-right(15px); | 87 | @include margin-right(15px); |
88 | |||
97 | min-width: $video-thumbnail-medium-width; | 89 | min-width: $video-thumbnail-medium-width; |
98 | max-width: $video-thumbnail-medium-width; | 90 | max-width: $video-thumbnail-medium-width; |
99 | } | 91 | } |
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss index 044db9536..862da7c18 100644 --- a/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss +++ b/client/src/app/shared/shared-custom-markup/custom-markup-container.component.scss | |||
@@ -6,5 +6,15 @@ | |||
6 | h4 { | 6 | h4 { |
7 | margin-bottom: 0; | 7 | margin-bottom: 0; |
8 | } | 8 | } |
9 | |||
10 | .layout-row { | ||
11 | display: flex; | ||
12 | flex-direction: row; | ||
13 | } | ||
14 | |||
15 | .layout-column { | ||
16 | display: flex; | ||
17 | flex-direction: column; | ||
18 | } | ||
9 | } | 19 | } |
10 | } | 20 | } |
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 index db5f64ee8..aa5dbe643 100644 --- a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts +++ b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts | |||
@@ -122,7 +122,13 @@ export class CustomMarkupService { | |||
122 | const data = el.dataset as ChannelMiniatureMarkupData | 122 | const data = el.dataset as ChannelMiniatureMarkupData |
123 | const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent) | 123 | const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent) |
124 | 124 | ||
125 | this.dynamicElementService.setModel(component, { name: data.name }) | 125 | const model = { |
126 | name: data.name, | ||
127 | displayLatestVideo: this.buildBoolean(data.displayLatestVideo) ?? true, | ||
128 | displayDescription: this.buildBoolean(data.displayDescription) ?? true | ||
129 | } | ||
130 | |||
131 | this.dynamicElementService.setModel(component, model) | ||
126 | 132 | ||
127 | return component | 133 | return component |
128 | } | 134 | } |
@@ -178,7 +184,12 @@ export class CustomMarkupService { | |||
178 | const data = el.dataset as ContainerMarkupData | 184 | const data = el.dataset as ContainerMarkupData |
179 | 185 | ||
180 | const root = document.createElement('div') | 186 | const root = document.createElement('div') |
181 | root.classList.add('peertube-container') | 187 | |
188 | const layoutClass = data.layout | ||
189 | ? 'layout-' + data.layout | ||
190 | : 'layout-row' | ||
191 | |||
192 | root.classList.add('peertube-container', layoutClass) | ||
182 | 193 | ||
183 | if (data.width) { | 194 | if (data.width) { |
184 | root.setAttribute('width', data.width) | 195 | root.setAttribute('width', data.width) |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html index da81006b9..2efc56ab2 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html | |||
@@ -1,8 +1,28 @@ | |||
1 | <div *ngIf="channel" class="channel"> | 1 | <div *ngIf="channel" class="channel"> |
2 | <my-actor-avatar [channel]="channel" size="34"></my-actor-avatar> | ||
3 | 2 | ||
4 | <div class="display-name">{{ channel.displayName }}</div> | 3 | <div class="channel-avatar-row"> |
5 | <div class="username">{{ channel.name }}</div> | 4 | <my-actor-avatar [channel]="channel" [internalHref]="getVideoChannelLink()" i18n-title title="See this video channel"></my-actor-avatar> |
6 | 5 | ||
7 | <div class="description">{{ channel.description }}</div> | 6 | <h6> |
7 | <a [routerLink]="getVideoChannelLink()" i18n-title title="See this video channel"> | ||
8 | {{ channel.displayName }} | ||
9 | </a> | ||
10 | </h6> | ||
11 | |||
12 | <div class="actor-counters"> | ||
13 | <div class="followers" i18n>{channel.followersCount, plural, =1 {1 subscriber} other {{{ channel.followersCount }} subscribers}}</div> | ||
14 | |||
15 | <span class="videos-count" *ngIf="totalVideos !== undefined" i18n> | ||
16 | {totalVideos, plural, =1 {1 videos} other {{{ totalVideos }} videos}} | ||
17 | </span> | ||
18 | </div> | ||
19 | |||
20 | <div *ngIf="displayDescription" class="description-html" [innerHTML]="descriptionHTML"></div> | ||
21 | </div> | ||
22 | |||
23 | <div class="video" *ngIf="video && displayLatestVideo"> | ||
24 | <div i18n class="video-label">Latest published video</div> | ||
25 | |||
26 | <my-video-miniature-markup [uuid]="video.uuid" [onlyDisplayTitle]="true"></my-video-miniature-markup> | ||
27 | </div> | ||
8 | </div> | 28 | </div> |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss index 85018afe2..80c36a58b 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss | |||
@@ -2,8 +2,58 @@ | |||
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .channel { | 4 | .channel { |
5 | border-radius: 15px; | 5 | padding: 20px; |
6 | padding: 10px; | 6 | background-color: pvar(--channelBackgroundColor); |
7 | width: min-content; | 7 | margin: 0 30px 30px 0; |
8 | border: 1px solid pvar(--mainColor); | 8 | width: fit-content; |
9 | } | ||
10 | |||
11 | .channel-avatar-row, | ||
12 | .video { | ||
13 | width: 280px; | ||
14 | } | ||
15 | |||
16 | .channel-avatar-row { | ||
17 | display: grid; | ||
18 | grid-template-columns: auto 1fr; | ||
19 | grid-template-rows: auto auto 1fr; | ||
20 | column-gap: 15px; | ||
21 | |||
22 | a { | ||
23 | @include peertube-word-wrap; | ||
24 | |||
25 | color: pvar(--mainForegroundColor); | ||
26 | } | ||
27 | |||
28 | my-actor-avatar { | ||
29 | @include actor-avatar-size(75px); | ||
30 | |||
31 | grid-column: 1; | ||
32 | grid-row: 1 / 4; | ||
33 | } | ||
34 | |||
35 | h6 { | ||
36 | grid-column: 2; | ||
37 | margin: 0; | ||
38 | } | ||
39 | |||
40 | .actor-counters { | ||
41 | @include actor-counters(5px); | ||
42 | |||
43 | font-size: 13px; | ||
44 | grid-column: 2; | ||
45 | } | ||
46 | |||
47 | .description-html { | ||
48 | @include fade-text(30px, pvar(--channelBackgroundColor)); | ||
49 | |||
50 | max-height: 60px; | ||
51 | grid-column: 2; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | .video-label { | ||
56 | font-size: 12px; | ||
57 | color: pvar(--greyForegroundColor); | ||
58 | margin: 15px 0 5px; | ||
9 | } | 59 | } |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts index 25deafb80..87caec8a5 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts | |||
@@ -1,5 +1,8 @@ | |||
1 | import { map, switchMap } from 'rxjs/operators' | ||
1 | import { Component, Input, OnInit } from '@angular/core' | 2 | import { Component, Input, OnInit } from '@angular/core' |
2 | import { VideoChannel, VideoChannelService } from '../../shared-main' | 3 | import { MarkdownService, UserService } from '@app/core' |
4 | import { Video, VideoSortField } from '@shared/models/videos' | ||
5 | import { VideoChannel, VideoChannelService, VideoService } from '../../shared-main' | ||
3 | 6 | ||
4 | /* | 7 | /* |
5 | * Markup component that creates a channel miniature only | 8 | * Markup component that creates a channel miniature only |
@@ -12,15 +15,55 @@ import { VideoChannel, VideoChannelService } from '../../shared-main' | |||
12 | }) | 15 | }) |
13 | export class ChannelMiniatureMarkupComponent implements OnInit { | 16 | export class ChannelMiniatureMarkupComponent implements OnInit { |
14 | @Input() name: string | 17 | @Input() name: string |
18 | @Input() displayLatestVideo: boolean | ||
19 | @Input() displayDescription: boolean | ||
15 | 20 | ||
16 | channel: VideoChannel | 21 | channel: VideoChannel |
22 | descriptionHTML: string | ||
23 | totalVideos: number | ||
24 | video: Video | ||
17 | 25 | ||
18 | constructor ( | 26 | constructor ( |
19 | private channelService: VideoChannelService | 27 | private markdown: MarkdownService, |
28 | private channelService: VideoChannelService, | ||
29 | private videoService: VideoService, | ||
30 | private userService: UserService | ||
20 | ) { } | 31 | ) { } |
21 | 32 | ||
22 | ngOnInit () { | 33 | ngOnInit () { |
23 | this.channelService.getVideoChannel(this.name) | 34 | this.channelService.getVideoChannel(this.name) |
24 | .subscribe(channel => this.channel = channel) | 35 | .subscribe(async channel => { |
36 | this.channel = channel | ||
37 | |||
38 | this.descriptionHTML = await this.markdown.textMarkdownToHTML(channel.description) | ||
39 | |||
40 | this.loadVideos() | ||
41 | }) | ||
42 | } | ||
43 | |||
44 | getVideoChannelLink () { | ||
45 | return [ '/c', this.channel.nameWithHost ] | ||
46 | } | ||
47 | |||
48 | private loadVideos () { | ||
49 | const videoOptions = { | ||
50 | videoChannel: this.channel, | ||
51 | videoPagination: { | ||
52 | currentPage: 1, | ||
53 | itemsPerPage: 1 | ||
54 | }, | ||
55 | sort: '-publishedAt' as VideoSortField, | ||
56 | count: 1 | ||
57 | } | ||
58 | |||
59 | this.userService.getAnonymousOrLoggedUser() | ||
60 | .pipe( | ||
61 | map(user => user.nsfwPolicy), | ||
62 | switchMap(nsfwPolicy => this.videoService.getVideoChannelVideos({ ...videoOptions, nsfwPolicy })) | ||
63 | ) | ||
64 | .subscribe(({ total, data }) => { | ||
65 | this.totalVideos = total | ||
66 | this.video = data[0] | ||
67 | }) | ||
25 | } | 68 | } |
26 | } | 69 | } |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index 19454cdb2..0822e0ca6 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -569,6 +569,19 @@ | |||
569 | min-height: $size; | 569 | min-height: $size; |
570 | } | 570 | } |
571 | 571 | ||
572 | @mixin actor-counters ($separator-margin: 10px) { | ||
573 | color: pvar(--greyForegroundColor); | ||
574 | font-size: 16px; | ||
575 | display: flex; | ||
576 | align-items: center; | ||
577 | |||
578 | > *:not(:last-child)::after { | ||
579 | content: '•'; | ||
580 | margin: 0 $separator-margin; | ||
581 | color: pvar(--mainColor); | ||
582 | } | ||
583 | } | ||
584 | |||
572 | @mixin chevron ($size, $border-width) { | 585 | @mixin chevron ($size, $border-width) { |
573 | border-style: solid; | 586 | border-style: solid; |
574 | border-width: $border-width $border-width 0 0; | 587 | border-width: $border-width $border-width 0 0; |
diff --git a/shared/models/custom-markup/custom-markup-data.model.ts b/shared/models/custom-markup/custom-markup-data.model.ts index 085ea7cf6..f3c23ec2c 100644 --- a/shared/models/custom-markup/custom-markup-data.model.ts +++ b/shared/models/custom-markup/custom-markup-data.model.ts | |||
@@ -18,6 +18,9 @@ export type PlaylistMiniatureMarkupData = { | |||
18 | export type ChannelMiniatureMarkupData = { | 18 | export type ChannelMiniatureMarkupData = { |
19 | // Channel name (username) | 19 | // Channel name (username) |
20 | name: string | 20 | name: string |
21 | |||
22 | displayLatestVideo?: string // boolean | ||
23 | displayDescription?: string // boolean | ||
21 | } | 24 | } |
22 | 25 | ||
23 | export type VideosListMarkupData = { | 26 | export type VideosListMarkupData = { |
@@ -43,4 +46,5 @@ export type ContainerMarkupData = { | |||
43 | width?: string | 46 | width?: string |
44 | title?: string | 47 | title?: string |
45 | description?: string | 48 | description?: string |
49 | layout?: 'row' | 'column' | ||
46 | } | 50 | } |