mirror of
				https://github.com/Chocobozzz/PeerTube.git
				synced 2025-02-25 18:55:32 -06:00 
			
		
		
		
	Improve channel card custom markup
This commit is contained in:
		@@ -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'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user