Improve channel card custom markup
This commit is contained in:
parent
9105634f16
commit
61cbafc1f8
|
@ -52,19 +52,10 @@
|
||||||
|
|
||||||
.actor-counters {
|
.actor-counters {
|
||||||
@include margin-left(15px);
|
@include margin-left(15px);
|
||||||
|
@include actor-counters;
|
||||||
|
|
||||||
grid-row: 1;
|
grid-row: 1;
|
||||||
grid-column: 3;
|
grid-column: 3;
|
||||||
color: pvar(--greyForegroundColor);
|
|
||||||
font-size: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actor-counters > *:not(:last-child)::after {
|
|
||||||
content: '•';
|
|
||||||
margin: 0 10px;
|
|
||||||
color: pvar(--mainColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-html {
|
.description-html {
|
||||||
|
@ -94,6 +85,7 @@ my-subscribe-button {
|
||||||
|
|
||||||
my-video-miniature {
|
my-video-miniature {
|
||||||
@include margin-right(15px);
|
@include margin-right(15px);
|
||||||
|
|
||||||
min-width: $video-thumbnail-medium-width;
|
min-width: $video-thumbnail-medium-width;
|
||||||
max-width: $video-thumbnail-medium-width;
|
max-width: $video-thumbnail-medium-width;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,15 @@
|
||||||
h4 {
|
h4 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layout-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,13 @@ export class CustomMarkupService {
|
||||||
const data = el.dataset as ChannelMiniatureMarkupData
|
const data = el.dataset as ChannelMiniatureMarkupData
|
||||||
const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent)
|
const component = this.dynamicElementService.createElement(ChannelMiniatureMarkupComponent)
|
||||||
|
|
||||||
this.dynamicElementService.setModel(component, { name: data.name })
|
const model = {
|
||||||
|
name: data.name,
|
||||||
|
displayLatestVideo: this.buildBoolean(data.displayLatestVideo) ?? true,
|
||||||
|
displayDescription: this.buildBoolean(data.displayDescription) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dynamicElementService.setModel(component, model)
|
||||||
|
|
||||||
return component
|
return component
|
||||||
}
|
}
|
||||||
|
@ -178,7 +184,12 @@ export class CustomMarkupService {
|
||||||
const data = el.dataset as ContainerMarkupData
|
const data = el.dataset as ContainerMarkupData
|
||||||
|
|
||||||
const root = document.createElement('div')
|
const root = document.createElement('div')
|
||||||
root.classList.add('peertube-container')
|
|
||||||
|
const layoutClass = data.layout
|
||||||
|
? 'layout-' + data.layout
|
||||||
|
: 'layout-row'
|
||||||
|
|
||||||
|
root.classList.add('peertube-container', layoutClass)
|
||||||
|
|
||||||
if (data.width) {
|
if (data.width) {
|
||||||
root.setAttribute('width', data.width)
|
root.setAttribute('width', data.width)
|
||||||
|
|
|
@ -1,8 +1,28 @@
|
||||||
<div *ngIf="channel" class="channel">
|
<div *ngIf="channel" class="channel">
|
||||||
<my-actor-avatar [channel]="channel" size="34"></my-actor-avatar>
|
|
||||||
|
|
||||||
<div class="display-name">{{ channel.displayName }}</div>
|
<div class="channel-avatar-row">
|
||||||
<div class="username">{{ channel.name }}</div>
|
<my-actor-avatar [channel]="channel" [internalHref]="getVideoChannelLink()" i18n-title title="See this video channel"></my-actor-avatar>
|
||||||
|
|
||||||
<div class="description">{{ channel.description }}</div>
|
<h6>
|
||||||
|
<a [routerLink]="getVideoChannelLink()" i18n-title title="See this video channel">
|
||||||
|
{{ channel.displayName }}
|
||||||
|
</a>
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<div class="actor-counters">
|
||||||
|
<div class="followers" i18n>{channel.followersCount, plural, =1 {1 subscriber} other {{{ channel.followersCount }} subscribers}}</div>
|
||||||
|
|
||||||
|
<span class="videos-count" *ngIf="totalVideos !== undefined" i18n>
|
||||||
|
{totalVideos, plural, =1 {1 videos} other {{{ totalVideos }} videos}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="displayDescription" class="description-html" [innerHTML]="descriptionHTML"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="video" *ngIf="video && displayLatestVideo">
|
||||||
|
<div i18n class="video-label">Latest published video</div>
|
||||||
|
|
||||||
|
<my-video-miniature-markup [uuid]="video.uuid" [onlyDisplayTitle]="true"></my-video-miniature-markup>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,8 +2,58 @@
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
|
|
||||||
.channel {
|
.channel {
|
||||||
border-radius: 15px;
|
padding: 20px;
|
||||||
padding: 10px;
|
background-color: pvar(--channelBackgroundColor);
|
||||||
width: min-content;
|
margin: 0 30px 30px 0;
|
||||||
border: 1px solid pvar(--mainColor);
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-avatar-row,
|
||||||
|
.video {
|
||||||
|
width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-avatar-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-template-rows: auto auto 1fr;
|
||||||
|
column-gap: 15px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
@include peertube-word-wrap;
|
||||||
|
|
||||||
|
color: pvar(--mainForegroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
my-actor-avatar {
|
||||||
|
@include actor-avatar-size(75px);
|
||||||
|
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1 / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
grid-column: 2;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-counters {
|
||||||
|
@include actor-counters(5px);
|
||||||
|
|
||||||
|
font-size: 13px;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-html {
|
||||||
|
@include fade-text(30px, pvar(--channelBackgroundColor));
|
||||||
|
|
||||||
|
max-height: 60px;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: pvar(--greyForegroundColor);
|
||||||
|
margin: 15px 0 5px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import { map, switchMap } from 'rxjs/operators'
|
||||||
import { Component, Input, OnInit } from '@angular/core'
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
import { VideoChannel, VideoChannelService } from '../../shared-main'
|
import { MarkdownService, UserService } from '@app/core'
|
||||||
|
import { Video, VideoSortField } from '@shared/models/videos'
|
||||||
|
import { VideoChannel, VideoChannelService, VideoService } from '../../shared-main'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Markup component that creates a channel miniature only
|
* Markup component that creates a channel miniature only
|
||||||
|
@ -12,15 +15,55 @@ import { VideoChannel, VideoChannelService } from '../../shared-main'
|
||||||
})
|
})
|
||||||
export class ChannelMiniatureMarkupComponent implements OnInit {
|
export class ChannelMiniatureMarkupComponent implements OnInit {
|
||||||
@Input() name: string
|
@Input() name: string
|
||||||
|
@Input() displayLatestVideo: boolean
|
||||||
|
@Input() displayDescription: boolean
|
||||||
|
|
||||||
channel: VideoChannel
|
channel: VideoChannel
|
||||||
|
descriptionHTML: string
|
||||||
|
totalVideos: number
|
||||||
|
video: Video
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private channelService: VideoChannelService
|
private markdown: MarkdownService,
|
||||||
|
private channelService: VideoChannelService,
|
||||||
|
private videoService: VideoService,
|
||||||
|
private userService: UserService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.channelService.getVideoChannel(this.name)
|
this.channelService.getVideoChannel(this.name)
|
||||||
.subscribe(channel => this.channel = channel)
|
.subscribe(async channel => {
|
||||||
|
this.channel = channel
|
||||||
|
|
||||||
|
this.descriptionHTML = await this.markdown.textMarkdownToHTML(channel.description)
|
||||||
|
|
||||||
|
this.loadVideos()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideoChannelLink () {
|
||||||
|
return [ '/c', this.channel.nameWithHost ]
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadVideos () {
|
||||||
|
const videoOptions = {
|
||||||
|
videoChannel: this.channel,
|
||||||
|
videoPagination: {
|
||||||
|
currentPage: 1,
|
||||||
|
itemsPerPage: 1
|
||||||
|
},
|
||||||
|
sort: '-publishedAt' as VideoSortField,
|
||||||
|
count: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
|
.pipe(
|
||||||
|
map(user => user.nsfwPolicy),
|
||||||
|
switchMap(nsfwPolicy => this.videoService.getVideoChannelVideos({ ...videoOptions, nsfwPolicy }))
|
||||||
|
)
|
||||||
|
.subscribe(({ total, data }) => {
|
||||||
|
this.totalVideos = total
|
||||||
|
this.video = data[0]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,6 +569,19 @@
|
||||||
min-height: $size;
|
min-height: $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin actor-counters ($separator-margin: 10px) {
|
||||||
|
color: pvar(--greyForegroundColor);
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> *:not(:last-child)::after {
|
||||||
|
content: '•';
|
||||||
|
margin: 0 $separator-margin;
|
||||||
|
color: pvar(--mainColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@mixin chevron ($size, $border-width) {
|
@mixin chevron ($size, $border-width) {
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: $border-width $border-width 0 0;
|
border-width: $border-width $border-width 0 0;
|
||||||
|
|
|
@ -18,6 +18,9 @@ export type PlaylistMiniatureMarkupData = {
|
||||||
export type ChannelMiniatureMarkupData = {
|
export type ChannelMiniatureMarkupData = {
|
||||||
// Channel name (username)
|
// Channel name (username)
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
|
displayLatestVideo?: string // boolean
|
||||||
|
displayDescription?: string // boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VideosListMarkupData = {
|
export type VideosListMarkupData = {
|
||||||
|
@ -43,4 +46,5 @@ export type ContainerMarkupData = {
|
||||||
width?: string
|
width?: string
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
|
layout?: 'row' | 'column'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue