Channel/account page redesign feedbacks

Fix owner default avatar
Semi bold orange inverted button
Max width account description
Increase account's channels padding
Use owner avatar/display name links
Move "view owner account" link on mobile
Try to always display channel in video miniatures
Add small border radius for channel's avatar
Use main foreground color for the magnifying glass
This commit is contained in:
Chocobozzz 2021-03-31 08:59:52 +02:00 committed by Chocobozzz
parent c8e80d1461
commit 733dbc535d
20 changed files with 63 additions and 41 deletions

View File

@ -22,7 +22,7 @@
<div class="followers" i18n>{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div> <div class="followers" i18n>{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div>
<span class="videos-count" *ngIf="getTotalVideosOf(videoChannel) !== undefined" i18n> <span class="videos-count" *ngIf="getTotalVideosOf(videoChannel) !== undefined" i18n>
{getTotalVideosOf(videoChannel), splural, =1 {1 videos} other {{{ getTotalVideosOf(videoChannel) }} videos}} {getTotalVideosOf(videoChannel), plural, =1 {1 videos} other {{{ getTotalVideosOf(videoChannel) }} videos}}
</span> </span>
</div> </div>

View File

@ -9,7 +9,7 @@
.channel { .channel {
max-width: $max-channels-width; max-width: $max-channels-width;
background-color: pvar(--channelBackgroundColor); background-color: pvar(--channelBackgroundColor);
padding: 15px; padding: 30px;
margin: 30px 0; margin: 30px 0;
@ -120,6 +120,10 @@ my-subscribe-button {
} }
@media screen and (max-width: $mobile-view) { @media screen and (max-width: $mobile-view) {
.channel {
padding: 15px;
}
.channel-avatar-row { .channel-avatar-row {
grid-template-columns: auto auto auto 1fr; grid-template-columns: auto auto auto 1fr;

View File

@ -52,7 +52,7 @@
<div class="created-at" i18n>Account created on {{ account.createdAt | date }}</div> <div class="created-at" i18n>Account created on {{ account.createdAt | date }}</div>
</div> </div>
<div *ngIf="!accountDescriptionExpanded" class="show-more" role="button" <div *ngIf="hasShowMoreDescription()" class="show-more" role="button"
(click)="accountDescriptionExpanded = !accountDescriptionExpanded" (click)="accountDescriptionExpanded = !accountDescriptionExpanded"
title="Show the complete description" i18n-title i18n title="Show the complete description" i18n-title i18n
> >

View File

@ -62,6 +62,8 @@ my-user-moderation-dropdown,
.description { .description {
grid-column: 1 / 3; grid-column: 1 / 3;
max-width: 1000px;
word-break: break-word;
} }
.created-at { .created-at {

View File

@ -147,6 +147,10 @@ export class AccountsComponent implements OnInit, OnDestroy {
return this.videoChannels.length !== 0 return this.videoChannels.length !== 0
} }
hasShowMoreDescription () {
return !this.accountDescriptionExpanded && this.accountDescriptionHTML.length > 100
}
private async onAccount (account: Account) { private async onAccount (account: Account) {
this.accountFollowerTitle = $localize`${account.followersCount} direct account followers` this.accountFollowerTitle = $localize`${account.followersCount} direct account followers`

View File

@ -34,7 +34,6 @@
[miniatureDisplayOptions]="miniatureDisplayOptions" [miniatureDisplayOptions]="miniatureDisplayOptions"
[titlePage]="titlePage" [titlePage]="titlePage"
[getVideosObservableFunction]="getVideosObservableFunction" [getVideosObservableFunction]="getVideosObservableFunction"
[ownerDisplayType]="ownerDisplayType"
[user]="user" [user]="user"
#videosSelection #videosSelection
> >

View File

@ -2,12 +2,12 @@ import { concat, Observable, Subject } from 'rxjs'
import { debounceTime, tap, toArray } from 'rxjs/operators' import { debounceTime, tap, toArray } from 'rxjs/operators'
import { Component, OnInit, ViewChild } from '@angular/core' import { Component, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User, UserService } from '@app/core' import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core'
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' import { LiveStreamInformationComponent } from '@app/shared/shared-video-live'
import { MiniatureDisplayOptions, OwnerDisplayType, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature'
import { VideoSortField } from '@shared/models' import { VideoSortField } from '@shared/models'
import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component' import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component'
@ -36,7 +36,6 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
state: true, state: true,
blacklistInfo: true blacklistInfo: true
} }
ownerDisplayType: OwnerDisplayType = 'videoChannel'
videoActions: DropdownAction<{ video: Video }>[] = [] videoActions: DropdownAction<{ video: Video }>[] = []

View File

@ -17,10 +17,14 @@
<ng-template #ownerTemplate> <ng-template #ownerTemplate>
<div class="owner-block"> <div class="owner-block">
<div class="avatar-row"> <div class="avatar-row">
<a [routerLink]="getAccountUrl()" title="View account" i18n-title>
<img class="account-avatar" [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" /> <img class="account-avatar" [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" />
</a>
<div class="actor-info"> <div class="actor-info">
<h4>{{ videoChannel.ownerAccount.displayName }}</h4> <h4>
<a [routerLink]="getAccountUrl()" title="View account" i18n-title>{{ videoChannel.ownerAccount.displayName }}</a>
</h4>
<div class="actor-handle">@{{ videoChannel.ownerBy }}</div> <div class="actor-handle">@{{ videoChannel.ownerBy }}</div>
</div> </div>
@ -30,11 +34,11 @@
<div class="description-html" [innerHTML]="ownerDescriptionHTML"></div> <div class="description-html" [innerHTML]="ownerDescriptionHTML"></div>
</div> </div>
<a class="view-account short" [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n> <a class="view-account short" [routerLink]="getAccountUrl()" i18n>
View account View account
</a> </a>
<a class="view-account complete" [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n> <a class="view-account complete" [routerLink]="getAccountUrl()" i18n>
View owner account View owner account
</a> </a>
</div> </div>
@ -83,7 +87,7 @@
<div class="created-at" i18n>Channel created on {{ videoChannel.createdAt | date }}</div> <div class="created-at" i18n>Channel created on {{ videoChannel.createdAt | date }}</div>
</div> </div>
<div *ngIf="!channelDescriptionExpanded" class="show-more" role="button" <div *ngIf="hasShowMoreDescription()" class="show-more" role="button"
(click)="channelDescriptionExpanded = !channelDescriptionExpanded" (click)="channelDescriptionExpanded = !channelDescriptionExpanded"
title="Show the complete description" i18n-title i18n title="Show the complete description" i18n-title i18n
> >

View File

@ -42,6 +42,7 @@
.channel-description { .channel-description {
grid-column: 1; grid-column: 1;
word-break: break-word;
} }
.show-more { .show-more {
@ -108,6 +109,10 @@
h4 { h4 {
font-size: 18px; font-size: 18px;
margin: 0; margin: 0;
a {
color: pvar(--mainForegroundColor);
}
} }
.actor-handle { .actor-handle {
@ -118,6 +123,7 @@
.owner-description { .owner-description {
height: 140px; height: 140px;
word-break: break-word;
@include fade-text(120px, pvar(--mainBackgroundColor)); @include fade-text(120px, pvar(--mainBackgroundColor));
} }
@ -217,7 +223,8 @@
} }
.view-account.complete { .view-account.complete {
display: inline-block; display: block;
text-align: right;
margin-top: 10px; margin-top: 10px;
color: pvar(--mainColor); color: pvar(--mainColor);
} }

View File

@ -103,10 +103,18 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
this.notifier.success($localize`Username copied`) this.notifier.success($localize`Username copied`)
} }
hasShowMoreDescription () {
return !this.channelDescriptionExpanded && this.channelDescriptionHTML.length > 100
}
showSupportModal () { showSupportModal () {
this.supportModal.show() this.supportModal.show()
} }
getAccountUrl () {
return [ '/accounts', this.videoChannel.ownerBy ]
}
private loadChannelVideosCount () { private loadChannelVideosCount () {
this.videoService.getVideoChannelVideos({ this.videoService.getVideoChannelVideos({
videoChannel: this.videoChannel, videoChannel: this.videoChannel,

View File

@ -7,7 +7,7 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { UserSubscriptionService } from '@app/shared/shared-user-subscription' import { UserSubscriptionService } from '@app/shared/shared-user-subscription'
import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { FeedFormat, VideoSortField } from '@shared/models' import { FeedFormat, VideoSortField } from '@shared/models'
import { environment } from '../../../environments/environment' import { environment } from '../../../environments/environment'
import { copyToClipboard } from '../../../root-helpers/utils' import { copyToClipboard } from '../../../root-helpers/utils'
@ -20,7 +20,6 @@ import { copyToClipboard } from '../../../root-helpers/utils'
export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy { export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string titlePage: string
sort = '-publishedAt' as VideoSortField sort = '-publishedAt' as VideoSortField
ownerDisplayType: OwnerDisplayType = 'auto'
groupByDate = true groupByDate = true
constructor ( constructor (

View File

@ -26,6 +26,7 @@
top:50%; top:50%;
left:50%; left:50%;
transform: translate(-50%,-50%); transform: translate(-50%,-50%);
border-radius: 5px;
&:not(.channel-avatar) { &:not(.channel-avatar) {
border-radius: 50%; border-radius: 50%;

View File

@ -16,7 +16,7 @@ my-global-icon {
} }
&[iconName=search] { &[iconName=search] {
color: pvar(--mainColor); color: pvar(--mainForegroundColor);
} }
&[iconName=cross] { &[iconName=cross] {

View File

@ -1,4 +1,5 @@
import { VideoChannel as ServerVideoChannel, ViewsPerDate, Account, Avatar } from '@shared/models' import { Account as ServerAccount, Avatar, VideoChannel as ServerVideoChannel, ViewsPerDate } from '@shared/models'
import { Account } from '../account/account.model'
import { Actor } from '../account/actor.model' import { Actor } from '../account/actor.model'
export class VideoChannel extends Actor implements ServerVideoChannel { export class VideoChannel extends Actor implements ServerVideoChannel {
@ -9,7 +10,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
nameWithHost: string nameWithHost: string
nameWithHostForced: string nameWithHostForced: string
ownerAccount?: Account ownerAccount?: ServerAccount
ownerBy?: string ownerBy?: string
ownerAvatarUrl?: string ownerAvatarUrl?: string
@ -46,7 +47,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
if (hash.ownerAccount) { if (hash.ownerAccount) {
this.ownerAccount = hash.ownerAccount this.ownerAccount = hash.ownerAccount
this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host)
this.ownerAvatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this.ownerAccount) this.ownerAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.ownerAccount)
} }
} }

View File

@ -52,8 +52,7 @@
<div class="video-wrapper"> <div class="video-wrapper">
<my-video-miniature <my-video-miniature
[fitWidth]="true" [fitWidth]="true" [video]="video" [user]="userMiniature"
[video]="video" [user]="userMiniature" [ownerDisplayType]="ownerDisplayType"
[displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
(videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
> >

View File

@ -28,8 +28,8 @@ import { isLastMonth, isLastWeek, isThisMonth, isToday, isYesterday } from '@sha
import { ServerConfig, UserRight, VideoFilter, VideoSortField } from '@shared/models' import { ServerConfig, UserRight, VideoFilter, VideoSortField } from '@shared/models'
import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
import { Syndication, Video } from '../shared-main' import { Syndication, Video } from '../shared-main'
import { MiniatureDisplayOptions, OwnerDisplayType } from './video-miniature.component'
import { GenericHeaderComponent, VideoListHeaderComponent } from './video-list-header.component' import { GenericHeaderComponent, VideoListHeaderComponent } from './video-list-header.component'
import { MiniatureDisplayOptions } from './video-miniature.component'
enum GroupDate { enum GroupDate {
UNKNOWN = 0, UNKNOWN = 0,
@ -65,7 +65,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
loadOnInit = true loadOnInit = true
loadUserVideoPreferences = false loadUserVideoPreferences = false
ownerDisplayType: OwnerDisplayType = 'auto'
displayModerationBlock = false displayModerationBlock = false
titleTooltip: string titleTooltip: string
displayVideoActions = true displayVideoActions = true

View File

@ -16,7 +16,7 @@ import { Video } from '../shared-main'
import { VideoPlaylistService } from '../shared-video-playlist' import { VideoPlaylistService } from '../shared-video-playlist'
import { VideoActionsDisplayType } from './video-actions-dropdown.component' import { VideoActionsDisplayType } from './video-actions-dropdown.component'
export type OwnerDisplayType = 'account' | 'videoChannel' | 'auto' export type OwnerDisplayType = 'account' | 'videoChannel'
export type MiniatureDisplayOptions = { export type MiniatureDisplayOptions = {
date?: boolean date?: boolean
views?: boolean views?: boolean
@ -40,7 +40,6 @@ export class VideoMiniatureComponent implements OnInit {
@Input() user: User @Input() user: User
@Input() video: Video @Input() video: Video
@Input() ownerDisplayType: OwnerDisplayType = 'account'
@Input() displayOptions: MiniatureDisplayOptions = { @Input() displayOptions: MiniatureDisplayOptions = {
date: true, date: true,
views: true, views: true,
@ -89,7 +88,7 @@ export class VideoMiniatureComponent implements OnInit {
videoHref: string videoHref: string
videoTarget: string videoTarget: string
private ownerDisplayTypeChosen: 'account' | 'videoChannel' private ownerDisplayType: 'account' | 'videoChannel'
constructor ( constructor (
private screenService: ScreenService, private screenService: ScreenService,
@ -140,11 +139,11 @@ export class VideoMiniatureComponent implements OnInit {
} }
displayOwnerAccount () { displayOwnerAccount () {
return this.ownerDisplayTypeChosen === 'account' return this.ownerDisplayType === 'account'
} }
displayOwnerVideoChannel () { displayOwnerVideoChannel () {
return this.ownerDisplayTypeChosen === 'videoChannel' return this.ownerDisplayType === 'videoChannel'
} }
isUnlistedVideo () { isUnlistedVideo () {
@ -245,21 +244,19 @@ export class VideoMiniatureComponent implements OnInit {
} }
private setUpBy () { private setUpBy () {
if (this.ownerDisplayType === 'account' || this.ownerDisplayType === 'videoChannel') { const accountName = this.video.account.name
this.ownerDisplayTypeChosen = this.ownerDisplayType
return
}
// If the video channel name is an UUID (not really displayable, we changed this behaviour in v1.0.0-beta.12) // If the video channel name is an UUID (not really displayable, we changed this behaviour in v1.0.0-beta.12)
// Or is just a suffix of the account (default created channel) // Or has not been customized (default created channel display name)
// -> Use the account name // -> Use the account name
if ( if (
this.video.channel.name === `${this.video.account.name}_channel` || this.video.channel.displayName === `Default ${accountName} channel` ||
this.video.channel.displayName === `Main ${accountName} channel` ||
this.video.channel.name.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/) this.video.channel.name.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
) { ) {
this.ownerDisplayTypeChosen = 'account' this.ownerDisplayType = 'account'
} else { } else {
this.ownerDisplayTypeChosen = 'videoChannel' this.ownerDisplayType = 'videoChannel'
} }
} }

View File

@ -9,8 +9,7 @@
<my-video-miniature <my-video-miniature
[video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions" [video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions"
[displayVideoActions]="false" [ownerDisplayType]="ownerDisplayType" [displayVideoActions]="false" [user]="user"
[user]="user"
></my-video-miniature> ></my-video-miniature>
<!-- Display only once --> <!-- Display only once -->

View File

@ -17,7 +17,7 @@ import { AuthService, ComponentPagination, LocalStorageService, Notifier, Screen
import { ResultList, VideoSortField } from '@shared/models' import { ResultList, VideoSortField } from '@shared/models'
import { PeerTubeTemplateDirective, Video } from '../shared-main' import { PeerTubeTemplateDirective, Video } from '../shared-main'
import { AbstractVideoList } from './abstract-video-list' import { AbstractVideoList } from './abstract-video-list'
import { MiniatureDisplayOptions, OwnerDisplayType } from './video-miniature.component' import { MiniatureDisplayOptions } from './video-miniature.component'
export type SelectionType = { [ id: number ]: boolean } export type SelectionType = { [ id: number ]: boolean }
@ -31,7 +31,6 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni
@Input() pagination: ComponentPagination @Input() pagination: ComponentPagination
@Input() titlePage: string @Input() titlePage: string
@Input() miniatureDisplayOptions: MiniatureDisplayOptions @Input() miniatureDisplayOptions: MiniatureDisplayOptions
@Input() ownerDisplayType: OwnerDisplayType
@Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>> @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>>

View File

@ -152,7 +152,7 @@
@include button-focus(pvar(--mainColorLightest)); @include button-focus(pvar(--mainColorLightest));
border: 2px solid pvar(--mainColor); border: 2px solid pvar(--mainColor);
font-weight: $font-regular; font-weight: $font-semibold;
&, &:active, &:focus { &, &:active, &:focus {
color: pvar(--mainColor); color: pvar(--mainColor);
@ -551,6 +551,7 @@
height: $size; height: $size;
min-width: $size; min-width: $size;
min-height: $size; min-height: $size;
border-radius: 5px;
} }
@mixin chevron ($size, $border-width) { @mixin chevron ($size, $border-width) {