Verified Commit 61cbafc1 authored by Chocobozzz's avatar Chocobozzz
Browse files

Improve channel card custom markup

parent 9105634f
...@@ -52,19 +52,10 @@ ...@@ -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 { ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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)
......
<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 @@ ...@@ -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;
} }
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' ...@@ -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 @@ ...@@ -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 = { ...@@ -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 = { ...@@ -43,4 +46,5 @@ export type ContainerMarkupData = {
width?: string width?: string
title?: string title?: string
description?: string description?: string
layout?: 'row' | 'column'
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment