diff options
Diffstat (limited to 'client/src')
243 files changed, 2049 insertions, 1607 deletions
diff --git a/client/src/app/+about/about-follows/about-follows.component.html b/client/src/app/+about/about-follows/about-follows.component.html index e9139b503..f81465f88 100644 --- a/client/src/app/+about/about-follows/about-follows.component.html +++ b/client/src/app/+about/about-follows/about-follows.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | {{ following }} | 21 | {{ following }} |
22 | </a> | 22 | </a> |
23 | 23 | ||
24 | <button i18n class="showMore" *ngIf="!loadedAllFollowings && canLoadMoreFollowings()" (click)="loadAllFollowings()">Show full list</button> | 24 | <button i18n class="show-more" *ngIf="!loadedAllFollowings && canLoadMoreFollowings()" (click)="loadAllFollowings()">Show full list</button> |
25 | </div> | 25 | </div> |
26 | 26 | ||
27 | </div> | 27 | </div> |
diff --git a/client/src/app/+about/about-follows/about-follows.component.scss b/client/src/app/+about/about-follows/about-follows.component.scss index a393c9d92..83241e727 100644 --- a/client/src/app/+about/about-follows/about-follows.component.scss +++ b/client/src/app/+about/about-follows/about-follows.component.scss | |||
@@ -17,9 +17,9 @@ a { | |||
17 | justify-content: flex-start; | 17 | justify-content: flex-start; |
18 | } | 18 | } |
19 | 19 | ||
20 | .showMore { | 20 | .show-more { |
21 | @include peertube-button-link; | 21 | @include peertube-button-link; |
22 | @include grey-button; | 22 | @include grey-button; |
23 | 23 | ||
24 | margin-top: 1%; | 24 | margin-top: 1%; |
25 | } | 25 | } |
diff --git a/client/src/app/+about/about-instance/about-instance.component.scss b/client/src/app/+about/about-instance/about-instance.component.scss index 7158a3a79..9886bdfef 100644 --- a/client/src/app/+about/about-instance/about-instance.component.scss +++ b/client/src/app/+about/about-instance/about-instance.component.scss | |||
@@ -63,7 +63,8 @@ | |||
63 | 63 | ||
64 | position: relative; | 64 | position: relative; |
65 | 65 | ||
66 | &:hover, &:active { | 66 | &:hover, |
67 | &:active { | ||
67 | &::after { | 68 | &::after { |
68 | content: '#'; | 69 | content: '#'; |
69 | display: inline-block; | 70 | display: inline-block; |
@@ -71,7 +72,8 @@ | |||
71 | } | 72 | } |
72 | } | 73 | } |
73 | 74 | ||
74 | .middle-title, .section-title { | 75 | .middle-title, |
76 | .section-title { | ||
75 | display: inline-block; | 77 | display: inline-block; |
76 | } | 78 | } |
77 | 79 | ||
diff --git a/client/src/app/+about/about-peertube/about-peertube.component.scss b/client/src/app/+about/about-peertube/about-peertube.component.scss index e67252410..e5d2bc5b8 100644 --- a/client/src/app/+about/about-peertube/about-peertube.component.scss +++ b/client/src/app/+about/about-peertube/about-peertube.component.scss | |||
@@ -45,7 +45,8 @@ | |||
45 | .p2p-privacy, | 45 | .p2p-privacy, |
46 | my-about-peertube-contributors { | 46 | my-about-peertube-contributors { |
47 | ::ng-deep { | 47 | ::ng-deep { |
48 | p, li { | 48 | p, |
49 | li { | ||
49 | font-size: 15px; | 50 | font-size: 15px; |
50 | } | 51 | } |
51 | } | 52 | } |
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html index 19a4b3c9c..922608127 100644 --- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html | |||
@@ -8,9 +8,10 @@ | |||
8 | <div class="channel" *ngFor="let videoChannel of videoChannels"> | 8 | <div class="channel" *ngFor="let videoChannel of videoChannels"> |
9 | 9 | ||
10 | <div class="channel-avatar-row"> | 10 | <div class="channel-avatar-row"> |
11 | <a class="avatar-link" [routerLink]="getVideoChannelLink(videoChannel)" i18n-title title="See this video channel"> | 11 | <my-actor-avatar |
12 | <img [src]="videoChannel.avatarUrl" alt="Avatar" /> | 12 | [channel]="videoChannel" [internalHref]="getVideoChannelLink(videoChannel)" |
13 | </a> | 13 | i18n-title title="See this video channel" |
14 | ></my-actor-avatar> | ||
14 | 15 | ||
15 | <h2> | 16 | <h2> |
16 | <a [routerLink]="getVideoChannelLink(videoChannel)" i18n-title title="See this video channel"> | 17 | <a [routerLink]="getVideoChannelLink(videoChannel)" i18n-title title="See this video channel"> |
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 7e88802f3..f9d097644 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 | |||
@@ -27,14 +27,12 @@ | |||
27 | grid-template-columns: auto auto 1fr; | 27 | grid-template-columns: auto auto 1fr; |
28 | grid-template-rows: auto 1fr; | 28 | grid-template-rows: auto 1fr; |
29 | 29 | ||
30 | .avatar-link { | 30 | my-actor-avatar { |
31 | @include actor-avatar-size(75px); | ||
32 | |||
31 | grid-column: 1; | 33 | grid-column: 1; |
32 | grid-row: 1 / 3; | 34 | grid-row: 1 / 3; |
33 | margin-right: 30px; | 35 | margin-right: 15px; |
34 | } | ||
35 | |||
36 | img { | ||
37 | @include channel-avatar(75px); | ||
38 | } | 36 | } |
39 | 37 | ||
40 | a { | 38 | a { |
@@ -67,13 +65,13 @@ | |||
67 | } | 65 | } |
68 | 66 | ||
69 | .description-html { | 67 | .description-html { |
68 | @include fade-text(30px, pvar(--channelBackgroundColor)); | ||
69 | |||
70 | grid-column: 2 / 4; | 70 | grid-column: 2 / 4; |
71 | grid-row: 2; | 71 | grid-row: 2; |
72 | 72 | ||
73 | max-height: 80px; | 73 | max-height: 80px; |
74 | font-size: 16px; | 74 | font-size: 16px; |
75 | |||
76 | @include fade-text(30px, pvar(--channelBackgroundColor)); | ||
77 | } | 75 | } |
78 | } | 76 | } |
79 | 77 | ||
diff --git a/client/src/app/+accounts/accounts.component.html b/client/src/app/+accounts/accounts.component.html index ea7a317eb..350c77f1e 100644 --- a/client/src/app/+accounts/accounts.component.html +++ b/client/src/app/+accounts/accounts.component.html | |||
@@ -2,7 +2,7 @@ | |||
2 | <div class="account-info"> | 2 | <div class="account-info"> |
3 | 3 | ||
4 | <div class="account-avatar-row"> | 4 | <div class="account-avatar-row"> |
5 | <my-account-avatar [account]="account" size="120"></my-account-avatar> | 5 | <my-actor-avatar class="main-avatar" [account]="account"></my-actor-avatar> |
6 | 6 | ||
7 | <div> | 7 | <div> |
8 | <div class="section-label" i18n>PEERTUBE ACCOUNT</div> | 8 | <div class="section-label" i18n>PEERTUBE ACCOUNT</div> |
diff --git a/client/src/app/+accounts/accounts.component.scss b/client/src/app/+accounts/accounts.component.scss index 56927dea6..2e99fe8a5 100644 --- a/client/src/app/+accounts/accounts.component.scss +++ b/client/src/app/+accounts/accounts.component.scss | |||
@@ -40,7 +40,7 @@ my-user-moderation-dropdown, | |||
40 | } | 40 | } |
41 | 41 | ||
42 | .copy-button { | 42 | .copy-button { |
43 | border: none; | 43 | border: 0; |
44 | } | 44 | } |
45 | 45 | ||
46 | .account-info { | 46 | .account-info { |
@@ -104,9 +104,9 @@ my-user-moderation-dropdown, | |||
104 | } | 104 | } |
105 | 105 | ||
106 | .description:not(.expanded) { | 106 | .description:not(.expanded) { |
107 | max-height: 70px; | ||
108 | |||
109 | @include fade-text(30px, pvar(--submenuBackgroundColor)); | 107 | @include fade-text(30px, pvar(--submenuBackgroundColor)); |
108 | |||
109 | max-height: 70px; | ||
110 | } | 110 | } |
111 | 111 | ||
112 | .show-more { | 112 | .show-more { |
diff --git a/client/src/app/+accounts/accounts.module.ts b/client/src/app/+accounts/accounts.module.ts index 22cdd0642..1bafc5141 100644 --- a/client/src/app/+accounts/accounts.module.ts +++ b/client/src/app/+accounts/accounts.module.ts | |||
@@ -10,7 +10,7 @@ import { AccountVideoChannelsComponent } from './account-video-channels/account- | |||
10 | import { AccountVideosComponent } from './account-videos/account-videos.component' | 10 | import { AccountVideosComponent } from './account-videos/account-videos.component' |
11 | import { AccountsRoutingModule } from './accounts-routing.module' | 11 | import { AccountsRoutingModule } from './accounts-routing.module' |
12 | import { AccountsComponent } from './accounts.component' | 12 | import { AccountsComponent } from './accounts.component' |
13 | import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' | 13 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' |
14 | 14 | ||
15 | @NgModule({ | 15 | @NgModule({ |
16 | imports: [ | 16 | imports: [ |
@@ -22,7 +22,7 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share | |||
22 | SharedModerationModule, | 22 | SharedModerationModule, |
23 | SharedVideoMiniatureModule, | 23 | SharedVideoMiniatureModule, |
24 | SharedGlobalIconModule, | 24 | SharedGlobalIconModule, |
25 | SharedAccountAvatarModule | 25 | SharedActorImageModule |
26 | ], | 26 | ], |
27 | 27 | ||
28 | declarations: [ | 28 | declarations: [ |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 8d1c3eadb..45366f9ec 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -3,12 +3,13 @@ import { SelectButtonModule } from 'primeng/selectbutton' | |||
3 | import { TableModule } from 'primeng/table' | 3 | import { TableModule } from 'primeng/table' |
4 | import { NgModule } from '@angular/core' | 4 | import { NgModule } from '@angular/core' |
5 | import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' | 5 | import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' |
6 | import { SharedActorImageModule } from '@app/shared/shared-actor-image' | 6 | import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' |
7 | import { SharedFormModule } from '@app/shared/shared-forms' | 7 | import { SharedFormModule } from '@app/shared/shared-forms' |
8 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 8 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
9 | import { SharedMainModule } from '@app/shared/shared-main' | 9 | import { SharedMainModule } from '@app/shared/shared-main' |
10 | import { SharedModerationModule } from '@app/shared/shared-moderation' | 10 | import { SharedModerationModule } from '@app/shared/shared-moderation' |
11 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' | 11 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' |
12 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' | ||
12 | import { AdminRoutingModule } from './admin-routing.module' | 13 | import { AdminRoutingModule } from './admin-routing.module' |
13 | import { AdminComponent } from './admin.component' | 14 | import { AdminComponent } from './admin.component' |
14 | import { | 15 | import { |
@@ -39,7 +40,6 @@ import { JobService, LogsComponent, LogsService, SystemComponent } from './syste | |||
39 | import { DebugComponent, DebugService } from './system/debug' | 40 | import { DebugComponent, DebugService } from './system/debug' |
40 | import { JobsComponent } from './system/jobs/jobs.component' | 41 | import { JobsComponent } from './system/jobs/jobs.component' |
41 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users' | 42 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users' |
42 | import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' | ||
43 | 43 | ||
44 | @NgModule({ | 44 | @NgModule({ |
45 | imports: [ | 45 | imports: [ |
@@ -51,8 +51,8 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share | |||
51 | SharedGlobalIconModule, | 51 | SharedGlobalIconModule, |
52 | SharedAbuseListModule, | 52 | SharedAbuseListModule, |
53 | SharedVideoCommentModule, | 53 | SharedVideoCommentModule, |
54 | SharedAccountAvatarModule, | ||
55 | SharedActorImageModule, | 54 | SharedActorImageModule, |
55 | SharedActorImageEditModule, | ||
56 | 56 | ||
57 | TableModule, | 57 | TableModule, |
58 | SelectButtonModule, | 58 | SelectButtonModule, |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss index c12465d45..cc2a98a17 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss | |||
@@ -57,7 +57,7 @@ input[type=submit] { | |||
57 | display: flex; | 57 | display: flex; |
58 | margin-left: auto; | 58 | margin-left: auto; |
59 | 59 | ||
60 | & + .form-error { | 60 | + .form-error { |
61 | display: inline; | 61 | display: inline; |
62 | margin-left: 5px; | 62 | margin-left: 5px; |
63 | } | 63 | } |
@@ -84,7 +84,8 @@ textarea { | |||
84 | } | 84 | } |
85 | 85 | ||
86 | .disabled-checkbox-extra { | 86 | .disabled-checkbox-extra { |
87 | &, ::ng-deep label { | 87 | &, |
88 | ::ng-deep label { | ||
88 | opacity: .5; | 89 | opacity: .5; |
89 | pointer-events: none; | 90 | pointer-events: none; |
90 | } | 91 | } |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-instance-information.component.html b/client/src/app/+admin/config/edit-custom-config/edit-instance-information.component.html index 35b42e742..cbff26e5a 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-instance-information.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-instance-information.component.html | |||
@@ -104,7 +104,7 @@ | |||
104 | <my-help> | 104 | <my-help> |
105 | <ng-template ptTemplate="customHtml"> | 105 | <ng-template ptTemplate="customHtml"> |
106 | <ng-container i18n> | 106 | <ng-container i18n> |
107 | With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video. | 107 | With <strong>Hide</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video. |
108 | </ng-container> | 108 | </ng-container> |
109 | </ng-template> | 109 | </ng-template> |
110 | </my-help> | 110 | </my-help> |
@@ -112,7 +112,7 @@ | |||
112 | <div class="peertube-select-container"> | 112 | <div class="peertube-select-container"> |
113 | <select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy" class="form-control"> | 113 | <select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy" class="form-control"> |
114 | <option i18n value="undefined" disabled>Policy for sensitive videos</option> | 114 | <option i18n value="undefined" disabled>Policy for sensitive videos</option> |
115 | <option i18n value="do_not_list">Do not list</option> | 115 | <option i18n value="do_not_list">Hide</option> |
116 | <option i18n value="blur">Blur thumbnails</option> | 116 | <option i18n value="blur">Blur thumbnails</option> |
117 | <option i18n value="display">Display</option> | 117 | <option i18n value="display">Display</option> |
118 | </select> | 118 | </select> |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 633de9677..c2e9a4df6 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -4,20 +4,16 @@ | |||
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <p-table | 6 | <p-table |
7 | [value]="followers" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 7 | [value]="followers" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
8 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | 8 | [sortField]="sort.field" [sortOrder]="sort.order" (onPage)="onPage($event)" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
9 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
10 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers" |
11 | > | 12 | > |
12 | <ng-template pTemplate="caption"> | 13 | <ng-template pTemplate="caption"> |
13 | <div class="caption"> | 14 | <div class="caption"> |
14 | <div class="ml-auto has-feedback has-clear"> | 15 | <div class="ml-auto"> |
15 | <input | 16 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
16 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
17 | (keyup)="onSearch($event)" | ||
18 | > | ||
19 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
20 | <span class="sr-only" i18n>Clear filters</span> | ||
21 | </div> | 17 | </div> |
22 | </div> | 18 | </div> |
23 | </ng-template> | 19 | </ng-template> |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.scss b/client/src/app/+admin/follows/followers-list/followers-list.component.scss index f2d752eb5..35f38aae0 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.scss +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.scss | |||
@@ -1,19 +1,12 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .caption { | ||
5 | justify-content: flex-end; | ||
6 | |||
7 | input { | ||
8 | @include peertube-input-text(250px); | ||
9 | } | ||
10 | } | ||
11 | |||
12 | a { | 4 | a { |
13 | @include disable-default-a-behaviour; | 5 | @include disable-default-a-behaviour; |
14 | display: inline-block; | 6 | display: inline-block; |
15 | 7 | ||
16 | &, &:hover { | 8 | &, |
9 | &:hover { | ||
17 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
18 | } | 11 | } |
19 | 12 | ||
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts index 904e3c338..4a312f6aa 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts | |||
@@ -59,7 +59,7 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
59 | const handle = follow.follower.name + '@' + follow.follower.host | 59 | const handle = follow.follower.name + '@' + follow.follower.host |
60 | this.notifier.success($localize`${handle} rejected from instance followers`) | 60 | this.notifier.success($localize`${handle} rejected from instance followers`) |
61 | 61 | ||
62 | this.loadData() | 62 | this.reloadData() |
63 | }, | 63 | }, |
64 | 64 | ||
65 | err => { | 65 | err => { |
@@ -80,14 +80,14 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
80 | const handle = follow.follower.name + '@' + follow.follower.host | 80 | const handle = follow.follower.name + '@' + follow.follower.host |
81 | this.notifier.success($localize`${handle} removed from instance followers`) | 81 | this.notifier.success($localize`${handle} removed from instance followers`) |
82 | 82 | ||
83 | this.loadData() | 83 | this.reloadData() |
84 | }, | 84 | }, |
85 | 85 | ||
86 | err => this.notifier.error(err.message) | 86 | err => this.notifier.error(err.message) |
87 | ) | 87 | ) |
88 | } | 88 | } |
89 | 89 | ||
90 | protected loadData () { | 90 | protected reloadData () { |
91 | this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) | 91 | this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) |
92 | .subscribe( | 92 | .subscribe( |
93 | resultList => { | 93 | resultList => { |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index f4e6a60fe..e7c0c9088 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -4,8 +4,9 @@ | |||
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <p-table | 6 | <p-table |
7 | [value]="following" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 7 | [value]="following" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
8 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | 8 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
9 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
10 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts" |
11 | > | 12 | > |
@@ -18,13 +19,8 @@ | |||
18 | </a> | 19 | </a> |
19 | </div> | 20 | </div> |
20 | 21 | ||
21 | <div class="ml-auto has-feedback has-clear"> | 22 | <div class="ml-auto"> |
22 | <input | 23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
23 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
24 | (keyup)="onSearch($event)" | ||
25 | > | ||
26 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
27 | <span class="sr-only" i18n>Clear filters</span> | ||
28 | </div> | 24 | </div> |
29 | </div> | 25 | </div> |
30 | </ng-template> | 26 | </ng-template> |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.scss b/client/src/app/+admin/follows/following-list/following-list.component.scss index b108218b8..9474b0a23 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.scss +++ b/client/src/app/+admin/follows/following-list/following-list.component.scss | |||
@@ -5,7 +5,8 @@ a { | |||
5 | @include disable-default-a-behaviour; | 5 | @include disable-default-a-behaviour; |
6 | display: inline-block; | 6 | display: inline-block; |
7 | 7 | ||
8 | &, &:hover { | 8 | &, |
9 | &:hover { | ||
9 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
10 | } | 11 | } |
11 | 12 | ||
@@ -15,14 +16,6 @@ a { | |||
15 | } | 16 | } |
16 | } | 17 | } |
17 | 18 | ||
18 | .caption { | ||
19 | justify-content: flex-end; | ||
20 | |||
21 | input { | ||
22 | @include peertube-input-text(250px); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | .follow-button { | 19 | .follow-button { |
27 | @include create-button; | 20 | @include create-button; |
28 | } | 21 | } |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts index f34490cc8..b63fe08c0 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.ts +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts | |||
@@ -45,7 +45,7 @@ export class FollowingListComponent extends RestTable implements OnInit { | |||
45 | this.followService.follow(hosts).subscribe( | 45 | this.followService.follow(hosts).subscribe( |
46 | () => { | 46 | () => { |
47 | this.notifier.success($localize`Follow request(s) sent!`) | 47 | this.notifier.success($localize`Follow request(s) sent!`) |
48 | this.loadData() | 48 | this.reloadData() |
49 | }, | 49 | }, |
50 | 50 | ||
51 | err => this.notifier.error(err.message) | 51 | err => this.notifier.error(err.message) |
@@ -62,14 +62,14 @@ export class FollowingListComponent extends RestTable implements OnInit { | |||
62 | this.followService.unfollow(follow).subscribe( | 62 | this.followService.unfollow(follow).subscribe( |
63 | () => { | 63 | () => { |
64 | this.notifier.success($localize`You are not following ${follow.following.host} anymore.`) | 64 | this.notifier.success($localize`You are not following ${follow.following.host} anymore.`) |
65 | this.loadData() | 65 | this.reloadData() |
66 | }, | 66 | }, |
67 | 67 | ||
68 | err => this.notifier.error(err.message) | 68 | err => this.notifier.error(err.message) |
69 | ) | 69 | ) |
70 | } | 70 | } |
71 | 71 | ||
72 | protected loadData () { | 72 | protected reloadData () { |
73 | this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search }) | 73 | this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search }) |
74 | .subscribe( | 74 | .subscribe( |
75 | resultList => { | 75 | resultList => { |
diff --git a/client/src/app/+admin/follows/follows.component.scss b/client/src/app/+admin/follows/follows.component.scss index 33ff17539..1ed0d925f 100644 --- a/client/src/app/+admin/follows/follows.component.scss +++ b/client/src/app/+admin/follows/follows.component.scss | |||
@@ -1,4 +1,4 @@ | |||
1 | @import "mixins"; | 1 | @import 'mixins'; |
2 | 2 | ||
3 | .form-sub-title { | 3 | .form-sub-title { |
4 | flex-grow: 0; | 4 | flex-grow: 0; |
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss index adcf2037e..30b9f2147 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss | |||
@@ -5,7 +5,8 @@ a { | |||
5 | @include disable-default-a-behaviour; | 5 | @include disable-default-a-behaviour; |
6 | display: inline-block; | 6 | display: inline-block; |
7 | 7 | ||
8 | &, &:hover { | 8 | &, |
9 | &:hover { | ||
9 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
10 | } | 11 | } |
11 | 12 | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts index d6fd1a1ab..3cd65dd6e 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts | |||
@@ -78,7 +78,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit | |||
78 | this.pagination.start = 0 | 78 | this.pagination.start = 0 |
79 | this.saveSelectLocalStorage() | 79 | this.saveSelectLocalStorage() |
80 | 80 | ||
81 | this.loadData() | 81 | this.reloadData() |
82 | } | 82 | } |
83 | 83 | ||
84 | getRedundancyStrategy (redundancy: VideoRedundancy) { | 84 | getRedundancyStrategy (redundancy: VideoRedundancy) { |
@@ -145,7 +145,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit | |||
145 | .subscribe( | 145 | .subscribe( |
146 | () => { | 146 | () => { |
147 | this.notifier.success($localize`Video redundancies removed!`) | 147 | this.notifier.success($localize`Video redundancies removed!`) |
148 | this.loadData() | 148 | this.reloadData() |
149 | }, | 149 | }, |
150 | 150 | ||
151 | err => this.notifier.error(err.message) | 151 | err => this.notifier.error(err.message) |
@@ -153,7 +153,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit | |||
153 | 153 | ||
154 | } | 154 | } |
155 | 155 | ||
156 | protected loadData () { | 156 | protected reloadData () { |
157 | const options = { | 157 | const options = { |
158 | pagination: this.pagination, | 158 | pagination: this.pagination, |
159 | sort: this.sort, | 159 | sort: this.sort, |
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html index 9a6c124e1..a9e0931f8 100644 --- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html +++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html | |||
@@ -3,4 +3,4 @@ | |||
3 | <ng-container i18n>Reports</ng-container> | 3 | <ng-container i18n>Reports</ng-container> |
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <my-abuse-list-table viewType="admin" baseRoute="/admin/moderation/abuses/list"></my-abuse-list-table> | 6 | <my-abuse-list-table viewType="admin"></my-abuse-list-table> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index f5cf93adb..e3a3a8320 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -1,18 +1,14 @@ | |||
1 | <p-table | 1 | <p-table |
2 | [value]="blockedAccounts" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 2 | [value]="blockedAccounts" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onPage)="onPage($event)" |
4 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 5 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts" | 6 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts" |
6 | > | 7 | > |
7 | <ng-template pTemplate="caption"> | 8 | <ng-template pTemplate="caption"> |
8 | <div class="caption"> | 9 | <div class="caption"> |
9 | <div class="ml-auto has-feedback has-clear"> | 10 | <div class="ml-auto"> |
10 | <input | 11 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
12 | (keyup)="onSearch($event)" | ||
13 | > | ||
14 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
15 | <span class="sr-only" i18n>Clear filters</span> | ||
16 | </div> | 12 | </div> |
17 | </div> | 13 | </div> |
18 | </ng-template> | 14 | </ng-template> |
@@ -34,7 +30,7 @@ | |||
34 | <td> | 30 | <td> |
35 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 31 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
36 | <div class="chip two-lines"> | 32 | <div class="chip two-lines"> |
37 | <my-account-avatar [account]="accountBlock.blockedAccount"></my-account-avatar> | 33 | <my-actor-avatar [account]="accountBlock.blockedAccount"></my-actor-avatar> |
38 | <div> | 34 | <div> |
39 | {{ accountBlock.blockedAccount.displayName }} | 35 | {{ accountBlock.blockedAccount.displayName }} |
40 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> | 36 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.scss b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.scss index 6028b75ea..1d98e44d9 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.scss +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.scss | |||
@@ -4,4 +4,4 @@ | |||
4 | .unblock-button { | 4 | .unblock-button { |
5 | @include peertube-button; | 5 | @include peertube-button; |
6 | @include grey-button; | 6 | @include grey-button; |
7 | } \ No newline at end of file | 7 | } |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html index c7275de1b..d89c8f244 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html | |||
@@ -4,8 +4,9 @@ | |||
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <p-table | 6 | <p-table |
7 | [value]="blocklist" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 7 | [value]="blocklist" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
8 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | 8 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
9 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
10 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blocked videos" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blocked videos" |
11 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 12 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
@@ -13,25 +14,7 @@ | |||
13 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
14 | <div class="caption"> | 15 | <div class="caption"> |
15 | <div class="ml-auto"> | 16 | <div class="ml-auto"> |
16 | <div class="input-group has-feedback has-clear"> | 17 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
17 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
18 | <div class="input-group-text" ngbDropdownToggle> | ||
19 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
20 | </div> | ||
21 | |||
22 | <div role="menu" ngbDropdownMenu> | ||
23 | <h6 class="dropdown-header" i18n>Advanced block filters</h6> | ||
24 | <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:auto' }" class="dropdown-item" i18n>Automatic blocks</a> | ||
25 | <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:manual' }" class="dropdown-item" i18n>Manual blocks</a> | ||
26 | </div> | ||
27 | </div> | ||
28 | <input | ||
29 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
30 | (keyup)="onSearch($event)" | ||
31 | > | ||
32 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
33 | <span class="sr-only" i18n>Clear filters</span> | ||
34 | </div> | ||
35 | </div> | 18 | </div> |
36 | </div> | 19 | </div> |
37 | </ng-template> | 20 | </ng-template> |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss index b67e33cc1..068aa2aee 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss | |||
@@ -5,23 +5,6 @@ my-global-icon { | |||
5 | height: 24px; | 5 | height: 24px; |
6 | } | 6 | } |
7 | 7 | ||
8 | .input-group { | ||
9 | @include peertube-input-group(300px); | ||
10 | |||
11 | .dropdown-toggle::after { | ||
12 | margin-left: 0; | ||
13 | } | ||
14 | } | ||
15 | |||
16 | .caption { | ||
17 | justify-content: flex-end; | ||
18 | |||
19 | input { | ||
20 | @include peertube-input-text(250px); | ||
21 | flex-grow: 1; | ||
22 | } | ||
23 | } | ||
24 | |||
25 | .badge { | 8 | .badge { |
26 | @include table-badge; | 9 | @include table-badge; |
27 | } | 10 | } |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index d6aca10e7..498d8321a 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts | |||
@@ -2,10 +2,11 @@ import { SortMeta } from 'primeng/api' | |||
2 | import { switchMap } from 'rxjs/operators' | 2 | import { switchMap } from 'rxjs/operators' |
3 | import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | 3 | import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' |
4 | import { environment } from 'src/environments/environment' | 4 | import { environment } from 'src/environments/environment' |
5 | import { AfterViewInit, Component, OnInit } from '@angular/core' | 5 | import { Component, OnInit } from '@angular/core' |
6 | import { DomSanitizer } from '@angular/platform-browser' | 6 | import { DomSanitizer } from '@angular/platform-browser' |
7 | import { ActivatedRoute, Params, Router } from '@angular/router' | 7 | import { ActivatedRoute, Router } from '@angular/router' |
8 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 8 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
9 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | ||
9 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 10 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
10 | import { VideoBlockService } from '@app/shared/shared-moderation' | 11 | import { VideoBlockService } from '@app/shared/shared-moderation' |
11 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' | 12 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' |
@@ -15,7 +16,7 @@ import { VideoBlacklist, VideoBlacklistType } from '@shared/models' | |||
15 | templateUrl: './video-block-list.component.html', | 16 | templateUrl: './video-block-list.component.html', |
16 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-block-list.component.scss' ] | 17 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-block-list.component.scss' ] |
17 | }) | 18 | }) |
18 | export class VideoBlockListComponent extends RestTable implements OnInit, AfterViewInit { | 19 | export class VideoBlockListComponent extends RestTable implements OnInit { |
19 | blocklist: (VideoBlacklist & { reasonHtml?: string, embedHtml?: string })[] = [] | 20 | blocklist: (VideoBlacklist & { reasonHtml?: string, embedHtml?: string })[] = [] |
20 | totalRecords = 0 | 21 | totalRecords = 0 |
21 | sort: SortMeta = { field: 'createdAt', order: -1 } | 22 | sort: SortMeta = { field: 'createdAt', order: -1 } |
@@ -24,6 +25,17 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
24 | 25 | ||
25 | videoBlocklistActions: DropdownAction<VideoBlacklist>[][] = [] | 26 | videoBlocklistActions: DropdownAction<VideoBlacklist>[][] = [] |
26 | 27 | ||
28 | inputFilters: AdvancedInputFilter[] = [ | ||
29 | { | ||
30 | queryParams: { 'search': 'type:auto' }, | ||
31 | label: $localize`Automatic blocks` | ||
32 | }, | ||
33 | { | ||
34 | queryParams: { 'search': 'type:manual' }, | ||
35 | label: $localize`Manual blocks` | ||
36 | } | ||
37 | ] | ||
38 | |||
27 | constructor ( | 39 | constructor ( |
28 | protected route: ActivatedRoute, | 40 | protected route: ActivatedRoute, |
29 | protected router: Router, | 41 | protected router: Router, |
@@ -52,7 +64,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
52 | ).subscribe( | 64 | ).subscribe( |
53 | () => { | 65 | () => { |
54 | this.notifier.success($localize`Video ${videoBlock.video.name} switched to manual block.`) | 66 | this.notifier.success($localize`Video ${videoBlock.video.name} switched to manual block.`) |
55 | this.loadData() | 67 | this.reloadData() |
56 | }, | 68 | }, |
57 | 69 | ||
58 | err => this.notifier.error(err.message) | 70 | err => this.notifier.error(err.message) |
@@ -104,31 +116,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
104 | }) | 116 | }) |
105 | 117 | ||
106 | this.initialize() | 118 | this.initialize() |
107 | this.listenToSearchChange() | ||
108 | } | ||
109 | |||
110 | ngAfterViewInit () { | ||
111 | if (this.search) this.setTableFilter(this.search, false) | ||
112 | } | ||
113 | |||
114 | /* Table filter functions */ | ||
115 | onBlockSearch (event: Event) { | ||
116 | this.onSearch(event) | ||
117 | this.setQueryParams((event.target as HTMLInputElement).value) | ||
118 | } | ||
119 | |||
120 | setQueryParams (search: string) { | ||
121 | const queryParams: Params = {} | ||
122 | if (search) Object.assign(queryParams, { search }) | ||
123 | this.router.navigate([ '/admin/moderation/video-blocks/list' ], { queryParams }) | ||
124 | } | ||
125 | |||
126 | resetTableFilter () { | ||
127 | this.setTableFilter('') | ||
128 | this.setQueryParams('') | ||
129 | this.resetSearch() | ||
130 | } | 119 | } |
131 | /* END Table filter functions */ | ||
132 | 120 | ||
133 | getIdentifier () { | 121 | getIdentifier () { |
134 | return 'VideoBlockListComponent' | 122 | return 'VideoBlockListComponent' |
@@ -151,7 +139,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
151 | this.videoBlocklistService.unblockVideo(entry.video.id).subscribe( | 139 | this.videoBlocklistService.unblockVideo(entry.video.id).subscribe( |
152 | () => { | 140 | () => { |
153 | this.notifier.success($localize`Video ${entry.video.name} unblocked.`) | 141 | this.notifier.success($localize`Video ${entry.video.name} unblocked.`) |
154 | this.loadData() | 142 | this.reloadData() |
155 | }, | 143 | }, |
156 | 144 | ||
157 | err => this.notifier.error(err.message) | 145 | err => this.notifier.error(err.message) |
@@ -169,7 +157,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
169 | ) | 157 | ) |
170 | } | 158 | } |
171 | 159 | ||
172 | protected loadData () { | 160 | protected reloadData () { |
173 | this.videoBlocklistService.listBlocks({ | 161 | this.videoBlocklistService.listBlocks({ |
174 | pagination: this.pagination, | 162 | pagination: this.pagination, |
175 | sort: this.sort, | 163 | sort: this.sort, |
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html index d360c3c51..9d9283536 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html | |||
@@ -8,8 +8,9 @@ | |||
8 | <em i18n>This view also shows comments from muted accounts.</em> | 8 | <em i18n>This view also shows comments from muted accounts.</em> |
9 | 9 | ||
10 | <p-table | 10 | <p-table |
11 | [value]="comments" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 11 | [value]="comments" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
12 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | 12 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" |
13 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
13 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 14 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
14 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" | 15 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" |
15 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 16 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
@@ -26,25 +27,7 @@ | |||
26 | </div> | 27 | </div> |
27 | 28 | ||
28 | <div class="ml-auto"> | 29 | <div class="ml-auto"> |
29 | <div class="input-group has-feedback has-clear"> | 30 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
30 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
31 | <div class="input-group-text" ngbDropdownToggle> | ||
32 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
33 | </div> | ||
34 | |||
35 | <div role="menu" ngbDropdownMenu> | ||
36 | <h6 class="dropdown-header" i18n>Advanced comments filters</h6> | ||
37 | <a [routerLink]="[ '/admin/moderation/video-comments/list' ]" [queryParams]="{ 'search': 'local:true' }" class="dropdown-item" i18n>Local comments</a> | ||
38 | <a [routerLink]="[ '/admin/moderation/video-comments/list' ]" [queryParams]="{ 'search': 'local:false' }" class="dropdown-item" i18n>Remote comments</a> | ||
39 | </div> | ||
40 | </div> | ||
41 | <input | ||
42 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
43 | (keyup)="onSearch($event)" | ||
44 | > | ||
45 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
46 | <span class="sr-only" i18n>Clear filters</span> | ||
47 | </div> | ||
48 | </div> | 31 | </div> |
49 | </div> | 32 | </div> |
50 | </ng-template> | 33 | </ng-template> |
@@ -86,7 +69,7 @@ | |||
86 | <td> | 69 | <td> |
87 | <a [href]="videoComment.account.localUrl" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 70 | <a [href]="videoComment.account.localUrl" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
88 | <div class="chip two-lines"> | 71 | <div class="chip two-lines"> |
89 | <my-account-avatar [account]="videoComment.account"></my-account-avatar> | 72 | <my-actor-avatar [account]="videoComment.account"></my-actor-avatar> |
90 | <div> | 73 | <div> |
91 | {{ videoComment.account.displayName }} | 74 | {{ videoComment.account.displayName }} |
92 | <span>{{ videoComment.by }}</span> | 75 | <span>{{ videoComment.by }}</span> |
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss index c9262da09..a6f931e3b 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss | |||
@@ -11,23 +11,6 @@ my-global-icon { | |||
11 | height: 24px; | 11 | height: 24px; |
12 | } | 12 | } |
13 | 13 | ||
14 | .input-group { | ||
15 | @include peertube-input-group(300px); | ||
16 | |||
17 | .dropdown-toggle::after { | ||
18 | margin-left: 0; | ||
19 | } | ||
20 | } | ||
21 | |||
22 | .caption { | ||
23 | justify-content: flex-end; | ||
24 | |||
25 | input { | ||
26 | @include peertube-input-text(250px); | ||
27 | flex-grow: 1; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | .video { | 14 | .video { |
32 | display: flex; | 15 | display: flex; |
33 | flex-direction: column; | 16 | flex-direction: column; |
@@ -49,7 +32,8 @@ my-global-icon { | |||
49 | max-height: 22px; | 32 | max-height: 22px; |
50 | } | 33 | } |
51 | 34 | ||
52 | div, p { | 35 | div, |
36 | p { | ||
53 | @include ellipsis; | 37 | @include ellipsis; |
54 | } | 38 | } |
55 | 39 | ||
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts index 63493d00d..e2ae993b0 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts | |||
@@ -2,6 +2,7 @@ import { SortMeta } from 'primeng/api' | |||
2 | import { AfterViewInit, Component, OnInit } from '@angular/core' | 2 | import { AfterViewInit, Component, OnInit } from '@angular/core' |
3 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' | 4 | import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' |
5 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | ||
5 | import { DropdownAction } from '@app/shared/shared-main' | 6 | import { DropdownAction } from '@app/shared/shared-main' |
6 | import { BulkService } from '@app/shared/shared-moderation' | 7 | import { BulkService } from '@app/shared/shared-moderation' |
7 | import { VideoCommentAdmin, VideoCommentService } from '@app/shared/shared-video-comment' | 8 | import { VideoCommentAdmin, VideoCommentService } from '@app/shared/shared-video-comment' |
@@ -12,9 +13,7 @@ import { FeedFormat, UserRight } from '@shared/models' | |||
12 | templateUrl: './video-comment-list.component.html', | 13 | templateUrl: './video-comment-list.component.html', |
13 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-comment-list.component.scss' ] | 14 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-comment-list.component.scss' ] |
14 | }) | 15 | }) |
15 | export class VideoCommentListComponent extends RestTable implements OnInit, AfterViewInit { | 16 | export class VideoCommentListComponent extends RestTable implements OnInit { |
16 | baseRoute = '/admin/moderation/video-comments/list' | ||
17 | |||
18 | comments: VideoCommentAdmin[] | 17 | comments: VideoCommentAdmin[] |
19 | totalRecords = 0 | 18 | totalRecords = 0 |
20 | sort: SortMeta = { field: 'createdAt', order: -1 } | 19 | sort: SortMeta = { field: 'createdAt', order: -1 } |
@@ -43,6 +42,17 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
43 | selectedComments: VideoCommentAdmin[] = [] | 42 | selectedComments: VideoCommentAdmin[] = [] |
44 | bulkCommentActions: DropdownAction<VideoCommentAdmin[]>[] = [] | 43 | bulkCommentActions: DropdownAction<VideoCommentAdmin[]>[] = [] |
45 | 44 | ||
45 | inputFilters: AdvancedInputFilter[] = [ | ||
46 | { | ||
47 | queryParams: { 'search': 'local:true' }, | ||
48 | label: $localize`Local comments` | ||
49 | }, | ||
50 | { | ||
51 | queryParams: { 'search': 'local:false' }, | ||
52 | label: $localize`Remote comments` | ||
53 | } | ||
54 | ] | ||
55 | |||
46 | get authUser () { | 56 | get authUser () { |
47 | return this.auth.getUser() | 57 | return this.auth.getUser() |
48 | } | 58 | } |
@@ -79,7 +89,6 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
79 | 89 | ||
80 | ngOnInit () { | 90 | ngOnInit () { |
81 | this.initialize() | 91 | this.initialize() |
82 | this.listenToSearchChange() | ||
83 | 92 | ||
84 | this.bulkCommentActions = [ | 93 | this.bulkCommentActions = [ |
85 | { | 94 | { |
@@ -91,10 +100,6 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
91 | ] | 100 | ] |
92 | } | 101 | } |
93 | 102 | ||
94 | ngAfterViewInit () { | ||
95 | if (this.search) this.setTableFilter(this.search, false) | ||
96 | } | ||
97 | |||
98 | getIdentifier () { | 103 | getIdentifier () { |
99 | return 'VideoCommentListComponent' | 104 | return 'VideoCommentListComponent' |
100 | } | 105 | } |
@@ -107,7 +112,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
107 | return this.selectedComments.length !== 0 | 112 | return this.selectedComments.length !== 0 |
108 | } | 113 | } |
109 | 114 | ||
110 | protected loadData () { | 115 | protected reloadData () { |
111 | this.videoCommentService.getAdminVideoComments({ | 116 | this.videoCommentService.getAdminVideoComments({ |
112 | pagination: this.pagination, | 117 | pagination: this.pagination, |
113 | sort: this.sort, | 118 | sort: this.sort, |
@@ -135,7 +140,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
135 | this.videoCommentService.deleteVideoComments(commentArgs).subscribe( | 140 | this.videoCommentService.deleteVideoComments(commentArgs).subscribe( |
136 | () => { | 141 | () => { |
137 | this.notifier.success($localize`${commentArgs.length} comments deleted.`) | 142 | this.notifier.success($localize`${commentArgs.length} comments deleted.`) |
138 | this.loadData() | 143 | this.reloadData() |
139 | }, | 144 | }, |
140 | 145 | ||
141 | err => this.notifier.error(err.message), | 146 | err => this.notifier.error(err.message), |
@@ -147,7 +152,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
147 | private deleteComment (comment: VideoCommentAdmin) { | 152 | private deleteComment (comment: VideoCommentAdmin) { |
148 | this.videoCommentService.deleteVideoComment(comment.video.id, comment.id) | 153 | this.videoCommentService.deleteVideoComment(comment.video.id, comment.id) |
149 | .subscribe( | 154 | .subscribe( |
150 | () => this.loadData(), | 155 | () => this.reloadData(), |
151 | 156 | ||
152 | err => this.notifier.error(err.message) | 157 | err => this.notifier.error(err.message) |
153 | ) | 158 | ) |
diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html index 9cbec03a1..bc4c2ef88 100644 --- a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html | |||
@@ -23,13 +23,17 @@ | |||
23 | </a> | 23 | </a> |
24 | 24 | ||
25 | <div class="buttons"> | 25 | <div class="buttons"> |
26 | <my-edit-button *ngIf="!isTheme(plugin)" [routerLink]="getShowRouterLink(plugin)" label="Settings" i18n-label></my-edit-button> | 26 | <my-edit-button |
27 | 27 | *ngIf="!isTheme(plugin)" [routerLink]="getShowRouterLink(plugin)" label="Settings" i18n-label | |
28 | <my-button class="update-button" *ngIf="isUpdateAvailable(plugin)" (click)="update(plugin)" [loading]="isUpdating(plugin)" | 28 | [responsiveLabel]="true" |
29 | [label]="getUpdateLabel(plugin)" icon="refresh" [attr.disabled]="isUpdating(plugin)" | 29 | ></my-edit-button> |
30 | |||
31 | <my-button | ||
32 | class="update-button" *ngIf="isUpdateAvailable(plugin)" (click)="update(plugin)" [loading]="isUpdating(plugin)" | ||
33 | [label]="getUpdateLabel(plugin)" icon="refresh" [attr.disabled]="isUpdating(plugin)" [responsiveLabel]="true" | ||
30 | ></my-button> | 34 | ></my-button> |
31 | 35 | ||
32 | <my-delete-button (click)="uninstall(plugin)" label="Uninstall" i18n-label></my-delete-button> | 36 | <my-delete-button (click)="uninstall(plugin)" label="Uninstall" i18n-label [responsiveLabel]="true"></my-delete-button> |
33 | </div> | 37 | </div> |
34 | </div> | 38 | </div> |
35 | 39 | ||
diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss index 9376e38b0..22d4a59ab 100644 --- a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss | |||
@@ -1,6 +1,6 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .update-button[disabled="true"] ::ng-deep .action-button { | 4 | .update-button[disabled=true] ::ng-deep .action-button { |
5 | cursor: default !important; | 5 | cursor: default !important; |
6 | } | 6 | } |
diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html index 727633399..6900e8717 100644 --- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html | |||
@@ -48,10 +48,15 @@ | |||
48 | <span *ngIf="plugin.installed" class="badge badge-success">Installed</span> | 48 | <span *ngIf="plugin.installed" class="badge badge-success">Installed</span> |
49 | 49 | ||
50 | <div class="buttons"> | 50 | <div class="buttons"> |
51 | <my-edit-button *ngIf="plugin.installed === true && !isThemeSearch()" [routerLink]="getShowRouterLink(plugin)" label="Settings" i18n-label></my-edit-button> | 51 | <my-edit-button |
52 | *ngIf="plugin.installed === true && !isThemeSearch()" [routerLink]="getShowRouterLink(plugin)" | ||
53 | label="Settings" i18n-label [responsiveLabel]="true" | ||
54 | ></my-edit-button> | ||
52 | 55 | ||
53 | <my-button class="update-button" *ngIf="plugin.installed === false" (click)="install(plugin)" [loading]="isInstalling(plugin)" | 56 | <my-button |
54 | label="Install" icon="cloud-download" [attr.disabled]="isInstalling(plugin)" | 57 | class="update-button" *ngIf="plugin.installed === false" (click)="install(plugin)" |
58 | [loading]="isInstalling(plugin)" label="Install" [responsiveLabel]="true" | ||
59 | icon="cloud-download" [attr.disabled]="isInstalling(plugin)" | ||
55 | ></my-button> | 60 | ></my-button> |
56 | </div> | 61 | </div> |
57 | </div> | 62 | </div> |
diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss index 5ab6e5f1b..6b7b84e29 100644 --- a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss +++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss | |||
@@ -5,7 +5,8 @@ h2 { | |||
5 | margin-bottom: 20px; | 5 | margin-bottom: 20px; |
6 | } | 6 | } |
7 | 7 | ||
8 | input[type=submit], button { | 8 | input[type=submit], |
9 | button { | ||
9 | @include peertube-button; | 10 | @include peertube-button; |
10 | @include orange-button; | 11 | @include orange-button; |
11 | 12 | ||
diff --git a/client/src/app/+admin/plugins/plugins.component.scss b/client/src/app/+admin/plugins/plugins.component.scss deleted file mode 100644 index ce9825f53..000000000 --- a/client/src/app/+admin/plugins/plugins.component.scss +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | @media screen and (max-width: $small-view) { | ||
5 | ::ng-deep .plugins .plugin .first-row { | ||
6 | flex-wrap: wrap; | ||
7 | |||
8 | .plugin-name, | ||
9 | .plugin-version, | ||
10 | .plugin-icon { | ||
11 | margin-bottom: 10px; | ||
12 | } | ||
13 | |||
14 | .buttons { | ||
15 | my-edit-button, | ||
16 | my-delete-button, | ||
17 | my-button { | ||
18 | .action-button { | ||
19 | padding: 0 13px; | ||
20 | } | ||
21 | |||
22 | .button-label { | ||
23 | display: none; | ||
24 | } | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | } | ||
diff --git a/client/src/app/+admin/plugins/plugins.component.ts b/client/src/app/+admin/plugins/plugins.component.ts index 6ec6fa4a1..de06c0671 100644 --- a/client/src/app/+admin/plugins/plugins.component.ts +++ b/client/src/app/+admin/plugins/plugins.component.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | templateUrl: './plugins.component.html', | 4 | templateUrl: './plugins.component.html' |
5 | styleUrls: [ './plugins.component.scss' ] | ||
6 | }) | 5 | }) |
7 | export class PluginsComponent { | 6 | export class PluginsComponent { |
8 | } | 7 | } |
diff --git a/client/src/app/+admin/plugins/shared/plugin-list.component.scss b/client/src/app/+admin/plugins/shared/plugin-list.component.scss index f59a01b74..47cb1e6e5 100644 --- a/client/src/app/+admin/plugins/shared/plugin-list.component.scss +++ b/client/src/app/+admin/plugins/shared/plugin-list.component.scss | |||
@@ -27,7 +27,7 @@ | |||
27 | my-global-icon { | 27 | my-global-icon { |
28 | @include apply-svg-color(pvar(--greyForegroundColor)); | 28 | @include apply-svg-color(pvar(--greyForegroundColor)); |
29 | 29 | ||
30 | &[iconName="npm"] { | 30 | &[iconName=npm] { |
31 | @include fill-svg-color(pvar(--greyForegroundColor)); | 31 | @include fill-svg-color(pvar(--greyForegroundColor)); |
32 | } | 32 | } |
33 | } | 33 | } |
@@ -36,6 +36,7 @@ | |||
36 | .buttons { | 36 | .buttons { |
37 | margin-left: auto; | 37 | margin-left: auto; |
38 | width: max-content; | 38 | width: max-content; |
39 | |||
39 | > *:not(:last-child) { | 40 | > *:not(:last-child) { |
40 | margin-right: 10px; | 41 | margin-right: 10px; |
41 | } | 42 | } |
@@ -49,7 +50,7 @@ | |||
49 | justify-content: space-between; | 50 | justify-content: space-between; |
50 | 51 | ||
51 | .description { | 52 | .description { |
52 | opacity: 0.8 | 53 | opacity: 0.8; |
53 | } | 54 | } |
54 | } | 55 | } |
55 | 56 | ||
@@ -57,3 +58,14 @@ | |||
57 | @include peertube-button-link; | 58 | @include peertube-button-link; |
58 | @include button-with-icon(21px, 0, -2px); | 59 | @include button-with-icon(21px, 0, -2px); |
59 | } | 60 | } |
61 | |||
62 | @media screen and (max-width: $small-view) { | ||
63 | .first-row { | ||
64 | flex-wrap: wrap; | ||
65 | |||
66 | .buttons { | ||
67 | flex-basis: 100%; | ||
68 | margin-top: 10px; | ||
69 | } | ||
70 | } | ||
71 | } | ||
diff --git a/client/src/app/+admin/system/jobs/jobs.component.scss b/client/src/app/+admin/system/jobs/jobs.component.scss index 7c6159420..65ee6ec5f 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.scss +++ b/client/src/app/+admin/system/jobs/jobs.component.scss | |||
@@ -51,7 +51,7 @@ pre { | |||
51 | } | 51 | } |
52 | 52 | ||
53 | .job-error { | 53 | .job-error { |
54 | color: red; | 54 | color: #ff0000; |
55 | } | 55 | } |
56 | 56 | ||
57 | .badge { | 57 | .badge { |
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts index 43578eedd..29ba95c5c 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.ts +++ b/client/src/app/+admin/system/jobs/jobs.component.ts | |||
@@ -86,7 +86,7 @@ export class JobsComponent extends RestTable implements OnInit { | |||
86 | onJobStateOrTypeChanged () { | 86 | onJobStateOrTypeChanged () { |
87 | this.pagination.start = 0 | 87 | this.pagination.start = 0 |
88 | 88 | ||
89 | this.loadData() | 89 | this.reloadData() |
90 | this.saveJobStateAndType() | 90 | this.saveJobStateAndType() |
91 | } | 91 | } |
92 | 92 | ||
@@ -104,10 +104,10 @@ export class JobsComponent extends RestTable implements OnInit { | |||
104 | this.jobs = [] | 104 | this.jobs = [] |
105 | this.totalRecords = 0 | 105 | this.totalRecords = 0 |
106 | 106 | ||
107 | this.loadData() | 107 | this.reloadData() |
108 | } | 108 | } |
109 | 109 | ||
110 | protected loadData () { | 110 | protected reloadData () { |
111 | let jobState = this.jobState as JobState | 111 | let jobState = this.jobState as JobState |
112 | if (this.jobState === 'all') jobState = null | 112 | if (this.jobState === 'all') jobState = null |
113 | 113 | ||
diff --git a/client/src/app/+admin/system/logs/logs.component.scss b/client/src/app/+admin/system/logs/logs.component.scss index 587a9795c..1a7c3be75 100644 --- a/client/src/app/+admin/system/logs/logs.component.scss +++ b/client/src/app/+admin/system/logs/logs.component.scss | |||
@@ -66,7 +66,7 @@ | |||
66 | ng-select, | 66 | ng-select, |
67 | my-button { | 67 | my-button { |
68 | width: 100% !important; | 68 | width: 100% !important; |
69 | margin-left: 0px !important; | 69 | margin-left: 0 !important; |
70 | margin-bottom: 10px !important; | 70 | margin-bottom: 10px !important; |
71 | } | 71 | } |
72 | 72 | ||
@@ -85,7 +85,7 @@ | |||
85 | ng-select, | 85 | ng-select, |
86 | my-button { | 86 | my-button { |
87 | width: 100% !important; | 87 | width: 100% !important; |
88 | margin-left: 0px !important; | 88 | margin-left: 0 !important; |
89 | margin-bottom: 10px !important; | 89 | margin-bottom: 10px !important; |
90 | } | 90 | } |
91 | 91 | ||
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.scss b/client/src/app/+admin/users/user-edit/user-edit.component.scss index 8b0ac8783..145177fb9 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.component.scss +++ b/client/src/app/+admin/users/user-edit/user-edit.component.scss | |||
@@ -37,7 +37,8 @@ my-select-custom-value { | |||
37 | display: block; | 37 | display: block; |
38 | } | 38 | } |
39 | 39 | ||
40 | input[type=submit], button { | 40 | input[type=submit], |
41 | button { | ||
41 | @include peertube-button; | 42 | @include peertube-button; |
42 | @include orange-button; | 43 | @include orange-button; |
43 | 44 | ||
diff --git a/client/src/app/+admin/users/user-edit/user-password.component.scss b/client/src/app/+admin/users/user-edit/user-password.component.scss index 1f0d49227..66d15ee9c 100644 --- a/client/src/app/+admin/users/user-edit/user-password.component.scss +++ b/client/src/app/+admin/users/user-edit/user-password.component.scss | |||
@@ -7,7 +7,7 @@ input:not([type=submit]):not([type=checkbox]) { | |||
7 | display: block; | 7 | display: block; |
8 | border-top-right-radius: 0; | 8 | border-top-right-radius: 0; |
9 | border-bottom-right-radius: 0; | 9 | border-bottom-right-radius: 0; |
10 | border-right: none; | 10 | border-right: 0; |
11 | } | 11 | } |
12 | 12 | ||
13 | input[type=submit] { | 13 | input[type=submit] { |
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index e114f3425..44d8a7e87 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <p-table | 1 | <p-table |
2 | [value]="users" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 2 | [value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedUsers" |
4 | [(selection)]="selectedUsers" | 4 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
5 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 5 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
6 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" | 6 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" |
7 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 7 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
@@ -22,24 +22,7 @@ | |||
22 | </div> | 22 | </div> |
23 | 23 | ||
24 | <div class="ml-auto"> | 24 | <div class="ml-auto"> |
25 | <div class="input-group has-feedback has-clear"> | 25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
26 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
27 | <div class="input-group-text" ngbDropdownToggle> | ||
28 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
29 | </div> | ||
30 | |||
31 | <div role="menu" ngbDropdownMenu> | ||
32 | <h6 class="dropdown-header" i18n>Advanced user filters</h6> | ||
33 | <a [routerLink]="[ '/admin/users/list' ]" [queryParams]="{ 'search': 'banned:true' }" class="dropdown-item" i18n>Banned users</a> | ||
34 | </div> | ||
35 | </div> | ||
36 | <input | ||
37 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
38 | (keyup)="onSearch($event)" | ||
39 | > | ||
40 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
41 | <span class="sr-only" i18n>Clear filters</span> | ||
42 | </div> | ||
43 | </div> | 26 | </div> |
44 | 27 | ||
45 | </div> | 28 | </div> |
@@ -106,7 +89,7 @@ | |||
106 | <td *ngIf="isSelected('username')"> | 89 | <td *ngIf="isSelected('username')"> |
107 | <a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/accounts/' + user.username ]"> | 90 | <a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/accounts/' + user.username ]"> |
108 | <div class="chip two-lines"> | 91 | <div class="chip two-lines"> |
109 | <my-account-avatar [account]="user?.account"></my-account-avatar> | 92 | <my-actor-avatar [account]="user?.account" size="32"></my-actor-avatar> |
110 | <div> | 93 | <div> |
111 | <span class="user-table-primary-text">{{ user.account.displayName }}</span> | 94 | <span class="user-table-primary-text">{{ user.account.displayName }}</span> |
112 | <span class="text-muted">{{ user.username }}</span> | 95 | <span class="text-muted">{{ user.username }}</span> |
diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss index 50080bad6..db4979a51 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/users/user-list/user-list.component.scss | |||
@@ -11,6 +11,7 @@ tr.banned > td { | |||
11 | 11 | ||
12 | .table-email { | 12 | .table-email { |
13 | @include disable-default-a-behaviour; | 13 | @include disable-default-a-behaviour; |
14 | |||
14 | color: pvar(--mainForegroundColor); | 15 | color: pvar(--mainForegroundColor); |
15 | } | 16 | } |
16 | 17 | ||
@@ -24,18 +25,10 @@ tr.banned > td { | |||
24 | 25 | ||
25 | .user-table-primary-text .glyphicon { | 26 | .user-table-primary-text .glyphicon { |
26 | font-size: 80%; | 27 | font-size: 80%; |
27 | color: gray; | 28 | color: #808080; |
28 | margin-left: 0.1rem; | 29 | margin-left: 0.1rem; |
29 | } | 30 | } |
30 | 31 | ||
31 | .caption { | ||
32 | justify-content: space-between; | ||
33 | |||
34 | input { | ||
35 | @include peertube-input-text(250px); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | p-tableCheckbox { | 32 | p-tableCheckbox { |
40 | position: relative; | 33 | position: relative; |
41 | top: -2.5px; | 34 | top: -2.5px; |
@@ -55,18 +48,7 @@ my-global-icon { | |||
55 | 48 | ||
56 | .progress { | 49 | .progress { |
57 | @include progressbar($small: true); | 50 | @include progressbar($small: true); |
51 | |||
58 | width: auto; | 52 | width: auto; |
59 | max-width: 100%; | 53 | max-width: 100%; |
60 | } | 54 | } |
61 | |||
62 | .input-group { | ||
63 | @include peertube-input-group(300px); | ||
64 | |||
65 | input { | ||
66 | flex: 1; | ||
67 | } | ||
68 | |||
69 | .dropdown-toggle::after { | ||
70 | margin-left: 0; | ||
71 | } | ||
72 | } | ||
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 339e18206..1c60adf89 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { Component, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, OnInit, ViewChild } from '@angular/core' |
3 | import { ActivatedRoute, Params, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService, UserService } from '@app/core' | 4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService, UserService } from '@app/core' |
5 | import { Account, DropdownAction } from '@app/shared/shared-main' | 5 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
6 | import { DropdownAction } from '@app/shared/shared-main' | ||
6 | import { UserBanModalComponent } from '@app/shared/shared-moderation' | 7 | import { UserBanModalComponent } from '@app/shared/shared-moderation' |
7 | import { ServerConfig, User, UserRole } from '@shared/models' | 8 | import { ServerConfig, User, UserRole } from '@shared/models' |
8 | 9 | ||
@@ -22,15 +23,24 @@ export class UserListComponent extends RestTable implements OnInit { | |||
22 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent | 23 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent |
23 | 24 | ||
24 | users: User[] = [] | 25 | users: User[] = [] |
26 | |||
25 | totalRecords = 0 | 27 | totalRecords = 0 |
26 | sort: SortMeta = { field: 'createdAt', order: 1 } | 28 | sort: SortMeta = { field: 'createdAt', order: 1 } |
27 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 29 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
30 | |||
28 | highlightBannedUsers = false | 31 | highlightBannedUsers = false |
29 | 32 | ||
30 | selectedUsers: User[] = [] | 33 | selectedUsers: User[] = [] |
31 | bulkUserActions: DropdownAction<User[]>[][] = [] | 34 | bulkUserActions: DropdownAction<User[]>[][] = [] |
32 | columns: { id: string, label: string }[] | 35 | columns: { id: string, label: string }[] |
33 | 36 | ||
37 | inputFilters: AdvancedInputFilter[] = [ | ||
38 | { | ||
39 | queryParams: { 'search': 'banned:true' }, | ||
40 | label: $localize`Banned users` | ||
41 | } | ||
42 | ] | ||
43 | |||
34 | private _selectedColumns: string[] | 44 | private _selectedColumns: string[] |
35 | private serverConfig: ServerConfig | 45 | private serverConfig: ServerConfig |
36 | 46 | ||
@@ -68,7 +78,6 @@ export class UserListComponent extends RestTable implements OnInit { | |||
68 | .subscribe(config => this.serverConfig = config) | 78 | .subscribe(config => this.serverConfig = config) |
69 | 79 | ||
70 | this.initialize() | 80 | this.initialize() |
71 | this.listenToSearchChange() | ||
72 | 81 | ||
73 | this.bulkUserActions = [ | 82 | this.bulkUserActions = [ |
74 | [ | 83 | [ |
@@ -160,7 +169,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
160 | } | 169 | } |
161 | 170 | ||
162 | onUserChanged () { | 171 | onUserChanged () { |
163 | this.loadData() | 172 | this.reloadData() |
164 | } | 173 | } |
165 | 174 | ||
166 | async unbanUsers (users: User[]) { | 175 | async unbanUsers (users: User[]) { |
@@ -171,7 +180,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
171 | .subscribe( | 180 | .subscribe( |
172 | () => { | 181 | () => { |
173 | this.notifier.success($localize`${users.length} users unbanned.`) | 182 | this.notifier.success($localize`${users.length} users unbanned.`) |
174 | this.loadData() | 183 | this.reloadData() |
175 | }, | 184 | }, |
176 | 185 | ||
177 | err => this.notifier.error(err.message) | 186 | err => this.notifier.error(err.message) |
@@ -193,7 +202,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
193 | this.userService.removeUser(users).subscribe( | 202 | this.userService.removeUser(users).subscribe( |
194 | () => { | 203 | () => { |
195 | this.notifier.success($localize`${users.length} users deleted.`) | 204 | this.notifier.success($localize`${users.length} users deleted.`) |
196 | this.loadData() | 205 | this.reloadData() |
197 | }, | 206 | }, |
198 | 207 | ||
199 | err => this.notifier.error(err.message) | 208 | err => this.notifier.error(err.message) |
@@ -204,7 +213,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
204 | this.userService.updateUsers(users, { emailVerified: true }).subscribe( | 213 | this.userService.updateUsers(users, { emailVerified: true }).subscribe( |
205 | () => { | 214 | () => { |
206 | this.notifier.success($localize`${users.length} users email set as verified.`) | 215 | this.notifier.success($localize`${users.length} users email set as verified.`) |
207 | this.loadData() | 216 | this.reloadData() |
208 | }, | 217 | }, |
209 | 218 | ||
210 | err => this.notifier.error(err.message) | 219 | err => this.notifier.error(err.message) |
@@ -215,7 +224,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
215 | return this.selectedUsers.length !== 0 | 224 | return this.selectedUsers.length !== 0 |
216 | } | 225 | } |
217 | 226 | ||
218 | protected loadData () { | 227 | protected reloadData () { |
219 | this.selectedUsers = [] | 228 | this.selectedUsers = [] |
220 | 229 | ||
221 | this.userService.getUsers({ | 230 | this.userService.getUsers({ |
diff --git a/client/src/app/+login/login.component.scss b/client/src/app/+login/login.component.scss index eddaff542..62ae722c3 100644 --- a/client/src/app/+login/login.component.scss +++ b/client/src/app/+login/login.component.scss | |||
@@ -33,7 +33,8 @@ input[type=email] { | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | .create-an-account, .forgot-password-button { | 36 | .create-an-account, |
37 | .forgot-password-button { | ||
37 | color: pvar(--mainForegroundColor); | 38 | color: pvar(--mainForegroundColor); |
38 | cursor: pointer; | 39 | cursor: pointer; |
39 | transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1); | 40 | transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1); |
@@ -49,7 +50,7 @@ input[type=email] { | |||
49 | justify-content: space-around; | 50 | justify-content: space-around; |
50 | flex-wrap: wrap; | 51 | flex-wrap: wrap; |
51 | 52 | ||
52 | & > div { | 53 | > div { |
53 | flex: 1 1; | 54 | flex: 1 1; |
54 | } | 55 | } |
55 | 56 | ||
@@ -65,7 +66,8 @@ input[type=email] { | |||
65 | form { | 66 | form { |
66 | margin: 0; | 67 | margin: 0; |
67 | 68 | ||
68 | &, input { | 69 | &, |
70 | input { | ||
69 | width: 100%; | 71 | width: 100%; |
70 | } | 72 | } |
71 | 73 | ||
@@ -82,7 +84,8 @@ input[type=email] { | |||
82 | 84 | ||
83 | color: var(--mainColor); | 85 | color: var(--mainColor); |
84 | 86 | ||
85 | &:hover, &:active { | 87 | &:hover, |
88 | &:active { | ||
86 | color: var(--mainHoverColor); | 89 | color: var(--mainHoverColor); |
87 | } | 90 | } |
88 | } | 91 | } |
@@ -111,7 +114,7 @@ input[type=email] { | |||
111 | min-width: 100px; | 114 | min-width: 100px; |
112 | 115 | ||
113 | &:hover { | 116 | &:hover { |
114 | background-color: rgba(209, 215, 224, 0.5) | 117 | background-color: rgba(209, 215, 224, 0.5); |
115 | } | 118 | } |
116 | } | 119 | } |
117 | } | 120 | } |
@@ -138,7 +141,7 @@ input[type=email] { | |||
138 | } | 141 | } |
139 | } | 142 | } |
140 | 143 | ||
141 | @mixin columnReverseDisplay { | 144 | @mixin column-reverse-display { |
142 | flex-direction: column-reverse; | 145 | flex-direction: column-reverse; |
143 | 146 | ||
144 | .login-form-and-externals, | 147 | .login-form-and-externals, |
@@ -168,14 +171,14 @@ input[type=email] { | |||
168 | 171 | ||
169 | @media screen and (max-width: breakpoint(md)) { | 172 | @media screen and (max-width: breakpoint(md)) { |
170 | .wrapper { | 173 | .wrapper { |
171 | @include columnReverseDisplay(); | 174 | @include column-reverse-display(); |
172 | } | 175 | } |
173 | } | 176 | } |
174 | 177 | ||
175 | @media screen and (max-width: breakpoint(md) + $menu-width) { | 178 | @media screen and (max-width: breakpoint(md) + $menu-width) { |
176 | :host-context(.main-col:not(.expanded)) { | 179 | :host-context(.main-col:not(.expanded)) { |
177 | .wrapper { | 180 | .wrapper { |
178 | @include columnReverseDisplay(); | 181 | @include column-reverse-display(); |
179 | } | 182 | } |
180 | } | 183 | } |
181 | } | 184 | } |
diff --git a/client/src/app/+my-account/my-account-abuses/my-account-abuses-list.component.html b/client/src/app/+my-account/my-account-abuses/my-account-abuses-list.component.html index 59ca61be6..e83b59019 100644 --- a/client/src/app/+my-account/my-account-abuses/my-account-abuses-list.component.html +++ b/client/src/app/+my-account/my-account-abuses/my-account-abuses-list.component.html | |||
@@ -3,4 +3,4 @@ | |||
3 | <ng-container i18n>Reports</ng-container> | 3 | <ng-container i18n>Reports</ng-container> |
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <my-abuse-list-table viewType="user" baseRoute="/my-account/abuses"></my-abuse-list-table> | 6 | <my-abuse-list-table viewType="user"></my-abuse-list-table> |
diff --git a/client/src/app/+my-account/my-account-applications/my-account-applications.component.scss b/client/src/app/+my-account/my-account-applications/my-account-applications.component.scss index 704132c03..c1e1f2432 100644 --- a/client/src/app/+my-account/my-account-applications/my-account-applications.component.scss +++ b/client/src/app/+my-account/my-account-applications/my-account-applications.component.scss | |||
@@ -21,7 +21,7 @@ input[type=submit] { | |||
21 | display: flex; | 21 | display: flex; |
22 | margin-left: auto; | 22 | margin-left: auto; |
23 | 23 | ||
24 | & + .form-error { | 24 | + .form-error { |
25 | display: inline; | 25 | display: inline; |
26 | margin-left: 5px; | 26 | margin-left: 5px; |
27 | } | 27 | } |
diff --git a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss index 035fa2b27..abf52504a 100644 --- a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss +++ b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss | |||
@@ -32,7 +32,8 @@ my-user-notifications { | |||
32 | .header { | 32 | .header { |
33 | flex-direction: column; | 33 | flex-direction: column; |
34 | 34 | ||
35 | & >:first-child, .peertube-select-container { | 35 | > :first-child, |
36 | .peertube-select-container { | ||
36 | margin-bottom: 15px; | 37 | margin-bottom: 15px; |
37 | } | 38 | } |
38 | 39 | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.scss b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.scss index d79ff690b..64f960964 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.scss +++ b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.scss | |||
@@ -7,4 +7,4 @@ | |||
7 | @include danger-button; | 7 | @include danger-button; |
8 | @include disable-outline; | 8 | @include disable-outline; |
9 | } | 9 | } |
10 | } \ No newline at end of file | 10 | } |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.scss b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.scss index b06d8b16d..42319400d 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.scss +++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.scss | |||
@@ -10,7 +10,7 @@ | |||
10 | font-size: 16px; | 10 | font-size: 16px; |
11 | } | 11 | } |
12 | 12 | ||
13 | & > div { | 13 | > div { |
14 | padding: 10px; | 14 | padding: 10px; |
15 | 15 | ||
16 | &:first-child { | 16 | &:first-child { |
diff --git a/client/src/app/+my-account/my-account.component.scss b/client/src/app/+my-account/my-account.component.scss index a5bb499b4..b32bc84e7 100644 --- a/client/src/app/+my-account/my-account.component.scss +++ b/client/src/app/+my-account/my-account.component.scss | |||
@@ -2,12 +2,12 @@ | |||
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .row { | 4 | .row { |
5 | @include sub-menu-h1; | ||
6 | |||
5 | flex-direction: column; | 7 | flex-direction: column; |
6 | width: 100%; | 8 | width: 100%; |
7 | 9 | ||
8 | & > my-top-menu-dropdown:nth-child(1) { | 10 | > my-top-menu-dropdown:nth-child(1) { |
9 | flex-grow: 1; | 11 | flex-grow: 1; |
10 | } | 12 | } |
11 | |||
12 | @include sub-menu-h1; | ||
13 | } | 13 | } |
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 050cd4b34..4081e4f01 100644 --- a/client/src/app/+my-account/my-account.module.ts +++ b/client/src/app/+my-account/my-account.module.ts | |||
@@ -3,13 +3,14 @@ import { TableModule } from 'primeng/table' | |||
3 | import { DragDropModule } from '@angular/cdk/drag-drop' | 3 | import { DragDropModule } from '@angular/cdk/drag-drop' |
4 | import { NgModule } from '@angular/core' | 4 | import { NgModule } from '@angular/core' |
5 | import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' | 5 | import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' |
6 | import { SharedActorImageModule } from '@app/shared/shared-actor-image' | 6 | import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' |
7 | import { SharedFormModule } from '@app/shared/shared-forms' | 7 | import { SharedFormModule } from '@app/shared/shared-forms' |
8 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 8 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
9 | import { SharedMainModule } from '@app/shared/shared-main' | 9 | import { SharedMainModule } from '@app/shared/shared-main' |
10 | import { SharedModerationModule } from '@app/shared/shared-moderation' | 10 | import { SharedModerationModule } from '@app/shared/shared-moderation' |
11 | import { SharedShareModal } from '@app/shared/shared-share-modal' | 11 | import { SharedShareModal } from '@app/shared/shared-share-modal' |
12 | import { SharedUserInterfaceSettingsModule } from '@app/shared/shared-user-settings' | 12 | import { SharedUserInterfaceSettingsModule } from '@app/shared/shared-user-settings' |
13 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' | ||
13 | import { MyAccountAbusesListComponent } from './my-account-abuses/my-account-abuses-list.component' | 14 | import { MyAccountAbusesListComponent } from './my-account-abuses/my-account-abuses-list.component' |
14 | import { MyAccountApplicationsComponent } from './my-account-applications/my-account-applications.component' | 15 | import { MyAccountApplicationsComponent } from './my-account-applications/my-account-applications.component' |
15 | import { MyAccountBlocklistComponent } from './my-account-blocklist/my-account-blocklist.component' | 16 | import { MyAccountBlocklistComponent } from './my-account-blocklist/my-account-blocklist.component' |
@@ -23,7 +24,6 @@ import { MyAccountNotificationPreferencesComponent } from './my-account-settings | |||
23 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' | 24 | import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' |
24 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' | 25 | import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' |
25 | import { MyAccountComponent } from './my-account.component' | 26 | import { MyAccountComponent } from './my-account.component' |
26 | import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' | ||
27 | 27 | ||
28 | @NgModule({ | 28 | @NgModule({ |
29 | imports: [ | 29 | imports: [ |
@@ -40,8 +40,8 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share | |||
40 | SharedGlobalIconModule, | 40 | SharedGlobalIconModule, |
41 | SharedAbuseListModule, | 41 | SharedAbuseListModule, |
42 | SharedShareModal, | 42 | SharedShareModal, |
43 | SharedAccountAvatarModule, | 43 | SharedActorImageModule, |
44 | SharedActorImageModule | 44 | SharedActorImageEditModule |
45 | ], | 45 | ], |
46 | 46 | ||
47 | declarations: [ | 47 | declarations: [ |
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss index 22de103d1..667726c22 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss +++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss | |||
@@ -66,7 +66,8 @@ textarea { | |||
66 | width: auto !important; | 66 | width: auto !important; |
67 | } | 67 | } |
68 | 68 | ||
69 | label[for=name] + div, textarea { | 69 | label[for=name] + div, |
70 | textarea { | ||
70 | width: 100%; | 71 | width: 100%; |
71 | } | 72 | } |
72 | } | 73 | } |
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html index b704a1cc6..e41cbe921 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html | |||
@@ -1,18 +1,11 @@ | |||
1 | <h1> | 1 | <h1> |
2 | <span> | 2 | <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> |
3 | <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> | 3 | <ng-container i18n>My channels</ng-container> |
4 | <ng-container i18n>My channels</ng-container> | 4 | <span class="badge badge-secondary">{{ totalItems }}</span> |
5 | <span class="badge badge-secondary">{{ totalItems }}</span> | ||
6 | </span> | ||
7 | </h1> | 5 | </h1> |
8 | 6 | ||
9 | <div class="video-channels-header d-flex justify-content-between"> | 7 | <div class="video-channels-header d-flex justify-content-between"> |
10 | <div class="has-feedback has-clear"> | 8 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
11 | <input type="text" placeholder="Search your channels" i18n-placeholder [(ngModel)]="channelsSearch" | ||
12 | (ngModelChange)="onChannelsSearchChanged()" /> | ||
13 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
14 | <span class="sr-only" i18n>Clear filters</span> | ||
15 | </div> | ||
16 | 9 | ||
17 | <a class="create-button" routerLink="create"> | 10 | <a class="create-button" routerLink="create"> |
18 | <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> | 11 | <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> |
@@ -20,11 +13,11 @@ | |||
20 | </a> | 13 | </a> |
21 | </div> | 14 | </div> |
22 | 15 | ||
16 | <div class="no-results" i18n *ngIf="totalItems === 0">No channel found.</div> | ||
17 | |||
23 | <div class="video-channels"> | 18 | <div class="video-channels"> |
24 | <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel"> | 19 | <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel"> |
25 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"> | 20 | <my-actor-avatar [channel]="videoChannel" [internalHref]="[ '/video-channels', videoChannel.nameWithHost ]"></my-actor-avatar> |
26 | <img [src]="videoChannel.avatarUrl" alt="Avatar" /> | ||
27 | </a> | ||
28 | 21 | ||
29 | <div class="video-channel-info"> | 22 | <div class="video-channel-info"> |
30 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> | 23 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> |
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss index 8804fa95c..191c5169d 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss | |||
@@ -1,6 +1,11 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | h1 my-global-icon { | ||
5 | position: relative; | ||
6 | top: -2px; | ||
7 | } | ||
8 | |||
4 | .create-button { | 9 | .create-button { |
5 | @include create-button; | 10 | @include create-button; |
6 | } | 11 | } |
@@ -9,10 +14,8 @@ input[type=text] { | |||
9 | @include peertube-input-text(300px); | 14 | @include peertube-input-text(300px); |
10 | } | 15 | } |
11 | 16 | ||
12 | ::ng-deep .action-button { | 17 | my-edit-button { |
13 | &.action-button-edit { | 18 | margin-right: 10px; |
14 | margin-right: 10px; | ||
15 | } | ||
16 | } | 19 | } |
17 | 20 | ||
18 | .video-channel { | 21 | .video-channel { |
@@ -20,40 +23,40 @@ input[type=text] { | |||
20 | 23 | ||
21 | padding-bottom: 0; | 24 | padding-bottom: 0; |
22 | 25 | ||
23 | img { | 26 | my-actor-avatar { |
24 | @include channel-avatar(80px); | 27 | @include actor-avatar-size(80px); |
25 | 28 | ||
26 | margin-right: 10px; | 29 | margin-right: 10px; |
27 | } | 30 | } |
31 | } | ||
28 | 32 | ||
29 | .video-channel-info { | 33 | .video-channel-info { |
30 | flex-grow: 1; | 34 | flex-grow: 1; |
31 | 35 | } | |
32 | a.video-channel-names { | ||
33 | @include disable-default-a-behaviour; | ||
34 | |||
35 | width: fit-content; | ||
36 | display: flex; | ||
37 | align-items: baseline; | ||
38 | color: pvar(--mainForegroundColor); | ||
39 | |||
40 | .video-channel-display-name { | ||
41 | font-weight: $font-semibold; | ||
42 | font-size: 18px; | ||
43 | } | ||
44 | |||
45 | .video-channel-name { | ||
46 | font-size: 14px; | ||
47 | color: $grey-actor-name; | ||
48 | margin-left: 5px; | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | 36 | ||
53 | .video-channel-buttons { | 37 | .video-channel-names { |
54 | margin-top: 10px; | 38 | @include disable-default-a-behaviour; |
55 | min-width: 190px; | 39 | |
56 | } | 40 | width: fit-content; |
41 | display: flex; | ||
42 | align-items: baseline; | ||
43 | color: pvar(--mainForegroundColor); | ||
44 | } | ||
45 | |||
46 | .video-channel-display-name { | ||
47 | font-weight: $font-semibold; | ||
48 | font-size: 18px; | ||
49 | } | ||
50 | |||
51 | .video-channel-name { | ||
52 | font-size: 14px; | ||
53 | color: $grey-actor-name; | ||
54 | margin-left: 5px; | ||
55 | } | ||
56 | |||
57 | .video-channel-buttons { | ||
58 | margin-top: 10px; | ||
59 | min-width: 190px; | ||
57 | } | 60 | } |
58 | 61 | ||
59 | ::ng-deep .chartjs-render-monitor { | 62 | ::ng-deep .chartjs-render-monitor { |
@@ -73,21 +76,6 @@ input[type=text] { | |||
73 | .video-channel { | 76 | .video-channel { |
74 | padding-bottom: 10px; | 77 | padding-bottom: 10px; |
75 | 78 | ||
76 | .video-channel-info { | ||
77 | padding-bottom: 10px; | ||
78 | text-align: center; | ||
79 | |||
80 | .video-channel-names { | ||
81 | flex-direction: column; | ||
82 | align-items: center !important; | ||
83 | margin: auto; | ||
84 | |||
85 | .video-channel-name { | ||
86 | margin-left: 0px !important; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | img { | 79 | img { |
92 | margin-right: 0; | 80 | margin-right: 0; |
93 | } | 81 | } |
@@ -96,6 +84,21 @@ input[type=text] { | |||
96 | align-self: center; | 84 | align-self: center; |
97 | } | 85 | } |
98 | } | 86 | } |
87 | |||
88 | .video-channel-info { | ||
89 | padding-bottom: 10px; | ||
90 | text-align: center; | ||
91 | } | ||
92 | |||
93 | .video-channel-names { | ||
94 | flex-direction: column; | ||
95 | align-items: center !important; | ||
96 | margin: auto; | ||
97 | } | ||
98 | |||
99 | .video-channel-name { | ||
100 | margin-left: 0 !important; | ||
101 | } | ||
99 | } | 102 | } |
100 | 103 | ||
101 | @media screen and (max-width: $mobile-view) { | 104 | @media screen and (max-width: $mobile-view) { |
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts index f6ba50a48..9e3bf35b4 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts | |||
@@ -1,29 +1,26 @@ | |||
1 | import { ChartData } from 'chart.js' | 1 | import { ChartData } from 'chart.js' |
2 | import { max, maxBy, min, minBy } from 'lodash-es' | 2 | import { max, maxBy, min, minBy } from 'lodash-es' |
3 | import { Subject } from 'rxjs' | 3 | import { mergeMap } from 'rxjs/operators' |
4 | import { debounceTime, mergeMap } from 'rxjs/operators' | 4 | import { Component } from '@angular/core' |
5 | import { Component, OnInit } from '@angular/core' | 5 | import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core' |
6 | import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core' | ||
7 | import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' | 6 | import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' |
8 | 7 | ||
9 | @Component({ | 8 | @Component({ |
10 | templateUrl: './my-video-channels.component.html', | 9 | templateUrl: './my-video-channels.component.html', |
11 | styleUrls: [ './my-video-channels.component.scss' ] | 10 | styleUrls: [ './my-video-channels.component.scss' ] |
12 | }) | 11 | }) |
13 | export class MyVideoChannelsComponent implements OnInit { | 12 | export class MyVideoChannelsComponent { |
14 | totalItems: number | 13 | totalItems: number |
15 | 14 | ||
16 | videoChannels: VideoChannel[] = [] | 15 | videoChannels: VideoChannel[] = [] |
16 | |||
17 | videoChannelsChartData: ChartData[] | 17 | videoChannelsChartData: ChartData[] |
18 | videoChannelsMinimumDailyViews = 0 | 18 | videoChannelsMinimumDailyViews = 0 |
19 | videoChannelsMaximumDailyViews: number | 19 | videoChannelsMaximumDailyViews: number |
20 | 20 | ||
21 | channelsSearch: string | ||
22 | channelsSearchChanged = new Subject<string>() | ||
23 | |||
24 | chartOptions: any | 21 | chartOptions: any |
25 | 22 | ||
26 | private user: User | 23 | search: string |
27 | 24 | ||
28 | constructor ( | 25 | constructor ( |
29 | private authService: AuthService, | 26 | private authService: AuthService, |
@@ -31,31 +28,15 @@ export class MyVideoChannelsComponent implements OnInit { | |||
31 | private confirmService: ConfirmService, | 28 | private confirmService: ConfirmService, |
32 | private videoChannelService: VideoChannelService, | 29 | private videoChannelService: VideoChannelService, |
33 | private screenService: ScreenService | 30 | private screenService: ScreenService |
34 | ) {} | 31 | ) {} |
35 | |||
36 | ngOnInit () { | ||
37 | this.user = this.authService.getUser() | ||
38 | |||
39 | this.loadVideoChannels() | ||
40 | |||
41 | this.channelsSearchChanged | ||
42 | .pipe(debounceTime(500)) | ||
43 | .subscribe(() => { | ||
44 | this.loadVideoChannels() | ||
45 | }) | ||
46 | } | ||
47 | 32 | ||
48 | get isInSmallView () { | 33 | get isInSmallView () { |
49 | return this.screenService.isInSmallView() | 34 | return this.screenService.isInSmallView() |
50 | } | 35 | } |
51 | 36 | ||
52 | resetSearch () { | 37 | onSearch (search: string) { |
53 | this.channelsSearch = '' | 38 | this.search = search |
54 | this.onChannelsSearchChanged() | 39 | this.loadVideoChannels() |
55 | } | ||
56 | |||
57 | onChannelsSearchChanged () { | ||
58 | this.channelsSearchChanged.next() | ||
59 | } | 40 | } |
60 | 41 | ||
61 | async deleteVideoChannel (videoChannel: VideoChannel) { | 42 | async deleteVideoChannel (videoChannel: VideoChannel) { |
@@ -85,8 +66,11 @@ channel with the same name (${videoChannel.name})!`, | |||
85 | 66 | ||
86 | private loadVideoChannels () { | 67 | private loadVideoChannels () { |
87 | this.authService.userInformationLoaded | 68 | this.authService.userInformationLoaded |
88 | .pipe(mergeMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true, this.channelsSearch))) | 69 | .pipe(mergeMap(() => { |
89 | .subscribe(res => { | 70 | const user = this.authService.getUser() |
71 | |||
72 | return this.videoChannelService.listAccountVideoChannels(user.account, null, true, this.search) | ||
73 | })).subscribe(res => { | ||
90 | this.videoChannels = res.data | 74 | this.videoChannels = res.data |
91 | this.totalItems = res.total | 75 | this.totalItems = res.total |
92 | 76 | ||
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts index 53557ca02..c775bfdee 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { ChartModule } from 'primeng/chart' | 1 | import { ChartModule } from 'primeng/chart' |
2 | import { NgModule } from '@angular/core' | 2 | import { NgModule } from '@angular/core' |
3 | import { SharedActorImageModule } from '@app/shared/shared-actor-image' | 3 | import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' |
4 | import { SharedFormModule } from '@app/shared/shared-forms' | 4 | import { SharedFormModule } from '@app/shared/shared-forms' |
5 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 5 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
6 | import { SharedMainModule } from '@app/shared/shared-main' | 6 | import { SharedMainModule } from '@app/shared/shared-main' |
@@ -8,6 +8,7 @@ import { MyVideoChannelCreateComponent } from './my-video-channel-create.compone | |||
8 | import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component' | 8 | import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component' |
9 | import { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module' | 9 | import { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module' |
10 | import { MyVideoChannelsComponent } from './my-video-channels.component' | 10 | import { MyVideoChannelsComponent } from './my-video-channels.component' |
11 | import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module' | ||
11 | 12 | ||
12 | @NgModule({ | 13 | @NgModule({ |
13 | imports: [ | 14 | imports: [ |
@@ -18,6 +19,7 @@ import { MyVideoChannelsComponent } from './my-video-channels.component' | |||
18 | SharedMainModule, | 19 | SharedMainModule, |
19 | SharedFormModule, | 20 | SharedFormModule, |
20 | SharedGlobalIconModule, | 21 | SharedGlobalIconModule, |
22 | SharedActorImageEditModule, | ||
21 | SharedActorImageModule | 23 | SharedActorImageModule |
22 | ], | 24 | ], |
23 | 25 | ||
diff --git a/client/src/app/+my-library/my-history/my-history.component.html b/client/src/app/+my-library/my-history/my-history.component.html index 9dec64645..45ca37e0d 100644 --- a/client/src/app/+my-library/my-history/my-history.component.html +++ b/client/src/app/+my-library/my-history/my-history.component.html | |||
@@ -5,14 +5,7 @@ | |||
5 | 5 | ||
6 | <div class="top-buttons"> | 6 | <div class="top-buttons"> |
7 | <div class="search-wrapper"> | 7 | <div class="search-wrapper"> |
8 | <div class="input-group has-feedback has-clear"> | 8 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
9 | <input | ||
10 | type="text" name="history-search" id="history-search" i18n-placeholder placeholder="Search your history" | ||
11 | (keyup)="onSearch($event)" | ||
12 | > | ||
13 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
14 | <span class="sr-only" i18n>Clear filters</span> | ||
15 | </div> | ||
16 | </div> | 9 | </div> |
17 | 10 | ||
18 | <div class="history-switch"> | 11 | <div class="history-switch"> |
@@ -26,14 +19,15 @@ | |||
26 | </button> | 19 | </button> |
27 | </div> | 20 | </div> |
28 | 21 | ||
29 | 22 | <my-videos-selection | |
30 | <div class="no-history" i18n *ngIf="hasDoneFirstQuery && videos.length === 0">You don't have any video in your watch history yet.</div> | 23 | [pagination]="pagination" |
31 | 24 | [(videosModel)]="videos" | |
32 | <div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()" class="videos"> | 25 | [miniatureDisplayOptions]="miniatureDisplayOptions" |
33 | <div class="video" *ngFor="let video of videos"> | 26 | [titlePage]="titlePage" |
34 | <my-video-miniature | 27 | [getVideosObservableFunction]="getVideosObservableFunction" |
35 | [video]="video" [displayAsRow]="true" | 28 | [user]="user" |
36 | (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)" | 29 | [loadOnInit]="false" |
37 | ></my-video-miniature> | 30 | i18n-noResultMessage noResultMessage="You don't have any video in your watch history yet." |
38 | </div> | 31 | [enableSelection]="false" |
39 | </div> | 32 | #videosSelection |
33 | ></my-videos-selection> | ||
diff --git a/client/src/app/+my-library/my-history/my-history.component.scss b/client/src/app/+my-library/my-history/my-history.component.scss index af4a34b4b..28b809f71 100644 --- a/client/src/app/+my-library/my-history/my-history.component.scss +++ b/client/src/app/+my-library/my-history/my-history.component.scss | |||
@@ -39,12 +39,12 @@ | |||
39 | } | 39 | } |
40 | 40 | ||
41 | .delete-history { | 41 | .delete-history { |
42 | grid-column: 4; | ||
43 | |||
44 | @include peertube-button; | 42 | @include peertube-button; |
45 | @include grey-button; | 43 | @include grey-button; |
46 | @include button-with-icon; | 44 | @include button-with-icon; |
47 | 45 | ||
46 | grid-column: 4; | ||
47 | |||
48 | font-size: 15px; | 48 | font-size: 15px; |
49 | } | 49 | } |
50 | } | 50 | } |
diff --git a/client/src/app/+my-library/my-history/my-history.component.ts b/client/src/app/+my-library/my-history/my-history.component.ts index 1695bd7ad..ad83db7ab 100644 --- a/client/src/app/+my-library/my-history/my-history.component.ts +++ b/client/src/app/+my-library/my-history/my-history.component.ts | |||
@@ -1,36 +1,55 @@ | |||
1 | import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core' | 1 | import { Subject } from 'rxjs' |
2 | import { tap } from 'rxjs/operators' | ||
3 | import { Component, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | 4 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { | 5 | import { |
4 | AuthService, | 6 | AuthService, |
5 | ComponentPagination, | 7 | ComponentPagination, |
6 | ConfirmService, | 8 | ConfirmService, |
9 | DisableForReuseHook, | ||
7 | LocalStorageService, | 10 | LocalStorageService, |
8 | Notifier, | 11 | Notifier, |
9 | ScreenService, | 12 | ScreenService, |
10 | ServerService, | 13 | ServerService, |
14 | User, | ||
11 | UserService | 15 | UserService |
12 | } from '@app/core' | 16 | } from '@app/core' |
13 | import { immutableAssign } from '@app/helpers' | 17 | import { immutableAssign } from '@app/helpers' |
14 | import { UserHistoryService } from '@app/shared/shared-main' | 18 | import { UserHistoryService, Video } from '@app/shared/shared-main' |
15 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' | 19 | import { MiniatureDisplayOptions, VideosSelectionComponent } from '@app/shared/shared-video-miniature' |
16 | import { Subject } from 'rxjs' | ||
17 | import { debounceTime, tap, distinctUntilChanged } from 'rxjs/operators' | ||
18 | 20 | ||
19 | @Component({ | 21 | @Component({ |
20 | templateUrl: './my-history.component.html', | 22 | templateUrl: './my-history.component.html', |
21 | styleUrls: [ './my-history.component.scss' ] | 23 | styleUrls: [ './my-history.component.scss' ] |
22 | }) | 24 | }) |
23 | export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnDestroy { | 25 | export class MyHistoryComponent implements OnInit, DisableForReuseHook { |
26 | @ViewChild('videosSelection', { static: true }) videosSelection: VideosSelectionComponent | ||
27 | |||
24 | titlePage: string | 28 | titlePage: string |
25 | pagination: ComponentPagination = { | 29 | pagination: ComponentPagination = { |
26 | currentPage: 1, | 30 | currentPage: 1, |
27 | itemsPerPage: 5, | 31 | itemsPerPage: 5, |
28 | totalItems: null | 32 | totalItems: null |
29 | } | 33 | } |
34 | |||
30 | videosHistoryEnabled: boolean | 35 | videosHistoryEnabled: boolean |
31 | search: string | ||
32 | 36 | ||
33 | protected searchStream: Subject<string> | 37 | miniatureDisplayOptions: MiniatureDisplayOptions = { |
38 | date: true, | ||
39 | views: true, | ||
40 | by: true, | ||
41 | privacyLabel: false, | ||
42 | privacyText: true, | ||
43 | state: true, | ||
44 | blacklistInfo: true | ||
45 | } | ||
46 | |||
47 | getVideosObservableFunction = this.getVideosObservable.bind(this) | ||
48 | |||
49 | user: User | ||
50 | |||
51 | videos: Video[] = [] | ||
52 | search: string | ||
34 | 53 | ||
35 | constructor ( | 54 | constructor ( |
36 | protected router: Router, | 55 | protected router: Router, |
@@ -45,45 +64,31 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD | |||
45 | private userHistoryService: UserHistoryService, | 64 | private userHistoryService: UserHistoryService, |
46 | protected cfr: ComponentFactoryResolver | 65 | protected cfr: ComponentFactoryResolver |
47 | ) { | 66 | ) { |
48 | super() | ||
49 | |||
50 | this.titlePage = $localize`My watch history` | 67 | this.titlePage = $localize`My watch history` |
51 | } | 68 | } |
52 | 69 | ||
53 | ngOnInit () { | 70 | ngOnInit () { |
54 | super.ngOnInit() | 71 | this.user = this.authService.getUser() |
55 | 72 | ||
56 | this.authService.userInformationLoaded | 73 | this.authService.userInformationLoaded |
57 | .subscribe(() => { | 74 | .subscribe(() => this.videosHistoryEnabled = this.user.videosHistoryEnabled) |
58 | this.videosHistoryEnabled = this.authService.getUser().videosHistoryEnabled | 75 | } |
59 | }) | ||
60 | |||
61 | this.searchStream = new Subject() | ||
62 | 76 | ||
63 | this.searchStream | 77 | disableForReuse () { |
64 | .pipe( | 78 | this.videosSelection.disableForReuse() |
65 | debounceTime(400), | ||
66 | distinctUntilChanged() | ||
67 | ) | ||
68 | .subscribe(search => { | ||
69 | this.search = search | ||
70 | this.reloadVideos() | ||
71 | }) | ||
72 | } | 79 | } |
73 | 80 | ||
74 | onSearch (event: Event) { | 81 | enabledForReuse () { |
75 | const target = event.target as HTMLInputElement | 82 | this.videosSelection.enabledForReuse() |
76 | this.searchStream.next(target.value) | ||
77 | } | 83 | } |
78 | 84 | ||
79 | resetSearch () { | 85 | reloadData () { |
80 | const searchInput = document.getElementById('history-search') as HTMLInputElement | 86 | this.videosSelection.reloadVideos() |
81 | searchInput.value = '' | ||
82 | this.searchStream.next('') | ||
83 | } | 87 | } |
84 | 88 | ||
85 | ngOnDestroy () { | 89 | onSearch (search: string) { |
86 | super.ngOnDestroy() | 90 | this.search = search |
91 | this.reloadData() | ||
87 | } | 92 | } |
88 | 93 | ||
89 | getVideosObservable (page: number) { | 94 | getVideosObservable (page: number) { |
@@ -129,7 +134,7 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD | |||
129 | () => { | 134 | () => { |
130 | this.notifier.success($localize`Videos history deleted`) | 135 | this.notifier.success($localize`Videos history deleted`) |
131 | 136 | ||
132 | this.reloadVideos() | 137 | this.reloadData() |
133 | }, | 138 | }, |
134 | 139 | ||
135 | err => this.notifier.error(err.message) | 140 | err => this.notifier.error(err.message) |
diff --git a/client/src/app/+my-library/my-library.component.scss b/client/src/app/+my-library/my-library.component.scss index a5bb499b4..b32bc84e7 100644 --- a/client/src/app/+my-library/my-library.component.scss +++ b/client/src/app/+my-library/my-library.component.scss | |||
@@ -2,12 +2,12 @@ | |||
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .row { | 4 | .row { |
5 | @include sub-menu-h1; | ||
6 | |||
5 | flex-direction: column; | 7 | flex-direction: column; |
6 | width: 100%; | 8 | width: 100%; |
7 | 9 | ||
8 | & > my-top-menu-dropdown:nth-child(1) { | 10 | > my-top-menu-dropdown:nth-child(1) { |
9 | flex-grow: 1; | 11 | flex-grow: 1; |
10 | } | 12 | } |
11 | |||
12 | @include sub-menu-h1; | ||
13 | } | 13 | } |
diff --git a/client/src/app/+my-library/my-library.module.ts b/client/src/app/+my-library/my-library.module.ts index a1d706f0b..264ad03f7 100644 --- a/client/src/app/+my-library/my-library.module.ts +++ b/client/src/app/+my-library/my-library.module.ts | |||
@@ -26,7 +26,7 @@ import { MyVideoPlaylistUpdateComponent } from './my-video-playlists/my-video-pl | |||
26 | import { MyVideoPlaylistsComponent } from './my-video-playlists/my-video-playlists.component' | 26 | import { MyVideoPlaylistsComponent } from './my-video-playlists/my-video-playlists.component' |
27 | import { VideoChangeOwnershipComponent } from './my-videos/modals/video-change-ownership.component' | 27 | import { VideoChangeOwnershipComponent } from './my-videos/modals/video-change-ownership.component' |
28 | import { MyVideosComponent } from './my-videos/my-videos.component' | 28 | import { MyVideosComponent } from './my-videos/my-videos.component' |
29 | import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' | 29 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' |
30 | 30 | ||
31 | @NgModule({ | 31 | @NgModule({ |
32 | imports: [ | 32 | imports: [ |
@@ -47,7 +47,7 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share | |||
47 | SharedAbuseListModule, | 47 | SharedAbuseListModule, |
48 | SharedShareModal, | 48 | SharedShareModal, |
49 | SharedVideoLiveModule, | 49 | SharedVideoLiveModule, |
50 | SharedAccountAvatarModule | 50 | SharedActorImageModule |
51 | ], | 51 | ], |
52 | 52 | ||
53 | declarations: [ | 53 | declarations: [ |
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.html b/client/src/app/+my-library/my-ownership/my-ownership.component.html index d0eff0521..4c02c78fc 100644 --- a/client/src/app/+my-library/my-ownership/my-ownership.component.html +++ b/client/src/app/+my-library/my-ownership/my-ownership.component.html | |||
@@ -37,7 +37,7 @@ | |||
37 | <td> | 37 | <td> |
38 | <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 38 | <a [href]="videoChangeOwnership.initiatorAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
39 | <div class="chip two-lines"> | 39 | <div class="chip two-lines"> |
40 | <my-account-avatar [account]="videoChangeOwnership.initiatorAccount"></my-account-avatar> | 40 | <my-actor-avatar [account]="videoChangeOwnership.initiatorAccount"></my-actor-avatar> |
41 | <div> | 41 | <div> |
42 | {{ videoChangeOwnership.initiatorAccount.displayName }} | 42 | {{ videoChangeOwnership.initiatorAccount.displayName }} |
43 | <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span> | 43 | <span class="text-muted">{{ videoChangeOwnership.initiatorAccount.nameWithHost }}</span> |
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.scss b/client/src/app/+my-library/my-ownership/my-ownership.component.scss index 7cac9c9f3..dfc8fc99e 100644 --- a/client/src/app/+my-library/my-ownership/my-ownership.component.scss +++ b/client/src/app/+my-library/my-ownership/my-ownership.component.scss | |||
@@ -13,15 +13,15 @@ | |||
13 | display: inline-flex; | 13 | display: inline-flex; |
14 | 14 | ||
15 | .video-table-video-image { | 15 | .video-table-video-image { |
16 | @include miniature-thumbnail; | ||
17 | |||
18 | $image-height: 45px; | 16 | $image-height: 45px; |
19 | 17 | ||
18 | @include miniature-thumbnail; | ||
19 | |||
20 | height: $image-height; | 20 | height: $image-height; |
21 | width: #{(16/9) * $image-height}; | 21 | width: #{(16/9) * $image-height}; |
22 | margin-right: 0.5rem; | 22 | margin-right: 0.5rem; |
23 | border-radius: 2px; | 23 | border-radius: 2px; |
24 | border: none; | 24 | border: 0; |
25 | background: transparent; | 25 | background: transparent; |
26 | display: inline-flex; | 26 | display: inline-flex; |
27 | justify-content: center; | 27 | justify-content: center; |
@@ -60,7 +60,7 @@ | |||
60 | 60 | ||
61 | div .glyphicon { | 61 | div .glyphicon { |
62 | font-size: 80%; | 62 | font-size: 80%; |
63 | color: gray; | 63 | color: #808080; |
64 | margin-left: 0.1rem; | 64 | margin-left: 0.1rem; |
65 | } | 65 | } |
66 | 66 | ||
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-ownership.component.ts index a938023b4..aaf028474 100644 --- a/client/src/app/+my-library/my-ownership/my-ownership.component.ts +++ b/client/src/app/+my-library/my-ownership/my-ownership.component.ts | |||
@@ -48,18 +48,18 @@ export class MyOwnershipComponent extends RestTable implements OnInit { | |||
48 | } | 48 | } |
49 | 49 | ||
50 | accepted () { | 50 | accepted () { |
51 | this.loadData() | 51 | this.reloadData() |
52 | } | 52 | } |
53 | 53 | ||
54 | refuse (videoChangeOwnership: VideoChangeOwnership) { | 54 | refuse (videoChangeOwnership: VideoChangeOwnership) { |
55 | this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id) | 55 | this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id) |
56 | .subscribe( | 56 | .subscribe( |
57 | () => this.loadData(), | 57 | () => this.reloadData(), |
58 | err => this.notifier.error(err.message) | 58 | err => this.notifier.error(err.message) |
59 | ) | 59 | ) |
60 | } | 60 | } |
61 | 61 | ||
62 | protected loadData () { | 62 | protected reloadData () { |
63 | return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) | 63 | return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) |
64 | .subscribe( | 64 | .subscribe( |
65 | resultList => { | 65 | resultList => { |
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html index ff448ad87..f91cebacf 100644 --- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html +++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.html | |||
@@ -7,21 +7,14 @@ | |||
7 | </h1> | 7 | </h1> |
8 | 8 | ||
9 | <div class="video-subscriptions-header"> | 9 | <div class="video-subscriptions-header"> |
10 | <div class="has-feedback has-clear"> | 10 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
11 | <input type="text" placeholder="Search your subscriptions" i18n-placeholder [(ngModel)]="subscriptionsSearch" | ||
12 | (ngModelChange)="onSubscriptionsSearchChanged()" /> | ||
13 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
14 | <span class="sr-only" i18n>Clear filters</span> | ||
15 | </div> | ||
16 | </div> | 11 | </div> |
17 | 12 | ||
18 | <div class="no-results" i18n *ngIf="pagination.totalItems === 0">You don't have any subscription yet.</div> | 13 | <div class="no-results" i18n *ngIf="pagination.totalItems === 0">You don't have any subscription yet.</div> |
19 | 14 | ||
20 | <div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()"> | 15 | <div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()"> |
21 | <div *ngFor="let videoChannel of videoChannels" class="video-channel"> | 16 | <div *ngFor="let videoChannel of videoChannels" class="video-channel"> |
22 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]"> | 17 | <my-actor-avatar [channel]="videoChannel" [internalHref]="[ '/video-channels', videoChannel.nameWithHost ]"></my-actor-avatar> |
23 | <img [src]="videoChannel.avatarUrl" alt="Avatar" /> | ||
24 | </a> | ||
25 | 18 | ||
26 | <div class="video-channel-info"> | 19 | <div class="video-channel-info"> |
27 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> | 20 | <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page"> |
@@ -33,7 +26,8 @@ | |||
33 | 26 | ||
34 | <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Owner account page" class="actor-owner"> | 27 | <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Owner account page" class="actor-owner"> |
35 | <span i18n>Created by {{ videoChannel.ownerBy }}</span> | 28 | <span i18n>Created by {{ videoChannel.ownerBy }}</span> |
36 | <img [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" /> | 29 | |
30 | <my-actor-avatar [account]="videoChannel.ownerAccount" size="18"></my-actor-avatar> | ||
37 | </a> | 31 | </a> |
38 | </div> | 32 | </div> |
39 | 33 | ||
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss index 3c1a4d2ad..6c1ddf716 100644 --- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss +++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.scss | |||
@@ -8,8 +8,8 @@ input[type=text] { | |||
8 | .video-channel { | 8 | .video-channel { |
9 | @include row-blocks; | 9 | @include row-blocks; |
10 | 10 | ||
11 | img { | 11 | > my-actor-avatar { |
12 | @include channel-avatar(80px); | 12 | @include actor-avatar-size(80px); |
13 | 13 | ||
14 | margin-right: 10px; | 14 | margin-right: 10px; |
15 | } | 15 | } |
@@ -40,13 +40,25 @@ input[type=text] { | |||
40 | } | 40 | } |
41 | 41 | ||
42 | .actor-owner { | 42 | .actor-owner { |
43 | @include actor-owner; | 43 | @include disable-default-a-behaviour; |
44 | |||
45 | font-size: 13px; | ||
46 | color: pvar(--mainForegroundColor); | ||
44 | 47 | ||
45 | margin-top: 0; | 48 | span:hover { |
49 | opacity: 0.8; | ||
50 | } | ||
51 | |||
52 | my-actor-avatar { | ||
53 | margin-left: 7px; | ||
54 | display: inline-block; | ||
55 | vertical-align: top; | ||
56 | } | ||
46 | } | 57 | } |
47 | 58 | ||
48 | .video-subscriptions-header { | 59 | .video-subscriptions-header { |
49 | margin-bottom: 30px; | 60 | margin-bottom: 30px; |
61 | display: flex; | ||
50 | } | 62 | } |
51 | 63 | ||
52 | @media screen and (max-width: $small-view) { | 64 | @media screen and (max-width: $small-view) { |
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts index 3b748eccf..1f4a931a0 100644 --- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts +++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Subject } from 'rxjs' | 1 | import { Subject } from 'rxjs' |
2 | import { debounceTime } from 'rxjs/operators' | 2 | import { Component } from '@angular/core' |
3 | import { Component, OnInit } from '@angular/core' | ||
4 | import { ComponentPagination, Notifier } from '@app/core' | 3 | import { ComponentPagination, Notifier } from '@app/core' |
5 | import { VideoChannel } from '@app/shared/shared-main' | 4 | import { VideoChannel } from '@app/shared/shared-main' |
6 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' | 5 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' |
@@ -9,7 +8,7 @@ import { UserSubscriptionService } from '@app/shared/shared-user-subscription' | |||
9 | templateUrl: './my-subscriptions.component.html', | 8 | templateUrl: './my-subscriptions.component.html', |
10 | styleUrls: [ './my-subscriptions.component.scss' ] | 9 | styleUrls: [ './my-subscriptions.component.scss' ] |
11 | }) | 10 | }) |
12 | export class MySubscriptionsComponent implements OnInit { | 11 | export class MySubscriptionsComponent { |
13 | videoChannels: VideoChannel[] = [] | 12 | videoChannels: VideoChannel[] = [] |
14 | 13 | ||
15 | pagination: ComponentPagination = { | 14 | pagination: ComponentPagination = { |
@@ -20,34 +19,13 @@ export class MySubscriptionsComponent implements OnInit { | |||
20 | 19 | ||
21 | onDataSubject = new Subject<any[]>() | 20 | onDataSubject = new Subject<any[]>() |
22 | 21 | ||
23 | subscriptionsSearch: string | 22 | search: string |
24 | subscriptionsSearchChanged = new Subject<string>() | ||
25 | 23 | ||
26 | constructor ( | 24 | constructor ( |
27 | private userSubscriptionService: UserSubscriptionService, | 25 | private userSubscriptionService: UserSubscriptionService, |
28 | private notifier: Notifier | 26 | private notifier: Notifier |
29 | ) {} | 27 | ) {} |
30 | 28 | ||
31 | ngOnInit () { | ||
32 | this.loadSubscriptions() | ||
33 | |||
34 | this.subscriptionsSearchChanged | ||
35 | .pipe(debounceTime(500)) | ||
36 | .subscribe(() => { | ||
37 | this.pagination.currentPage = 1 | ||
38 | this.loadSubscriptions(false) | ||
39 | }) | ||
40 | } | ||
41 | |||
42 | resetSearch () { | ||
43 | this.subscriptionsSearch = '' | ||
44 | this.onSubscriptionsSearchChanged() | ||
45 | } | ||
46 | |||
47 | onSubscriptionsSearchChanged () { | ||
48 | this.subscriptionsSearchChanged.next() | ||
49 | } | ||
50 | |||
51 | onNearOfBottom () { | 29 | onNearOfBottom () { |
52 | // Last page | 30 | // Last page |
53 | if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return | 31 | if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return |
@@ -56,8 +34,13 @@ export class MySubscriptionsComponent implements OnInit { | |||
56 | this.loadSubscriptions() | 34 | this.loadSubscriptions() |
57 | } | 35 | } |
58 | 36 | ||
37 | onSearch (search: string) { | ||
38 | this.search = search | ||
39 | this.loadSubscriptions(false) | ||
40 | } | ||
41 | |||
59 | private loadSubscriptions (more = true) { | 42 | private loadSubscriptions (more = true) { |
60 | this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.subscriptionsSearch }) | 43 | this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.search }) |
61 | .subscribe( | 44 | .subscribe( |
62 | res => { | 45 | res => { |
63 | this.videoChannels = more | 46 | this.videoChannels = more |
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss b/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss index a93c28028..c4b847c3d 100644 --- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss +++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.scss | |||
@@ -6,7 +6,7 @@ pre { | |||
6 | } | 6 | } |
7 | 7 | ||
8 | .video-import-error { | 8 | .video-import-error { |
9 | color: red; | 9 | color: #ff0000; |
10 | } | 10 | } |
11 | 11 | ||
12 | .badge { | 12 | .badge { |
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts index d6d7d7a1b..359535526 100644 --- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts +++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts | |||
@@ -62,7 +62,7 @@ export class MyVideoImportsComponent extends RestTable implements OnInit { | |||
62 | return '/videos/update/' + video.uuid | 62 | return '/videos/update/' + video.uuid |
63 | } | 63 | } |
64 | 64 | ||
65 | protected loadData () { | 65 | protected reloadData () { |
66 | this.videoImportService.getMyVideoImports(this.pagination, this.sort) | 66 | this.videoImportService.getMyVideoImports(this.pagination, this.sort) |
67 | .subscribe( | 67 | .subscribe( |
68 | resultList => { | 68 | resultList => { |
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss index 0c68dedf6..67587a58a 100644 --- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss +++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.scss | |||
@@ -25,8 +25,8 @@ | |||
25 | } | 25 | } |
26 | 26 | ||
27 | .playlist-buttons { | 27 | .playlist-buttons { |
28 | display:flex; | 28 | display: flex; |
29 | margin: 30px 0 10px 0; | 29 | margin: 30px 0 10px; |
30 | 30 | ||
31 | .share-button { | 31 | .share-button { |
32 | @include peertube-button; | 32 | @include peertube-button; |
@@ -42,9 +42,10 @@ | |||
42 | .cdk-drag-preview { | 42 | .cdk-drag-preview { |
43 | box-sizing: border-box; | 43 | box-sizing: border-box; |
44 | border-radius: 4px; | 44 | border-radius: 4px; |
45 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), | 45 | box-shadow: |
46 | 0 8px 10px 1px rgba(0, 0, 0, 0.14), | 46 | 0 5px 5px -3px rgba(0, 0, 0, 0.2), |
47 | 0 3px 14px 2px rgba(0, 0, 0, 0.12); | 47 | 0 8px 10px 1px rgba(0, 0, 0, 0.14), |
48 | 0 3px 14px 2px rgba(0, 0, 0, 0.12); | ||
48 | } | 49 | } |
49 | 50 | ||
50 | .cdk-drag-placeholder { | 51 | .cdk-drag-placeholder { |
@@ -56,7 +57,7 @@ | |||
56 | } | 57 | } |
57 | 58 | ||
58 | .video:last-child { | 59 | .video:last-child { |
59 | border: none; | 60 | border: 0; |
60 | } | 61 | } |
61 | 62 | ||
62 | .videos.cdk-drop-list-dragging .video:not(.cdk-drag-placeholder) { | 63 | .videos.cdk-drop-list-dragging .video:not(.cdk-drag-placeholder) { |
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html index b88ea3db7..309afcf13 100644 --- a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html +++ b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html | |||
@@ -4,12 +4,7 @@ | |||
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <div class="video-playlists-header d-flex justify-content-between"> | 6 | <div class="video-playlists-header d-flex justify-content-between"> |
7 | <div class="has-feedback has-clear"> | 7 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
8 | <input type="text" placeholder="Search your playlists" i18n-placeholder [(ngModel)]="videoPlaylistsSearch" | ||
9 | (ngModelChange)="onVideoPlaylistSearchChanged()" /> | ||
10 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
11 | <span class="sr-only" i18n>Clear filters</span> | ||
12 | </div> | ||
13 | 8 | ||
14 | <a class="create-button" routerLink="create"> | 9 | <a class="create-button" routerLink="create"> |
15 | <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> | 10 | <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> |
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts index f6d394923..d90102693 100644 --- a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts +++ b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Subject } from 'rxjs' | 1 | import { Subject } from 'rxjs' |
2 | import { debounceTime, mergeMap } from 'rxjs/operators' | 2 | import { mergeMap } from 'rxjs/operators' |
3 | import { Component, OnInit } from '@angular/core' | 3 | import { Component } from '@angular/core' |
4 | import { AuthService, ComponentPagination, ConfirmService, Notifier, User } from '@app/core' | 4 | import { AuthService, ComponentPagination, ConfirmService, Notifier } from '@app/core' |
5 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' | 5 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' |
6 | import { VideoPlaylistType } from '@shared/models' | 6 | import { VideoPlaylistType } from '@shared/models' |
7 | 7 | ||
@@ -9,10 +9,8 @@ import { VideoPlaylistType } from '@shared/models' | |||
9 | templateUrl: './my-video-playlists.component.html', | 9 | templateUrl: './my-video-playlists.component.html', |
10 | styleUrls: [ './my-video-playlists.component.scss' ] | 10 | styleUrls: [ './my-video-playlists.component.scss' ] |
11 | }) | 11 | }) |
12 | export class MyVideoPlaylistsComponent implements OnInit { | 12 | export class MyVideoPlaylistsComponent { |
13 | videoPlaylistsSearch: string | ||
14 | videoPlaylists: VideoPlaylist[] = [] | 13 | videoPlaylists: VideoPlaylist[] = [] |
15 | videoPlaylistSearchChanged = new Subject<string>() | ||
16 | 14 | ||
17 | pagination: ComponentPagination = { | 15 | pagination: ComponentPagination = { |
18 | currentPage: 1, | 16 | currentPage: 1, |
@@ -22,27 +20,14 @@ export class MyVideoPlaylistsComponent implements OnInit { | |||
22 | 20 | ||
23 | onDataSubject = new Subject<any[]>() | 21 | onDataSubject = new Subject<any[]>() |
24 | 22 | ||
25 | private user: User | 23 | search: string |
26 | 24 | ||
27 | constructor ( | 25 | constructor ( |
28 | private authService: AuthService, | 26 | private authService: AuthService, |
29 | private notifier: Notifier, | 27 | private notifier: Notifier, |
30 | private confirmService: ConfirmService, | 28 | private confirmService: ConfirmService, |
31 | private videoPlaylistService: VideoPlaylistService | 29 | private videoPlaylistService: VideoPlaylistService |
32 | ) {} | 30 | ) {} |
33 | |||
34 | ngOnInit () { | ||
35 | this.user = this.authService.getUser() | ||
36 | |||
37 | this.loadVideoPlaylists() | ||
38 | |||
39 | this.videoPlaylistSearchChanged | ||
40 | .pipe( | ||
41 | debounceTime(500)) | ||
42 | .subscribe(() => { | ||
43 | this.loadVideoPlaylists(true) | ||
44 | }) | ||
45 | } | ||
46 | 31 | ||
47 | async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { | 32 | async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { |
48 | const res = await this.confirmService.confirm( | 33 | const res = await this.confirmService.confirm( |
@@ -76,22 +61,20 @@ export class MyVideoPlaylistsComponent implements OnInit { | |||
76 | this.loadVideoPlaylists() | 61 | this.loadVideoPlaylists() |
77 | } | 62 | } |
78 | 63 | ||
79 | resetSearch () { | 64 | onSearch (search: string) { |
80 | this.videoPlaylistsSearch = '' | 65 | this.search = search |
81 | this.onVideoPlaylistSearchChanged() | 66 | this.loadVideoPlaylists(true) |
82 | } | ||
83 | |||
84 | onVideoPlaylistSearchChanged () { | ||
85 | this.videoPlaylistSearchChanged.next() | ||
86 | } | 67 | } |
87 | 68 | ||
88 | private loadVideoPlaylists (reset = false) { | 69 | private loadVideoPlaylists (reset = false) { |
89 | this.authService.userInformationLoaded | 70 | this.authService.userInformationLoaded |
90 | .pipe(mergeMap(() => { | 71 | .pipe(mergeMap(() => { |
91 | return this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt', this.videoPlaylistsSearch) | 72 | const user = this.authService.getUser() |
92 | })) | 73 | |
93 | .subscribe(res => { | 74 | return this.videoPlaylistService.listAccountPlaylists(user.account, this.pagination, '-updatedAt', this.search) |
75 | })).subscribe(res => { | ||
94 | if (reset) this.videoPlaylists = [] | 76 | if (reset) this.videoPlaylists = [] |
77 | |||
95 | this.videoPlaylists = this.videoPlaylists.concat(res.data) | 78 | this.videoPlaylists = this.videoPlaylists.concat(res.data) |
96 | this.pagination.totalItems = res.total | 79 | this.pagination.totalItems = res.total |
97 | 80 | ||
diff --git a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss index a79fec179..16187bc4a 100644 --- a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss +++ b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.scss | |||
@@ -7,4 +7,4 @@ p-autocomplete { | |||
7 | 7 | ||
8 | .form-group { | 8 | .form-group { |
9 | margin: 20px 0; | 9 | margin: 20px 0; |
10 | } \ No newline at end of file | 10 | } |
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.html b/client/src/app/+my-library/my-videos/my-videos.component.html index e9f436378..8d8b482ad 100644 --- a/client/src/app/+my-library/my-videos/my-videos.component.html +++ b/client/src/app/+my-library/my-videos/my-videos.component.html | |||
@@ -19,12 +19,7 @@ | |||
19 | </h1> | 19 | </h1> |
20 | 20 | ||
21 | <div class="videos-header d-flex justify-content-between"> | 21 | <div class="videos-header d-flex justify-content-between"> |
22 | <div class="has-feedback has-clear"> | 22 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
23 | <input type="text" placeholder="Search your videos" i18n-placeholder [(ngModel)]="videosSearch" | ||
24 | (ngModelChange)="onVideosSearchChanged()" /> | ||
25 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
26 | <span class="sr-only" i18n>Clear filters</span> | ||
27 | </div> | ||
28 | 23 | ||
29 | <div class="peertube-select-container peertube-select-button"> | 24 | <div class="peertube-select-container peertube-select-button"> |
30 | <select [(ngModel)]="sort" (ngModelChange)="onChangeSortColumn()" class="form-control"> | 25 | <select [(ngModel)]="sort" (ngModelChange)="onChangeSortColumn()" class="form-control"> |
@@ -46,6 +41,7 @@ | |||
46 | [titlePage]="titlePage" | 41 | [titlePage]="titlePage" |
47 | [getVideosObservableFunction]="getVideosObservableFunction" | 42 | [getVideosObservableFunction]="getVideosObservableFunction" |
48 | [user]="user" | 43 | [user]="user" |
44 | [loadOnInit]="false" | ||
49 | #videosSelection | 45 | #videosSelection |
50 | > | 46 | > |
51 | <ng-template ptTemplate="globalButtons"> | 47 | <ng-template ptTemplate="globalButtons"> |
@@ -64,6 +60,5 @@ | |||
64 | </ng-template> | 60 | </ng-template> |
65 | </my-videos-selection> | 61 | </my-videos-selection> |
66 | 62 | ||
67 | |||
68 | <my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership> | 63 | <my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership> |
69 | <my-live-stream-information #liveStreamInformationModal></my-live-stream-information> | 64 | <my-live-stream-information #liveStreamInformationModal></my-live-stream-information> |
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.scss b/client/src/app/+my-library/my-videos/my-videos.component.scss index aaf21126b..57623c36f 100644 --- a/client/src/app/+my-library/my-videos/my-videos.component.scss +++ b/client/src/app/+my-library/my-videos/my-videos.component.scss | |||
@@ -26,12 +26,12 @@ h1 { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | .action-button-delete-selection { | 28 | .action-button-delete-selection { |
29 | display: inline-block; | ||
30 | |||
31 | @include peertube-button; | 29 | @include peertube-button; |
32 | @include orange-button; | 30 | @include orange-button; |
33 | @include button-with-icon(21px); | 31 | @include button-with-icon(21px); |
34 | 32 | ||
33 | display: inline-block; | ||
34 | |||
35 | my-global-icon { | 35 | my-global-icon { |
36 | @include apply-svg-color(#fff); | 36 | @include apply-svg-color(#fff); |
37 | } | 37 | } |
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.ts b/client/src/app/+my-library/my-videos/my-videos.component.ts index 356e158d6..1e4a4406d 100644 --- a/client/src/app/+my-library/my-videos/my-videos.component.ts +++ b/client/src/app/+my-library/my-videos/my-videos.component.ts | |||
@@ -1,10 +1,11 @@ | |||
1 | import { concat, Observable, Subject } from 'rxjs' | 1 | import { concat, Observable } from 'rxjs' |
2 | import { debounceTime, tap, toArray } from 'rxjs/operators' | 2 | import { tap, toArray } from 'rxjs/operators' |
3 | import { Component, OnInit, ViewChild } from '@angular/core' | 3 | import { Component, OnInit, ViewChild } from '@angular/core' |
4 | import { ActivatedRoute, Router } from '@angular/router' | 4 | import { ActivatedRoute, Router } from '@angular/router' |
5 | import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core' | 5 | import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core' |
6 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' | 6 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' |
7 | import { immutableAssign } from '@app/helpers' | 7 | import { immutableAssign } from '@app/helpers' |
8 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | ||
8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 9 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
9 | import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' | 10 | import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' |
10 | import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' | 11 | import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' |
@@ -40,13 +41,21 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
40 | videoActions: DropdownAction<{ video: Video }>[] = [] | 41 | videoActions: DropdownAction<{ video: Video }>[] = [] |
41 | 42 | ||
42 | videos: Video[] = [] | 43 | videos: Video[] = [] |
43 | videosSearch: string | ||
44 | videosSearchChanged = new Subject<string>() | ||
45 | getVideosObservableFunction = this.getVideosObservable.bind(this) | 44 | getVideosObservableFunction = this.getVideosObservable.bind(this) |
45 | |||
46 | sort: VideoSortField = '-publishedAt' | 46 | sort: VideoSortField = '-publishedAt' |
47 | 47 | ||
48 | user: User | 48 | user: User |
49 | 49 | ||
50 | inputFilters: AdvancedInputFilter[] = [ | ||
51 | { | ||
52 | queryParams: { 'search': 'isLive:true' }, | ||
53 | label: $localize`Only live videos` | ||
54 | } | ||
55 | ] | ||
56 | |||
57 | private search: string | ||
58 | |||
50 | constructor ( | 59 | constructor ( |
51 | protected router: Router, | 60 | protected router: Router, |
52 | protected serverService: ServerService, | 61 | protected serverService: ServerService, |
@@ -64,21 +73,15 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
64 | this.buildActions() | 73 | this.buildActions() |
65 | 74 | ||
66 | this.user = this.authService.getUser() | 75 | this.user = this.authService.getUser() |
67 | |||
68 | this.videosSearchChanged | ||
69 | .pipe(debounceTime(500)) | ||
70 | .subscribe(() => { | ||
71 | this.videosSelection.reloadVideos() | ||
72 | }) | ||
73 | } | 76 | } |
74 | 77 | ||
75 | resetSearch () { | 78 | onSearch (search: string) { |
76 | this.videosSearch = '' | 79 | this.search = search |
77 | this.onVideosSearchChanged() | 80 | this.reloadData() |
78 | } | 81 | } |
79 | 82 | ||
80 | onVideosSearchChanged () { | 83 | reloadData () { |
81 | this.videosSearchChanged.next() | 84 | this.videosSelection.reloadVideos() |
82 | } | 85 | } |
83 | 86 | ||
84 | onChangeSortColumn () { | 87 | onChangeSortColumn () { |
@@ -96,7 +99,7 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
96 | getVideosObservable (page: number) { | 99 | getVideosObservable (page: number) { |
97 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | 100 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) |
98 | 101 | ||
99 | return this.videoService.getMyVideos(newPagination, this.sort, this.videosSearch) | 102 | return this.videoService.getMyVideos(newPagination, this.sort, this.search) |
100 | .pipe( | 103 | .pipe( |
101 | tap(res => this.pagination.totalItems = res.total) | 104 | tap(res => this.pagination.totalItems = res.total) |
102 | ) | 105 | ) |
diff --git a/client/src/app/+search/search-filters.component.scss b/client/src/app/+search/search-filters.component.scss index 68ac6d021..cfb7a1d98 100644 --- a/client/src/app/+search/search-filters.component.scss +++ b/client/src/app/+search/search-filters.component.scss | |||
@@ -46,7 +46,7 @@ input[type=submit] { | |||
46 | 46 | ||
47 | font-weight: $font-semibold; | 47 | font-weight: $font-semibold; |
48 | display: inline-block; | 48 | display: inline-block; |
49 | padding: 0 10px 0 10px; | 49 | padding: 0 10px; |
50 | white-space: nowrap; | 50 | white-space: nowrap; |
51 | background: transparent; | 51 | background: transparent; |
52 | 52 | ||
diff --git a/client/src/app/+search/search.component.html b/client/src/app/+search/search.component.html index 65d4b6ecd..130be75fc 100644 --- a/client/src/app/+search/search.component.html +++ b/client/src/app/+search/search.component.html | |||
@@ -33,20 +33,15 @@ | |||
33 | 33 | ||
34 | <ng-container *ngFor="let result of results"> | 34 | <ng-container *ngFor="let result of results"> |
35 | <div *ngIf="isVideoChannel(result)" class="entry video-channel"> | 35 | <div *ngIf="isVideoChannel(result)" class="entry video-channel"> |
36 | <a class="link-avatar" *ngIf="!isExternalChannelUrl()" [routerLink]="getChannelUrl(result)"> | ||
37 | <img [src]="result.avatarUrl" alt="Avatar" /> | ||
38 | </a> | ||
39 | 36 | ||
40 | <a class="link-avatar" *ngIf="isExternalChannelUrl()" [href]="getChannelUrl(result)" target="_blank"> | 37 | <my-actor-avatar [channel]="result" [internalHref]="getInternalChannelUrl(result)" [href]="getExternalChannelUrl(result)"></my-actor-avatar> |
41 | <img [src]="result.avatarUrl" alt="Avatar" /> | ||
42 | </a> | ||
43 | 38 | ||
44 | <div class="video-channel-info"> | 39 | <div class="video-channel-info"> |
45 | <a *ngIf="!isExternalChannelUrl()" [routerLink]="getChannelUrl(result)" class="video-channel-names"> | 40 | <a *ngIf="!isExternalChannelUrl()" [routerLink]="getInternalChannelUrl(result)" class="video-channel-names"> |
46 | <ng-container *ngTemplateOutlet="aContent"></ng-container> | 41 | <ng-container *ngTemplateOutlet="aContent"></ng-container> |
47 | </a> | 42 | </a> |
48 | 43 | ||
49 | <a *ngIf="isExternalChannelUrl()" [href]="getChannelUrl(result)" target="_blank" class="video-channel-names"> | 44 | <a *ngIf="isExternalChannelUrl()" [href]="getExternalChannelUrl(result)" target="_blank" class="video-channel-names"> |
50 | <ng-container *ngTemplateOutlet="aContent"></ng-container> | 45 | <ng-container *ngTemplateOutlet="aContent"></ng-container> |
51 | </a> | 46 | </a> |
52 | 47 | ||
diff --git a/client/src/app/+search/search.component.scss b/client/src/app/+search/search.component.scss index 91c8272d7..a8002ba88 100644 --- a/client/src/app/+search/search.component.scss +++ b/client/src/app/+search/search.component.scss | |||
@@ -5,7 +5,7 @@ | |||
5 | $image-size: min(130px, $video-img-width); | 5 | $image-size: min(130px, $video-img-width); |
6 | $margin-size: ($video-img-width - $image-size) / 2; // So we have the same width than the video miniature | 6 | $margin-size: ($video-img-width - $image-size) / 2; // So we have the same width than the video miniature |
7 | 7 | ||
8 | @include channel-avatar($image-size); | 8 | @include actor-avatar-size($image-size); |
9 | 9 | ||
10 | margin: 0 $margin-size 0 $margin-size; | 10 | margin: 0 $margin-size 0 $margin-size; |
11 | } | 11 | } |
@@ -53,10 +53,8 @@ | |||
53 | max-width: 800px; | 53 | max-width: 800px; |
54 | } | 54 | } |
55 | 55 | ||
56 | .video-channel { | 56 | .video-channel my-actor-avatar { |
57 | img { | 57 | @include build-channel-img-size($video-thumbnail-width); |
58 | @include build-channel-img-size($video-thumbnail-width); | ||
59 | } | ||
60 | } | 58 | } |
61 | 59 | ||
62 | .video-channel-info { | 60 | .video-channel-info { |
@@ -92,14 +90,12 @@ | |||
92 | grid-template-columns: auto 1fr; | 90 | grid-template-columns: auto 1fr; |
93 | grid-template-rows: auto auto; | 91 | grid-template-rows: auto auto; |
94 | 92 | ||
95 | .link-avatar { | 93 | my-actor-avatar { |
94 | @include build-channel-img-size($video-thumbnail-medium-width); | ||
95 | |||
96 | grid-column: 1; | 96 | grid-column: 1; |
97 | grid-row: 1 / -1; | 97 | grid-row: 1 / -1; |
98 | } | 98 | } |
99 | |||
100 | img { | ||
101 | @include build-channel-img-size($video-thumbnail-medium-width); | ||
102 | } | ||
103 | } | 99 | } |
104 | 100 | ||
105 | .video-channel-info { | 101 | .video-channel-info { |
@@ -115,7 +111,7 @@ | |||
115 | } | 111 | } |
116 | 112 | ||
117 | @include on-mobile-main-col { | 113 | @include on-mobile-main-col { |
118 | .video-channel img { | 114 | .video-channel my-actor-avatar { |
119 | @include build-channel-img-size($video-thumbnail-small-width); | 115 | @include build-channel-img-size($video-thumbnail-small-width); |
120 | } | 116 | } |
121 | } | 117 | } |
diff --git a/client/src/app/+search/search.component.ts b/client/src/app/+search/search.component.ts index 2be952e16..ecede19a3 100644 --- a/client/src/app/+search/search.component.ts +++ b/client/src/app/+search/search.component.ts | |||
@@ -132,10 +132,6 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
132 | return 'internal' | 132 | return 'internal' |
133 | } | 133 | } |
134 | 134 | ||
135 | isExternalChannelUrl () { | ||
136 | return this.getVideoLinkType() === 'external' | ||
137 | } | ||
138 | |||
139 | search () { | 135 | search () { |
140 | forkJoin([ | 136 | forkJoin([ |
141 | this.getVideosObs(), | 137 | this.getVideosObs(), |
@@ -200,17 +196,33 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
200 | this.results = this.results.filter(r => !this.isVideo(r) || r.id !== video.id) | 196 | this.results = this.results.filter(r => !this.isVideo(r) || r.id !== video.id) |
201 | } | 197 | } |
202 | 198 | ||
203 | getChannelUrl (channel: VideoChannel) { | 199 | isExternalChannelUrl () { |
200 | return this.getVideoLinkType() === 'external' | ||
201 | } | ||
202 | |||
203 | getExternalChannelUrl (channel: VideoChannel) { | ||
204 | // Same algorithm than videos | 204 | // Same algorithm than videos |
205 | if (this.getVideoLinkType() === 'external') { | 205 | if (this.getVideoLinkType() === 'external') { |
206 | return channel.url | 206 | return channel.url |
207 | } | 207 | } |
208 | 208 | ||
209 | if (this.getVideoLinkType() === 'internal') { | 209 | // lazy-load or internal |
210 | return undefined | ||
211 | } | ||
212 | |||
213 | getInternalChannelUrl (channel: VideoChannel) { | ||
214 | const linkType = this.getVideoLinkType() | ||
215 | |||
216 | if (linkType === 'internal') { | ||
210 | return [ '/video-channels', channel.nameWithHost ] | 217 | return [ '/video-channels', channel.nameWithHost ] |
211 | } | 218 | } |
212 | 219 | ||
213 | return [ '/search/lazy-load-channel', { url: channel.url } ] | 220 | if (linkType === 'lazy-load') { |
221 | return [ '/search/lazy-load-channel', { url: channel.url } ] | ||
222 | } | ||
223 | |||
224 | // external | ||
225 | return undefined | ||
214 | } | 226 | } |
215 | 227 | ||
216 | hideActions () { | 228 | hideActions () { |
diff --git a/client/src/app/+search/search.module.ts b/client/src/app/+search/search.module.ts index e85ae07d0..390833abc 100644 --- a/client/src/app/+search/search.module.ts +++ b/client/src/app/+search/search.module.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module' | ||
2 | import { SharedFormModule } from '@app/shared/shared-forms' | 3 | import { SharedFormModule } from '@app/shared/shared-forms' |
3 | import { SharedMainModule } from '@app/shared/shared-main' | 4 | import { SharedMainModule } from '@app/shared/shared-main' |
4 | import { SharedSearchModule } from '@app/shared/shared-search' | 5 | import { SharedSearchModule } from '@app/shared/shared-search' |
@@ -18,6 +19,7 @@ import { VideoLazyLoadResolver } from './video-lazy-load.resolver' | |||
18 | SharedMainModule, | 19 | SharedMainModule, |
19 | SharedSearchModule, | 20 | SharedSearchModule, |
20 | SharedFormModule, | 21 | SharedFormModule, |
22 | SharedActorImageModule, | ||
21 | SharedUserSubscriptionModule, | 23 | SharedUserSubscriptionModule, |
22 | SharedVideoMiniatureModule | 24 | SharedVideoMiniatureModule |
23 | ], | 25 | ], |
diff --git a/client/src/app/+signup/+register/register.component.scss b/client/src/app/+signup/+register/register.component.scss index 16ba9e2c0..f6a846ffa 100644 --- a/client/src/app/+signup/+register/register.component.scss +++ b/client/src/app/+signup/+register/register.component.scss | |||
@@ -84,7 +84,7 @@ button { | |||
84 | border-color: pvar(--mainColor) transparent transparent transparent; | 84 | border-color: pvar(--mainColor) transparent transparent transparent; |
85 | } | 85 | } |
86 | 86 | ||
87 | & + div { | 87 | + div { |
88 | font-size: 15px; | 88 | font-size: 15px; |
89 | } | 89 | } |
90 | } | 90 | } |
diff --git a/client/src/app/+signup/shared/signup-success.component.scss b/client/src/app/+signup/shared/signup-success.component.scss index fbc27c8bc..b302366e2 100644 --- a/client/src/app/+signup/shared/signup-success.component.scss +++ b/client/src/app/+signup/shared/signup-success.component.scss | |||
@@ -9,19 +9,16 @@ svg { | |||
9 | stroke-dashoffset: 0; | 9 | stroke-dashoffset: 0; |
10 | 10 | ||
11 | &.circle { | 11 | &.circle { |
12 | -webkit-animation: dash .9s ease-in-out; | ||
13 | animation: dash .9s ease-in-out; | 12 | animation: dash .9s ease-in-out; |
14 | } | 13 | } |
15 | 14 | ||
16 | &.line { | 15 | &.line { |
17 | stroke-dashoffset: 1000; | 16 | stroke-dashoffset: 1000; |
18 | -webkit-animation: dash .9s .35s ease-in-out forwards; | ||
19 | animation: dash .9s .35s ease-in-out forwards; | 17 | animation: dash .9s .35s ease-in-out forwards; |
20 | } | 18 | } |
21 | 19 | ||
22 | &.check { | 20 | &.check { |
23 | stroke-dashoffset: -100; | 21 | stroke-dashoffset: -100; |
24 | -webkit-animation: dash-check .9s .35s ease-in-out forwards; | ||
25 | animation: dash-check .9s .35s ease-in-out forwards; | 22 | animation: dash-check .9s .35s ease-in-out forwards; |
26 | } | 23 | } |
27 | } | 24 | } |
@@ -38,16 +35,6 @@ svg { | |||
38 | text-align: center; | 35 | text-align: center; |
39 | } | 36 | } |
40 | 37 | ||
41 | |||
42 | @-webkit-keyframes dash { | ||
43 | 0% { | ||
44 | stroke-dashoffset: 1000; | ||
45 | } | ||
46 | 100% { | ||
47 | stroke-dashoffset: 0; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | @keyframes dash { | 38 | @keyframes dash { |
52 | 0% { | 39 | 0% { |
53 | stroke-dashoffset: 1000; | 40 | stroke-dashoffset: 1000; |
@@ -57,15 +44,6 @@ svg { | |||
57 | } | 44 | } |
58 | } | 45 | } |
59 | 46 | ||
60 | @-webkit-keyframes dash-check { | ||
61 | 0% { | ||
62 | stroke-dashoffset: -100; | ||
63 | } | ||
64 | 100% { | ||
65 | stroke-dashoffset: 900; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | @keyframes dash-check { | 47 | @keyframes dash-check { |
70 | 0% { | 48 | 0% { |
71 | stroke-dashoffset: -100; | 49 | stroke-dashoffset: -100; |
diff --git a/client/src/app/+video-channels/video-channels.component.html b/client/src/app/+video-channels/video-channels.component.html index 9308d5bb6..b4d81fe39 100644 --- a/client/src/app/+video-channels/video-channels.component.html +++ b/client/src/app/+video-channels/video-channels.component.html | |||
@@ -6,16 +6,16 @@ | |||
6 | <div class="channel-info"> | 6 | <div class="channel-info"> |
7 | 7 | ||
8 | <ng-template #buttonsTemplate> | 8 | <ng-template #buttonsTemplate> |
9 | <a *ngIf="isManageable()" [routerLink]="[ '/my-library/video-channels/update', videoChannel.nameWithHost ]" class="peertube-button-link orange-button" i18n> | 9 | <a *ngIf="isManageable()" [routerLink]="[ '/my-library/video-channels/update', videoChannel.nameWithHost ]" class="peertube-button-link orange-button" i18n> |
10 | Manage channel | 10 | Manage channel |
11 | </a> | 11 | </a> |
12 | 12 | ||
13 | <my-subscribe-button *ngIf="!isManageable()" #subscribeButton [videoChannels]="[videoChannel]"></my-subscribe-button> | 13 | <my-subscribe-button *ngIf="!isManageable()" #subscribeButton [videoChannels]="[videoChannel]"></my-subscribe-button> |
14 | 14 | ||
15 | <button *ngIf="videoChannel.support" (click)="showSupportModal()" class="support-button peertube-button orange-button-inverted"> | 15 | <button *ngIf="videoChannel.support" (click)="showSupportModal()" class="support-button peertube-button orange-button-inverted"> |
16 | <my-global-icon iconName="support" aria-hidden="true"></my-global-icon> | 16 | <my-global-icon iconName="support" aria-hidden="true"></my-global-icon> |
17 | <span class="icon-text" i18n>Support</span> | 17 | <span class="icon-text" i18n>Support</span> |
18 | </button> | 18 | </button> |
19 | </ng-template> | 19 | </ng-template> |
20 | 20 | ||
21 | <ng-template #ownerTemplate> | 21 | <ng-template #ownerTemplate> |
@@ -23,7 +23,7 @@ | |||
23 | <div class="section-label" i18n>OWNER ACCOUNT</div> | 23 | <div class="section-label" i18n>OWNER ACCOUNT</div> |
24 | 24 | ||
25 | <div class="avatar-row"> | 25 | <div class="avatar-row"> |
26 | <my-account-avatar [account]="videoChannel.ownerAccount" [internalHref]="getAccountUrl()" size="120"></my-account-avatar> | 26 | <my-actor-avatar class="account-avatar" [account]="videoChannel.ownerAccount" [internalHref]="getAccountUrl()"></my-actor-avatar> |
27 | 27 | ||
28 | <div class="actor-info"> | 28 | <div class="actor-info"> |
29 | <h4> | 29 | <h4> |
@@ -49,7 +49,7 @@ | |||
49 | </ng-template> | 49 | </ng-template> |
50 | 50 | ||
51 | <div class="channel-avatar-row"> | 51 | <div class="channel-avatar-row"> |
52 | <img class="channel-avatar" [src]="videoChannel.avatarUrl" alt="Avatar" /> | 52 | <my-actor-avatar class="main-avatar" [channel]="videoChannel"></my-actor-avatar> |
53 | 53 | ||
54 | <div> | 54 | <div> |
55 | <div class="section-label" i18n>VIDEO CHANNEL</div> | 55 | <div class="section-label" i18n>VIDEO CHANNEL</div> |
diff --git a/client/src/app/+video-channels/video-channels.component.scss b/client/src/app/+video-channels/video-channels.component.scss index e946707ef..470f64878 100644 --- a/client/src/app/+video-channels/video-channels.component.scss +++ b/client/src/app/+video-channels/video-channels.component.scss | |||
@@ -107,8 +107,8 @@ | |||
107 | display: flex; | 107 | display: flex; |
108 | margin-bottom: 15px; | 108 | margin-bottom: 15px; |
109 | 109 | ||
110 | img { | 110 | .account-avatar { |
111 | @include avatar(48px); | 111 | @include actor-avatar-size(48px); |
112 | } | 112 | } |
113 | 113 | ||
114 | .actor-info { | 114 | .actor-info { |
@@ -131,10 +131,10 @@ | |||
131 | } | 131 | } |
132 | 132 | ||
133 | .owner-description { | 133 | .owner-description { |
134 | @include fade-text(120px, pvar(--mainBackgroundColor)); | ||
135 | |||
134 | max-height: 140px; | 136 | max-height: 140px; |
135 | word-break: break-word; | 137 | word-break: break-word; |
136 | |||
137 | @include fade-text(120px, pvar(--mainBackgroundColor)); | ||
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
@@ -150,7 +150,7 @@ | |||
150 | } | 150 | } |
151 | 151 | ||
152 | .copy-button { | 152 | .copy-button { |
153 | border: none; | 153 | border: 0; |
154 | } | 154 | } |
155 | 155 | ||
156 | @media screen and (max-width: 1400px) { | 156 | @media screen and (max-width: 1400px) { |
@@ -178,9 +178,9 @@ | |||
178 | } | 178 | } |
179 | 179 | ||
180 | .channel-description:not(.expanded) { | 180 | .channel-description:not(.expanded) { |
181 | max-height: 70px; | ||
182 | |||
183 | @include fade-text(30px, pvar(--channelBackgroundColor)); | 181 | @include fade-text(30px, pvar(--channelBackgroundColor)); |
182 | |||
183 | max-height: 70px; | ||
184 | } | 184 | } |
185 | 185 | ||
186 | .show-more { | 186 | .show-more { |
@@ -220,10 +220,10 @@ | |||
220 | } | 220 | } |
221 | 221 | ||
222 | .owner-description { | 222 | .owner-description { |
223 | @include fade-text(30px, pvar(--mainBackgroundColor)); | ||
224 | |||
223 | grid-column: 2; | 225 | grid-column: 2; |
224 | max-height: 70px; | 226 | max-height: 70px; |
225 | |||
226 | @include fade-text(30px, pvar(--mainBackgroundColor)); | ||
227 | } | 227 | } |
228 | 228 | ||
229 | .view-account { | 229 | .view-account { |
@@ -289,8 +289,8 @@ | |||
289 | margin-top: -5px; | 289 | margin-top: -5px; |
290 | } | 290 | } |
291 | 291 | ||
292 | img { | 292 | .account-avatar { |
293 | @include channel-avatar(64px); | 293 | @include actor-avatar-size(64px); |
294 | 294 | ||
295 | margin: -30px 0 0 15px; | 295 | margin: -30px 0 0 15px; |
296 | } | 296 | } |
diff --git a/client/src/app/+video-channels/video-channels.module.ts b/client/src/app/+video-channels/video-channels.module.ts index 2e387f401..35c39cc2e 100644 --- a/client/src/app/+video-channels/video-channels.module.ts +++ b/client/src/app/+video-channels/video-channels.module.ts | |||
@@ -10,7 +10,7 @@ import { VideoChannelPlaylistsComponent } from './video-channel-playlists/video- | |||
10 | import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component' | 10 | import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component' |
11 | import { VideoChannelsRoutingModule } from './video-channels-routing.module' | 11 | import { VideoChannelsRoutingModule } from './video-channels-routing.module' |
12 | import { VideoChannelsComponent } from './video-channels.component' | 12 | import { VideoChannelsComponent } from './video-channels.component' |
13 | import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/shared-account-avatar.module' | 13 | import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' |
14 | 14 | ||
15 | @NgModule({ | 15 | @NgModule({ |
16 | imports: [ | 16 | imports: [ |
@@ -23,7 +23,7 @@ import { SharedAccountAvatarModule } from '../shared/shared-account-avatar/share | |||
23 | SharedUserSubscriptionModule, | 23 | SharedUserSubscriptionModule, |
24 | SharedGlobalIconModule, | 24 | SharedGlobalIconModule, |
25 | SharedSupportModal, | 25 | SharedSupportModal, |
26 | SharedAccountAvatarModule | 26 | SharedActorImageModule |
27 | ], | 27 | ], |
28 | 28 | ||
29 | declarations: [ | 29 | declarations: [ |
diff --git a/client/src/app/+videos/+video-edit/shared/video-caption-add-modal.component.scss b/client/src/app/+videos/+video-edit/shared/video-caption-add-modal.component.scss index 0958b5f80..a85cf444c 100644 --- a/client/src/app/+videos/+video-edit/shared/video-caption-add-modal.component.scss +++ b/client/src/app/+videos/+video-edit/shared/video-caption-add-modal.component.scss | |||
@@ -16,6 +16,6 @@ label { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | .warning-replace-caption { | 18 | .warning-replace-caption { |
19 | color: red; | 19 | color: #ff0000; |
20 | margin-top: 10px; | 20 | margin-top: 10px; |
21 | } \ No newline at end of file | 21 | } |
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.html b/client/src/app/+videos/+video-edit/shared/video-edit.component.html index 6fe52af67..094b4d3b3 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.html | |||
@@ -132,7 +132,7 @@ | |||
132 | </ng-template> | 132 | </ng-template> |
133 | 133 | ||
134 | <ng-template ptTemplate="help"> | 134 | <ng-template ptTemplate="help"> |
135 | <ng-container i18n>Some instances do not list videos containing mature or explicit content by default.</ng-container> | 135 | <ng-container i18n>Some instances hide videos containing mature or explicit content by default.</ng-container> |
136 | </ng-template> | 136 | </ng-template> |
137 | </my-peertube-checkbox> | 137 | </my-peertube-checkbox> |
138 | 138 | ||
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.scss b/client/src/app/+videos/+video-edit/shared/video-edit.component.scss index 0b70b0270..bc32d7964 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.component.scss +++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.scss | |||
@@ -150,7 +150,7 @@ p-calendar { | |||
150 | @include media-breakpoint-up(md) { | 150 | @include media-breakpoint-up(md) { |
151 | @include make-col(7); | 151 | @include make-col(7); |
152 | 152 | ||
153 | & + .col-video-edit { | 153 | + .col-video-edit { |
154 | @include make-col(5); | 154 | @include make-col(5); |
155 | } | 155 | } |
156 | } | 156 | } |
@@ -158,7 +158,7 @@ p-calendar { | |||
158 | @include media-breakpoint-up(xl) { | 158 | @include media-breakpoint-up(xl) { |
159 | @include make-col(8); | 159 | @include make-col(8); |
160 | 160 | ||
161 | & + .col-video-edit { | 161 | + .col-video-edit { |
162 | @include make-col(4); | 162 | @include make-col(4); |
163 | } | 163 | } |
164 | } | 164 | } |
@@ -169,7 +169,7 @@ p-calendar { | |||
169 | @include media-breakpoint-up(md) { | 169 | @include media-breakpoint-up(md) { |
170 | @include make-col(8); | 170 | @include make-col(8); |
171 | 171 | ||
172 | & + .col-video-edit { | 172 | + .col-video-edit { |
173 | @include make-col(4); | 173 | @include make-col(4); |
174 | } | 174 | } |
175 | } | 175 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-send.scss b/client/src/app/+videos/+video-edit/video-add-components/video-send.scss index 17c5f63e9..dc9153b2b 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-send.scss +++ b/client/src/app/+videos/+video-edit/video-add-components/video-send.scss | |||
@@ -6,7 +6,7 @@ $width-size: 190px; | |||
6 | .alert.alert-danger { | 6 | .alert.alert-danger { |
7 | text-align: center; | 7 | text-align: center; |
8 | 8 | ||
9 | & > div { | 9 | > div { |
10 | font-weight: $font-semibold; | 10 | font-weight: $font-semibold; |
11 | } | 11 | } |
12 | } | 12 | } |
@@ -17,10 +17,10 @@ $width-size: 190px; | |||
17 | align-items: center; | 17 | align-items: center; |
18 | 18 | ||
19 | .upload-icon { | 19 | .upload-icon { |
20 | @include apply-svg-color(#C6C6C6); | ||
21 | |||
20 | width: 90px; | 22 | width: 90px; |
21 | margin-bottom: 25px; | 23 | margin-bottom: 25px; |
22 | |||
23 | @include apply-svg-color(#C6C6C6); | ||
24 | } | 24 | } |
25 | 25 | ||
26 | .peertube-select-container { | 26 | .peertube-select-container { |
diff --git a/client/src/app/+videos/+video-edit/video-add.component.scss b/client/src/app/+videos/+video-edit/video-add.component.scss index 1ebee946b..35bca24d0 100644 --- a/client/src/app/+videos/+video-edit/video-add.component.scss +++ b/client/src/app/+videos/+video-edit/video-add.component.scss | |||
@@ -44,7 +44,7 @@ $nav-link-height: 40px; | |||
44 | 44 | ||
45 | ::ng-deep .video-add-nav { | 45 | ::ng-deep .video-add-nav { |
46 | border-bottom: $border-width $border-type $border-color; | 46 | border-bottom: $border-width $border-type $border-color; |
47 | margin: 20px 0 0 0 !important; | 47 | margin: 20px 0 0 !important; |
48 | 48 | ||
49 | &.hide-nav { | 49 | &.hide-nav { |
50 | display: none !important; | 50 | display: none !important; |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.html b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.html index 7bd9b7c90..42adfed8d 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.html +++ b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <form novalidate [formGroup]="form" (ngSubmit)="formValidated()"> | 1 | <form novalidate [formGroup]="form" (ngSubmit)="formValidated()"> |
2 | <div class="avatar-and-textarea"> | 2 | <div class="avatar-and-textarea"> |
3 | <my-account-avatar [account]="user?.account" size="25"></my-account-avatar> | 3 | <my-actor-avatar [account]="user?.account" size="25"></my-actor-avatar> |
4 | 4 | ||
5 | <div class="form-group"> | 5 | <div class="form-group"> |
6 | <textarea i18n-placeholder placeholder="Add comment..." myAutoResize | 6 | <textarea i18n-placeholder placeholder="Add comment..." myAutoResize |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.scss b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.scss index 1aa9255c2..7743bd41d 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.scss +++ b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.scss | |||
@@ -13,8 +13,7 @@ form { | |||
13 | display: flex; | 13 | display: flex; |
14 | margin-bottom: 10px; | 14 | margin-bottom: 10px; |
15 | 15 | ||
16 | my-account-avatar { | 16 | my-actor-avatar { |
17 | vertical-align: top; | ||
18 | margin-right: 10px; | 17 | margin-right: 10px; |
19 | } | 18 | } |
20 | 19 | ||
@@ -32,7 +31,7 @@ form { | |||
32 | padding-right: $markdown-icon-width + 15px !important; | 31 | padding-right: $markdown-icon-width + 15px !important; |
33 | 32 | ||
34 | @media screen and (max-width: 600px) { | 33 | @media screen and (max-width: 600px) { |
35 | padding-right: $markdown-icon-width + 19px !important; | 34 | padding-right: $markdown-icon-width + 19px !important; |
36 | } | 35 | } |
37 | 36 | ||
38 | &:focus::placeholder { | 37 | &:focus::placeholder { |
@@ -58,7 +57,9 @@ form { | |||
58 | } | 57 | } |
59 | } | 58 | } |
60 | 59 | ||
61 | &:focus, &:active, &:hover { | 60 | &:focus, |
61 | &:active, | ||
62 | &:hover { | ||
62 | my-global-icon svg { | 63 | my-global-icon svg { |
63 | background-color: #C6C6C6; | 64 | background-color: #C6C6C6; |
64 | color: pvar(--mainBackgroundColor); | 65 | color: pvar(--mainBackgroundColor); |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.html b/client/src/app/+videos/+video-watch/comment/video-comment.component.html index 2b0739261..d7ba40ef6 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.html +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.html | |||
@@ -1,12 +1,10 @@ | |||
1 | <div *ngIf="isCommentDisplayed()" class="root-comment"> | 1 | <div *ngIf="isCommentDisplayed()" class="root-comment" [ngClass]="{ 'is-child': isChild() }"> |
2 | <div class="left"> | 2 | <div class="left"> |
3 | <my-account-avatar *ngIf="!comment.isDeleted" [href]="comment.account.url" [account]="comment.account"></my-account-avatar> | 3 | <my-actor-avatar *ngIf="!comment.isDeleted" [href]="comment.account.url" [account]="comment.account"></my-actor-avatar> |
4 | <div class="vertical-border"></div> | 4 | <div class="vertical-border"></div> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="right" [ngClass]="{ 'mb-3': firstInThread }"> | 7 | <div class="right" [ngClass]="{ 'mb-3': firstInThread }"> |
8 | <span *ngIf="comment.isDeleted" class="comment-avatar"></span> | ||
9 | |||
10 | <div class="comment"> | 8 | <div class="comment"> |
11 | <ng-container *ngIf="!comment.isDeleted"> | 9 | <ng-container *ngIf="!comment.isDeleted"> |
12 | <div *ngIf="highlightedComment === true" class="highlighted-comment" i18n>Highlighted comment</div> | 10 | <div *ngIf="highlightedComment === true" class="highlighted-comment" i18n>Highlighted comment</div> |
@@ -68,7 +66,7 @@ | |||
68 | [textValue]="redraftValue" | 66 | [textValue]="redraftValue" |
69 | ></my-video-comment-add> | 67 | ></my-video-comment-add> |
70 | 68 | ||
71 | <div *ngIf="commentTree" class="children"> | 69 | <div *ngIf="commentTree"> |
72 | <div *ngFor="let commentChild of commentTree.children"> | 70 | <div *ngFor="let commentChild of commentTree.children"> |
73 | <my-video-comment | 71 | <my-video-comment |
74 | [comment]="commentChild.comment" | 72 | [comment]="commentChild.comment" |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.scss b/client/src/app/+videos/+video-watch/comment/video-comment.component.scss index cf33a5b0e..a4d2e237c 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.scss +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.scss | |||
@@ -24,6 +24,10 @@ | |||
24 | } | 24 | } |
25 | } | 25 | } |
26 | 26 | ||
27 | my-actor-avatar { | ||
28 | @include actor-avatar-size(36px); | ||
29 | } | ||
30 | |||
27 | .comment { | 31 | .comment { |
28 | flex-grow: 1; | 32 | flex-grow: 1; |
29 | // Fix word-wrap with flex | 33 | // Fix word-wrap with flex |
@@ -58,7 +62,7 @@ | |||
58 | display: inline-flex; | 62 | display: inline-flex; |
59 | padding-right: 6px; | 63 | padding-right: 6px; |
60 | padding-left: 6px; | 64 | padding-left: 6px; |
61 | color: white !important; | 65 | color: #fff !important; |
62 | } | 66 | } |
63 | 67 | ||
64 | .comment-account { | 68 | .comment-account { |
@@ -129,7 +133,10 @@ | |||
129 | cursor: pointer; | 133 | cursor: pointer; |
130 | margin-right: 10px; | 134 | margin-right: 10px; |
131 | 135 | ||
132 | &:hover, &:active, &:focus, &:focus-visible { | 136 | &:hover, |
137 | &:active, | ||
138 | &:focus, | ||
139 | &:focus-visible { | ||
133 | color: pvar(--mainForegroundColor); | 140 | color: pvar(--mainForegroundColor); |
134 | } | 141 | } |
135 | } | 142 | } |
@@ -148,10 +155,10 @@ my-video-comment-add { | |||
148 | } | 155 | } |
149 | } | 156 | } |
150 | 157 | ||
151 | .children { | 158 | .is-child { |
152 | // Reduce avatars size for replies | 159 | // Reduce avatars size for replies |
153 | .comment-avatar { | 160 | my-actor-avatar { |
154 | @include avatar(25px); | 161 | @include actor-avatar-size(25px); |
155 | } | 162 | } |
156 | 163 | ||
157 | .left { | 164 | .left { |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts index dd3db0c65..fd379e80e 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts | |||
@@ -138,6 +138,10 @@ export class VideoCommentComponent implements OnInit, OnChanges { | |||
138 | (this.commentTree?.hasDisplayedChildren) // Or this is a reply that have other replies | 138 | (this.commentTree?.hasDisplayedChildren) // Or this is a reply that have other replies |
139 | } | 139 | } |
140 | 140 | ||
141 | isChild () { | ||
142 | return this.parentComments.length !== 0 | ||
143 | } | ||
144 | |||
141 | private getUserIfNeeded (account: Account) { | 145 | private getUserIfNeeded (account: Account) { |
142 | if (!account.userId) return | 146 | if (!account.userId) return |
143 | if (!this.authService.isLoggedIn()) return | 147 | if (!this.authService.isLoggedIn()) return |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comments.component.scss b/client/src/app/+videos/+video-watch/comment/video-comments.component.scss index e6778e1a9..a7e858069 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comments.component.scss +++ b/client/src/app/+videos/+video-watch/comment/video-comments.component.scss | |||
@@ -11,7 +11,8 @@ | |||
11 | cursor: pointer; | 11 | cursor: pointer; |
12 | } | 12 | } |
13 | 13 | ||
14 | .glyphicon, .comment-thread-loading { | 14 | .glyphicon, |
15 | .comment-thread-loading { | ||
15 | margin-right: 5px; | 16 | margin-right: 5px; |
16 | display: inline-block; | 17 | display: inline-block; |
17 | font-size: 13px; | 18 | font-size: 13px; |
@@ -40,7 +41,7 @@ | |||
40 | #dropdown-sort-comments { | 41 | #dropdown-sort-comments { |
41 | font-weight: 600; | 42 | font-weight: 600; |
42 | text-transform: uppercase; | 43 | text-transform: uppercase; |
43 | border: none; | 44 | border: 0; |
44 | transform: translateY(-7%); | 45 | transform: translateY(-7%); |
45 | } | 46 | } |
46 | 47 | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html index e0e9f92e7..e1040fead 100644 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html +++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html | |||
@@ -15,7 +15,9 @@ | |||
15 | <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> | 15 | <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> |
16 | <my-video-miniature | 16 | <my-video-miniature |
17 | [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" [displayAsRow]="displayAsRow" | 17 | [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" [displayAsRow]="displayAsRow" |
18 | (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()"> | 18 | (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()" |
19 | actorImageSize="32" | ||
20 | > | ||
19 | </my-video-miniature> | 21 | </my-video-miniature> |
20 | 22 | ||
21 | <hr *ngIf="!playlist && i == 0 && length > 1" /> | 23 | <hr *ngIf="!playlist && i == 0 && length > 1" /> |
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss index c9fae6f27..5e0373afc 100644 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss +++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss | |||
@@ -8,7 +8,8 @@ | |||
8 | margin-bottom: 25px; | 8 | margin-bottom: 25px; |
9 | flex-wrap: wrap-reverse; | 9 | flex-wrap: wrap-reverse; |
10 | 10 | ||
11 | .title-page.active, .title-page.title-page-single { | 11 | .title-page.active, |
12 | .title-page.title-page-single { | ||
12 | margin-bottom: unset; | 13 | margin-bottom: unset; |
13 | margin-right: .5rem !important; | 14 | margin-right: .5rem !important; |
14 | } | 15 | } |
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.html b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html index a02373f2d..5f149cbd1 100644 --- a/client/src/app/+videos/+video-watch/video-avatar-channel.component.html +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html | |||
@@ -1,21 +1,11 @@ | |||
1 | <div class="wrapper" [ngClass]="'avatar-' + size"> | 1 | <div class="wrapper" [ngClass]="{ 'generic-channel': genericChannel }"> |
2 | <ng-container *ngIf="!isChannelAvatarNull() && !genericChannel"> | 2 | <my-actor-avatar |
3 | <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle"> | 3 | class="channel" [channel]="video.channel" |
4 | <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" /> | 4 | [internalHref]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle" |
5 | </a> | 5 | ></my-actor-avatar> |
6 | 6 | ||
7 | <my-account-avatar [account]="video.account" [title]="accountLinkTitle" [internalHref]="[ '/accounts', video.byAccount ]"></my-account-avatar> | 7 | <my-actor-avatar |
8 | </ng-container> | 8 | class="account" [account]="video.account" |
9 | 9 | [internalHref]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle"> | |
10 | <ng-container *ngIf="!isChannelAvatarNull() && genericChannel"> | 10 | </my-actor-avatar> |
11 | <my-account-avatar [account]="video.account" [title]="accountLinkTitle" [internalHref]="[ '/accounts', video.byAccount ]"></my-account-avatar> | ||
12 | |||
13 | <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle"> | ||
14 | <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" /> | ||
15 | </a> | ||
16 | </ng-container> | ||
17 | |||
18 | <ng-container *ngIf="isChannelAvatarNull()"> | ||
19 | <my-account-avatar [account]="video.account" [title]="accountLinkTitle" [internalHref]="[ '/accounts', video.byAccount ]"></my-account-avatar> | ||
20 | </ng-container> | ||
21 | </div> | 11 | </div> |
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss index 4998e85fa..20e32240c 100644 --- a/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss | |||
@@ -1,44 +1,42 @@ | |||
1 | @import '_mixins'; | 1 | @import '_mixins'; |
2 | 2 | ||
3 | @mixin main { | ||
4 | @include actor-avatar-size(35px); | ||
5 | } | ||
6 | |||
7 | @mixin secondary { | ||
8 | height: 60%; | ||
9 | width: 60%; | ||
10 | position: absolute; | ||
11 | bottom: -5px; | ||
12 | right: -5px; | ||
13 | background-color: rgba(0, 0, 0, 0); | ||
14 | } | ||
15 | |||
3 | .wrapper { | 16 | .wrapper { |
4 | $avatar-size: 35px; | 17 | @include actor-avatar-size(35px); |
5 | 18 | ||
6 | width: $avatar-size; | ||
7 | height: $avatar-size; | ||
8 | position: relative; | 19 | position: relative; |
9 | margin-right: 5px; | 20 | margin-right: 5px; |
10 | margin-bottom: 5px; | 21 | margin-bottom: 5px; |
11 | 22 | ||
12 | &.avatar-sm { | 23 | &.generic-channel { |
13 | width: 28px; | 24 | .account { |
14 | height: 28px; | 25 | @include main(); |
15 | margin-bottom: 3px; | 26 | } |
16 | } | ||
17 | 27 | ||
18 | a { | 28 | .channel { |
19 | @include disable-outline; | 29 | display: none !important; |
30 | } | ||
20 | } | 31 | } |
21 | 32 | ||
22 | a img { | 33 | &:not(.generic-channel) { |
23 | height: 100%; | 34 | .account { |
24 | object-fit: cover; | 35 | @include secondary(); |
25 | position: absolute; | ||
26 | top:50%; | ||
27 | left:50%; | ||
28 | transform: translate(-50%,-50%); | ||
29 | border-radius: 5px; | ||
30 | |||
31 | &:not(.channel-avatar) { | ||
32 | border-radius: 50%; | ||
33 | } | 36 | } |
34 | } | ||
35 | 37 | ||
36 | a:nth-of-type(2) img { | 38 | .channel { |
37 | height: 60%; | 39 | @include main(); |
38 | width: 60%; | 40 | } |
39 | border: 2px solid pvar(--mainBackgroundColor); | ||
40 | transform: translateX(15%); | ||
41 | position: relative; | ||
42 | background-color: pvar(--mainBackgroundColor); | ||
43 | } | 41 | } |
44 | } | 42 | } |
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts index 0b6e796df..63edd7bad 100644 --- a/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts | |||
@@ -10,7 +10,6 @@ export class VideoAvatarChannelComponent implements OnInit { | |||
10 | @Input() video: Video | 10 | @Input() video: Video |
11 | @Input() byAccount: string | 11 | @Input() byAccount: string |
12 | 12 | ||
13 | @Input() size: 'md' | 'sm' = 'md' | ||
14 | @Input() genericChannel: boolean | 13 | @Input() genericChannel: boolean |
15 | 14 | ||
16 | channelLinkTitle = '' | 15 | channelLinkTitle = '' |
diff --git a/client/src/app/+videos/+video-watch/video-watch-playlist.component.scss b/client/src/app/+videos/+video-watch/video-watch-playlist.component.scss index 0b0a2a899..b3f93b83c 100644 --- a/client/src/app/+videos/+video-watch/video-watch-playlist.component.scss +++ b/client/src/app/+videos/+video-watch/video-watch-playlist.component.scss | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | my-global-icon { | 46 | my-global-icon { |
47 | &:not(.active) { | 47 | &:not(.active) { |
48 | opacity: .5 | 48 | opacity: .5; |
49 | } | 49 | } |
50 | 50 | ||
51 | ::ng-deep { | 51 | ::ng-deep { |
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.html b/client/src/app/+videos/+video-watch/video-watch.component.html index eadb2148a..4779602d2 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.html +++ b/client/src/app/+videos/+video-watch/video-watch.component.html | |||
@@ -79,7 +79,7 @@ | |||
79 | <span [innerHTML]="getRatePopoverText()"></span> | 79 | <span [innerHTML]="getRatePopoverText()"></span> |
80 | </ng-template> | 80 | </ng-template> |
81 | 81 | ||
82 | <div class="video-actions fullWidth justify-content-end"> | 82 | <div class="video-actions full-width justify-content-end"> |
83 | <button | 83 | <button |
84 | [ngbPopover]="getRatePopoverText() && ratePopoverText" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()" (keyup.enter)="setLike()" | 84 | [ngbPopover]="getRatePopoverText() && ratePopoverText" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()" (keyup.enter)="setLike()" |
85 | class="action-button action-button-like" [attr.aria-pressed]="userRating === 'like'" [attr.aria-label]="tooltipLike" | 85 | class="action-button action-button-like" [attr.aria-pressed]="userRating === 'like'" [attr.aria-label]="tooltipLike" |
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.scss b/client/src/app/+videos/+video-watch/video-watch.component.scss index e8ad10a11..301762695 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.scss +++ b/client/src/app/+videos/+video-watch/video-watch.component.scss | |||
@@ -6,12 +6,12 @@ | |||
6 | $player-factor: 16/9; | 6 | $player-factor: 16/9; |
7 | $video-info-margin-left: 44px; | 7 | $video-info-margin-left: 44px; |
8 | 8 | ||
9 | @function getPlayerHeight($width){ | 9 | @function getPlayerHeight ($width) { |
10 | @return calc(#{$width} / #{$player-factor}) | 10 | @return calc(#{$width} / #{$player-factor}); |
11 | } | 11 | } |
12 | 12 | ||
13 | @function getPlayerWidth($height){ | 13 | @function getPlayerWidth ($height) { |
14 | @return calc(#{$height} * #{$player-factor}) | 14 | @return calc(#{$height} * #{$player-factor}); |
15 | } | 15 | } |
16 | 16 | ||
17 | @mixin playlist-below-player { | 17 | @mixin playlist-below-player { |
@@ -24,11 +24,11 @@ $video-info-margin-left: 44px; | |||
24 | 24 | ||
25 | .root { | 25 | .root { |
26 | &.theater-enabled #video-wrapper { | 26 | &.theater-enabled #video-wrapper { |
27 | $height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); | ||
28 | |||
27 | flex-direction: column; | 29 | flex-direction: column; |
28 | justify-content: center; | 30 | justify-content: center; |
29 | 31 | ||
30 | $height: calc(100vh - #{$header-height} - #{$theater-bottom-space}); | ||
31 | |||
32 | #videojs-wrapper { | 32 | #videojs-wrapper { |
33 | width: 100%; | 33 | width: 100%; |
34 | height: $height; | 34 | height: $height; |
@@ -141,7 +141,7 @@ $video-info-margin-left: 44px; | |||
141 | .video-info-first-row { | 141 | .video-info-first-row { |
142 | display: flex; | 142 | display: flex; |
143 | 143 | ||
144 | & > div:first-child { | 144 | > div:first-child { |
145 | flex-grow: 1; | 145 | flex-grow: 1; |
146 | } | 146 | } |
147 | 147 | ||
@@ -207,7 +207,7 @@ $video-info-margin-left: 44px; | |||
207 | } | 207 | } |
208 | 208 | ||
209 | .video-actions-rates { | 209 | .video-actions-rates { |
210 | margin: 0 0 10px 0; | 210 | margin: 0 0 10px; |
211 | align-items: start; | 211 | align-items: start; |
212 | width: max-content; | 212 | width: max-content; |
213 | margin-left: auto; | 213 | margin-left: auto; |
@@ -231,7 +231,7 @@ $video-info-margin-left: 44px; | |||
231 | font-size: 100%; | 231 | font-size: 100%; |
232 | font-weight: $font-semibold; | 232 | font-weight: $font-semibold; |
233 | display: inline-block; | 233 | display: inline-block; |
234 | padding: 0 10px 0 10px; | 234 | padding: 0 10px; |
235 | white-space: nowrap; | 235 | white-space: nowrap; |
236 | background-color: transparent !important; | 236 | background-color: transparent !important; |
237 | color: pvar(--actionButtonColor); | 237 | color: pvar(--actionButtonColor); |
@@ -346,7 +346,8 @@ $video-info-margin-left: 44px; | |||
346 | } | 346 | } |
347 | } | 347 | } |
348 | 348 | ||
349 | .glyphicon, .description-loading { | 349 | .glyphicon, |
350 | .description-loading { | ||
350 | margin-left: 3px; | 351 | margin-left: 3px; |
351 | } | 352 | } |
352 | 353 | ||
@@ -396,7 +397,7 @@ $video-info-margin-left: 44px; | |||
396 | &.video-attribute-tags { | 397 | &.video-attribute-tags { |
397 | .video-attribute-value:not(:nth-child(2)) { | 398 | .video-attribute-value:not(:nth-child(2)) { |
398 | &::before { | 399 | &::before { |
399 | content: ', ' | 400 | content: ', '; |
400 | } | 401 | } |
401 | } | 402 | } |
402 | } | 403 | } |
diff --git a/client/src/app/+videos/+video-watch/video-watch.module.ts b/client/src/app/+videos/+video-watch/video-watch.module.ts index cf6afd852..62ce7be2d 100644 --- a/client/src/app/+videos/+video-watch/video-watch.module.ts +++ b/client/src/app/+videos/+video-watch/video-watch.module.ts | |||
@@ -20,7 +20,7 @@ import { TimestampRouteTransformerDirective } from './timestamp-route-transforme | |||
20 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' | 20 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' |
21 | import { VideoWatchRoutingModule } from './video-watch-routing.module' | 21 | import { VideoWatchRoutingModule } from './video-watch-routing.module' |
22 | import { VideoWatchComponent } from './video-watch.component' | 22 | import { VideoWatchComponent } from './video-watch.component' |
23 | import { SharedAccountAvatarModule } from '../../shared/shared-account-avatar/shared-account-avatar.module' | 23 | import { SharedActorImageModule } from '../../shared/shared-actor-image/shared-actor-image.module' |
24 | import { VideoAvatarChannelComponent } from './video-avatar-channel.component' | 24 | import { VideoAvatarChannelComponent } from './video-avatar-channel.component' |
25 | 25 | ||
26 | @NgModule({ | 26 | @NgModule({ |
@@ -39,7 +39,7 @@ import { VideoAvatarChannelComponent } from './video-avatar-channel.component' | |||
39 | SharedShareModal, | 39 | SharedShareModal, |
40 | SharedVideoModule, | 40 | SharedVideoModule, |
41 | SharedSupportModal, | 41 | SharedSupportModal, |
42 | SharedAccountAvatarModule | 42 | SharedActorImageModule |
43 | ], | 43 | ], |
44 | 44 | ||
45 | declarations: [ | 45 | declarations: [ |
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.html b/client/src/app/+videos/video-list/overview/video-overview.component.html index 639a96c43..e21bffb6c 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.html +++ b/client/src/app/+videos/video-list/overview/video-overview.component.html | |||
@@ -33,7 +33,7 @@ | |||
33 | <div class="section channel videos" *ngFor="let object of overview.channels"> | 33 | <div class="section channel videos" *ngFor="let object of overview.channels"> |
34 | <div class="section-title"> | 34 | <div class="section-title"> |
35 | <a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]"> | 35 | <a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]"> |
36 | <img [src]="buildVideoChannelAvatarUrl(object)" alt="Avatar" /> | 36 | <my-actor-avatar [channel]="buildVideoChannel(object)"></my-actor-avatar> |
37 | 37 | ||
38 | <h2 class="section-title">{{ object.channel.displayName }}</h2> | 38 | <h2 class="section-title">{{ object.channel.displayName }}</h2> |
39 | </a> | 39 | </a> |
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.scss b/client/src/app/+videos/video-list/overview/video-overview.component.scss index ec73c628c..8fbac1b46 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.scss +++ b/client/src/app/+videos/video-list/overview/video-overview.component.scss | |||
@@ -16,7 +16,7 @@ | |||
16 | padding-top: 30px; | 16 | padding-top: 30px; |
17 | 17 | ||
18 | .section-title { | 18 | .section-title { |
19 | border-top: none !important; | 19 | border-top: 0 !important; |
20 | } | 20 | } |
21 | } | 21 | } |
22 | 22 | ||
@@ -33,12 +33,14 @@ | |||
33 | } | 33 | } |
34 | 34 | ||
35 | a { | 35 | a { |
36 | &:hover, &:focus:not(.focus-visible), &:active { | 36 | color: pvar(--mainForegroundColor); |
37 | |||
38 | &:hover, | ||
39 | &:focus:not(.focus-visible), | ||
40 | &:active { | ||
37 | text-decoration: none; | 41 | text-decoration: none; |
38 | outline: none; | 42 | outline: none; |
39 | } | 43 | } |
40 | |||
41 | color: pvar(--mainForegroundColor); | ||
42 | } | 44 | } |
43 | } | 45 | } |
44 | 46 | ||
@@ -49,9 +51,10 @@ | |||
49 | width: fit-content; | 51 | width: fit-content; |
50 | align-items: center; | 52 | align-items: center; |
51 | 53 | ||
52 | img { | 54 | my-actor-avatar { |
53 | @include channel-avatar(28px); | 55 | @include actor-avatar-size(28px); |
54 | 56 | ||
57 | font-size: initial; | ||
55 | margin-right: 8px; | 58 | margin-right: 8px; |
56 | } | 59 | } |
57 | } | 60 | } |
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.ts b/client/src/app/+videos/video-list/overview/video-overview.component.ts index b3be1d7b5..14532ca1e 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.ts +++ b/client/src/app/+videos/video-list/overview/video-overview.component.ts | |||
@@ -45,8 +45,8 @@ export class VideoOverviewComponent implements OnInit { | |||
45 | return object.videos[0].byVideoChannel | 45 | return object.videos[0].byVideoChannel |
46 | } | 46 | } |
47 | 47 | ||
48 | buildVideoChannelAvatarUrl (object: { videos: Video[] }) { | 48 | buildVideoChannel (object: { videos: Video[] }) { |
49 | return object.videos[0].videoChannelAvatarUrl | 49 | return object.videos[0].channel |
50 | } | 50 | } |
51 | 51 | ||
52 | buildVideos (videos: Video[]) { | 52 | buildVideos (videos: Video[]) { |
diff --git a/client/src/app/+videos/video-list/trending/video-trending-header.component.scss b/client/src/app/+videos/video-list/trending/video-trending-header.component.scss index 923a1d67a..6daacc78e 100644 --- a/client/src/app/+videos/video-list/trending/video-trending-header.component.scss +++ b/client/src/app/+videos/video-list/trending/video-trending-header.component.scss | |||
@@ -14,4 +14,4 @@ | |||
14 | height: 1rem; | 14 | height: 1rem; |
15 | margin-right: .1rem; | 15 | margin-right: .1rem; |
16 | } | 16 | } |
17 | } \ No newline at end of file | 17 | } |
diff --git a/client/src/app/+videos/videos.module.ts b/client/src/app/+videos/videos.module.ts index 61d012d63..8a35015d6 100644 --- a/client/src/app/+videos/videos.module.ts +++ b/client/src/app/+videos/videos.module.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module' | ||
2 | import { SharedFormModule } from '@app/shared/shared-forms' | 3 | import { SharedFormModule } from '@app/shared/shared-forms' |
3 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 4 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
4 | import { SharedMainModule } from '@app/shared/shared-main' | 5 | import { SharedMainModule } from '@app/shared/shared-main' |
@@ -21,7 +22,8 @@ import { VideosComponent } from './videos.component' | |||
21 | SharedFormModule, | 22 | SharedFormModule, |
22 | SharedVideoMiniatureModule, | 23 | SharedVideoMiniatureModule, |
23 | SharedUserSubscriptionModule, | 24 | SharedUserSubscriptionModule, |
24 | SharedGlobalIconModule | 25 | SharedGlobalIconModule, |
26 | SharedActorImageModule | ||
25 | ], | 27 | ], |
26 | 28 | ||
27 | declarations: [ | 29 | declarations: [ |
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index e7d05369b..e21ada0f1 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss | |||
@@ -79,7 +79,7 @@ | |||
79 | display: inline-block; | 79 | display: inline-block; |
80 | width: 23px; | 80 | width: 23px; |
81 | height: 24px; | 81 | height: 24px; |
82 | margin-right: .5rem; | 82 | margin-right: 0.5rem; |
83 | } | 83 | } |
84 | 84 | ||
85 | @media screen and (max-width: $mobile-view) { | 85 | @media screen and (max-width: $mobile-view) { |
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 41c59cc86..3cec6d739 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts | |||
@@ -24,7 +24,7 @@ import { SharedGlobalIconModule } from './shared/shared-icons' | |||
24 | import { SharedInstanceModule } from './shared/shared-instance' | 24 | import { SharedInstanceModule } from './shared/shared-instance' |
25 | import { SharedMainModule } from './shared/shared-main' | 25 | import { SharedMainModule } from './shared/shared-main' |
26 | import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings' | 26 | import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings' |
27 | import { SharedAccountAvatarModule } from './shared/shared-account-avatar/shared-account-avatar.module' | 27 | import { SharedActorImageModule } from './shared/shared-actor-image/shared-actor-image.module' |
28 | 28 | ||
29 | registerLocaleData(localeOc, 'oc') | 29 | registerLocaleData(localeOc, 'oc') |
30 | 30 | ||
@@ -60,7 +60,7 @@ registerLocaleData(localeOc, 'oc') | |||
60 | SharedUserInterfaceSettingsModule, | 60 | SharedUserInterfaceSettingsModule, |
61 | SharedGlobalIconModule, | 61 | SharedGlobalIconModule, |
62 | SharedInstanceModule, | 62 | SharedInstanceModule, |
63 | SharedAccountAvatarModule, | 63 | SharedActorImageModule, |
64 | 64 | ||
65 | MetaModule.forRoot({ | 65 | MetaModule.forRoot({ |
66 | provide: MetaLoader, | 66 | provide: MetaLoader, |
diff --git a/client/src/app/core/hotkeys/hotkeys.component.scss b/client/src/app/core/hotkeys/hotkeys.component.scss index a970260c9..b39ffa98d 100644 --- a/client/src/app/core/hotkeys/hotkeys.component.scss +++ b/client/src/app/core/hotkeys/hotkeys.component.scss | |||
@@ -12,16 +12,13 @@ | |||
12 | left: 0; | 12 | left: 0; |
13 | color: #333; | 13 | color: #333; |
14 | font-size: 1em; | 14 | font-size: 1em; |
15 | background-color: rgba(255,255,255,0.9); | 15 | background-color: rgba(255, 255, 255, 0.9); |
16 | } | 16 | } |
17 | 17 | ||
18 | .cfp-hotkeys-container.fade { | 18 | .cfp-hotkeys-container.fade { |
19 | z-index: -1024; | 19 | z-index: -1024; |
20 | visibility: hidden; | 20 | visibility: hidden; |
21 | opacity: 0; | 21 | opacity: 0; |
22 | -webkit-transition: opacity 0.15s linear; | ||
23 | -moz-transition: opacity 0.15s linear; | ||
24 | -o-transition: opacity 0.15s linear; | ||
25 | transition: opacity 0.15s linear; | 22 | transition: opacity 0.15s linear; |
26 | } | 23 | } |
27 | 24 | ||
diff --git a/client/src/app/core/rest/rest-table.ts b/client/src/app/core/rest/rest-table.ts index 32c1db446..a5b48f10c 100644 --- a/client/src/app/core/rest/rest-table.ts +++ b/client/src/app/core/rest/rest-table.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import * as debug from 'debug' | 1 | import * as debug from 'debug' |
2 | import { LazyLoadEvent, SortMeta } from 'primeng/api' | 2 | import { LazyLoadEvent, SortMeta } from 'primeng/api' |
3 | import { Subject } from 'rxjs' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { debounceTime, distinctUntilChanged } from 'rxjs/operators' | ||
5 | import { ActivatedRoute, Params, Router } from '@angular/router' | ||
6 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' | 4 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' |
7 | import { RestPagination } from './rest-pagination' | 5 | import { RestPagination } from './rest-pagination' |
8 | 6 | ||
@@ -14,14 +12,11 @@ export abstract class RestTable { | |||
14 | abstract sort: SortMeta | 12 | abstract sort: SortMeta |
15 | abstract pagination: RestPagination | 13 | abstract pagination: RestPagination |
16 | 14 | ||
17 | search: string | ||
18 | rowsPerPageOptions = [ 10, 20, 50, 100 ] | 15 | rowsPerPageOptions = [ 10, 20, 50, 100 ] |
19 | rowsPerPage = this.rowsPerPageOptions[0] | 16 | rowsPerPage = this.rowsPerPageOptions[0] |
20 | expandedRows = {} | 17 | expandedRows = {} |
21 | 18 | ||
22 | baseRoute: string | 19 | search: string |
23 | |||
24 | protected searchStream: Subject<string> | ||
25 | 20 | ||
26 | protected route: ActivatedRoute | 21 | protected route: ActivatedRoute |
27 | protected router: Router | 22 | protected router: Router |
@@ -30,7 +25,6 @@ export abstract class RestTable { | |||
30 | 25 | ||
31 | initialize () { | 26 | initialize () { |
32 | this.loadSort() | 27 | this.loadSort() |
33 | this.initSearch() | ||
34 | } | 28 | } |
35 | 29 | ||
36 | loadSort () { | 30 | loadSort () { |
@@ -58,7 +52,7 @@ export abstract class RestTable { | |||
58 | count: this.rowsPerPage | 52 | count: this.rowsPerPage |
59 | } | 53 | } |
60 | 54 | ||
61 | this.loadData() | 55 | this.reloadData() |
62 | this.saveSort() | 56 | this.saveSort() |
63 | } | 57 | } |
64 | 58 | ||
@@ -66,55 +60,6 @@ export abstract class RestTable { | |||
66 | peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort)) | 60 | peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort)) |
67 | } | 61 | } |
68 | 62 | ||
69 | initSearch () { | ||
70 | this.searchStream = new Subject() | ||
71 | |||
72 | this.searchStream | ||
73 | .pipe( | ||
74 | debounceTime(400), | ||
75 | distinctUntilChanged() | ||
76 | ) | ||
77 | .subscribe(search => { | ||
78 | this.search = search | ||
79 | |||
80 | logger('On search %s.', this.search) | ||
81 | |||
82 | this.loadData() | ||
83 | }) | ||
84 | } | ||
85 | |||
86 | onSearch (event: Event) { | ||
87 | const target = event.target as HTMLInputElement | ||
88 | this.searchStream.next(target.value) | ||
89 | |||
90 | this.setQueryParams((event.target as HTMLInputElement).value) | ||
91 | } | ||
92 | |||
93 | setQueryParams (search: string) { | ||
94 | if (!this.baseRoute) return | ||
95 | |||
96 | const queryParams: Params = {} | ||
97 | |||
98 | if (search) Object.assign(queryParams, { search }) | ||
99 | this.router.navigate([ this.baseRoute ], { queryParams }) | ||
100 | } | ||
101 | |||
102 | resetTableFilter () { | ||
103 | this.setTableFilter('') | ||
104 | this.setQueryParams('') | ||
105 | this.resetSearch() | ||
106 | } | ||
107 | |||
108 | listenToSearchChange () { | ||
109 | this.route.queryParams | ||
110 | .subscribe(params => { | ||
111 | this.search = params.search || '' | ||
112 | |||
113 | // Primeng table will run an event to load data | ||
114 | this.setTableFilter(this.search) | ||
115 | }) | ||
116 | } | ||
117 | |||
118 | onPage (event: { first: number, rows: number }) { | 63 | onPage (event: { first: number, rows: number }) { |
119 | logger('On page %o.', event) | 64 | logger('On page %o.', event) |
120 | 65 | ||
@@ -125,28 +70,18 @@ export abstract class RestTable { | |||
125 | count: this.rowsPerPage | 70 | count: this.rowsPerPage |
126 | } | 71 | } |
127 | 72 | ||
128 | this.loadData() | 73 | this.reloadData() |
129 | } | 74 | } |
130 | 75 | ||
131 | this.expandedRows = {} | 76 | this.expandedRows = {} |
132 | } | 77 | } |
133 | 78 | ||
134 | setTableFilter (filter: string, triggerEvent = true) { | 79 | onSearch (search: string) { |
135 | // FIXME: cannot use ViewChild, so create a component for the filter input | 80 | this.search = search |
136 | const filterInput = document.getElementById('table-filter') as HTMLInputElement | 81 | this.reloadData() |
137 | if (!filterInput) return | ||
138 | |||
139 | filterInput.value = filter | ||
140 | |||
141 | if (triggerEvent) filterInput.dispatchEvent(new Event('keyup')) | ||
142 | } | ||
143 | |||
144 | resetSearch () { | ||
145 | this.searchStream.next('') | ||
146 | this.setTableFilter('') | ||
147 | } | 82 | } |
148 | 83 | ||
149 | protected abstract loadData (): void | 84 | protected abstract reloadData (): void |
150 | 85 | ||
151 | private getSortLocalStorageKey () { | 86 | private getSortLocalStorageKey () { |
152 | return 'rest-table-sort-' + this.getIdentifier() | 87 | return 'rest-table-sort-' + this.getIdentifier() |
diff --git a/client/src/app/core/rest/rest.service.ts b/client/src/app/core/rest/rest.service.ts index 4f1fc8848..1696e6709 100644 --- a/client/src/app/core/rest/rest.service.ts +++ b/client/src/app/core/rest/rest.service.ts | |||
@@ -90,14 +90,20 @@ export class RestService { | |||
90 | 90 | ||
91 | const matchedTokens = tokens.filter(t => t.startsWith(prefix)) | 91 | const matchedTokens = tokens.filter(t => t.startsWith(prefix)) |
92 | .map(t => t.slice(prefix.length)) // Keep the value filter | 92 | .map(t => t.slice(prefix.length)) // Keep the value filter |
93 | .map(t => t.replace(/^"|"$/g, '')) | 93 | .map(t => t.replace(/^"|"$/g, '')) // Remove "" |
94 | .map(t => { | 94 | .map(t => { |
95 | if (prefixObj.handler) return prefixObj.handler(t) | 95 | if (prefixObj.handler) return prefixObj.handler(t) |
96 | 96 | ||
97 | if (prefixObj.isBoolean) { | ||
98 | if (t === 'true') return true | ||
99 | if (t === 'false') return false | ||
100 | |||
101 | return undefined | ||
102 | } | ||
103 | |||
97 | return t | 104 | return t |
98 | }) | 105 | }) |
99 | .filter(t => !!t || t === 0) | 106 | .filter(t => t !== null && t !== undefined) |
100 | .map(t => prefixObj.isBoolean ? t === 'true' : t) | ||
101 | 107 | ||
102 | if (matchedTokens.length === 0) continue | 108 | if (matchedTokens.length === 0) continue |
103 | 109 | ||
diff --git a/client/src/app/core/users/user.service.ts b/client/src/app/core/users/user.service.ts index 3de83152c..47db985e1 100644 --- a/client/src/app/core/users/user.service.ts +++ b/client/src/app/core/users/user.service.ts | |||
@@ -320,13 +320,7 @@ export class UserService { | |||
320 | const filters = this.restService.parseQueryStringFilter(search, { | 320 | const filters = this.restService.parseQueryStringFilter(search, { |
321 | blocked: { | 321 | blocked: { |
322 | prefix: 'banned:', | 322 | prefix: 'banned:', |
323 | isBoolean: true, | 323 | isBoolean: true |
324 | handler: v => { | ||
325 | if (v === 'true') return v | ||
326 | if (v === 'false') return v | ||
327 | |||
328 | return undefined | ||
329 | } | ||
330 | } | 324 | } |
331 | }) | 325 | }) |
332 | 326 | ||
diff --git a/client/src/app/core/wrappers/screen.service.ts b/client/src/app/core/wrappers/screen.service.ts index c133b5fe9..fd8268b35 100644 --- a/client/src/app/core/wrappers/screen.service.ts +++ b/client/src/app/core/wrappers/screen.service.ts | |||
@@ -39,9 +39,9 @@ export class ScreenService { | |||
39 | let numberOfVideos = 1 | 39 | let numberOfVideos = 1 |
40 | 40 | ||
41 | if (screenWidth > 1850) numberOfVideos = 5 | 41 | if (screenWidth > 1850) numberOfVideos = 5 |
42 | else if (screenWidth > 1600) numberOfVideos = 4 | 42 | else if (screenWidth > 1410) numberOfVideos = 4 |
43 | else if (screenWidth > 1370) numberOfVideos = 3 | 43 | else if (screenWidth > 1120) numberOfVideos = 3 |
44 | else if (screenWidth > 1100) numberOfVideos = 2 | 44 | else if (screenWidth > 890) numberOfVideos = 2 |
45 | 45 | ||
46 | return numberOfVideos | 46 | return numberOfVideos |
47 | } | 47 | } |
diff --git a/client/src/app/header/search-typeahead.component.scss b/client/src/app/header/search-typeahead.component.scss index c754a99d1..3e0350ba0 100644 --- a/client/src/app/header/search-typeahead.component.scss +++ b/client/src/app/header/search-typeahead.component.scss | |||
@@ -44,7 +44,8 @@ li.suggestion { | |||
44 | 44 | ||
45 | // soft border-radius for the last suggestion and the link inside | 45 | // soft border-radius for the last suggestion and the link inside |
46 | &:last-of-type { | 46 | &:last-of-type { |
47 | &, & ::ng-deep a { | 47 | &, |
48 | ::ng-deep a { | ||
48 | border-bottom-right-radius: 3px; | 49 | border-bottom-right-radius: 3px; |
49 | border-bottom-left-radius: 3px; | 50 | border-bottom-left-radius: 3px; |
50 | } | 51 | } |
@@ -74,7 +75,7 @@ li.suggestion { | |||
74 | #typeahead-container { | 75 | #typeahead-container { |
75 | input { | 76 | input { |
76 | border: 1px solid pvar(--mainBackgroundColor) !important; | 77 | border: 1px solid pvar(--mainBackgroundColor) !important; |
77 | box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 20px 0px; | 78 | box-shadow: rgba(0, 0, 0, 0.1) 0 1px 20px 0; |
78 | flex-grow: 1; | 79 | flex-grow: 1; |
79 | transition: box-shadow .3s ease, width .2s ease; | 80 | transition: box-shadow .3s ease, width .2s ease; |
80 | } | 81 | } |
@@ -95,7 +96,7 @@ li.suggestion { | |||
95 | right: 10px; | 96 | right: 10px; |
96 | } | 97 | } |
97 | 98 | ||
98 | & > div:last-child { | 99 | > div:last-child { |
99 | // we have to switch the display and not the opacity, | 100 | // we have to switch the display and not the opacity, |
100 | // to avoid clashing with the rest of the interface. | 101 | // to avoid clashing with the rest of the interface. |
101 | display: none; | 102 | display: none; |
@@ -103,7 +104,7 @@ li.suggestion { | |||
103 | 104 | ||
104 | &:focus, | 105 | &:focus, |
105 | ::ng-deep &:focus-within { | 106 | ::ng-deep &:focus-within { |
106 | & > div:last-child { | 107 | > div:last-child { |
107 | @media screen and (min-width: $mobile-view) { | 108 | @media screen and (min-width: $mobile-view) { |
108 | display: initial !important; | 109 | display: initial !important; |
109 | } | 110 | } |
@@ -111,12 +112,12 @@ li.suggestion { | |||
111 | #typeahead-help, | 112 | #typeahead-help, |
112 | #typeahead-instructions, | 113 | #typeahead-instructions, |
113 | li.suggestion { | 114 | li.suggestion { |
114 | box-shadow: rgba(0, 0, 0, 0.2) 0px 10px 20px -5px; | 115 | box-shadow: rgba(0, 0, 0, 0.2) 0 10px 20px -5px; |
115 | } | 116 | } |
116 | } | 117 | } |
117 | 118 | ||
118 | ::ng-deep input { | 119 | ::ng-deep input { |
119 | box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 20px 0px; | 120 | box-shadow: rgba(0, 0, 0, 0.2) 0 1px 20px 0; |
120 | border-end-start-radius: 0; | 121 | border-end-start-radius: 0; |
121 | border-end-end-radius: 0; | 122 | border-end-end-radius: 0; |
122 | 123 | ||
diff --git a/client/src/app/header/suggestion.component.scss b/client/src/app/header/suggestion.component.scss index 692a81daa..9163de0b1 100644 --- a/client/src/app/header/suggestion.component.scss +++ b/client/src/app/header/suggestion.component.scss | |||
@@ -2,9 +2,11 @@ | |||
2 | 2 | ||
3 | a { | 3 | a { |
4 | @include disable-default-a-behaviour; | 4 | @include disable-default-a-behaviour; |
5 | |||
5 | width: 100%; | 6 | width: 100%; |
6 | 7 | ||
7 | &, &:hover { | 8 | &, |
9 | &:hover { | ||
8 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
9 | 11 | ||
10 | &.focus-visible { | 12 | &.focus-visible { |
@@ -23,10 +25,10 @@ a { | |||
23 | } | 25 | } |
24 | 26 | ||
25 | my-global-icon { | 27 | my-global-icon { |
28 | @include apply-svg-color(pvar(--mainForegroundColor)); | ||
29 | |||
26 | width: 17px; | 30 | width: 17px; |
27 | position: relative; | 31 | position: relative; |
28 | top: -2px; | 32 | top: -2px; |
29 | margin: 5px; | 33 | margin: 5px; |
30 | |||
31 | @include apply-svg-color(pvar(--mainForegroundColor)); | ||
32 | } | 34 | } |
diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss index 6226a85cb..800b1ebef 100644 --- a/client/src/app/menu/language-chooser.component.scss +++ b/client/src/app/menu/language-chooser.component.scss | |||
@@ -5,12 +5,12 @@ | |||
5 | @include peertube-button-link; | 5 | @include peertube-button-link; |
6 | @include orange-button; | 6 | @include orange-button; |
7 | 7 | ||
8 | border-radius: 0; | ||
9 | |||
8 | &.focus-visible, | 10 | &.focus-visible, |
9 | &:focus { | 11 | &:focus { |
10 | box-shadow: none; | 12 | box-shadow: none; |
11 | } | 13 | } |
12 | |||
13 | border-radius: 0; | ||
14 | } | 14 | } |
15 | 15 | ||
16 | .modal-body { | 16 | .modal-body { |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index df5c7971d..2e07deca2 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <div> | 5 | <div> |
6 | <div class="logged-in-more" ngbDropdown #dropdown="ngbDropdown" placement="bottom-left" [container]="dropdownContainer" (openChange)="onDropdownOpenChange($event)" autoClose="outside"> | 6 | <div class="logged-in-more" ngbDropdown #dropdown="ngbDropdown" placement="bottom-left" [container]="dropdownContainer" (openChange)="onDropdownOpenChange($event)" autoClose="outside"> |
7 | <div ngbDropdownToggle> | 7 | <div ngbDropdownToggle> |
8 | <my-account-avatar [account]="user.account" size="34"></my-account-avatar> | 8 | <my-actor-avatar [account]="user.account" size="34"></my-actor-avatar> |
9 | <div class="logged-in-info"> | 9 | <div class="logged-in-info"> |
10 | <div class="logged-in-display-name">{{ user.account?.displayName }}</div> | 10 | <div class="logged-in-display-name">{{ user.account?.displayName }}</div> |
11 | 11 | ||
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index 00d1a1f69..d0edd820e 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss | |||
@@ -24,8 +24,9 @@ $footer-links-base-opacity: .8; | |||
24 | background-color: rgba(255, 255, 255, 0.15); | 24 | background-color: rgba(255, 255, 255, 0.15); |
25 | } | 25 | } |
26 | 26 | ||
27 | &:hover, &.focus-visible { | 27 | &:hover, |
28 | background-color: rgba(255, 255, 255, 0.10); | 28 | &.focus-visible { |
29 | background-color: rgba(255, 255, 255, 0.1); | ||
29 | } | 30 | } |
30 | 31 | ||
31 | my-global-icon { | 32 | my-global-icon { |
@@ -60,7 +61,8 @@ menu { | |||
60 | margin: 0; | 61 | margin: 0; |
61 | padding: 0; | 62 | padding: 0; |
62 | 63 | ||
63 | &:focus, &:hover { | 64 | &:focus, |
65 | &:hover { | ||
64 | overflow-y: auto; | 66 | overflow-y: auto; |
65 | } | 67 | } |
66 | 68 | ||
@@ -125,7 +127,7 @@ my-notification { | |||
125 | line-height: 1; | 127 | line-height: 1; |
126 | 128 | ||
127 | &.show { | 129 | &.show { |
128 | background-color: rgba(255, 255, 255, 0.20); | 130 | background-color: rgba(255, 255, 255, 0.2); |
129 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .325); | 131 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .325); |
130 | } | 132 | } |
131 | 133 | ||
@@ -158,14 +160,14 @@ my-notification { | |||
158 | position: absolute; | 160 | position: absolute; |
159 | right: -35px; | 161 | right: -35px; |
160 | top: -8px; | 162 | top: -8px; |
161 | color: grey; | 163 | color: #808080; |
162 | width: $main-radius; | 164 | width: $main-radius; |
163 | } | 165 | } |
164 | } | 166 | } |
165 | 167 | ||
166 | .dropdown-toggle { | 168 | .dropdown-toggle { |
167 | &::after { | 169 | &::after { |
168 | border: none; | 170 | border: 0; |
169 | } | 171 | } |
170 | } | 172 | } |
171 | 173 | ||
@@ -177,7 +179,7 @@ my-notification { | |||
177 | } | 179 | } |
178 | } | 180 | } |
179 | 181 | ||
180 | my-account-avatar { | 182 | my-actor-avatar { |
181 | margin-right: 10px; | 183 | margin-right: 10px; |
182 | } | 184 | } |
183 | 185 | ||
@@ -193,11 +195,11 @@ my-account-avatar { | |||
193 | } | 195 | } |
194 | 196 | ||
195 | .logged-in-display-name { | 197 | .logged-in-display-name { |
198 | @include disable-default-a-behaviour; | ||
199 | |||
196 | font-size: 16px; | 200 | font-size: 16px; |
197 | font-weight: $font-semibold; | 201 | font-weight: $font-semibold; |
198 | color: pvar(--menuForegroundColor); | 202 | color: pvar(--menuForegroundColor); |
199 | |||
200 | @include disable-default-a-behaviour; | ||
201 | } | 203 | } |
202 | 204 | ||
203 | .logged-in-username { | 205 | .logged-in-username { |
@@ -251,7 +253,7 @@ my-account-avatar { | |||
251 | } | 253 | } |
252 | 254 | ||
253 | .login-buttons-block { | 255 | .login-buttons-block { |
254 | margin: 30px 25px 35px 25px; | 256 | margin: 30px 25px 35px; |
255 | 257 | ||
256 | > a { | 258 | > a { |
257 | display: block; | 259 | display: block; |
@@ -305,7 +307,8 @@ my-account-avatar { | |||
305 | } | 307 | } |
306 | 308 | ||
307 | .footer-links { | 309 | .footer-links { |
308 | &, > div { | 310 | &, |
311 | > div { | ||
309 | display: flex; | 312 | display: flex; |
310 | flex-wrap: wrap; | 313 | flex-wrap: wrap; |
311 | } | 314 | } |
@@ -388,29 +391,29 @@ my-account-avatar { | |||
388 | .dropdown-item:hover, | 391 | .dropdown-item:hover, |
389 | .dropdown-item:active { | 392 | .dropdown-item:active { |
390 | &.settings-sensitive my-global-icon ::ng-deep svg { | 393 | &.settings-sensitive my-global-icon ::ng-deep svg { |
391 | margin-top: 0px !important; | 394 | margin-top: 0 !important; |
392 | } | 395 | } |
393 | } | 396 | } |
394 | } | 397 | } |
395 | 398 | ||
396 | my-global-icon { | 399 | my-global-icon { |
397 | &[iconName="playlists"] { | 400 | &[iconName=playlists] { |
398 | height: 24px; | 401 | height: 24px; |
399 | width: 24px; | 402 | width: 24px; |
400 | 403 | ||
401 | margin-right: 16px; | 404 | margin-right: 16px; |
402 | } | 405 | } |
403 | 406 | ||
404 | &[iconName="videos"] { | 407 | &[iconName=videos] { |
405 | position: relative; | 408 | position: relative; |
406 | right: -1px; | 409 | right: -1px; |
407 | } | 410 | } |
408 | 411 | ||
409 | &[iconName="channel"] { | 412 | &[iconName=channel] { |
410 | margin-top: -2px; | 413 | margin-top: -2px; |
411 | } | 414 | } |
412 | 415 | ||
413 | &[iconName="sign-out"] { | 416 | &[iconName='sign-out'] { |
414 | position: relative; | 417 | position: relative; |
415 | right: -2px; | 418 | right: -2px; |
416 | height: 20px; | 419 | height: 20px; |
diff --git a/client/src/app/menu/notification.component.scss b/client/src/app/menu/notification.component.scss index c65787779..554c20ca9 100644 --- a/client/src/app/menu/notification.component.scss +++ b/client/src/app/menu/notification.component.scss | |||
@@ -16,19 +16,20 @@ | |||
16 | .notification-inbox-popover, | 16 | .notification-inbox-popover, |
17 | .notification-inbox-link a { | 17 | .notification-inbox-link a { |
18 | @include apply-svg-color(#808080); | 18 | @include apply-svg-color(#808080); |
19 | ::ng-deep { | ||
20 | svg { | ||
21 | transition: color .1s ease-in-out; | ||
22 | } | ||
23 | } | ||
24 | 19 | ||
25 | transition: all .1s ease-in-out; | 20 | transition: all .1s ease-in-out; |
26 | border-radius: 25px; | 21 | border-radius: 25px; |
27 | cursor: pointer; | 22 | cursor: pointer; |
28 | 23 | ||
29 | &:hover, &:active { | 24 | ::ng-deep svg { |
30 | background-color: rgba(255, 255, 255, 0.15); | 25 | transition: color .1s ease-in-out; |
26 | } | ||
27 | |||
28 | &:hover, | ||
29 | &:active { | ||
31 | @include apply-svg-color(#fff); | 30 | @include apply-svg-color(#fff); |
31 | |||
32 | background-color: rgba(255, 255, 255, 0.15); | ||
32 | } | 33 | } |
33 | } | 34 | } |
34 | 35 | ||
@@ -59,7 +60,7 @@ | |||
59 | font-size: 14px; | 60 | font-size: 14px; |
60 | font-family: $main-fonts; | 61 | font-family: $main-fonts; |
61 | width: 400px; | 62 | width: 400px; |
62 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.30); | 63 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); |
63 | 64 | ||
64 | .loader { | 65 | .loader { |
65 | display: flex; | 66 | display: flex; |
@@ -80,7 +81,7 @@ | |||
80 | max-height: 500px; | 81 | max-height: 500px; |
81 | } | 82 | } |
82 | 83 | ||
83 | & > my-user-notifications:nth-child(2) { | 84 | > my-user-notifications:nth-child(2) { |
84 | overflow-y: auto; | 85 | overflow-y: auto; |
85 | flex-grow: 1; | 86 | flex-grow: 1; |
86 | } | 87 | } |
@@ -110,7 +111,8 @@ | |||
110 | background: transparent; | 111 | background: transparent; |
111 | } | 112 | } |
112 | 113 | ||
113 | a, button { | 114 | a, |
115 | button { | ||
114 | color: rgba(20, 20, 20, 0.5); | 116 | color: rgba(20, 20, 20, 0.5); |
115 | 117 | ||
116 | &:hover:not(:disabled) { | 118 | &:hover:not(:disabled) { |
@@ -133,7 +135,8 @@ | |||
133 | } | 135 | } |
134 | } | 136 | } |
135 | 137 | ||
136 | .notification-inbox-popover, .notification-inbox-link { | 138 | .notification-inbox-popover, |
139 | .notification-inbox-link { | ||
137 | cursor: pointer; | 140 | cursor: pointer; |
138 | position: relative; | 141 | position: relative; |
139 | 142 | ||
diff --git a/client/src/app/modal/welcome-modal.component.scss b/client/src/app/modal/welcome-modal.component.scss index 28d5dc49c..5e9e3dc51 100644 --- a/client/src/app/modal/welcome-modal.component.scss +++ b/client/src/app/modal/welcome-modal.component.scss | |||
@@ -42,7 +42,7 @@ li { | |||
42 | text-align: center; | 42 | text-align: center; |
43 | font-weight: 600; | 43 | font-weight: 600; |
44 | font-size: 18px; | 44 | font-size: 18px; |
45 | margin: 20px 0 40px 0; | 45 | margin: 20px 0 40px; |
46 | } | 46 | } |
47 | 47 | ||
48 | .columns { | 48 | .columns { |
diff --git a/client/src/app/shared/shared-abuse-list/abuse-details.component.html b/client/src/app/shared/shared-abuse-list/abuse-details.component.html index 658d42537..ca68de4b1 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-details.component.html +++ b/client/src/app/shared/shared-abuse-list/abuse-details.component.html | |||
@@ -7,16 +7,16 @@ | |||
7 | <span class="col-3 moderation-expanded-label" i18n>Reporter</span> | 7 | <span class="col-3 moderation-expanded-label" i18n>Reporter</span> |
8 | 8 | ||
9 | <span class="col-9 moderation-expanded-text"> | 9 | <span class="col-9 moderation-expanded-text"> |
10 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" | 10 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" |
11 | class="chip" | 11 | class="chip" |
12 | > | 12 | > |
13 | <my-account-avatar [account]="abuse.reporterAccount"></my-account-avatar> | 13 | <my-actor-avatar size="18" [account]="abuse.reporterAccount"></my-actor-avatar> |
14 | <div> | 14 | <div> |
15 | <span class="text-muted">{{ abuse.reporterAccount.nameWithHost }}</span> | 15 | <span class="text-muted">{{ abuse.reporterAccount.nameWithHost }}</span> |
16 | </div> | 16 | </div> |
17 | </a> | 17 | </a> |
18 | 18 | ||
19 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" | 19 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" |
20 | class="ml-auto text-muted abuse-details-links" i18n | 20 | class="ml-auto text-muted abuse-details-links" i18n |
21 | > | 21 | > |
22 | {abuse.countReportsForReporter, plural, =1 {1 report} other {{{ abuse.countReportsForReporter }} reports}}<span class="ml-1Â glyphicon glyphicon-flag"></span> | 22 | {abuse.countReportsForReporter, plural, =1 {1 report} other {{{ abuse.countReportsForReporter }} reports}}<span class="ml-1Â glyphicon glyphicon-flag"></span> |
@@ -27,16 +27,16 @@ | |||
27 | <div class="d-flex" *ngIf="abuse.flaggedAccount"> | 27 | <div class="d-flex" *ngIf="abuse.flaggedAccount"> |
28 | <span class="col-3 moderation-expanded-label" i18n>Reportee</span> | 28 | <span class="col-3 moderation-expanded-label" i18n>Reportee</span> |
29 | <span class="col-9 moderation-expanded-text"> | 29 | <span class="col-9 moderation-expanded-text"> |
30 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" | 30 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" |
31 | class="chip" | 31 | class="chip" |
32 | > | 32 | > |
33 | <my-account-avatar [account]="abuse.flaggedAccount"></my-account-avatar> | 33 | <my-actor-avatar size="18" [account]="abuse.flaggedAccount"></my-actor-avatar> |
34 | <div> | 34 | <div> |
35 | <span class="text-muted">{{ abuse.flaggedAccount ? abuse.flaggedAccount.nameWithHost : '' }}</span> | 35 | <span class="text-muted">{{ abuse.flaggedAccount ? abuse.flaggedAccount.nameWithHost : '' }}</span> |
36 | </div> | 36 | </div> |
37 | </a> | 37 | </a> |
38 | 38 | ||
39 | <a *ngIf="isAdminView" [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" | 39 | <a *ngIf="isAdminView" [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" |
40 | class="ml-auto text-muted abuse-details-links" i18n | 40 | class="ml-auto text-muted abuse-details-links" i18n |
41 | > | 41 | > |
42 | {abuse.countReportsForReportee, plural, =1 {1 report} other {{{ abuse.countReportsForReportee }} reports}}<span class="ml-1Â glyphicon glyphicon-flag"></span> | 42 | {abuse.countReportsForReportee, plural, =1 {1 report} other {{{ abuse.countReportsForReportee }} reports}}<span class="ml-1Â glyphicon glyphicon-flag"></span> |
@@ -53,7 +53,7 @@ | |||
53 | <div class="mt-3 d-flex"> | 53 | <div class="mt-3 d-flex"> |
54 | <span class="col-3 moderation-expanded-label"> | 54 | <span class="col-3 moderation-expanded-label"> |
55 | <ng-container i18n>Report</ng-container> | 55 | <ng-container i18n>Report</ng-container> |
56 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ml-1 text-muted">#{{ abuse.id }}</a> | 56 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ml-1 text-muted">#{{ abuse.id }}</a> |
57 | </span> | 57 | </span> |
58 | <span class="col-9 moderation-expanded-text" [innerHTML]="abuse.reasonHtml"></span> | 58 | <span class="col-9 moderation-expanded-text" [innerHTML]="abuse.reasonHtml"></span> |
59 | </div> | 59 | </div> |
@@ -61,7 +61,7 @@ | |||
61 | <div *ngIf="getPredefinedReasons()" class="mt-2 d-flex"> | 61 | <div *ngIf="getPredefinedReasons()" class="mt-2 d-flex"> |
62 | <span class="col-3"></span> | 62 | <span class="col-3"></span> |
63 | <span class="col-9"> | 63 | <span class="col-9"> |
64 | <a *ngFor="let reason of getPredefinedReasons()" [routerLink]="[ baseRoute ]" | 64 | <a *ngFor="let reason of getPredefinedReasons()" [routerLink]="[ '.' ]" |
65 | [queryParams]="{ 'search': 'tag:' + reason.id }" class="chip rectangular bg-secondary text-light" | 65 | [queryParams]="{ 'search': 'tag:' + reason.id }" class="chip rectangular bg-secondary text-light" |
66 | > | 66 | > |
67 | <div>{{ reason.label }}</div> | 67 | <div>{{ reason.label }}</div> |
diff --git a/client/src/app/shared/shared-abuse-list/abuse-details.component.ts b/client/src/app/shared/shared-abuse-list/abuse-details.component.ts index e8ce7e678..14674c5f0 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-details.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-details.component.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Component, Input } from '@angular/core' | 1 | import { Component, Input } from '@angular/core' |
2 | import { durationToString } from '@app/helpers' | 2 | import { durationToString } from '@app/helpers' |
3 | import { Account } from '@app/shared/shared-main' | ||
4 | import { AbusePredefinedReasonsString } from '@shared/models' | 3 | import { AbusePredefinedReasonsString } from '@shared/models' |
5 | import { ProcessedAbuse } from './processed-abuse.model' | 4 | import { ProcessedAbuse } from './processed-abuse.model' |
6 | 5 | ||
@@ -12,7 +11,6 @@ import { ProcessedAbuse } from './processed-abuse.model' | |||
12 | export class AbuseDetailsComponent { | 11 | export class AbuseDetailsComponent { |
13 | @Input() abuse: ProcessedAbuse | 12 | @Input() abuse: ProcessedAbuse |
14 | @Input() isAdminView: boolean | 13 | @Input() isAdminView: boolean |
15 | @Input() baseRoute: string | ||
16 | 14 | ||
17 | private predefinedReasonsTranslations: { [key in AbusePredefinedReasonsString]: string } | 15 | private predefinedReasonsTranslations: { [key in AbusePredefinedReasonsString]: string } |
18 | 16 | ||
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html index 29b51f09c..b1c065c7a 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html | |||
@@ -1,6 +1,7 @@ | |||
1 | <p-table | 1 | <p-table |
2 | [value]="abuses" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 2 | [value]="abuses" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" |
4 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 5 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" | 6 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" |
6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 7 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
@@ -8,28 +9,7 @@ | |||
8 | <ng-template pTemplate="caption"> | 9 | <ng-template pTemplate="caption"> |
9 | <div class="caption"> | 10 | <div class="caption"> |
10 | <div class="ml-auto"> | 11 | <div class="ml-auto"> |
11 | <div class="input-group has-feedback has-clear"> | 12 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
12 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
13 | <div class="input-group-text" ngbDropdownToggle> | ||
14 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
15 | </div> | ||
16 | |||
17 | <div role="menu" ngbDropdownMenu> | ||
18 | <h6 class="dropdown-header" i18n>Advanced report filters</h6> | ||
19 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> | ||
20 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> | ||
21 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> | ||
22 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blocked videos</a> | ||
23 | <a [routerLink]="[ baseRoute ]" [queryParams]="{ 'search': 'videoIs:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a> | ||
24 | </div> | ||
25 | </div> | ||
26 | <input | ||
27 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
28 | (keyup)="onSearch($event)" | ||
29 | > | ||
30 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
31 | <span class="sr-only" i18n>Clear filters</span> | ||
32 | </div> | ||
33 | </div> | 13 | </div> |
34 | </div> | 14 | </div> |
35 | </ng-template> | 15 | </ng-template> |
@@ -65,7 +45,7 @@ | |||
65 | <td *ngIf="isAdminView()"> | 45 | <td *ngIf="isAdminView()"> |
66 | <a *ngIf="abuse.reporterAccount" [href]="abuse.reporterAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 46 | <a *ngIf="abuse.reporterAccount" [href]="abuse.reporterAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
67 | <div class="chip two-lines"> | 47 | <div class="chip two-lines"> |
68 | <my-account-avatar [account]="abuse.reporterAccount"></my-account-avatar> | 48 | <my-actor-avatar [account]="abuse.reporterAccount"></my-actor-avatar> |
69 | <div> | 49 | <div> |
70 | {{ abuse.reporterAccount.displayName }} | 50 | {{ abuse.reporterAccount.displayName }} |
71 | <span>{{ abuse.reporterAccount.nameWithHost }}</span> | 51 | <span>{{ abuse.reporterAccount.nameWithHost }}</span> |
@@ -171,7 +151,7 @@ | |||
171 | <ng-template pTemplate="rowexpansion" let-abuse> | 151 | <ng-template pTemplate="rowexpansion" let-abuse> |
172 | <tr> | 152 | <tr> |
173 | <td class="expand-cell" colspan="8"> | 153 | <td class="expand-cell" colspan="8"> |
174 | <my-abuse-details [abuse]="abuse" [baseRoute]="baseRoute" [isAdminView]="isAdminView()"></my-abuse-details> | 154 | <my-abuse-details [abuse]="abuse" [isAdminView]="isAdminView()"></my-abuse-details> |
175 | </td> | 155 | </td> |
176 | </tr> | 156 | </tr> |
177 | </ng-template> | 157 | </ng-template> |
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index 8b5771237..4dc2b4f10 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts | |||
@@ -3,7 +3,7 @@ import truncate from 'lodash-es/truncate' | |||
3 | import { SortMeta } from 'primeng/api' | 3 | import { SortMeta } from 'primeng/api' |
4 | import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | 4 | import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' |
5 | import { environment } from 'src/environments/environment' | 5 | import { environment } from 'src/environments/environment' |
6 | import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core' | 6 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
7 | import { DomSanitizer } from '@angular/platform-browser' | 7 | import { DomSanitizer } from '@angular/platform-browser' |
8 | import { ActivatedRoute, Router } from '@angular/router' | 8 | import { ActivatedRoute, Router } from '@angular/router' |
9 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' | 9 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' |
@@ -11,6 +11,7 @@ import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared | |||
11 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' | 11 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' |
12 | import { VideoCommentService } from '@app/shared/shared-video-comment' | 12 | import { VideoCommentService } from '@app/shared/shared-video-comment' |
13 | import { AbuseState, AdminAbuse } from '@shared/models' | 13 | import { AbuseState, AdminAbuse } from '@shared/models' |
14 | import { AdvancedInputFilter } from '../shared-forms' | ||
14 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' | 15 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' |
15 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 16 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
16 | import { ProcessedAbuse } from './processed-abuse.model' | 17 | import { ProcessedAbuse } from './processed-abuse.model' |
@@ -22,9 +23,8 @@ const logger = debug('peertube:moderation:AbuseListTableComponent') | |||
22 | templateUrl: './abuse-list-table.component.html', | 23 | templateUrl: './abuse-list-table.component.html', |
23 | styleUrls: [ '../shared-moderation/moderation.scss', './abuse-list-table.component.scss' ] | 24 | styleUrls: [ '../shared-moderation/moderation.scss', './abuse-list-table.component.scss' ] |
24 | }) | 25 | }) |
25 | export class AbuseListTableComponent extends RestTable implements OnInit, AfterViewInit { | 26 | export class AbuseListTableComponent extends RestTable implements OnInit { |
26 | @Input() viewType: 'admin' | 'user' | 27 | @Input() viewType: 'admin' | 'user' |
27 | @Input() baseRoute: string | ||
28 | 28 | ||
29 | @ViewChild('abuseMessagesModal', { static: true }) abuseMessagesModal: AbuseMessageModalComponent | 29 | @ViewChild('abuseMessagesModal', { static: true }) abuseMessagesModal: AbuseMessageModalComponent |
30 | @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent | 30 | @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent |
@@ -36,6 +36,29 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
36 | 36 | ||
37 | abuseActions: DropdownAction<ProcessedAbuse>[][] = [] | 37 | abuseActions: DropdownAction<ProcessedAbuse>[][] = [] |
38 | 38 | ||
39 | inputFilters: AdvancedInputFilter[] = [ | ||
40 | { | ||
41 | queryParams: { 'search': 'state:pending' }, | ||
42 | label: $localize`Unsolved reports` | ||
43 | }, | ||
44 | { | ||
45 | queryParams: { 'search': 'state:accepted' }, | ||
46 | label: $localize`Accepted reports` | ||
47 | }, | ||
48 | { | ||
49 | queryParams: { 'search': 'state:rejected' }, | ||
50 | label: $localize`Refused reports` | ||
51 | }, | ||
52 | { | ||
53 | queryParams: { 'search': 'videoIs:blacklisted' }, | ||
54 | label: $localize`Reports with blocked videos` | ||
55 | }, | ||
56 | { | ||
57 | queryParams: { 'search': 'videoIs:deleted' }, | ||
58 | label: $localize`Reports with deleted videos` | ||
59 | } | ||
60 | ] | ||
61 | |||
39 | constructor ( | 62 | constructor ( |
40 | protected route: ActivatedRoute, | 63 | protected route: ActivatedRoute, |
41 | protected router: Router, | 64 | protected router: Router, |
@@ -66,11 +89,6 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
66 | ] | 89 | ] |
67 | 90 | ||
68 | this.initialize() | 91 | this.initialize() |
69 | this.listenToSearchChange() | ||
70 | } | ||
71 | |||
72 | ngAfterViewInit () { | ||
73 | if (this.search) this.setTableFilter(this.search, false) | ||
74 | } | 92 | } |
75 | 93 | ||
76 | isAdminView () { | 94 | isAdminView () { |
@@ -86,7 +104,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
86 | } | 104 | } |
87 | 105 | ||
88 | onModerationCommentUpdated () { | 106 | onModerationCommentUpdated () { |
89 | this.loadData() | 107 | this.reloadData() |
90 | } | 108 | } |
91 | 109 | ||
92 | isAbuseAccepted (abuse: AdminAbuse) { | 110 | isAbuseAccepted (abuse: AdminAbuse) { |
@@ -129,7 +147,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
129 | this.abuseService.removeAbuse(abuse).subscribe( | 147 | this.abuseService.removeAbuse(abuse).subscribe( |
130 | () => { | 148 | () => { |
131 | this.notifier.success($localize`Abuse deleted.`) | 149 | this.notifier.success($localize`Abuse deleted.`) |
132 | this.loadData() | 150 | this.reloadData() |
133 | }, | 151 | }, |
134 | 152 | ||
135 | err => this.notifier.error(err.message) | 153 | err => this.notifier.error(err.message) |
@@ -139,7 +157,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
139 | updateAbuseState (abuse: AdminAbuse, state: AbuseState) { | 157 | updateAbuseState (abuse: AdminAbuse, state: AbuseState) { |
140 | this.abuseService.updateAbuse(abuse, { state }) | 158 | this.abuseService.updateAbuse(abuse, { state }) |
141 | .subscribe( | 159 | .subscribe( |
142 | () => this.loadData(), | 160 | () => this.reloadData(), |
143 | 161 | ||
144 | err => this.notifier.error(err.message) | 162 | err => this.notifier.error(err.message) |
145 | ) | 163 | ) |
@@ -166,7 +184,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
166 | return Actor.IS_LOCAL(abuse.reporterAccount.host) | 184 | return Actor.IS_LOCAL(abuse.reporterAccount.host) |
167 | } | 185 | } |
168 | 186 | ||
169 | protected loadData () { | 187 | protected reloadData () { |
170 | logger('Loading data.') | 188 | logger('Loading data.') |
171 | 189 | ||
172 | const options = { | 190 | const options = { |
diff --git a/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts b/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts index 19b6d456d..8f3830a17 100644 --- a/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts +++ b/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts | |||
@@ -10,7 +10,7 @@ import { AbuseDetailsComponent } from './abuse-details.component' | |||
10 | import { AbuseListTableComponent } from './abuse-list-table.component' | 10 | import { AbuseListTableComponent } from './abuse-list-table.component' |
11 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' | 11 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' |
12 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 12 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
13 | import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-account-avatar.module' | 13 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' |
14 | 14 | ||
15 | @NgModule({ | 15 | @NgModule({ |
16 | imports: [ | 16 | imports: [ |
@@ -21,7 +21,7 @@ import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-accou | |||
21 | SharedModerationModule, | 21 | SharedModerationModule, |
22 | SharedGlobalIconModule, | 22 | SharedGlobalIconModule, |
23 | SharedVideoCommentModule, | 23 | SharedVideoCommentModule, |
24 | SharedAccountAvatarModule | 24 | SharedActorImageModule |
25 | ], | 25 | ], |
26 | 26 | ||
27 | declarations: [ | 27 | declarations: [ |
diff --git a/client/src/app/shared/shared-account-avatar/account-avatar.component.html b/client/src/app/shared/shared-account-avatar/account-avatar.component.html deleted file mode 100644 index ca4ceb12f..000000000 --- a/client/src/app/shared/shared-account-avatar/account-avatar.component.html +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | <ng-template #img> | ||
2 | <img [class]="class" [src]="avatarUrl" i18n-alt alt="Account avatar" /> | ||
3 | </ng-template> | ||
4 | |||
5 | <a *ngIf="account && href" [href]="href" target="_blank" rel="noopener noreferrer" [title]="title"> | ||
6 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
7 | </a> | ||
8 | |||
9 | <a *ngIf="account && internalHref" [routerLink]="internalHref" [title]="title"> | ||
10 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
11 | </a> | ||
12 | |||
13 | <ng-container *ngIf="!account || (!href && !internalHref)"> | ||
14 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
15 | </ng-container> | ||
diff --git a/client/src/app/shared/shared-account-avatar/account-avatar.component.scss b/client/src/app/shared/shared-account-avatar/account-avatar.component.scss deleted file mode 100644 index bb941d712..000000000 --- a/client/src/app/shared/shared-account-avatar/account-avatar.component.scss +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .avatar-25 { | ||
5 | @include avatar(25px); | ||
6 | } | ||
7 | |||
8 | .avatar-34 { | ||
9 | @include avatar(34px); | ||
10 | } | ||
11 | |||
12 | .avatar-36 { | ||
13 | @include avatar(36px); | ||
14 | } | ||
15 | |||
16 | .avatar-40 { | ||
17 | @include avatar(40px); | ||
18 | } | ||
19 | |||
20 | .avatar-120 { | ||
21 | @include avatar(120px); | ||
22 | } \ No newline at end of file | ||
diff --git a/client/src/app/shared/shared-account-avatar/account-avatar.component.ts b/client/src/app/shared/shared-account-avatar/account-avatar.component.ts deleted file mode 100644 index 02a0a18bf..000000000 --- a/client/src/app/shared/shared-account-avatar/account-avatar.component.ts +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | import { Account } from '../shared-main/account/account.model' | ||
3 | |||
4 | @Component({ | ||
5 | selector: 'my-account-avatar', | ||
6 | styleUrls: [ './account-avatar.component.scss' ], | ||
7 | templateUrl: './account-avatar.component.html' | ||
8 | }) | ||
9 | export class AccountAvatarComponent { | ||
10 | @Input() account: { | ||
11 | name: string | ||
12 | avatar?: { url?: string, path: string } | ||
13 | url: string | ||
14 | } | ||
15 | @Input() size: '25' | '34' | '36' | '40' | '120' = '36' | ||
16 | |||
17 | // Use an external link | ||
18 | @Input() href: string | ||
19 | // Use routerLink | ||
20 | @Input() internalHref: string | string[] | ||
21 | |||
22 | @Input() set title (value) { | ||
23 | this._title = value | ||
24 | } | ||
25 | |||
26 | private _title: string | ||
27 | |||
28 | get title () { | ||
29 | return this._title || $localize`${this.account.name} (account page)` | ||
30 | } | ||
31 | |||
32 | get class () { | ||
33 | return `avatar avatar-${this.size}` | ||
34 | } | ||
35 | |||
36 | get avatarUrl () { | ||
37 | return Account.GET_ACTOR_AVATAR_URL(this.account) | ||
38 | } | ||
39 | } | ||
diff --git a/client/src/app/shared/shared-account-avatar/index.ts b/client/src/app/shared/shared-account-avatar/index.ts deleted file mode 100644 index 40c742ba5..000000000 --- a/client/src/app/shared/shared-account-avatar/index.ts +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | export * from './account-avatar.component' | ||
2 | export * from './shared-account-avatar.module' \ No newline at end of file | ||
diff --git a/client/src/app/shared/shared-account-avatar/shared-account-avatar.module.ts b/client/src/app/shared/shared-account-avatar/shared-account-avatar.module.ts deleted file mode 100644 index 17b27589f..000000000 --- a/client/src/app/shared/shared-account-avatar/shared-account-avatar.module.ts +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | |||
2 | import { NgModule } from '@angular/core' | ||
3 | import { SharedGlobalIconModule } from '../shared-icons' | ||
4 | import { SharedMainModule } from '../shared-main/shared-main.module' | ||
5 | import { AccountAvatarComponent } from './account-avatar.component' | ||
6 | |||
7 | @NgModule({ | ||
8 | imports: [ | ||
9 | SharedMainModule, | ||
10 | SharedGlobalIconModule | ||
11 | ], | ||
12 | |||
13 | declarations: [ | ||
14 | AccountAvatarComponent | ||
15 | ], | ||
16 | |||
17 | exports: [ | ||
18 | AccountAvatarComponent | ||
19 | ], | ||
20 | |||
21 | providers: [ ] | ||
22 | }) | ||
23 | export class SharedAccountAvatarModule { } | ||
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.html b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html index 0829263f4..e9c5fadcf 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.html +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div class="actor" *ngIf="actor"> | 1 | <div class="actor" *ngIf="actor"> |
2 | <div class="d-flex"> | 2 | <div class="d-flex"> |
3 | <img [ngClass]="{ channel: isChannel() }" [src]="preview || actor.avatarUrl" alt="Avatar" /> | 3 | <my-actor-avatar [channel]="getChannel()" [account]="getAccount()" [previewImage]="preview" size="100"></my-actor-avatar> |
4 | 4 | ||
5 | <div class="actor-img-edit-container"> | 5 | <div class="actor-img-edit-container"> |
6 | 6 | ||
@@ -34,6 +34,7 @@ | |||
34 | <span for="avatarfile" i18n>Upload a new avatar</span> | 34 | <span for="avatarfile" i18n>Upload a new avatar</span> |
35 | <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> | 35 | <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> |
36 | </div> | 36 | </div> |
37 | |||
37 | <div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()"> | 38 | <div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()"> |
38 | <my-global-icon iconName="delete"></my-global-icon> | 39 | <my-global-icon iconName="delete"></my-global-icon> |
39 | <span i18n>Remove avatar</span> | 40 | <span i18n>Remove avatar</span> |
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.scss b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss index 8b0172315..08e80c3b4 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.scss +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss | |||
@@ -4,16 +4,8 @@ | |||
4 | .actor { | 4 | .actor { |
5 | display: flex; | 5 | display: flex; |
6 | 6 | ||
7 | img { | 7 | my-actor-avatar { |
8 | margin-right: 15px; | 8 | margin-right: 15px; |
9 | |||
10 | &:not(.channel) { | ||
11 | @include avatar(100px); | ||
12 | } | ||
13 | |||
14 | &.channel { | ||
15 | @include channel-avatar(100px); | ||
16 | } | ||
17 | } | 9 | } |
18 | 10 | ||
19 | .actor-info { | 11 | .actor-info { |
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts index d0d269489..840946690 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar-edit.component.ts +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts | |||
@@ -80,4 +80,16 @@ export class ActorAvatarEditComponent implements OnInit { | |||
80 | isChannel () { | 80 | isChannel () { |
81 | return !!(this.actor as VideoChannel).ownerAccount | 81 | return !!(this.actor as VideoChannel).ownerAccount |
82 | } | 82 | } |
83 | |||
84 | getChannel (): VideoChannel { | ||
85 | if (this.isChannel()) return this.actor as VideoChannel | ||
86 | |||
87 | return undefined | ||
88 | } | ||
89 | |||
90 | getAccount (): Account { | ||
91 | if (this.isChannel()) return undefined | ||
92 | |||
93 | return this.actor as Account | ||
94 | } | ||
83 | } | 95 | } |
diff --git a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.html b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.html index 266fc26c5..266fc26c5 100644 --- a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.html +++ b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.html | |||
diff --git a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.scss b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.scss index 23606f871..23606f871 100644 --- a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.scss +++ b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.scss | |||
diff --git a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts index 8c12d3c4c..8c12d3c4c 100644 --- a/client/src/app/shared/shared-actor-image/actor-banner-edit.component.ts +++ b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts | |||
diff --git a/client/src/app/shared/shared-actor-image/actor-image-edit.scss b/client/src/app/shared/shared-actor-image-edit/actor-image-edit.scss index 918955a89..918955a89 100644 --- a/client/src/app/shared/shared-actor-image/actor-image-edit.scss +++ b/client/src/app/shared/shared-actor-image-edit/actor-image-edit.scss | |||
diff --git a/client/src/app/shared/shared-actor-image-edit/index.ts b/client/src/app/shared/shared-actor-image-edit/index.ts new file mode 100644 index 000000000..276b2e2fb --- /dev/null +++ b/client/src/app/shared/shared-actor-image-edit/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './shared-actor-image-edit.module' | |||
diff --git a/client/src/app/shared/shared-actor-image-edit/shared-actor-image-edit.module.ts b/client/src/app/shared/shared-actor-image-edit/shared-actor-image-edit.module.ts new file mode 100644 index 000000000..f6a397d5c --- /dev/null +++ b/client/src/app/shared/shared-actor-image-edit/shared-actor-image-edit.module.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | |||
2 | import { CommonModule } from '@angular/common' | ||
3 | import { NgModule } from '@angular/core' | ||
4 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' | ||
5 | import { SharedGlobalIconModule } from '../shared-icons' | ||
6 | import { SharedMainModule } from '../shared-main' | ||
7 | import { ActorAvatarEditComponent } from './actor-avatar-edit.component' | ||
8 | import { ActorBannerEditComponent } from './actor-banner-edit.component' | ||
9 | |||
10 | @NgModule({ | ||
11 | imports: [ | ||
12 | CommonModule, | ||
13 | |||
14 | SharedMainModule, | ||
15 | SharedActorImageModule, | ||
16 | SharedGlobalIconModule | ||
17 | ], | ||
18 | |||
19 | declarations: [ | ||
20 | ActorAvatarEditComponent, | ||
21 | ActorBannerEditComponent | ||
22 | ], | ||
23 | |||
24 | exports: [ | ||
25 | ActorAvatarEditComponent, | ||
26 | ActorBannerEditComponent | ||
27 | ], | ||
28 | |||
29 | providers: [ ] | ||
30 | }) | ||
31 | export class SharedActorImageEditModule { } | ||
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.html b/client/src/app/shared/shared-actor-image/actor-avatar.component.html new file mode 100644 index 000000000..13a5385a8 --- /dev/null +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.html | |||
@@ -0,0 +1,19 @@ | |||
1 | <ng-template #img> | ||
2 | <img *ngIf="previewImage || avatarUrl || !initial" [class]="getClass('avatar')" [src]="previewImage || avatarUrl || defaultAvatarUrl" [alt]="alt" /> | ||
3 | |||
4 | <div *ngIf="!avatarUrl && initial" [class]="getClass('initial')"> | ||
5 | <span>{{ initial }}</span> | ||
6 | </div> | ||
7 | </ng-template> | ||
8 | |||
9 | <a *ngIf="hasActor() && href" [href]="href" target="_blank" rel="noopener noreferrer" [title]="title"> | ||
10 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
11 | </a> | ||
12 | |||
13 | <a *ngIf="hasActor() && internalHref" [routerLink]="internalHref" [title]="title"> | ||
14 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
15 | </a> | ||
16 | |||
17 | <ng-container *ngIf="!hasActor() || (!href && !internalHref)"> | ||
18 | <ng-template *ngTemplateOutlet="img"></ng-template> | ||
19 | </ng-container> | ||
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.scss b/client/src/app/shared/shared-actor-image/actor-avatar.component.scss new file mode 100644 index 000000000..bf50de4e9 --- /dev/null +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.scss | |||
@@ -0,0 +1,101 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .avatar { | ||
5 | --avatarSize: 100%; | ||
6 | --initialFontSize: 22px; | ||
7 | |||
8 | width: var(--avatarSize); | ||
9 | height: var(--avatarSize); | ||
10 | min-width: var(--avatarSize); | ||
11 | min-height: var(--avatarSize); | ||
12 | |||
13 | &.account { | ||
14 | object-fit: cover; | ||
15 | border-radius: 50%; | ||
16 | } | ||
17 | |||
18 | &.channel { | ||
19 | border-radius: 5px; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | .avatar-18 { | ||
24 | --avatarSize: 18px; | ||
25 | --initialFontSize: 13px; | ||
26 | } | ||
27 | |||
28 | .avatar-25 { | ||
29 | --avatarSize: 25px; | ||
30 | } | ||
31 | |||
32 | .avatar-32 { | ||
33 | --avatarSize: 32px; | ||
34 | } | ||
35 | |||
36 | .avatar-34 { | ||
37 | --avatarSize: 34px; | ||
38 | } | ||
39 | |||
40 | .avatar-36 { | ||
41 | --avatarSize: 36px; | ||
42 | } | ||
43 | |||
44 | .avatar-40 { | ||
45 | --avatarSize: 40px; | ||
46 | } | ||
47 | |||
48 | .avatar-100 { | ||
49 | --avatarSize: 100px; | ||
50 | --initialFontSize: 40px; | ||
51 | } | ||
52 | |||
53 | .avatar-120 { | ||
54 | --avatarSize: 120px; | ||
55 | --initialFontSize: 46px; | ||
56 | } | ||
57 | |||
58 | a:hover { | ||
59 | text-decoration: none; | ||
60 | } | ||
61 | |||
62 | .initial { | ||
63 | background-color: #3C2109; | ||
64 | color: #fff; | ||
65 | display: flex; | ||
66 | align-items: center; | ||
67 | justify-content: center; | ||
68 | font-size: var(--initialFontSize); | ||
69 | |||
70 | &.blue { | ||
71 | background-color: #009FD4; | ||
72 | } | ||
73 | |||
74 | &.green { | ||
75 | background-color: #00AA55; | ||
76 | } | ||
77 | |||
78 | &.purple { | ||
79 | background-color: #B381B3; | ||
80 | } | ||
81 | |||
82 | &.gray { | ||
83 | background-color: #939393; | ||
84 | } | ||
85 | |||
86 | &.yellow { | ||
87 | background-color: #AA8F00; | ||
88 | } | ||
89 | |||
90 | &.orange { | ||
91 | background-color: #D47500; | ||
92 | } | ||
93 | |||
94 | &.red { | ||
95 | background-color: #E76E3C; | ||
96 | } | ||
97 | |||
98 | &.dark-blue { | ||
99 | background-color: #0A3055; | ||
100 | } | ||
101 | } | ||
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts new file mode 100644 index 000000000..b06c2bae6 --- /dev/null +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts | |||
@@ -0,0 +1,111 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | import { SafeResourceUrl } from '@angular/platform-browser' | ||
3 | import { VideoChannel } from '../shared-main' | ||
4 | import { Account } from '../shared-main/account/account.model' | ||
5 | |||
6 | type ActorInput = { | ||
7 | name: string | ||
8 | avatar?: { url?: string, path: string } | ||
9 | url: string | ||
10 | } | ||
11 | |||
12 | export type ActorAvatarSize = '18' | '25' | '32' | '34' | '36' | '40' | '100' | '120' | ||
13 | |||
14 | @Component({ | ||
15 | selector: 'my-actor-avatar', | ||
16 | styleUrls: [ './actor-avatar.component.scss' ], | ||
17 | templateUrl: './actor-avatar.component.html' | ||
18 | }) | ||
19 | export class ActorAvatarComponent { | ||
20 | @Input() account: ActorInput | ||
21 | @Input() channel: ActorInput | ||
22 | |||
23 | @Input() previewImage: SafeResourceUrl | ||
24 | |||
25 | @Input() size: ActorAvatarSize | ||
26 | |||
27 | // Use an external link | ||
28 | @Input() href: string | ||
29 | // Use routerLink | ||
30 | @Input() internalHref: string | any[] | ||
31 | |||
32 | @Input() set title (value) { | ||
33 | this._title = value | ||
34 | } | ||
35 | |||
36 | private _title: string | ||
37 | |||
38 | get title () { | ||
39 | if (this._title) return this._title | ||
40 | if (this.account) return $localize`${this.account.name} (account page)` | ||
41 | if (this.channel) return $localize`${this.channel.name} (channel page)` | ||
42 | |||
43 | return '' | ||
44 | } | ||
45 | |||
46 | get alt () { | ||
47 | if (this.account) return $localize`Account avatar` | ||
48 | if (this.channel) return $localize`Channel avatar` | ||
49 | |||
50 | return '' | ||
51 | } | ||
52 | |||
53 | getClass (type: 'avatar' | 'initial') { | ||
54 | const base = [ 'avatar' ] | ||
55 | |||
56 | if (this.size) base.push(`avatar-${this.size}`) | ||
57 | |||
58 | if (this.channel) base.push('channel') | ||
59 | else base.push('account') | ||
60 | |||
61 | if (type === 'initial' && this.initial) { | ||
62 | base.push('initial') | ||
63 | base.push(this.getColorTheme()) | ||
64 | } | ||
65 | |||
66 | return base | ||
67 | } | ||
68 | |||
69 | get defaultAvatarUrl () { | ||
70 | if (this.channel) return VideoChannel.GET_DEFAULT_AVATAR_URL() | ||
71 | |||
72 | return Account.GET_DEFAULT_AVATAR_URL() | ||
73 | } | ||
74 | |||
75 | get avatarUrl () { | ||
76 | if (this.account) return Account.GET_ACTOR_AVATAR_URL(this.account) | ||
77 | if (this.channel) return VideoChannel.GET_ACTOR_AVATAR_URL(this.channel) | ||
78 | |||
79 | return '' | ||
80 | } | ||
81 | |||
82 | get initial () { | ||
83 | const name = this.account?.name | ||
84 | if (!name) return '' | ||
85 | |||
86 | return name.slice(0, 1) | ||
87 | } | ||
88 | |||
89 | hasActor () { | ||
90 | return !!this.account || !!this.channel | ||
91 | } | ||
92 | |||
93 | private getColorTheme () { | ||
94 | // Keep consistency with CSS | ||
95 | const themes = { | ||
96 | abc: 'blue', | ||
97 | def: 'green', | ||
98 | ghi: 'purple', | ||
99 | jkl: 'gray', | ||
100 | mno: 'yellow', | ||
101 | pqr: 'orange', | ||
102 | stvu: 'red', | ||
103 | wxyz: 'dark-blue' | ||
104 | } | ||
105 | |||
106 | const theme = Object.keys(themes) | ||
107 | .find(chars => chars.includes(this.initial)) | ||
108 | |||
109 | return themes[theme] | ||
110 | } | ||
111 | } | ||
diff --git a/client/src/app/shared/shared-actor-image/shared-actor-image.module.ts b/client/src/app/shared/shared-actor-image/shared-actor-image.module.ts index 6044f9925..8ea4bb2bf 100644 --- a/client/src/app/shared/shared-actor-image/shared-actor-image.module.ts +++ b/client/src/app/shared/shared-actor-image/shared-actor-image.module.ts | |||
@@ -1,27 +1,21 @@ | |||
1 | 1 | ||
2 | import { CommonModule } from '@angular/common' | ||
3 | import { NgModule } from '@angular/core' | 2 | import { NgModule } from '@angular/core' |
4 | import { SharedGlobalIconModule } from '../shared-icons' | 3 | import { SharedGlobalIconModule } from '../shared-icons' |
5 | import { SharedMainModule } from '../shared-main' | 4 | import { SharedMainModule } from '../shared-main/shared-main.module' |
6 | import { ActorAvatarEditComponent } from './actor-avatar-edit.component' | 5 | import { ActorAvatarComponent } from './actor-avatar.component' |
7 | import { ActorBannerEditComponent } from './actor-banner-edit.component' | ||
8 | 6 | ||
9 | @NgModule({ | 7 | @NgModule({ |
10 | imports: [ | 8 | imports: [ |
11 | CommonModule, | ||
12 | |||
13 | SharedMainModule, | 9 | SharedMainModule, |
14 | SharedGlobalIconModule | 10 | SharedGlobalIconModule |
15 | ], | 11 | ], |
16 | 12 | ||
17 | declarations: [ | 13 | declarations: [ |
18 | ActorAvatarEditComponent, | 14 | ActorAvatarComponent |
19 | ActorBannerEditComponent | ||
20 | ], | 15 | ], |
21 | 16 | ||
22 | exports: [ | 17 | exports: [ |
23 | ActorAvatarEditComponent, | 18 | ActorAvatarComponent |
24 | ActorBannerEditComponent | ||
25 | ], | 19 | ], |
26 | 20 | ||
27 | providers: [ ] | 21 | providers: [ ] |
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.html b/client/src/app/shared/shared-forms/advanced-input-filter.component.html new file mode 100644 index 000000000..10d1296cf --- /dev/null +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.html | |||
@@ -0,0 +1,24 @@ | |||
1 | <div class="input-group has-feedback has-clear"> | ||
2 | <div *ngIf="hasFilters()" class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
3 | <div class="input-group-text" ngbDropdownToggle> | ||
4 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
5 | </div> | ||
6 | |||
7 | <div role="menu" ngbDropdownMenu> | ||
8 | <h6 class="dropdown-header" i18n>Advanced filters</h6> | ||
9 | |||
10 | <a *ngFor="let filter of filters" [routerLink]="[ '.' ]" [queryParams]="filter.queryParams" class="dropdown-item"> | ||
11 | {{ filter.label }} | ||
12 | </a> | ||
13 | </div> | ||
14 | </div> | ||
15 | |||
16 | <input | ||
17 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
18 | [(ngModel)]="searchValue" | ||
19 | (keyup)="onInputSearch($event)" | ||
20 | > | ||
21 | |||
22 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="onResetTableFilter()"></a> | ||
23 | <span class="sr-only" i18n>Clear filters</span> | ||
24 | </div> | ||
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.scss b/client/src/app/shared/shared-forms/advanced-input-filter.component.scss new file mode 100644 index 000000000..7c2198927 --- /dev/null +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.scss | |||
@@ -0,0 +1,10 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | input { | ||
5 | @include peertube-input-text(250px); | ||
6 | } | ||
7 | |||
8 | .input-group-text { | ||
9 | background-color: transparent; | ||
10 | } | ||
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts new file mode 100644 index 000000000..c11f1ad1d --- /dev/null +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts | |||
@@ -0,0 +1,116 @@ | |||
1 | import * as debug from 'debug' | ||
2 | import { Subject } from 'rxjs' | ||
3 | import { debounceTime, distinctUntilChanged } from 'rxjs/operators' | ||
4 | import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' | ||
5 | import { ActivatedRoute, Params, Router } from '@angular/router' | ||
6 | |||
7 | export type AdvancedInputFilter = { | ||
8 | label: string | ||
9 | queryParams: Params | ||
10 | } | ||
11 | |||
12 | const logger = debug('peertube:AdvancedInputFilterComponent') | ||
13 | |||
14 | @Component({ | ||
15 | selector: 'my-advanced-input-filter', | ||
16 | templateUrl: './advanced-input-filter.component.html', | ||
17 | styleUrls: [ './advanced-input-filter.component.scss' ] | ||
18 | }) | ||
19 | export class AdvancedInputFilterComponent implements OnInit, AfterViewInit { | ||
20 | @Input() filters: AdvancedInputFilter[] = [] | ||
21 | |||
22 | @Output() search = new EventEmitter<string>() | ||
23 | |||
24 | searchValue: string | ||
25 | |||
26 | private searchStream: Subject<string> | ||
27 | |||
28 | private viewInitialized = false | ||
29 | private emitSearchAfterViewInit = false | ||
30 | |||
31 | constructor ( | ||
32 | private route: ActivatedRoute, | ||
33 | private router: Router | ||
34 | ) { } | ||
35 | |||
36 | ngOnInit () { | ||
37 | this.initSearchStream() | ||
38 | this.listenToRouteSearchChange() | ||
39 | } | ||
40 | |||
41 | ngAfterViewInit () { | ||
42 | this.viewInitialized = true | ||
43 | |||
44 | // Init after view init to not send an event too early | ||
45 | if (this.emitSearchAfterViewInit) this.emitSearch() | ||
46 | } | ||
47 | |||
48 | onInputSearch (event: Event) { | ||
49 | this.scheduleSearchUpdate((event.target as HTMLInputElement).value) | ||
50 | } | ||
51 | |||
52 | onResetTableFilter () { | ||
53 | this.immediateSearchUpdate('') | ||
54 | } | ||
55 | |||
56 | hasFilters () { | ||
57 | return this.filters.length !== 0 | ||
58 | } | ||
59 | |||
60 | private scheduleSearchUpdate (value: string) { | ||
61 | this.searchValue = value | ||
62 | this.searchStream.next(this.searchValue) | ||
63 | } | ||
64 | |||
65 | private immediateSearchUpdate (value: string) { | ||
66 | this.searchValue = value | ||
67 | |||
68 | this.setQueryParams(this.searchValue) | ||
69 | this.emitSearch() | ||
70 | } | ||
71 | |||
72 | private listenToRouteSearchChange () { | ||
73 | this.route.queryParams | ||
74 | .subscribe(params => { | ||
75 | const search = params.search || '' | ||
76 | |||
77 | logger('On route search change "%s".', search) | ||
78 | |||
79 | this.searchValue = search | ||
80 | this.emitSearch() | ||
81 | }) | ||
82 | } | ||
83 | |||
84 | private initSearchStream () { | ||
85 | this.searchStream = new Subject() | ||
86 | |||
87 | this.searchStream | ||
88 | .pipe( | ||
89 | debounceTime(300), | ||
90 | distinctUntilChanged() | ||
91 | ) | ||
92 | .subscribe(() => { | ||
93 | this.setQueryParams(this.searchValue) | ||
94 | |||
95 | this.emitSearch() | ||
96 | }) | ||
97 | } | ||
98 | |||
99 | private emitSearch () { | ||
100 | if (!this.viewInitialized) { | ||
101 | this.emitSearchAfterViewInit = true | ||
102 | return | ||
103 | } | ||
104 | |||
105 | logger('On search "%s".', this.searchValue) | ||
106 | |||
107 | this.search.emit(this.searchValue) | ||
108 | } | ||
109 | |||
110 | private setQueryParams (search: string) { | ||
111 | const queryParams: Params = {} | ||
112 | |||
113 | if (search) Object.assign(queryParams, { search }) | ||
114 | this.router.navigate([ ], { queryParams }) | ||
115 | } | ||
116 | } | ||
diff --git a/client/src/app/shared/shared-forms/index.ts b/client/src/app/shared/shared-forms/index.ts index 1d859b991..727416a40 100644 --- a/client/src/app/shared/shared-forms/index.ts +++ b/client/src/app/shared/shared-forms/index.ts | |||
@@ -1,12 +1,14 @@ | |||
1 | export * from './form-validator.service' | 1 | export * from './advanced-input-filter.component' |
2 | export * from './form-reactive' | 2 | export * from './form-reactive' |
3 | export * from './select' | 3 | export * from './form-validator.service' |
4 | export * from './input-toggle-hidden.component' | 4 | export * from './form-validator.service' |
5 | export * from './input-switch.component' | 5 | export * from './input-switch.component' |
6 | export * from './input-toggle-hidden.component' | ||
6 | export * from './markdown-textarea.component' | 7 | export * from './markdown-textarea.component' |
7 | export * from './peertube-checkbox.component' | 8 | export * from './peertube-checkbox.component' |
8 | export * from './preview-upload.component' | 9 | export * from './preview-upload.component' |
9 | export * from './reactive-file.component' | 10 | export * from './reactive-file.component' |
11 | export * from './select' | ||
12 | export * from './shared-form.module' | ||
10 | export * from './textarea-autoresize.directive' | 13 | export * from './textarea-autoresize.directive' |
11 | export * from './timestamp-input.component' | 14 | export * from './timestamp-input.component' |
12 | export * from './shared-form.module' | ||
diff --git a/client/src/app/shared/shared-forms/input-switch.component.scss b/client/src/app/shared/shared-forms/input-switch.component.scss index c14950bd7..290a70db8 100644 --- a/client/src/app/shared/shared-forms/input-switch.component.scss +++ b/client/src/app/shared/shared-forms/input-switch.component.scss | |||
@@ -5,7 +5,7 @@ input { | |||
5 | position: absolute; | 5 | position: absolute; |
6 | visibility: hidden; | 6 | visibility: hidden; |
7 | 7 | ||
8 | & + label { | 8 | + label { |
9 | cursor: pointer; | 9 | cursor: pointer; |
10 | text-indent: -9999px; | 10 | text-indent: -9999px; |
11 | width: 35px; | 11 | width: 35px; |
@@ -16,7 +16,7 @@ input { | |||
16 | position: relative; | 16 | position: relative; |
17 | margin: 0; | 17 | margin: 0; |
18 | 18 | ||
19 | &:after { | 19 | &::after { |
20 | content: ''; | 20 | content: ''; |
21 | position: absolute; | 21 | position: absolute; |
22 | top: 3px; | 22 | top: 3px; |
@@ -28,7 +28,7 @@ input { | |||
28 | transition: 0.3s ease-out; | 28 | transition: 0.3s ease-out; |
29 | } | 29 | } |
30 | 30 | ||
31 | &:active:after { | 31 | &:active::after { |
32 | width: 40px; | 32 | width: 40px; |
33 | } | 33 | } |
34 | } | 34 | } |
@@ -36,7 +36,7 @@ input { | |||
36 | &:checked + label { | 36 | &:checked + label { |
37 | background: pvar(--mainColor); | 37 | background: pvar(--mainColor); |
38 | 38 | ||
39 | &:after { | 39 | &::after { |
40 | left: calc(100% - 3px); | 40 | left: calc(100% - 3px); |
41 | transform: translateX(-100%); | 41 | transform: translateX(-100%); |
42 | } | 42 | } |
diff --git a/client/src/app/shared/shared-forms/markdown-textarea.component.scss b/client/src/app/shared/shared-forms/markdown-textarea.component.scss index 8203c7d1c..1f72dbc32 100644 --- a/client/src/app/shared/shared-forms/markdown-textarea.component.scss +++ b/client/src/app/shared/shared-forms/markdown-textarea.component.scss | |||
@@ -18,7 +18,7 @@ $input-border-radius: 3px; | |||
18 | 18 | ||
19 | font-family: monospace; | 19 | font-family: monospace; |
20 | font-size: 13px; | 20 | font-size: 13px; |
21 | border-bottom: none; | 21 | border-bottom: 0; |
22 | border-bottom-left-radius: unset; | 22 | border-bottom-left-radius: unset; |
23 | border-bottom-right-radius: unset; | 23 | border-bottom-right-radius: unset; |
24 | } | 24 | } |
@@ -51,7 +51,8 @@ $input-border-radius: 3px; | |||
51 | opacity: 0.6; | 51 | opacity: 0.6; |
52 | } | 52 | } |
53 | 53 | ||
54 | &:hover, &:active { | 54 | &:hover, |
55 | &:active { | ||
55 | svg { | 56 | svg { |
56 | opacity: 1; | 57 | opacity: 1; |
57 | } | 58 | } |
@@ -105,6 +106,8 @@ $input-border-radius: 3px; | |||
105 | } | 106 | } |
106 | 107 | ||
107 | @mixin maximized-base { | 108 | @mixin maximized-base { |
109 | $nav-preview-vertical-padding: 40px; | ||
110 | |||
108 | flex-direction: row; | 111 | flex-direction: row; |
109 | z-index: #{z(header) - 1}; | 112 | z-index: #{z(header) - 1}; |
110 | position: fixed; | 113 | position: fixed; |
@@ -115,20 +118,18 @@ $input-border-radius: 3px; | |||
115 | width: calc(100% - #{$menu-width}); | 118 | width: calc(100% - #{$menu-width}); |
116 | height: calc(100vh - #{$header-height}) !important; | 119 | height: calc(100vh - #{$header-height}) !important; |
117 | 120 | ||
118 | $nav-preview-vertical-padding: 40px; | ||
119 | |||
120 | .nav-preview { | 121 | .nav-preview { |
121 | @include nav-preview-medium(); | 122 | @include nav-preview-medium(); |
122 | padding-top: #{$nav-preview-vertical-padding / 2}; | 123 | padding-top: #{$nav-preview-vertical-padding / 2}; |
123 | padding-bottom: #{$nav-preview-vertical-padding / 2}; | 124 | padding-bottom: #{$nav-preview-vertical-padding / 2}; |
124 | padding-left: 0px; | 125 | padding-left: 0; |
125 | padding-right: 0px; | 126 | padding-right: 0; |
126 | position: absolute; | 127 | position: absolute; |
127 | background-color: pvar(--mainBackgroundColor); | 128 | background-color: pvar(--mainBackgroundColor); |
128 | width: 100% !important; | 129 | width: 100% !important; |
129 | border-top: none; | 130 | border-top: 0; |
130 | border-left: none; | 131 | border-left: 0; |
131 | border-right: none; | 132 | border-right: 0; |
132 | 133 | ||
133 | :last-child { | 134 | :last-child { |
134 | margin-right: pvar(--horizontalMarginContent); | 135 | margin-right: pvar(--horizontalMarginContent); |
@@ -148,7 +149,7 @@ $input-border-radius: 3px; | |||
148 | margin-top: #{$nav-preview-tab-height + $nav-preview-vertical-padding} !important; | 149 | margin-top: #{$nav-preview-tab-height + $nav-preview-vertical-padding} !important; |
149 | height: calc(100vh - #{$header-height + $nav-preview-tab-height + $nav-preview-vertical-padding}) !important; | 150 | height: calc(100vh - #{$header-height + $nav-preview-tab-height + $nav-preview-vertical-padding}) !important; |
150 | width: 50% !important; | 151 | width: 50% !important; |
151 | border: none !important; | 152 | border: 0 !important; |
152 | border-radius: unset !important; | 153 | border-radius: unset !important; |
153 | } | 154 | } |
154 | 155 | ||
@@ -249,11 +250,11 @@ $input-border-radius: 3px; | |||
249 | } | 250 | } |
250 | 251 | ||
251 | @media only screen and (min-width: $small-view) { | 252 | @media only screen and (min-width: $small-view) { |
253 | @include maximized-in-medium-view(); | ||
254 | |||
252 | :host-context(.expanded) { | 255 | :host-context(.expanded) { |
253 | @include in-medium-view(); | 256 | @include in-medium-view(); |
254 | } | 257 | } |
255 | |||
256 | @include maximized-in-medium-view(); | ||
257 | } | 258 | } |
258 | 259 | ||
259 | @media only screen and (min-width: #{$small-view + $menu-width}) { | 260 | @media only screen and (min-width: #{$small-view + $menu-width}) { |
diff --git a/client/src/app/shared/shared-forms/peertube-checkbox.component.scss b/client/src/app/shared/shared-forms/peertube-checkbox.component.scss index cf8540dc3..203b82d0b 100644 --- a/client/src/app/shared/shared-forms/peertube-checkbox.component.scss +++ b/client/src/app/shared/shared-forms/peertube-checkbox.component.scss | |||
@@ -46,7 +46,7 @@ | |||
46 | line-height: 12px; | 46 | line-height: 12px; |
47 | font-weight: 500; | 47 | font-weight: 500; |
48 | color: pvar(--inputPlaceholderColor); | 48 | color: pvar(--inputPlaceholderColor); |
49 | background-color: rgba(217,225,232,.1); | 49 | background-color: rgba(217, 225, 232, .1); |
50 | border: 1px solid rgba(217,225,232,.5); | 50 | border: 1px solid rgba(217, 225, 232, .5); |
51 | } | 51 | } |
52 | } \ No newline at end of file | 52 | } |
diff --git a/client/src/app/shared/shared-forms/preview-upload.component.scss b/client/src/app/shared/shared-forms/preview-upload.component.scss index 88eccd5f7..c2ee0d6a9 100644 --- a/client/src/app/shared/shared-forms/preview-upload.component.scss +++ b/client/src/app/shared/shared-forms/preview-upload.component.scss | |||
@@ -21,7 +21,7 @@ | |||
21 | max-width: 100%; | 21 | max-width: 100%; |
22 | 22 | ||
23 | &.no-image { | 23 | &.no-image { |
24 | border: 2px solid grey; | 24 | border: 2px solid #808080; |
25 | background-color: pvar(--mainBackgroundColor); | 25 | background-color: pvar(--mainBackgroundColor); |
26 | } | 26 | } |
27 | } | 27 | } |
diff --git a/client/src/app/shared/shared-forms/select/select-shared.component.scss b/client/src/app/shared/shared-forms/select/select-shared.component.scss index 80196b8df..7006adab1 100644 --- a/client/src/app/shared/shared-forms/select/select-shared.component.scss +++ b/client/src/app/shared/shared-forms/select/select-shared.component.scss | |||
@@ -32,7 +32,7 @@ ng-select ::ng-deep { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | .root { | 34 | .root { |
35 | display:flex; | 35 | display: flex; |
36 | align-items: center; | 36 | align-items: center; |
37 | 37 | ||
38 | > my-select-options { | 38 | > my-select-options { |
@@ -41,9 +41,9 @@ ng-select ::ng-deep { | |||
41 | } | 41 | } |
42 | 42 | ||
43 | my-select-options + input { | 43 | my-select-options + input { |
44 | margin-left: 5px; | ||
45 | |||
46 | @include peertube-input-text($form-base-input-width); | 44 | @include peertube-input-text($form-base-input-width); |
45 | |||
46 | margin-left: 5px; | ||
47 | display: block; | 47 | display: block; |
48 | } | 48 | } |
49 | 49 | ||
diff --git a/client/src/app/shared/shared-forms/shared-form.module.ts b/client/src/app/shared/shared-forms/shared-form.module.ts index 9bdd138a1..5417f7342 100644 --- a/client/src/app/shared/shared-forms/shared-form.module.ts +++ b/client/src/app/shared/shared-forms/shared-form.module.ts | |||
@@ -5,6 +5,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms' | |||
5 | import { NgSelectModule } from '@ng-select/ng-select' | 5 | import { NgSelectModule } from '@ng-select/ng-select' |
6 | import { SharedGlobalIconModule } from '../shared-icons' | 6 | import { SharedGlobalIconModule } from '../shared-icons' |
7 | import { SharedMainModule } from '../shared-main/shared-main.module' | 7 | import { SharedMainModule } from '../shared-main/shared-main.module' |
8 | import { AdvancedInputFilterComponent } from './advanced-input-filter.component' | ||
8 | import { DynamicFormFieldComponent } from './dynamic-form-field.component' | 9 | import { DynamicFormFieldComponent } from './dynamic-form-field.component' |
9 | import { FormValidatorService } from './form-validator.service' | 10 | import { FormValidatorService } from './form-validator.service' |
10 | import { InputSwitchComponent } from './input-switch.component' | 11 | import { InputSwitchComponent } from './input-switch.component' |
@@ -52,7 +53,9 @@ import { TimestampInputComponent } from './timestamp-input.component' | |||
52 | SelectCheckboxComponent, | 53 | SelectCheckboxComponent, |
53 | SelectCustomValueComponent, | 54 | SelectCustomValueComponent, |
54 | 55 | ||
55 | DynamicFormFieldComponent | 56 | DynamicFormFieldComponent, |
57 | |||
58 | AdvancedInputFilterComponent | ||
56 | ], | 59 | ], |
57 | 60 | ||
58 | exports: [ | 61 | exports: [ |
@@ -78,7 +81,9 @@ import { TimestampInputComponent } from './timestamp-input.component' | |||
78 | SelectCheckboxComponent, | 81 | SelectCheckboxComponent, |
79 | SelectCustomValueComponent, | 82 | SelectCustomValueComponent, |
80 | 83 | ||
81 | DynamicFormFieldComponent | 84 | DynamicFormFieldComponent, |
85 | |||
86 | AdvancedInputFilterComponent | ||
82 | ], | 87 | ], |
83 | 88 | ||
84 | providers: [ | 89 | providers: [ |
diff --git a/client/src/app/shared/shared-forms/timestamp-input.component.scss b/client/src/app/shared/shared-forms/timestamp-input.component.scss index 66e9aa032..36f5711a6 100644 --- a/client/src/app/shared/shared-forms/timestamp-input.component.scss +++ b/client/src/app/shared/shared-forms/timestamp-input.component.scss | |||
@@ -4,8 +4,7 @@ p-inputmask { | |||
4 | ::ng-deep input { | 4 | ::ng-deep input { |
5 | width: 80px; | 5 | width: 80px; |
6 | font-size: 15px; | 6 | font-size: 15px; |
7 | 7 | border: 0; | |
8 | border: none; | ||
9 | 8 | ||
10 | &:focus-within, | 9 | &:focus-within, |
11 | &:focus { | 10 | &:focus { |
diff --git a/client/src/app/shared/shared-instance/instance-about-accordion.component.scss b/client/src/app/shared/shared-instance/instance-about-accordion.component.scss index 2f6b420e3..615e08bcc 100644 --- a/client/src/app/shared/shared-instance/instance-about-accordion.component.scss +++ b/client/src/app/shared/shared-instance/instance-about-accordion.component.scss | |||
@@ -1,6 +1,6 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | @import "./_bootstrap-variables"; | 3 | @import './_bootstrap-variables'; |
4 | 4 | ||
5 | @import '~bootstrap/scss/functions'; | 5 | @import '~bootstrap/scss/functions'; |
6 | @import '~bootstrap/scss/variables'; | 6 | @import '~bootstrap/scss/variables'; |
@@ -30,7 +30,7 @@ ngb-accordion ::ng-deep { | |||
30 | background-color: unset; | 30 | background-color: unset; |
31 | padding: 0; | 31 | padding: 0; |
32 | 32 | ||
33 | & + .collapse.show { | 33 | + .collapse.show { |
34 | background-color: var(--submenuBackgroundColor); | 34 | background-color: var(--submenuBackgroundColor); |
35 | } | 35 | } |
36 | } | 36 | } |
diff --git a/client/src/app/shared/shared-instance/instance-features-table.component.scss b/client/src/app/shared/shared-instance/instance-features-table.component.scss index d17e91fc2..11cf11616 100644 --- a/client/src/app/shared/shared-instance/instance-features-table.component.scss +++ b/client/src/app/shared/shared-instance/instance-features-table.component.scss | |||
@@ -19,7 +19,7 @@ table { | |||
19 | .more-info { | 19 | .more-info { |
20 | font-style: italic; | 20 | font-style: italic; |
21 | font-weight: initial; | 21 | font-weight: initial; |
22 | font-size: 14px | 22 | font-size: 14px; |
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
diff --git a/client/src/app/shared/shared-main/account/account.model.ts b/client/src/app/shared/shared-main/account/account.model.ts index 65e6798d4..6d9f0ee65 100644 --- a/client/src/app/shared/shared-main/account/account.model.ts +++ b/client/src/app/shared/shared-main/account/account.model.ts | |||
@@ -14,7 +14,7 @@ export class Account extends Actor implements ServerAccount { | |||
14 | userId?: number | 14 | userId?: number |
15 | 15 | ||
16 | static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { | 16 | static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { |
17 | return Actor.GET_ACTOR_AVATAR_URL(actor) || this.GET_DEFAULT_AVATAR_URL() | 17 | return Actor.GET_ACTOR_AVATAR_URL(actor) |
18 | } | 18 | } |
19 | 19 | ||
20 | static GET_DEFAULT_AVATAR_URL () { | 20 | static GET_DEFAULT_AVATAR_URL () { |
@@ -24,8 +24,6 @@ export class Account extends Actor implements ServerAccount { | |||
24 | constructor (hash: ServerAccount) { | 24 | constructor (hash: ServerAccount) { |
25 | super(hash) | 25 | super(hash) |
26 | 26 | ||
27 | this.updateComputedAttributes() | ||
28 | |||
29 | this.displayName = hash.displayName | 27 | this.displayName = hash.displayName |
30 | this.description = hash.description | 28 | this.description = hash.description |
31 | this.userId = hash.userId | 29 | this.userId = hash.userId |
@@ -40,16 +38,9 @@ export class Account extends Actor implements ServerAccount { | |||
40 | 38 | ||
41 | updateAvatar (newAvatar: ActorImage) { | 39 | updateAvatar (newAvatar: ActorImage) { |
42 | this.avatar = newAvatar | 40 | this.avatar = newAvatar |
43 | |||
44 | this.updateComputedAttributes() | ||
45 | } | 41 | } |
46 | 42 | ||
47 | resetAvatar () { | 43 | resetAvatar () { |
48 | this.avatar = null | 44 | this.avatar = null |
49 | this.avatarUrl = Account.GET_DEFAULT_AVATAR_URL() | ||
50 | } | ||
51 | |||
52 | private updateComputedAttributes () { | ||
53 | this.avatarUrl = Account.GET_ACTOR_AVATAR_URL(this) | ||
54 | } | 45 | } |
55 | } | 46 | } |
diff --git a/client/src/app/shared/shared-main/account/actor.model.ts b/client/src/app/shared/shared-main/account/actor.model.ts index 4b036341f..6ba0bb09e 100644 --- a/client/src/app/shared/shared-main/account/actor.model.ts +++ b/client/src/app/shared/shared-main/account/actor.model.ts | |||
@@ -15,7 +15,6 @@ export abstract class Actor implements ServerActor { | |||
15 | updatedAt: Date | string | 15 | updatedAt: Date | string |
16 | 16 | ||
17 | avatar: ActorImage | 17 | avatar: ActorImage |
18 | avatarUrl: string | ||
19 | 18 | ||
20 | isLocal: boolean | 19 | isLocal: boolean |
21 | 20 | ||
diff --git a/client/src/app/shared/shared-main/buttons/action-dropdown.component.scss b/client/src/app/shared/shared-main/buttons/action-dropdown.component.scss index 724a04efc..b9a4d46dc 100644 --- a/client/src/app/shared/shared-main/buttons/action-dropdown.component.scss +++ b/client/src/app/shared/shared-main/buttons/action-dropdown.component.scss | |||
@@ -8,6 +8,9 @@ | |||
8 | .action-button { | 8 | .action-button { |
9 | @include peertube-button; | 9 | @include peertube-button; |
10 | 10 | ||
11 | display: inline-block; | ||
12 | padding: 0 10px; | ||
13 | |||
11 | &.button-styled { | 14 | &.button-styled { |
12 | 15 | ||
13 | &.grey { | 16 | &.grey { |
@@ -18,14 +21,13 @@ | |||
18 | @include orange-button; | 21 | @include orange-button; |
19 | } | 22 | } |
20 | 23 | ||
21 | &:hover, &:active, &:focus { | 24 | &:hover, |
25 | &:active, | ||
26 | &:focus { | ||
22 | background-color: $grey-background-color; | 27 | background-color: $grey-background-color; |
23 | } | 28 | } |
24 | } | 29 | } |
25 | 30 | ||
26 | display: inline-block; | ||
27 | padding: 0 10px; | ||
28 | |||
29 | &::after { | 31 | &::after { |
30 | display: none; | 32 | display: none; |
31 | } | 33 | } |
@@ -64,7 +66,8 @@ | |||
64 | @include dropdown-with-icon-item; | 66 | @include dropdown-with-icon-item; |
65 | } | 67 | } |
66 | 68 | ||
67 | a, span { | 69 | a, |
70 | span { | ||
68 | display: block; | 71 | display: block; |
69 | width: 100%; | 72 | width: 100%; |
70 | } | 73 | } |
diff --git a/client/src/app/shared/shared-main/buttons/button.component.scss b/client/src/app/shared/shared-main/buttons/button.component.scss index f73b7b808..09b5f95d7 100644 --- a/client/src/app/shared/shared-main/buttons/button.component.scss +++ b/client/src/app/shared/shared-main/buttons/button.component.scss | |||
@@ -1,6 +1,16 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | @mixin responsive-label { | ||
5 | .action-button { | ||
6 | padding: 0 13px; | ||
7 | } | ||
8 | |||
9 | .button-label { | ||
10 | display: none; | ||
11 | } | ||
12 | } | ||
13 | |||
4 | :host { | 14 | :host { |
5 | outline: none; | 15 | outline: none; |
6 | } | 16 | } |
@@ -46,12 +56,12 @@ span[class$=-button] { | |||
46 | // In a table, try to minimize the space taken by this button | 56 | // In a table, try to minimize the space taken by this button |
47 | @media screen and (max-width: 1400px) { | 57 | @media screen and (max-width: 1400px) { |
48 | :host-context(td) { | 58 | :host-context(td) { |
49 | .action-button { | 59 | @include responsive-label; |
50 | padding: 0 13px; | 60 | } |
51 | } | 61 | } |
52 | 62 | ||
53 | .button-label { | 63 | @media screen and (max-width: $small-view) { |
54 | display: none; | 64 | .responsive-label { |
55 | } | 65 | @include responsive-label; |
56 | } | 66 | } |
57 | } | 67 | } |
diff --git a/client/src/app/shared/shared-main/buttons/button.component.ts b/client/src/app/shared/shared-main/buttons/button.component.ts index 1d2be0bf9..ee74b3d12 100644 --- a/client/src/app/shared/shared-main/buttons/button.component.ts +++ b/client/src/app/shared/shared-main/buttons/button.component.ts | |||
@@ -3,7 +3,7 @@ import { GlobalIconName } from '@app/shared/shared-icons' | |||
3 | 3 | ||
4 | @Component({ | 4 | @Component({ |
5 | selector: 'my-button', | 5 | selector: 'my-button', |
6 | styleUrls: ['./button.component.scss'], | 6 | styleUrls: [ './button.component.scss' ], |
7 | templateUrl: './button.component.html' | 7 | templateUrl: './button.component.html' |
8 | }) | 8 | }) |
9 | 9 | ||
@@ -14,6 +14,7 @@ export class ButtonComponent { | |||
14 | @Input() title: string = undefined | 14 | @Input() title: string = undefined |
15 | @Input() loading = false | 15 | @Input() loading = false |
16 | @Input() disabled = false | 16 | @Input() disabled = false |
17 | @Input() responsiveLabel = false | ||
17 | 18 | ||
18 | getTitle () { | 19 | getTitle () { |
19 | return this.title || this.label | 20 | return this.title || this.label |
@@ -22,7 +23,8 @@ export class ButtonComponent { | |||
22 | getClasses () { | 23 | getClasses () { |
23 | return { | 24 | return { |
24 | [this.className]: true, | 25 | [this.className]: true, |
25 | disabled: this.disabled | 26 | disabled: this.disabled, |
27 | 'responsive-label': this.responsiveLabel | ||
26 | } | 28 | } |
27 | } | 29 | } |
28 | } | 30 | } |
diff --git a/client/src/app/shared/shared-main/buttons/delete-button.component.html b/client/src/app/shared/shared-main/buttons/delete-button.component.html index c94d8d0c9..d7a6702a7 100644 --- a/client/src/app/shared/shared-main/buttons/delete-button.component.html +++ b/client/src/app/shared/shared-main/buttons/delete-button.component.html | |||
@@ -1,4 +1,7 @@ | |||
1 | <span class="action-button action-button-delete grey-button" [ngbTooltip]="title" role="button" tabindex="0"> | 1 | <span |
2 | class="action-button action-button-delete grey-button" | ||
3 | [ngClass]="{ 'responsive-label': responsiveLabel }" [ngbTooltip]="title" role="button" tabindex="0" | ||
4 | > | ||
2 | <my-global-icon iconName="delete" aria-hidden="true"></my-global-icon> | 5 | <my-global-icon iconName="delete" aria-hidden="true"></my-global-icon> |
3 | 6 | ||
4 | <span class="button-label" *ngIf="label">{{ label }}</span> | 7 | <span class="button-label" *ngIf="label">{{ label }}</span> |
diff --git a/client/src/app/shared/shared-main/buttons/delete-button.component.ts b/client/src/app/shared/shared-main/buttons/delete-button.component.ts index 18995422a..c091f5309 100644 --- a/client/src/app/shared/shared-main/buttons/delete-button.component.ts +++ b/client/src/app/shared/shared-main/buttons/delete-button.component.ts | |||
@@ -9,6 +9,7 @@ import { Component, Input, OnInit } from '@angular/core' | |||
9 | export class DeleteButtonComponent implements OnInit { | 9 | export class DeleteButtonComponent implements OnInit { |
10 | @Input() label: string | 10 | @Input() label: string |
11 | @Input() title: string | 11 | @Input() title: string |
12 | @Input() responsiveLabel = false | ||
12 | 13 | ||
13 | ngOnInit () { | 14 | ngOnInit () { |
14 | // <my-delete-button /> No label | 15 | // <my-delete-button /> No label |
diff --git a/client/src/app/shared/shared-main/buttons/edit-button.component.html b/client/src/app/shared/shared-main/buttons/edit-button.component.html index ecb709be1..8beeee6c4 100644 --- a/client/src/app/shared/shared-main/buttons/edit-button.component.html +++ b/client/src/app/shared/shared-main/buttons/edit-button.component.html | |||
@@ -1,4 +1,7 @@ | |||
1 | <a class="action-button action-button-edit grey-button" [routerLink]="routerLink" [ngbTooltip]="title"> | 1 | <a |
2 | class="action-button action-button-edit grey-button" | ||
3 | [ngClass]="{ 'responsive-label': responsiveLabel }" [routerLink]="routerLink" [ngbTooltip]="title" | ||
4 | > | ||
2 | <my-global-icon iconName="edit" aria-hidden="true"></my-global-icon> | 5 | <my-global-icon iconName="edit" aria-hidden="true"></my-global-icon> |
3 | 6 | ||
4 | <span class="button-label" *ngIf="label">{{ label }}</span> | 7 | <span class="button-label" *ngIf="label">{{ label }}</span> |
diff --git a/client/src/app/shared/shared-main/buttons/edit-button.component.ts b/client/src/app/shared/shared-main/buttons/edit-button.component.ts index 4b76551ca..24c8625ff 100644 --- a/client/src/app/shared/shared-main/buttons/edit-button.component.ts +++ b/client/src/app/shared/shared-main/buttons/edit-button.component.ts | |||
@@ -5,11 +5,11 @@ import { Component, Input, OnInit } from '@angular/core' | |||
5 | styleUrls: [ './button.component.scss' ], | 5 | styleUrls: [ './button.component.scss' ], |
6 | templateUrl: './edit-button.component.html' | 6 | templateUrl: './edit-button.component.html' |
7 | }) | 7 | }) |
8 | |||
9 | export class EditButtonComponent implements OnInit { | 8 | export class EditButtonComponent implements OnInit { |
10 | @Input() label: string | 9 | @Input() label: string |
11 | @Input() title: string | 10 | @Input() title: string |
12 | @Input() routerLink: string[] | string = [] | 11 | @Input() routerLink: string[] | string = [] |
12 | @Input() responsiveLabel = false | ||
13 | 13 | ||
14 | ngOnInit () { | 14 | ngOnInit () { |
15 | // <my-edit-button /> No label | 15 | // <my-edit-button /> No label |
diff --git a/client/src/app/shared/shared-main/date/date-toggle.component.scss b/client/src/app/shared/shared-main/date/date-toggle.component.scss index 86700d1d4..b87f7c475 100644 --- a/client/src/app/shared/shared-main/date/date-toggle.component.scss +++ b/client/src/app/shared/shared-main/date/date-toggle.component.scss | |||
@@ -1,5 +1,5 @@ | |||
1 | .date-toggle { | 1 | .date-toggle { |
2 | &:hover { | 2 | &:hover { |
3 | cursor: default | 3 | cursor: default; |
4 | } | 4 | } |
5 | } | 5 | } |
diff --git a/client/src/app/shared/shared-main/feeds/feed.component.scss b/client/src/app/shared/shared-main/feeds/feed.component.scss index b655ee708..d39f31d70 100644 --- a/client/src/app/shared/shared-main/feeds/feed.component.scss +++ b/client/src/app/shared/shared-main/feeds/feed.component.scss | |||
@@ -5,14 +5,14 @@ | |||
5 | width: 100%; | 5 | width: 100%; |
6 | 6 | ||
7 | a { | 7 | a { |
8 | color: black; | 8 | color: #000; |
9 | display: block; | 9 | display: block; |
10 | } | 10 | } |
11 | } | 11 | } |
12 | 12 | ||
13 | my-global-icon { | 13 | my-global-icon { |
14 | @include apply-svg-color(pvar(--mainForegroundColor)); | ||
15 | |||
14 | cursor: pointer; | 16 | cursor: pointer; |
15 | width: 100%; | 17 | width: 100%; |
16 | |||
17 | @include apply-svg-color(pvar(--mainForegroundColor)) | ||
18 | } | 18 | } |
diff --git a/client/src/app/shared/shared-main/loaders/loader.component.scss b/client/src/app/shared/shared-main/loaders/loader.component.scss index ffac9c707..64138afe4 100644 --- a/client/src/app/shared/shared-main/loaders/loader.component.scss +++ b/client/src/app/shared/shared-main/loaders/loader.component.scss | |||
@@ -20,7 +20,7 @@ | |||
20 | border: 4px solid; | 20 | border: 4px solid; |
21 | border-radius: 50%; | 21 | border-radius: 50%; |
22 | animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; | 22 | animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; |
23 | border-color: #999999 transparent transparent transparent; | 23 | border-color: #999999 transparent transparent; |
24 | } | 24 | } |
25 | 25 | ||
26 | .loader div:nth-child(1) { | 26 | .loader div:nth-child(1) { |
diff --git a/client/src/app/shared/shared-main/misc/help.component.scss b/client/src/app/shared/shared-main/misc/help.component.scss index ccc91ffab..68d7ad48f 100644 --- a/client/src/app/shared/shared-main/misc/help.component.scss +++ b/client/src/app/shared/shared-main/misc/help.component.scss | |||
@@ -2,20 +2,19 @@ | |||
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .help-tooltip-button { | 4 | .help-tooltip-button { |
5 | cursor: pointer; | 5 | @include disable-outline; |
6 | border: none; | ||
7 | 6 | ||
7 | cursor: pointer; | ||
8 | border: 0; | ||
8 | margin: 5px; | 9 | margin: 5px; |
9 | 10 | ||
10 | my-global-icon { | 11 | my-global-icon { |
12 | @include apply-svg-color(pvar(--greyForegroundColor)); | ||
13 | |||
11 | width: 17px; | 14 | width: 17px; |
12 | position: relative; | 15 | position: relative; |
13 | top: -1px; | 16 | top: -1px; |
14 | |||
15 | @include apply-svg-color(pvar(--greyForegroundColor)) | ||
16 | } | 17 | } |
17 | |||
18 | @include disable-outline; | ||
19 | } | 18 | } |
20 | 19 | ||
21 | ::ng-deep { | 20 | ::ng-deep { |
diff --git a/client/src/app/shared/shared-main/misc/list-overflow.component.html b/client/src/app/shared/shared-main/misc/list-overflow.component.html index 986572801..b2e0982f1 100644 --- a/client/src/app/shared/shared-main/misc/list-overflow.component.html +++ b/client/src/app/shared/shared-main/misc/list-overflow.component.html | |||
@@ -2,19 +2,19 @@ | |||
2 | <span [id]="getId(id)" #itemsRendered *ngFor="let item of items; index as id"> | 2 | <span [id]="getId(id)" #itemsRendered *ngFor="let item of items; index as id"> |
3 | <ng-container *ngTemplateOutlet="itemTemplate; context: {item: item}"></ng-container> | 3 | <ng-container *ngTemplateOutlet="itemTemplate; context: {item: item}"></ng-container> |
4 | </span> | 4 | </span> |
5 | 5 | ||
6 | <ng-container *ngIf="isMenuDisplayed()"> | 6 | <ng-container *ngIf="isMenuDisplayed()"> |
7 | <button *ngIf="isInMobileView" class="btn btn-outline-secondary btn-sm list-overflow-menu" (click)="toggleModal()"> | 7 | <button *ngIf="isInMobileView" class="btn btn-outline-secondary btn-sm list-overflow-menu" (click)="toggleModal()"> |
8 | <span class="glyphicon glyphicon-chevron-down"></span> | 8 | <span class="glyphicon glyphicon-chevron-down"></span> |
9 | </button> | 9 | </button> |
10 | 10 | ||
11 | <div *ngIf="!isInMobileView" class="list-overflow-menu" ngbDropdown container="body" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)" (mouseenter)="openDropdownOnHover(dropdown)"> | 11 | <div *ngIf="!isInMobileView" class="list-overflow-menu" ngbDropdown container="body" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)" (mouseenter)="openDropdownOnHover(dropdown)"> |
12 | <button class="btn btn-outline-secondary btn-sm" [ngClass]="{ routeActive: active }" | 12 | <button class="btn btn-outline-secondary btn-sm" [ngClass]="{ 'route-active': active }" |
13 | ngbDropdownAnchor (click)="dropdownAnchorClicked(dropdown)" role="button" | 13 | ngbDropdownAnchor (click)="dropdownAnchorClicked(dropdown)" role="button" |
14 | > | 14 | > |
15 | <span class="glyphicon glyphicon-chevron-down"></span> | 15 | <span class="glyphicon glyphicon-chevron-down"></span> |
16 | </button> | 16 | </button> |
17 | 17 | ||
18 | <div ngbDropdownMenu> | 18 | <div ngbDropdownMenu> |
19 | <a *ngFor="let item of items | slice:showItemsUntilIndexExcluded:items.length" | 19 | <a *ngFor="let item of items | slice:showItemsUntilIndexExcluded:items.length" |
20 | [routerLink]="item.routerLink" routerLinkActive="active" class="dropdown-item"> | 20 | [routerLink]="item.routerLink" routerLinkActive="active" class="dropdown-item"> |
diff --git a/client/src/app/shared/shared-main/misc/list-overflow.component.scss b/client/src/app/shared/shared-main/misc/list-overflow.component.scss index 1ec044489..7e31d3850 100644 --- a/client/src/app/shared/shared-main/misc/list-overflow.component.scss +++ b/client/src/app/shared/shared-main/misc/list-overflow.component.scss | |||
@@ -15,13 +15,13 @@ | |||
15 | 15 | ||
16 | button { | 16 | button { |
17 | width: 30px; | 17 | width: 30px; |
18 | border: none; | 18 | border: 0; |
19 | 19 | ||
20 | &::after { | 20 | &::after { |
21 | display: none; | 21 | display: none; |
22 | } | 22 | } |
23 | 23 | ||
24 | &.routeActive { | 24 | &.route-active { |
25 | &::after { | 25 | &::after { |
26 | display: inherit; | 26 | display: inherit; |
27 | border: 2px solid pvar(--mainColor); | 27 | border: 2px solid pvar(--mainColor); |
@@ -36,7 +36,7 @@ button { | |||
36 | margin-top: 0 !important; | 36 | margin-top: 0 !important; |
37 | position: static; | 37 | position: static; |
38 | right: auto; | 38 | right: auto; |
39 | bottom: auto | 39 | bottom: auto; |
40 | } | 40 | } |
41 | 41 | ||
42 | .modal-body { | 42 | .modal-body { |
diff --git a/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.scss b/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.scss index 84dd7dce3..ffabb3646 100644 --- a/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.scss +++ b/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.scss | |||
@@ -11,12 +11,12 @@ | |||
11 | } | 11 | } |
12 | } | 12 | } |
13 | 13 | ||
14 | ::ng-deep .dropdown-toggle::after { | 14 | .sub-menu ::ng-deep .dropdown-toggle::after { |
15 | position: relative; | 15 | position: relative; |
16 | top: 2px; | 16 | top: 2px; |
17 | } | 17 | } |
18 | 18 | ||
19 | ::ng-deep .dropdown-menu { | 19 | .sub-menu ::ng-deep .dropdown-menu { |
20 | margin-top: 0 !important; | 20 | margin-top: 0 !important; |
21 | } | 21 | } |
22 | 22 | ||
diff --git a/client/src/app/shared/shared-main/users/user-notification.model.ts b/client/src/app/shared/shared-main/users/user-notification.model.ts index 88a4811da..ed5791794 100644 --- a/client/src/app/shared/shared-main/users/user-notification.model.ts +++ b/client/src/app/shared/shared-main/users/user-notification.model.ts | |||
@@ -258,10 +258,10 @@ export class UserNotification implements UserNotificationServer { | |||
258 | } | 258 | } |
259 | 259 | ||
260 | private setAccountAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { | 260 | private setAccountAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { |
261 | actor.avatarUrl = Account.GET_ACTOR_AVATAR_URL(actor) | 261 | actor.avatarUrl = Account.GET_ACTOR_AVATAR_URL(actor) || Account.GET_DEFAULT_AVATAR_URL() |
262 | } | 262 | } |
263 | 263 | ||
264 | private setVideoChannelAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { | 264 | private setVideoChannelAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { |
265 | actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor) | 265 | actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor) || VideoChannel.GET_DEFAULT_AVATAR_URL() |
266 | } | 266 | } |
267 | } | 267 | } |
diff --git a/client/src/app/shared/shared-main/users/user-notifications.component.scss b/client/src/app/shared/shared-main/users/user-notifications.component.scss index 5166bd559..b69d4b5d6 100644 --- a/client/src/app/shared/shared-main/users/user-notifications.component.scss +++ b/client/src/app/shared/shared-main/users/user-notifications.component.scss | |||
@@ -21,16 +21,19 @@ | |||
21 | } | 21 | } |
22 | 22 | ||
23 | my-global-icon { | 23 | my-global-icon { |
24 | @include apply-svg-color(#333); | ||
25 | |||
24 | width: 24px; | 26 | width: 24px; |
25 | margin-right: 11px; | 27 | margin-right: 11px; |
26 | margin-left: 3px; | 28 | margin-left: 3px; |
27 | |||
28 | @include apply-svg-color(#333); | ||
29 | } | 29 | } |
30 | 30 | ||
31 | .avatar { | 31 | .avatar { |
32 | @include avatar(30px); | 32 | width: 30px; |
33 | 33 | height: 30px; | |
34 | min-width: 30px; | ||
35 | min-height: 30px; | ||
36 | border-radius: 5px; | ||
34 | margin-right: 10px; | 37 | margin-right: 10px; |
35 | } | 38 | } |
36 | 39 | ||
diff --git a/client/src/app/shared/shared-main/users/user-quota.component.scss b/client/src/app/shared/shared-main/users/user-quota.component.scss index c670559d3..c06cafe29 100644 --- a/client/src/app/shared/shared-main/users/user-quota.component.scss +++ b/client/src/app/shared/shared-main/users/user-quota.component.scss | |||
@@ -11,7 +11,8 @@ label { | |||
11 | margin-right: 5px; | 11 | margin-right: 5px; |
12 | } | 12 | } |
13 | 13 | ||
14 | &, .progress { | 14 | &, |
15 | .progress { | ||
15 | width: 100% !important; | 16 | width: 100% !important; |
16 | } | 17 | } |
17 | 18 | ||
diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts index 1ba3fcc0e..c40dd5311 100644 --- a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts +++ b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts | |||
@@ -18,14 +18,13 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
18 | 18 | ||
19 | ownerAccount?: ServerAccount | 19 | ownerAccount?: ServerAccount |
20 | ownerBy?: string | 20 | ownerBy?: string |
21 | ownerAvatarUrl?: string | ||
22 | 21 | ||
23 | videosCount?: number | 22 | videosCount?: number |
24 | 23 | ||
25 | viewsPerDay?: ViewsPerDate[] | 24 | viewsPerDay?: ViewsPerDate[] |
26 | 25 | ||
27 | static GET_ACTOR_AVATAR_URL (actor: object) { | 26 | static GET_ACTOR_AVATAR_URL (actor: object) { |
28 | return Actor.GET_ACTOR_AVATAR_URL(actor) || this.GET_DEFAULT_AVATAR_URL() | 27 | return Actor.GET_ACTOR_AVATAR_URL(actor) |
29 | } | 28 | } |
30 | 29 | ||
31 | static GET_ACTOR_BANNER_URL (channel: ServerVideoChannel) { | 30 | static GET_ACTOR_BANNER_URL (channel: ServerVideoChannel) { |
@@ -67,7 +66,6 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
67 | if (hash.ownerAccount) { | 66 | if (hash.ownerAccount) { |
68 | this.ownerAccount = hash.ownerAccount | 67 | this.ownerAccount = hash.ownerAccount |
69 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) | 68 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) |
70 | this.ownerAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.ownerAccount) | ||
71 | } | 69 | } |
72 | 70 | ||
73 | this.updateComputedAttributes() | 71 | this.updateComputedAttributes() |
@@ -94,7 +92,6 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
94 | } | 92 | } |
95 | 93 | ||
96 | updateComputedAttributes () { | 94 | updateComputedAttributes () { |
97 | this.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this) | ||
98 | this.bannerUrl = VideoChannel.GET_ACTOR_BANNER_URL(this) | 95 | this.bannerUrl = VideoChannel.GET_ACTOR_BANNER_URL(this) |
99 | } | 96 | } |
100 | } | 97 | } |
diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts index 14c507295..526d10e32 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts | |||
@@ -20,8 +20,6 @@ export class Video implements VideoServerModel { | |||
20 | byVideoChannel: string | 20 | byVideoChannel: string |
21 | byAccount: string | 21 | byAccount: string |
22 | 22 | ||
23 | videoChannelAvatarUrl: string | ||
24 | |||
25 | createdAt: Date | 23 | createdAt: Date |
26 | updatedAt: Date | 24 | updatedAt: Date |
27 | publishedAt: Date | 25 | publishedAt: Date |
@@ -143,7 +141,6 @@ export class Video implements VideoServerModel { | |||
143 | 141 | ||
144 | this.byAccount = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host) | 142 | this.byAccount = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host) |
145 | this.byVideoChannel = Actor.CREATE_BY_STRING(hash.channel.name, hash.channel.host) | 143 | this.byVideoChannel = Actor.CREATE_BY_STRING(hash.channel.name, hash.channel.host) |
146 | this.videoChannelAvatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this.channel) | ||
147 | 144 | ||
148 | this.category.label = peertubeTranslate(this.category.label, translations) | 145 | this.category.label = peertubeTranslate(this.category.label, translations) |
149 | this.licence.label = peertubeTranslate(this.licence.label, translations) | 146 | this.licence.label = peertubeTranslate(this.licence.label, translations) |
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts index 0b708b692..7b17bd2ab 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts | |||
@@ -124,7 +124,17 @@ export class VideoService implements VideosProvider { | |||
124 | 124 | ||
125 | let params = new HttpParams() | 125 | let params = new HttpParams() |
126 | params = this.restService.addRestGetParams(params, pagination, sort) | 126 | params = this.restService.addRestGetParams(params, pagination, sort) |
127 | params = this.restService.addObjectParams(params, { search }) | 127 | |
128 | if (search) { | ||
129 | const filters = this.restService.parseQueryStringFilter(search, { | ||
130 | isLive: { | ||
131 | prefix: 'isLive:', | ||
132 | isBoolean: true | ||
133 | } | ||
134 | }) | ||
135 | |||
136 | params = this.restService.addObjectParams(params, filters) | ||
137 | } | ||
128 | 138 | ||
129 | return this.authHttp | 139 | return this.authHttp |
130 | .get<ResultList<Video>>(UserService.BASE_USERS_URL + 'me/videos', { params }) | 140 | .get<ResultList<Video>>(UserService.BASE_USERS_URL + 'me/videos', { params }) |
diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.html b/client/src/app/shared/shared-moderation/account-blocklist.component.html index 3f2f55559..a9fac0810 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.html +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.html | |||
@@ -11,13 +11,8 @@ | |||
11 | > | 11 | > |
12 | <ng-template pTemplate="caption"> | 12 | <ng-template pTemplate="caption"> |
13 | <div class="caption"> | 13 | <div class="caption"> |
14 | <div class="ml-auto has-feedback has-clear"> | 14 | <div class="ml-auto"> |
15 | <input | 15 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
16 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
17 | (keyup)="onSearch($event)" | ||
18 | > | ||
19 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
20 | <span class="sr-only" i18n>Clear filters</span> | ||
21 | </div> | 16 | </div> |
22 | </div> | 17 | </div> |
23 | </ng-template> | 18 | </ng-template> |
@@ -38,7 +33,7 @@ | |||
38 | <td> | 33 | <td> |
39 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 34 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
40 | <div class="chip two-lines"> | 35 | <div class="chip two-lines"> |
41 | <my-account-avatar [account]="accountBlock.blockedAccount"></my-account-avatar> | 36 | <my-actor-avatar [account]="accountBlock.blockedAccount"></my-actor-avatar> |
42 | <div> | 37 | <div> |
43 | {{ accountBlock.blockedAccount.displayName }} | 38 | {{ accountBlock.blockedAccount.displayName }} |
44 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> | 39 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> |
diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.scss b/client/src/app/shared/shared-moderation/account-blocklist.component.scss index 3eede44eb..bc441811e 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.scss +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.scss | |||
@@ -1,15 +1,6 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .caption { | ||
5 | justify-content: flex-end; | ||
6 | |||
7 | input { | ||
8 | @include peertube-input-text(250px); | ||
9 | flex-grow: 1; | ||
10 | } | ||
11 | } | ||
12 | |||
13 | .chip { | 4 | .chip { |
14 | @include chip; | 5 | @include chip; |
15 | } | 6 | } |
@@ -17,4 +8,4 @@ | |||
17 | .unblock-button { | 8 | .unblock-button { |
18 | @include peertube-button; | 9 | @include peertube-button; |
19 | @include grey-button; | 10 | @include grey-button; |
20 | } \ No newline at end of file | 11 | } |
diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.ts b/client/src/app/shared/shared-moderation/account-blocklist.component.ts index 1bce65bf0..1146aeec0 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.ts +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.ts | |||
@@ -44,12 +44,12 @@ export class GenericAccountBlocklistComponent extends RestTable implements OnIni | |||
44 | : $localize`Account ${blockedAccount.nameWithHost} unmuted by your instance.` | 44 | : $localize`Account ${blockedAccount.nameWithHost} unmuted by your instance.` |
45 | ) | 45 | ) |
46 | 46 | ||
47 | this.loadData() | 47 | this.reloadData() |
48 | } | 48 | } |
49 | ) | 49 | ) |
50 | } | 50 | } |
51 | 51 | ||
52 | protected loadData () { | 52 | protected reloadData () { |
53 | const operation = this.mode === BlocklistComponentType.Account | 53 | const operation = this.mode === BlocklistComponentType.Account |
54 | ? this.blocklistService.getUserAccountBlocklist({ | 54 | ? this.blocklistService.getUserAccountBlocklist({ |
55 | pagination: this.pagination, | 55 | pagination: this.pagination, |
diff --git a/client/src/app/shared/shared-moderation/moderation.scss b/client/src/app/shared/shared-moderation/moderation.scss index cdcc12fe0..b13d06f03 100644 --- a/client/src/app/shared/shared-moderation/moderation.scss +++ b/client/src/app/shared/shared-moderation/moderation.scss | |||
@@ -17,33 +17,25 @@ | |||
17 | word-wrap: break-word; | 17 | word-wrap: break-word; |
18 | 18 | ||
19 | ::ng-deep p:last-child { | 19 | ::ng-deep p:last-child { |
20 | margin-bottom: 0px !important; | 20 | margin-bottom: 0 !important; |
21 | } | 21 | } |
22 | } | 22 | } |
23 | } | 23 | } |
24 | 24 | ||
25 | .screenratio { | 25 | .screenratio { |
26 | div { | ||
27 | @include miniature-thumbnail; | ||
28 | |||
29 | display: inline-flex; | ||
30 | justify-content: center; | ||
31 | align-items: center; | ||
32 | color: pvar(--inputPlaceholderColor); | ||
33 | } | ||
34 | |||
35 | @include block-ratio($selector: 'div, ::ng-deep iframe') { | 26 | @include block-ratio($selector: 'div, ::ng-deep iframe') { |
36 | width: 100% !important; | 27 | width: 100% !important; |
37 | height: 100% !important; | 28 | height: 100% !important; |
38 | left: 0; | 29 | left: 0; |
39 | }; | 30 | }; |
40 | } | ||
41 | 31 | ||
42 | .input-group { | 32 | div { |
43 | @include peertube-input-group(300px); | 33 | @include miniature-thumbnail; |
44 | 34 | ||
45 | .dropdown-toggle::after { | 35 | display: inline-flex; |
46 | margin-left: 0; | 36 | justify-content: center; |
37 | align-items: center; | ||
38 | color: pvar(--inputPlaceholderColor); | ||
47 | } | 39 | } |
48 | } | 40 | } |
49 | 41 | ||
@@ -51,15 +43,6 @@ | |||
51 | @include chip; | 43 | @include chip; |
52 | } | 44 | } |
53 | 45 | ||
54 | .caption { | ||
55 | justify-content: flex-end; | ||
56 | |||
57 | input { | ||
58 | @include peertube-input-text(250px); | ||
59 | flex-grow: 1; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | my-action-dropdown.show { | 46 | my-action-dropdown.show { |
64 | ::ng-deep .dropdown-root { | 47 | ::ng-deep .dropdown-root { |
65 | display: block !important; | 48 | display: block !important; |
@@ -93,15 +76,15 @@ my-action-dropdown.show { | |||
93 | display: inline-flex; | 76 | display: inline-flex; |
94 | 77 | ||
95 | .table-video-image { | 78 | .table-video-image { |
96 | @include miniature-thumbnail; | ||
97 | |||
98 | $image-height: 45px; | 79 | $image-height: 45px; |
99 | 80 | ||
81 | @include miniature-thumbnail; | ||
82 | |||
100 | height: $image-height; | 83 | height: $image-height; |
101 | width: #{(16/9) * $image-height}; | 84 | width: #{(16/9) * $image-height}; |
102 | margin-right: 0.5rem; | 85 | margin-right: 0.5rem; |
103 | border-radius: 2px; | 86 | border-radius: 2px; |
104 | border: none; | 87 | border: 0; |
105 | background: transparent; | 88 | background: transparent; |
106 | display: inline-flex; | 89 | display: inline-flex; |
107 | justify-content: center; | 90 | justify-content: center; |
@@ -139,7 +122,7 @@ my-action-dropdown.show { | |||
139 | 122 | ||
140 | div .glyphicon { | 123 | div .glyphicon { |
141 | font-size: 80%; | 124 | font-size: 80%; |
142 | color: gray; | 125 | color: #808080; |
143 | margin-left: 0.1rem; | 126 | margin-left: 0.1rem; |
144 | } | 127 | } |
145 | 128 | ||
diff --git a/client/src/app/shared/shared-moderation/server-blocklist.component.html b/client/src/app/shared/shared-moderation/server-blocklist.component.html index 537186f05..c6d29bb21 100644 --- a/client/src/app/shared/shared-moderation/server-blocklist.component.html +++ b/client/src/app/shared/shared-moderation/server-blocklist.component.html | |||
@@ -4,8 +4,9 @@ | |||
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <p-table | 6 | <p-table |
7 | [value]="blockedServers" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 7 | [value]="blockedServers" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
8 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | 8 | [sortField]="sort.field" [sortOrder]="sort.order" (onPage)="onPage($event)" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
9 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
10 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted instances" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted instances" |
11 | > | 12 | > |
@@ -18,13 +19,8 @@ | |||
18 | </a> | 19 | </a> |
19 | </div> | 20 | </div> |
20 | 21 | ||
21 | <div class="ml-auto has-feedback has-clear"> | 22 | <div class="ml-auto"> |
22 | <input | 23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
23 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
24 | (keyup)="onSearch($event)" | ||
25 | > | ||
26 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
27 | <span class="sr-only" i18n>Clear filters</span> | ||
28 | </div> | 24 | </div> |
29 | </div> | 25 | </div> |
30 | </ng-template> | 26 | </ng-template> |
diff --git a/client/src/app/shared/shared-moderation/server-blocklist.component.scss b/client/src/app/shared/shared-moderation/server-blocklist.component.scss index 31db4d92b..a22972c5f 100644 --- a/client/src/app/shared/shared-moderation/server-blocklist.component.scss +++ b/client/src/app/shared/shared-moderation/server-blocklist.component.scss | |||
@@ -5,7 +5,8 @@ a { | |||
5 | @include disable-default-a-behaviour; | 5 | @include disable-default-a-behaviour; |
6 | display: inline-block; | 6 | display: inline-block; |
7 | 7 | ||
8 | &, &:hover { | 8 | &, |
9 | &:hover { | ||
9 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
10 | } | 11 | } |
11 | 12 | ||
@@ -15,15 +16,6 @@ a { | |||
15 | } | 16 | } |
16 | } | 17 | } |
17 | 18 | ||
18 | .caption { | ||
19 | justify-content: flex-end; | ||
20 | |||
21 | input { | ||
22 | @include peertube-input-text(250px); | ||
23 | flex-grow: 1; | ||
24 | } | ||
25 | } | ||
26 | |||
27 | .unblock-button { | 19 | .unblock-button { |
28 | @include peertube-button; | 20 | @include peertube-button; |
29 | @include grey-button; | 21 | @include grey-button; |
@@ -33,15 +25,6 @@ a { | |||
33 | @include create-button; | 25 | @include create-button; |
34 | } | 26 | } |
35 | 27 | ||
36 | .caption { | ||
37 | justify-content: flex-end; | ||
38 | |||
39 | input { | ||
40 | @include peertube-input-text(250px); | ||
41 | flex-grow: 1; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | .chip { | 28 | .chip { |
46 | @include chip; | 29 | @include chip; |
47 | } | 30 | } |
diff --git a/client/src/app/shared/shared-moderation/server-blocklist.component.ts b/client/src/app/shared/shared-moderation/server-blocklist.component.ts index 546fd53c3..274d8f6e9 100644 --- a/client/src/app/shared/shared-moderation/server-blocklist.component.ts +++ b/client/src/app/shared/shared-moderation/server-blocklist.component.ts | |||
@@ -46,7 +46,7 @@ export class GenericServerBlocklistComponent extends RestTable implements OnInit | |||
46 | : $localize`Instance ${host} unmuted by your instance.` | 46 | : $localize`Instance ${host} unmuted by your instance.` |
47 | ) | 47 | ) |
48 | 48 | ||
49 | this.loadData() | 49 | this.reloadData() |
50 | } | 50 | } |
51 | ) | 51 | ) |
52 | } | 52 | } |
@@ -69,13 +69,13 @@ export class GenericServerBlocklistComponent extends RestTable implements OnInit | |||
69 | : $localize`Instance ${domain} muted by your instance.` | 69 | : $localize`Instance ${domain} muted by your instance.` |
70 | ) | 70 | ) |
71 | 71 | ||
72 | this.loadData() | 72 | this.reloadData() |
73 | } | 73 | } |
74 | ) | 74 | ) |
75 | }) | 75 | }) |
76 | } | 76 | } |
77 | 77 | ||
78 | protected loadData () { | 78 | protected reloadData () { |
79 | const operation = this.mode === BlocklistComponentType.Account | 79 | const operation = this.mode === BlocklistComponentType.Account |
80 | ? this.blocklistService.getUserServerBlocklist({ | 80 | ? this.blocklistService.getUserServerBlocklist({ |
81 | pagination: this.pagination, | 81 | pagination: this.pagination, |
diff --git a/client/src/app/shared/shared-moderation/shared-moderation.module.ts b/client/src/app/shared/shared-moderation/shared-moderation.module.ts index c7e201792..95213e2bd 100644 --- a/client/src/app/shared/shared-moderation/shared-moderation.module.ts +++ b/client/src/app/shared/shared-moderation/shared-moderation.module.ts | |||
@@ -13,7 +13,7 @@ import { UserBanModalComponent } from './user-ban-modal.component' | |||
13 | import { UserModerationDropdownComponent } from './user-moderation-dropdown.component' | 13 | import { UserModerationDropdownComponent } from './user-moderation-dropdown.component' |
14 | import { VideoBlockComponent } from './video-block.component' | 14 | import { VideoBlockComponent } from './video-block.component' |
15 | import { VideoBlockService } from './video-block.service' | 15 | import { VideoBlockService } from './video-block.service' |
16 | import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-account-avatar.module' | 16 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' |
17 | 17 | ||
18 | @NgModule({ | 18 | @NgModule({ |
19 | imports: [ | 19 | imports: [ |
@@ -21,7 +21,7 @@ import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-accou | |||
21 | SharedFormModule, | 21 | SharedFormModule, |
22 | SharedGlobalIconModule, | 22 | SharedGlobalIconModule, |
23 | SharedVideoCommentModule, | 23 | SharedVideoCommentModule, |
24 | SharedAccountAvatarModule | 24 | SharedActorImageModule |
25 | ], | 25 | ], |
26 | 26 | ||
27 | declarations: [ | 27 | declarations: [ |
diff --git a/client/src/app/shared/shared-moderation/video-block.component.scss b/client/src/app/shared/shared-moderation/video-block.component.scss index afa0d96f7..a6e33070b 100644 --- a/client/src/app/shared/shared-moderation/video-block.component.scss +++ b/client/src/app/shared/shared-moderation/video-block.component.scss | |||
@@ -7,5 +7,5 @@ textarea { | |||
7 | 7 | ||
8 | .live-info { | 8 | .live-info { |
9 | font-size: 15px; | 9 | font-size: 15px; |
10 | margin: 40px 0 20px 0; | 10 | margin: 40px 0 20px; |
11 | } | 11 | } |
diff --git a/client/src/app/shared/shared-search/advanced-search.model.ts b/client/src/app/shared/shared-search/advanced-search.model.ts index 30badc8fa..0e3924841 100644 --- a/client/src/app/shared/shared-search/advanced-search.model.ts +++ b/client/src/app/shared/shared-search/advanced-search.model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { NSFWQuery, SearchTargetType } from '@shared/models' | 1 | import { BooleanBothQuery, SearchTargetType } from '@shared/models' |
2 | 2 | ||
3 | export class AdvancedSearch { | 3 | export class AdvancedSearch { |
4 | startDate: string // ISO 8601 | 4 | startDate: string // ISO 8601 |
@@ -7,7 +7,7 @@ export class AdvancedSearch { | |||
7 | originallyPublishedStartDate: string // ISO 8601 | 7 | originallyPublishedStartDate: string // ISO 8601 |
8 | originallyPublishedEndDate: string // ISO 8601 | 8 | originallyPublishedEndDate: string // ISO 8601 |
9 | 9 | ||
10 | nsfw: NSFWQuery | 10 | nsfw: BooleanBothQuery |
11 | 11 | ||
12 | categoryOneOf: string | 12 | categoryOneOf: string |
13 | 13 | ||
@@ -33,7 +33,7 @@ export class AdvancedSearch { | |||
33 | endDate?: string | 33 | endDate?: string |
34 | originallyPublishedStartDate?: string | 34 | originallyPublishedStartDate?: string |
35 | originallyPublishedEndDate?: string | 35 | originallyPublishedEndDate?: string |
36 | nsfw?: NSFWQuery | 36 | nsfw?: BooleanBothQuery |
37 | categoryOneOf?: string | 37 | categoryOneOf?: string |
38 | licenceOneOf?: string | 38 | licenceOneOf?: string |
39 | languageOneOf?: string | 39 | languageOneOf?: string |
diff --git a/client/src/app/shared/shared-thumbnail/video-thumbnail.component.scss b/client/src/app/shared/shared-thumbnail/video-thumbnail.component.scss index ea59ab346..e678d6edf 100644 --- a/client/src/app/shared/shared-thumbnail/video-thumbnail.component.scss +++ b/client/src/app/shared/shared-thumbnail/video-thumbnail.component.scss | |||
@@ -11,7 +11,7 @@ | |||
11 | width: 100%; | 11 | width: 100%; |
12 | position: absolute; | 12 | position: absolute; |
13 | bottom: 0; | 13 | bottom: 0; |
14 | background-color: rgba(0, 0, 0, 0.20); | 14 | background-color: rgba(0, 0, 0, 0.2); |
15 | 15 | ||
16 | div { | 16 | div { |
17 | height: 100%; | 17 | height: 100%; |
@@ -39,8 +39,8 @@ | |||
39 | top: 5px; | 39 | top: 5px; |
40 | font-weight: $font-bold; | 40 | font-weight: $font-bold; |
41 | 41 | ||
42 | &.warning { background-color: orange; } | 42 | &.warning { background-color: #ffa500; } |
43 | &.danger { background-color: red; } | 43 | &.danger { background-color: #ff0000; } |
44 | } | 44 | } |
45 | 45 | ||
46 | .video-thumbnail-duration-overlay, | 46 | .video-thumbnail-duration-overlay, |
@@ -77,9 +77,9 @@ | |||
77 | padding: 3px; | 77 | padding: 3px; |
78 | 78 | ||
79 | my-global-icon { | 79 | my-global-icon { |
80 | @include apply-svg-color(#fff); | ||
81 | |||
80 | width: 22px; | 82 | width: 22px; |
81 | height: 22px; | 83 | height: 22px; |
82 | |||
83 | @include apply-svg-color(#fff); | ||
84 | } | 84 | } |
85 | } | 85 | } |
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.html b/client/src/app/shared/shared-user-settings/user-video-settings.component.html index aa261fdce..a49e11485 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.html +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <my-help> | 5 | <my-help> |
6 | <ng-template ptTemplate="customHtml"> | 6 | <ng-template ptTemplate="customHtml"> |
7 | <ng-container i18n> | 7 | <ng-container i18n> |
8 | With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video. | 8 | With <strong>Hide</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video. |
9 | </ng-container> | 9 | </ng-container> |
10 | </ng-template> | 10 | </ng-template> |
11 | </my-help> | 11 | </my-help> |
@@ -13,7 +13,7 @@ | |||
13 | <div class="peertube-select-container"> | 13 | <div class="peertube-select-container"> |
14 | <select id="nsfwPolicy" formControlName="nsfwPolicy" class="form-control"> | 14 | <select id="nsfwPolicy" formControlName="nsfwPolicy" class="form-control"> |
15 | <option i18n value="undefined" disabled>Policy for sensitive videos</option> | 15 | <option i18n value="undefined" disabled>Policy for sensitive videos</option> |
16 | <option i18n value="do_not_list">Do not list</option> | 16 | <option i18n value="do_not_list">Hide</option> |
17 | <option i18n value="blur">Blur thumbnails</option> | 17 | <option i18n value="blur">Blur thumbnails</option> |
18 | <option i18n value="display">Display</option> | 18 | <option i18n value="display">Display</option> |
19 | </select> | 19 | </select> |
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts index d74c2b2d8..ae95030c7 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts | |||
@@ -38,8 +38,6 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
38 | ngOnInit () { | 38 | ngOnInit () { |
39 | this.allLanguagesGroup = $localize`All languages` | 39 | this.allLanguagesGroup = $localize`All languages` |
40 | 40 | ||
41 | let oldForm: any | ||
42 | |||
43 | this.buildForm({ | 41 | this.buildForm({ |
44 | nsfwPolicy: null, | 42 | nsfwPolicy: null, |
45 | webTorrentEnabled: null, | 43 | webTorrentEnabled: null, |
@@ -73,16 +71,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
73 | videoLanguages | 71 | videoLanguages |
74 | }) | 72 | }) |
75 | 73 | ||
76 | if (this.reactiveUpdate) { | 74 | if (this.reactiveUpdate) this.handleReactiveUpdate() |
77 | oldForm = { ...this.form.value } | ||
78 | |||
79 | this.formValuesWatcher = this.form.valueChanges.subscribe((formValue: any) => { | ||
80 | const updatedKey = Object.keys(formValue).find(k => formValue[k] !== oldForm[k]) | ||
81 | oldForm = { ...this.form.value } | ||
82 | |||
83 | this.updateDetails([ updatedKey ]) | ||
84 | }) | ||
85 | } | ||
86 | }) | 75 | }) |
87 | } | 76 | } |
88 | 77 | ||
@@ -96,7 +85,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
96 | const autoPlayVideo = this.form.value['autoPlayVideo'] | 85 | const autoPlayVideo = this.form.value['autoPlayVideo'] |
97 | const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] | 86 | const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] |
98 | 87 | ||
99 | const videoLanguagesForm = this.form.value['videoLanguages'] | 88 | let videoLanguagesForm = this.form.value['videoLanguages'] |
100 | 89 | ||
101 | if (Array.isArray(videoLanguagesForm)) { | 90 | if (Array.isArray(videoLanguagesForm)) { |
102 | if (videoLanguagesForm.length > 20) { | 91 | if (videoLanguagesForm.length > 20) { |
@@ -104,13 +93,14 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
104 | return | 93 | return |
105 | } | 94 | } |
106 | 95 | ||
96 | // Automatically use "All languages" if the user did not select any language | ||
107 | if (videoLanguagesForm.length === 0) { | 97 | if (videoLanguagesForm.length === 0) { |
108 | this.notifier.error($localize`You need to enable at least 1 video language.`) | 98 | videoLanguagesForm = [ this.allLanguagesGroup ] |
109 | return | 99 | this.form.patchValue({ videoLanguages: [ { group: this.allLanguagesGroup } ] }) |
110 | } | 100 | } |
111 | } | 101 | } |
112 | 102 | ||
113 | const videoLanguages = this.getVideoLanguages(videoLanguagesForm) | 103 | const videoLanguages = this.buildLanguagesFromForm(videoLanguagesForm) |
114 | 104 | ||
115 | let details: UserUpdateMe = { | 105 | let details: UserUpdateMe = { |
116 | nsfwPolicy, | 106 | nsfwPolicy, |
@@ -127,22 +117,13 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
127 | if (onlyKeys) details = pick(details, onlyKeys) | 117 | if (onlyKeys) details = pick(details, onlyKeys) |
128 | 118 | ||
129 | if (this.authService.isLoggedIn()) { | 119 | if (this.authService.isLoggedIn()) { |
130 | this.userService.updateMyProfile(details).subscribe( | 120 | return this.updateLoggedProfile(details) |
131 | () => { | ||
132 | this.authService.refreshUserInformation() | ||
133 | |||
134 | if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`) | ||
135 | }, | ||
136 | |||
137 | err => this.notifier.error(err.message) | ||
138 | ) | ||
139 | } else { | ||
140 | this.userService.updateMyAnonymousProfile(details) | ||
141 | if (this.notifyOnUpdate) this.notifier.success($localize`Display/Video settings updated.`) | ||
142 | } | 121 | } |
122 | |||
123 | return this.updateAnonymousProfile(details) | ||
143 | } | 124 | } |
144 | 125 | ||
145 | private getVideoLanguages (videoLanguages: ItemSelectCheckboxValue[]) { | 126 | private buildLanguagesFromForm (videoLanguages: ItemSelectCheckboxValue[]) { |
146 | if (!Array.isArray(videoLanguages)) return undefined | 127 | if (!Array.isArray(videoLanguages)) return undefined |
147 | 128 | ||
148 | // null means "All" | 129 | // null means "All" |
@@ -166,4 +147,34 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
166 | return l.id + '' | 147 | return l.id + '' |
167 | }) | 148 | }) |
168 | } | 149 | } |
150 | |||
151 | private handleReactiveUpdate () { | ||
152 | let oldForm = { ...this.form.value } | ||
153 | |||
154 | this.formValuesWatcher = this.form.valueChanges.subscribe((formValue: any) => { | ||
155 | const updatedKey = Object.keys(formValue) | ||
156 | .find(k => formValue[k] !== oldForm[k]) | ||
157 | |||
158 | oldForm = { ...this.form.value } | ||
159 | |||
160 | this.updateDetails([ updatedKey ]) | ||
161 | }) | ||
162 | } | ||
163 | |||
164 | private updateLoggedProfile (details: UserUpdateMe) { | ||
165 | this.userService.updateMyProfile(details).subscribe( | ||
166 | () => { | ||
167 | this.authService.refreshUserInformation() | ||
168 | |||
169 | if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`) | ||
170 | }, | ||
171 | |||
172 | err => this.notifier.error(err.message) | ||
173 | ) | ||
174 | } | ||
175 | |||
176 | private updateAnonymousProfile (details: UserUpdateMe) { | ||
177 | this.userService.updateMyAnonymousProfile(details) | ||
178 | if (this.notifyOnUpdate) this.notifier.success($localize`Display/Video settings updated.`) | ||
179 | } | ||
169 | } | 180 | } |
diff --git a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.scss b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.scss index 698c5866a..73db0d090 100644 --- a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.scss +++ b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.scss | |||
@@ -3,4 +3,4 @@ | |||
3 | .btn-remote-follow { | 3 | .btn-remote-follow { |
4 | @include peertube-button; | 4 | @include peertube-button; |
5 | @include orange-button; | 5 | @include orange-button; |
6 | } \ No newline at end of file | 6 | } |
diff --git a/client/src/app/shared/shared-user-subscription/subscribe-button.component.scss b/client/src/app/shared/shared-user-subscription/subscribe-button.component.scss index f6cdc11c0..897ee7799 100644 --- a/client/src/app/shared/shared-user-subscription/subscribe-button.component.scss +++ b/client/src/app/shared/shared-user-subscription/subscribe-button.component.scss | |||
@@ -8,8 +8,8 @@ | |||
8 | float: right; | 8 | float: right; |
9 | padding: 0; | 9 | padding: 0; |
10 | 10 | ||
11 | & > .btn, | 11 | > .btn, |
12 | & > .dropdown > .dropdown-toggle { | 12 | > .dropdown > .dropdown-toggle { |
13 | font-size: 15px; | 13 | font-size: 15px; |
14 | } | 14 | } |
15 | 15 | ||
@@ -20,7 +20,7 @@ | |||
20 | &.big { | 20 | &.big { |
21 | height: 35px; | 21 | height: 35px; |
22 | 22 | ||
23 | & > button:first-child { | 23 | > button:first-child { |
24 | width: max-content; | 24 | width: max-content; |
25 | min-width: 175px; | 25 | min-width: 175px; |
26 | } | 26 | } |
@@ -29,7 +29,7 @@ | |||
29 | span:first-child { | 29 | span:first-child { |
30 | line-height: 80%; | 30 | line-height: 80%; |
31 | } | 31 | } |
32 | 32 | ||
33 | span:not(:first-child) { | 33 | span:not(:first-child) { |
34 | font-size: 75%; | 34 | font-size: 75%; |
35 | } | 35 | } |
@@ -37,15 +37,15 @@ | |||
37 | } | 37 | } |
38 | 38 | ||
39 | // Unlogged | 39 | // Unlogged |
40 | & > .dropdown > .dropdown-toggle span { | 40 | > .dropdown > .dropdown-toggle span { |
41 | padding-right: 3px; | 41 | padding-right: 3px; |
42 | } | 42 | } |
43 | 43 | ||
44 | // Logged | 44 | // Logged |
45 | & > .btn { | 45 | > .btn { |
46 | padding-right: 4px; | 46 | padding-right: 4px; |
47 | 47 | ||
48 | & + .dropdown > button { | 48 | + .dropdown > button { |
49 | padding-left: 2px; | 49 | padding-left: 2px; |
50 | 50 | ||
51 | &::after { | 51 | &::after { |
diff --git a/client/src/app/shared/shared-video-comment/video-comment.service.ts b/client/src/app/shared/shared-video-comment/video-comment.service.ts index 0f09778df..c5aeb3c12 100644 --- a/client/src/app/shared/shared-video-comment/video-comment.service.ts +++ b/client/src/app/shared/shared-video-comment/video-comment.service.ts | |||
@@ -190,13 +190,7 @@ export class VideoCommentService { | |||
190 | const filters = this.restService.parseQueryStringFilter(search, { | 190 | const filters = this.restService.parseQueryStringFilter(search, { |
191 | isLocal: { | 191 | isLocal: { |
192 | prefix: 'local:', | 192 | prefix: 'local:', |
193 | isBoolean: true, | 193 | isBoolean: true |
194 | handler: v => { | ||
195 | if (v === 'true') return v | ||
196 | if (v === 'false') return v | ||
197 | |||
198 | return undefined | ||
199 | } | ||
200 | }, | 194 | }, |
201 | 195 | ||
202 | searchAccount: { prefix: 'account:' }, | 196 | searchAccount: { prefix: 'account:' }, |
diff --git a/client/src/app/shared/shared-video-miniature/abstract-video-list.scss b/client/src/app/shared/shared-video-miniature/abstract-video-list.scss index 467ca1d2c..d9cf7a14f 100644 --- a/client/src/app/shared/shared-video-miniature/abstract-video-list.scss +++ b/client/src/app/shared/shared-video-miniature/abstract-video-list.scss | |||
@@ -3,7 +3,7 @@ | |||
3 | @import '_mixins'; | 3 | @import '_mixins'; |
4 | @import '_miniature'; | 4 | @import '_miniature'; |
5 | 5 | ||
6 | $iconSize: 16px; | 6 | $icon-size: 16px; |
7 | 7 | ||
8 | ::ng-deep my-video-list-header { | 8 | ::ng-deep my-video-list-header { |
9 | display: flex; | 9 | display: flex; |
@@ -17,20 +17,19 @@ $iconSize: 16px; | |||
17 | 17 | ||
18 | my-feed { | 18 | my-feed { |
19 | display: inline-block; | 19 | display: inline-block; |
20 | width: calc(#{$iconSize} - 2px); | 20 | width: calc(#{$icon-size} - 2px); |
21 | } | 21 | } |
22 | 22 | ||
23 | .moderation-block { | 23 | .moderation-block { |
24 | |||
25 | my-global-icon { | ||
26 | position: relative; | ||
27 | width: $iconSize; | ||
28 | } | ||
29 | |||
30 | margin-left: .4rem; | 24 | margin-left: .4rem; |
31 | display: flex; | 25 | display: flex; |
32 | justify-content: flex-end; | 26 | justify-content: flex-end; |
33 | align-items: center; | 27 | align-items: center; |
28 | |||
29 | my-global-icon { | ||
30 | position: relative; | ||
31 | width: $icon-size; | ||
32 | } | ||
34 | } | 33 | } |
35 | } | 34 | } |
36 | 35 | ||
@@ -72,7 +71,7 @@ $iconSize: 16px; | |||
72 | 71 | ||
73 | .title-page { | 72 | .title-page { |
74 | margin-bottom: 10px; | 73 | margin-bottom: 10px; |
75 | margin-right: 0px; | 74 | margin-right: 0; |
76 | } | 75 | } |
77 | } | 76 | } |
78 | } | 77 | } |
diff --git a/client/src/app/shared/shared-video-miniature/shared-video-miniature.module.ts b/client/src/app/shared/shared-video-miniature/shared-video-miniature.module.ts index 32cfdfd68..03be6d2ff 100644 --- a/client/src/app/shared/shared-video-miniature/shared-video-miniature.module.ts +++ b/client/src/app/shared/shared-video-miniature/shared-video-miniature.module.ts | |||
@@ -13,7 +13,7 @@ import { VideoDownloadComponent } from './video-download.component' | |||
13 | import { VideoMiniatureComponent } from './video-miniature.component' | 13 | import { VideoMiniatureComponent } from './video-miniature.component' |
14 | import { VideosSelectionComponent } from './videos-selection.component' | 14 | import { VideosSelectionComponent } from './videos-selection.component' |
15 | import { VideoListHeaderComponent } from './video-list-header.component' | 15 | import { VideoListHeaderComponent } from './video-list-header.component' |
16 | import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-account-avatar.module' | 16 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' |
17 | 17 | ||
18 | @NgModule({ | 18 | @NgModule({ |
19 | imports: [ | 19 | imports: [ |
@@ -25,7 +25,7 @@ import { SharedAccountAvatarModule } from '../shared-account-avatar/shared-accou | |||
25 | SharedGlobalIconModule, | 25 | SharedGlobalIconModule, |
26 | SharedVideoLiveModule, | 26 | SharedVideoLiveModule, |
27 | SharedVideoModule, | 27 | SharedVideoModule, |
28 | SharedAccountAvatarModule | 28 | SharedActorImageModule |
29 | ], | 29 | ], |
30 | 30 | ||
31 | declarations: [ | 31 | declarations: [ |
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.scss b/client/src/app/shared/shared-video-miniature/video-download.component.scss index 7f6e03c87..b689b1046 100644 --- a/client/src/app/shared/shared-video-miniature/video-download.component.scss +++ b/client/src/app/shared/shared-video-miniature/video-download.component.scss | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | border-top-right-radius: 0; | 29 | border-top-right-radius: 0; |
30 | border-bottom-right-radius: 0; | 30 | border-bottom-right-radius: 0; |
31 | border-right: none; | 31 | border-right: 0; |
32 | 32 | ||
33 | select { | 33 | select { |
34 | height: inherit; | 34 | height: inherit; |
@@ -85,7 +85,7 @@ | |||
85 | &.metadata-attribute-tags { | 85 | &.metadata-attribute-tags { |
86 | .metadata-attribute-value:not(:nth-child(2)) { | 86 | .metadata-attribute-value:not(:nth-child(2)) { |
87 | &::before { | 87 | &::before { |
88 | content: ', ' | 88 | content: ', '; |
89 | } | 89 | } |
90 | } | 90 | } |
91 | } | 91 | } |
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.html b/client/src/app/shared/shared-video-miniature/video-miniature.component.html index bc19127aa..645be92bd 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.html +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.html | |||
@@ -10,14 +10,15 @@ | |||
10 | <div class="video-bottom"> | 10 | <div class="video-bottom"> |
11 | <div class="video-miniature-information"> | 11 | <div class="video-miniature-information"> |
12 | <div class="d-flex video-miniature-meta"> | 12 | <div class="d-flex video-miniature-meta"> |
13 | <a *ngIf="displayOptions.avatar && displayOwnerVideoChannel()" class="channel-avatar" [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle"> | 13 | <my-actor-avatar |
14 | <img [src]="getAvatarUrl()" alt="" /> | 14 | *ngIf="displayOptions.avatar && displayOwnerVideoChannel()" [title]="channelLinkTitle" |
15 | </a> | 15 | [channel]="video.channel" [size]="actorImageSize" [internalHref]="[ '/video-channels', video.byVideoChannel ]" |
16 | ></my-actor-avatar> | ||
16 | 17 | ||
17 | <my-account-avatar | 18 | <my-actor-avatar |
18 | *ngIf="displayOptions.avatar && displayOwnerAccount()" [title]="channelLinkTitle" | 19 | *ngIf="displayOptions.avatar && displayOwnerAccount()" [title]="channelLinkTitle" |
19 | [account]="video.account" size="40" [internalHref]="'/video-channels/' + video.byVideoChannel" | 20 | [account]="video.account" [size]="actorImageSize" [internalHref]="[ '/video-channels', video.byVideoChannel ]" |
20 | ></my-account-avatar> | 21 | ></my-actor-avatar> |
21 | 22 | ||
22 | <div class="w-100 d-flex flex-column"> | 23 | <div class="w-100 d-flex flex-column"> |
23 | <a *ngIf="!videoHref" tabindex="-1" class="video-miniature-name" | 24 | <a *ngIf="!videoHref" tabindex="-1" class="video-miniature-name" |
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.scss b/client/src/app/shared/shared-video-miniature/video-miniature.component.scss index f6f2925f0..5df89d019 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.scss +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.scss | |||
@@ -12,15 +12,10 @@ $more-button-width: 40px; | |||
12 | width: calc(100% - #{$more-button-width}); | 12 | width: calc(100% - #{$more-button-width}); |
13 | } | 13 | } |
14 | 14 | ||
15 | my-account-avatar, | 15 | my-actor-avatar { |
16 | .channel-avatar { | ||
17 | margin: 10px 10px 0 0; | 16 | margin: 10px 10px 0 0; |
18 | } | 17 | } |
19 | 18 | ||
20 | .channel-avatar img{ | ||
21 | @include channel-avatar(40px); | ||
22 | } | ||
23 | |||
24 | .video-miniature-created-at-views { | 19 | .video-miniature-created-at-views { |
25 | font-size: 13px; | 20 | font-size: 13px; |
26 | } | 21 | } |
@@ -46,7 +41,7 @@ my-account-avatar, | |||
46 | } | 41 | } |
47 | 42 | ||
48 | .video-info-blocked { | 43 | .video-info-blocked { |
49 | color: red; | 44 | color: #ff0000; |
50 | 45 | ||
51 | .blocked-reason::before { | 46 | .blocked-reason::before { |
52 | content: ' - '; | 47 | content: ' - '; |
@@ -54,7 +49,7 @@ my-account-avatar, | |||
54 | } | 49 | } |
55 | 50 | ||
56 | .video-info-nsfw { | 51 | .video-info-nsfw { |
57 | color: red; | 52 | color: #ff0000; |
58 | } | 53 | } |
59 | 54 | ||
60 | .video-actions { | 55 | .video-actions { |
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts index 8d66aaee2..b58c118be 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts | |||
@@ -12,6 +12,7 @@ import { | |||
12 | } from '@angular/core' | 12 | } from '@angular/core' |
13 | import { AuthService, ScreenService, ServerService, User } from '@app/core' | 13 | import { AuthService, ScreenService, ServerService, User } from '@app/core' |
14 | import { ServerConfig, VideoPlaylistType, VideoPrivacy, VideoState } from '@shared/models' | 14 | import { ServerConfig, VideoPlaylistType, VideoPrivacy, VideoState } from '@shared/models' |
15 | import { ActorAvatarSize } from '../shared-actor-image/actor-avatar.component' | ||
15 | import { Video } from '../shared-main' | 16 | import { Video } from '../shared-main' |
16 | import { VideoPlaylistService } from '../shared-video-playlist' | 17 | import { VideoPlaylistService } from '../shared-video-playlist' |
17 | import { VideoActionsDisplayType } from './video-actions-dropdown.component' | 18 | import { VideoActionsDisplayType } from './video-actions-dropdown.component' |
@@ -51,6 +52,8 @@ export class VideoMiniatureComponent implements OnInit { | |||
51 | } | 52 | } |
52 | @Input() displayVideoActions = true | 53 | @Input() displayVideoActions = true |
53 | 54 | ||
55 | @Input() actorImageSize: ActorAvatarSize = '40' | ||
56 | |||
54 | @Input() displayAsRow = false | 57 | @Input() displayAsRow = false |
55 | 58 | ||
56 | @Input() videoLinkType: VideoLinkType = 'internal' | 59 | @Input() videoLinkType: VideoLinkType = 'internal' |
@@ -180,14 +183,6 @@ export class VideoMiniatureComponent implements OnInit { | |||
180 | return '' | 183 | return '' |
181 | } | 184 | } |
182 | 185 | ||
183 | getAvatarUrl () { | ||
184 | if (this.displayOwnerAccount()) { | ||
185 | return this.video.account.avatar?.url | ||
186 | } | ||
187 | |||
188 | return this.video.videoChannelAvatarUrl | ||
189 | } | ||
190 | |||
191 | loadActions () { | 186 | loadActions () { |
192 | if (this.displayVideoActions) this.showActions = true | 187 | if (this.displayVideoActions) this.showActions = true |
193 | 188 | ||
diff --git a/client/src/app/shared/shared-video-miniature/videos-selection.component.html b/client/src/app/shared/shared-video-miniature/videos-selection.component.html index dec9e99f3..4ee90ce7f 100644 --- a/client/src/app/shared/shared-video-miniature/videos-selection.component.html +++ b/client/src/app/shared/shared-video-miniature/videos-selection.component.html | |||
@@ -1,9 +1,9 @@ | |||
1 | <div class="no-results" i18n *ngIf="hasDoneFirstQuery && videos.length === 0">No results.</div> | 1 | <div class="no-results" i18n *ngIf="hasDoneFirstQuery && videos.length === 0">{{ noResultMessage }}</div> |
2 | 2 | ||
3 | <div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()" class="videos"> | 3 | <div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()" class="videos"> |
4 | <div class="video" *ngFor="let video of videos; let i = index; trackBy: videoById"> | 4 | <div class="video" *ngFor="let video of videos; let i = index; trackBy: videoById"> |
5 | 5 | ||
6 | <div class="checkbox-container"> | 6 | <div class="checkbox-container" *ngIf="enableSelection"> |
7 | <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="_selection[video.id]"></my-peertube-checkbox> | 7 | <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="_selection[video.id]"></my-peertube-checkbox> |
8 | </div> | 8 | </div> |
9 | 9 | ||
diff --git a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts index f8c3800d7..d64ee9b98 100644 --- a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts +++ b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts | |||
@@ -31,6 +31,9 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni | |||
31 | @Input() pagination: ComponentPagination | 31 | @Input() pagination: ComponentPagination |
32 | @Input() titlePage: string | 32 | @Input() titlePage: string |
33 | @Input() miniatureDisplayOptions: MiniatureDisplayOptions | 33 | @Input() miniatureDisplayOptions: MiniatureDisplayOptions |
34 | @Input() noResultMessage = $localize`No results.` | ||
35 | @Input() enableSelection = true | ||
36 | @Input() loadOnInit = true | ||
34 | 37 | ||
35 | @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>> | 38 | @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<ResultList<Video>> |
36 | 39 | ||
diff --git a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.scss b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.scss index b84cacece..cb1168196 100644 --- a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.scss +++ b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.scss | |||
@@ -126,7 +126,7 @@ $timestamp-margin-right: 10px; | |||
126 | border-top: 1px solid $separator-border-color; | 126 | border-top: 1px solid $separator-border-color; |
127 | } | 127 | } |
128 | 128 | ||
129 | .new-playlist-button { | 129 | .new-playlist-button { |
130 | cursor: pointer; | 130 | cursor: pointer; |
131 | 131 | ||
132 | my-global-icon { | 132 | my-global-icon { |
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.scss b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.scss index 572f7d7a8..9ccd03912 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.scss +++ b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.scss | |||
@@ -84,21 +84,23 @@ my-video-thumbnail, | |||
84 | width: auto; | 84 | width: auto; |
85 | } | 85 | } |
86 | 86 | ||
87 | .video-info-account, .video-info-timestamp { | 87 | .video-info-account, |
88 | .video-info-timestamp { | ||
88 | color: pvar(--greyForegroundColor); | 89 | color: pvar(--greyForegroundColor); |
89 | } | 90 | } |
90 | } | 91 | } |
91 | } | 92 | } |
92 | 93 | ||
93 | .video-info-name { | 94 | .video-info-name { |
95 | @include ellipsis; | ||
96 | |||
94 | font-size: 18px; | 97 | font-size: 18px; |
95 | font-weight: $font-semibold; | 98 | font-weight: $font-semibold; |
96 | display: inline-block; | 99 | display: inline-block; |
97 | |||
98 | @include ellipsis; | ||
99 | } | 100 | } |
100 | 101 | ||
101 | .more, my-edit-button { | 102 | .more, |
103 | my-edit-button { | ||
102 | justify-self: flex-end; | 104 | justify-self: flex-end; |
103 | margin-left: auto; | 105 | margin-left: auto; |
104 | cursor: pointer; | 106 | cursor: pointer; |
@@ -118,7 +120,7 @@ my-video-thumbnail, | |||
118 | display: flex; | 120 | display: flex; |
119 | 121 | ||
120 | &::after { | 122 | &::after { |
121 | border: none; | 123 | border: 0; |
122 | } | 124 | } |
123 | } | 125 | } |
124 | } | 126 | } |
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.scss b/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.scss index 99089166c..a46a6e475 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.scss +++ b/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.scss | |||
@@ -6,7 +6,7 @@ | |||
6 | display: inline-block; | 6 | display: inline-block; |
7 | width: 100%; | 7 | width: 100%; |
8 | 8 | ||
9 | &.no-videos:not(.to-manage){ | 9 | &.no-videos:not(.to-manage) { |
10 | a { | 10 | a { |
11 | cursor: default !important; | 11 | cursor: default !important; |
12 | } | 12 | } |
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts index 9bec16d77..5b6ba9dbf 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts | |||
@@ -37,10 +37,8 @@ export class VideoPlaylist implements ServerVideoPlaylist { | |||
37 | embedUrl: string | 37 | embedUrl: string |
38 | 38 | ||
39 | ownerBy: string | 39 | ownerBy: string |
40 | ownerAvatarUrl: string | ||
41 | 40 | ||
42 | videoChannelBy?: string | 41 | videoChannelBy?: string |
43 | videoChannelAvatarUrl?: string | ||
44 | 42 | ||
45 | private thumbnailVersion: number | 43 | private thumbnailVersion: number |
46 | private originThumbnailUrl: string | 44 | private originThumbnailUrl: string |
@@ -78,12 +76,10 @@ export class VideoPlaylist implements ServerVideoPlaylist { | |||
78 | 76 | ||
79 | this.ownerAccount = hash.ownerAccount | 77 | this.ownerAccount = hash.ownerAccount |
80 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) | 78 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) |
81 | this.ownerAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.ownerAccount) | ||
82 | 79 | ||
83 | if (hash.videoChannel) { | 80 | if (hash.videoChannel) { |
84 | this.videoChannel = hash.videoChannel | 81 | this.videoChannel = hash.videoChannel |
85 | this.videoChannelBy = Actor.CREATE_BY_STRING(hash.videoChannel.name, hash.videoChannel.host) | 82 | this.videoChannelBy = Actor.CREATE_BY_STRING(hash.videoChannel.name, hash.videoChannel.host) |
86 | this.videoChannelAvatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this.videoChannel) | ||
87 | } | 83 | } |
88 | 84 | ||
89 | this.privacy.label = peertubeTranslate(this.privacy.label, translations) | 85 | this.privacy.label = peertubeTranslate(this.privacy.label, translations) |
diff --git a/client/src/assets/player/images/info.svg b/client/src/assets/player/images/info.svg new file mode 100644 index 000000000..bd1d9c6ca --- /dev/null +++ b/client/src/assets/player/images/info.svg | |||
@@ -0,0 +1 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-info"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg> \ No newline at end of file | |||
diff --git a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts index e97925ab5..4275a5e5e 100644 --- a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import * as Hlsjs from 'hls.js/dist/hls.light.js' | ||
2 | import { Events, Segment } from 'p2p-media-loader-core' | ||
3 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' | ||
1 | import videojs from 'video.js' | 4 | import videojs from 'video.js' |
2 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' | 5 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' |
3 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' | ||
4 | import { Events, Segment } from 'p2p-media-loader-core' | ||
5 | import { timeToInt } from '../utils' | 6 | import { timeToInt } from '../utils' |
6 | import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' | 7 | import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' |
7 | import * as Hlsjs from 'hls.js/dist/hls.light.js' | ||
8 | 8 | ||
9 | registerConfigPlugin(videojs) | 9 | registerConfigPlugin(videojs) |
10 | registerSourceHandler(videojs) | 10 | registerSourceHandler(videojs) |
@@ -36,6 +36,9 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
36 | 36 | ||
37 | private networkInfoInterval: any | 37 | private networkInfoInterval: any |
38 | 38 | ||
39 | private hlsjsCurrentLevel: number | ||
40 | private hlsjsLevels: Hlsjs.Level[] | ||
41 | |||
39 | constructor (player: videojs.Player, options?: P2PMediaLoaderPluginOptions) { | 42 | constructor (player: videojs.Player, options?: P2PMediaLoaderPluginOptions) { |
40 | super(player) | 43 | super(player) |
41 | 44 | ||
@@ -84,6 +87,16 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
84 | clearInterval(this.networkInfoInterval) | 87 | clearInterval(this.networkInfoInterval) |
85 | } | 88 | } |
86 | 89 | ||
90 | getCurrentLevel () { | ||
91 | return this.hlsjsLevels.find(l => l.level === this.hlsjsCurrentLevel) | ||
92 | } | ||
93 | |||
94 | getLiveLatency () { | ||
95 | return undefined as number | ||
96 | // FIXME: Use latency when hls >= V1 | ||
97 | // return this.hlsjs.latency | ||
98 | } | ||
99 | |||
87 | getHLSJS () { | 100 | getHLSJS () { |
88 | return this.hlsjs | 101 | return this.hlsjs |
89 | } | 102 | } |
@@ -140,6 +153,14 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
140 | this.p2pEngine.on(Events.PeerConnect, () => this.statsP2PBytes.numPeers++) | 153 | this.p2pEngine.on(Events.PeerConnect, () => this.statsP2PBytes.numPeers++) |
141 | this.p2pEngine.on(Events.PeerClose, () => this.statsP2PBytes.numPeers--) | 154 | this.p2pEngine.on(Events.PeerClose, () => this.statsP2PBytes.numPeers--) |
142 | 155 | ||
156 | this.hlsjs.on(Hlsjs.Events.MANIFEST_PARSED, (_e, manifest) => { | ||
157 | this.hlsjsCurrentLevel = manifest.firstLevel | ||
158 | this.hlsjsLevels = manifest.levels | ||
159 | }) | ||
160 | this.hlsjs.on(Hlsjs.Events.LEVEL_LOADED, (_e, level) => { | ||
161 | this.hlsjsCurrentLevel = level.levelId || (level as any).id | ||
162 | }) | ||
163 | |||
143 | this.networkInfoInterval = setInterval(() => { | 164 | this.networkInfoInterval = setInterval(() => { |
144 | const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload) | 165 | const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload) |
145 | const p2pUploadSpeed = this.arraySum(this.statsP2PBytes.pendingUpload) | 166 | const p2pUploadSpeed = this.arraySum(this.statsP2PBytes.pendingUpload) |
@@ -166,7 +187,8 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
166 | numPeers: this.statsP2PBytes.numPeers, | 187 | numPeers: this.statsP2PBytes.numPeers, |
167 | downloaded: this.statsP2PBytes.totalDownload, | 188 | downloaded: this.statsP2PBytes.totalDownload, |
168 | uploaded: this.statsP2PBytes.totalUpload | 189 | uploaded: this.statsP2PBytes.totalUpload |
169 | } | 190 | }, |
191 | bandwidthEstimate: (this.hlsjs as any).bandwidthEstimate / 8 | ||
170 | } as PlayerNetworkInfo) | 192 | } as PlayerNetworkInfo) |
171 | }, this.CONSTANTS.INFO_SCHEDULER) | 193 | }, this.CONSTANTS.INFO_SCHEDULER) |
172 | } | 194 | } |
diff --git a/client/src/assets/player/peertube-player-local-storage.ts b/client/src/assets/player/peertube-player-local-storage.ts index cf2cfb472..80aceb239 100644 --- a/client/src/assets/player/peertube-player-local-storage.ts +++ b/client/src/assets/player/peertube-player-local-storage.ts | |||
@@ -45,6 +45,7 @@ function saveTheaterInStore (enabled: boolean) { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | function saveAverageBandwidth (value: number) { | 47 | function saveAverageBandwidth (value: number) { |
48 | /** used to choose the most fitting resolution */ | ||
48 | return setLocalStorage('average-bandwidth', value.toString()) | 49 | return setLocalStorage('average-bandwidth', value.toString()) |
49 | } | 50 | } |
50 | 51 | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index ed82e0496..62dff8285 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -4,6 +4,8 @@ import 'videojs-contextmenu-pt' | |||
4 | import 'videojs-contrib-quality-levels' | 4 | import 'videojs-contrib-quality-levels' |
5 | import './upnext/end-card' | 5 | import './upnext/end-card' |
6 | import './upnext/upnext-plugin' | 6 | import './upnext/upnext-plugin' |
7 | import './stats/stats-card' | ||
8 | import './stats/stats-plugin' | ||
7 | import './bezels/bezels-plugin' | 9 | import './bezels/bezels-plugin' |
8 | import './peertube-plugin' | 10 | import './peertube-plugin' |
9 | import './videojs-components/next-previous-video-button' | 11 | import './videojs-components/next-previous-video-button' |
@@ -170,6 +172,11 @@ export class PeertubePlayerManager { | |||
170 | self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) | 172 | self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) |
171 | 173 | ||
172 | player.bezels() | 174 | player.bezels() |
175 | player.stats({ | ||
176 | videoUUID: options.common.videoUUID, | ||
177 | videoIsLive: options.common.isLive, | ||
178 | mode | ||
179 | }) | ||
173 | 180 | ||
174 | return res(player) | 181 | return res(player) |
175 | }) | 182 | }) |
@@ -538,6 +545,14 @@ export class PeertubePlayerManager { | |||
538 | }) | 545 | }) |
539 | } | 546 | } |
540 | 547 | ||
548 | items.push({ | ||
549 | icon: 'info', | ||
550 | label: player.localize('Stats for nerds'), | ||
551 | listener: () => { | ||
552 | player.stats().show() | ||
553 | } | ||
554 | }) | ||
555 | |||
541 | return items.map(i => ({ | 556 | return items.map(i => ({ |
542 | ...i, | 557 | ...i, |
543 | label: `<span class="vjs-icon-${i.icon || 'link-2'}"></span>` + i.label | 558 | label: `<span class="vjs-icon-${i.icon || 'link-2'}"></span>` + i.label |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index 4a6c80247..8afb424a7 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -7,7 +7,9 @@ import { PlayerMode } from './peertube-player-manager' | |||
7 | import { PeerTubePlugin } from './peertube-plugin' | 7 | import { PeerTubePlugin } from './peertube-plugin' |
8 | import { PlaylistPlugin } from './playlist/playlist-plugin' | 8 | import { PlaylistPlugin } from './playlist/playlist-plugin' |
9 | import { EndCardOptions } from './upnext/end-card' | 9 | import { EndCardOptions } from './upnext/end-card' |
10 | import { StatsCardOptions } from './stats/stats-card' | ||
10 | import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin' | 11 | import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin' |
12 | import { StatsForNerdsPlugin } from './stats/stats-plugin' | ||
11 | 13 | ||
12 | declare module 'video.js' { | 14 | declare module 'video.js' { |
13 | 15 | ||
@@ -36,6 +38,8 @@ declare module 'video.js' { | |||
36 | 38 | ||
37 | bezels (): void | 39 | bezels (): void |
38 | 40 | ||
41 | stats (options?: StatsCardOptions): StatsForNerdsPlugin | ||
42 | |||
39 | qualityLevels (): QualityLevels | 43 | qualityLevels (): QualityLevels |
40 | 44 | ||
41 | textTracks (): TextTrackList & { | 45 | textTracks (): TextTrackList & { |
@@ -195,6 +199,9 @@ type PlayerNetworkInfo = { | |||
195 | uploaded: number | 199 | uploaded: number |
196 | numPeers: number | 200 | numPeers: number |
197 | } | 201 | } |
202 | |||
203 | // In bytes | ||
204 | bandwidthEstimate: number | ||
198 | } | 205 | } |
199 | 206 | ||
200 | type PlaylistItemOptions = { | 207 | type PlaylistItemOptions = { |
diff --git a/client/src/assets/player/stats/stats-card.ts b/client/src/assets/player/stats/stats-card.ts new file mode 100644 index 000000000..d9f0d2fe9 --- /dev/null +++ b/client/src/assets/player/stats/stats-card.ts | |||
@@ -0,0 +1,273 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import { PlayerNetworkInfo as EventPlayerNetworkInfo } from '../peertube-videojs-typings' | ||
3 | import { bytes, secondsToTime } from '../utils' | ||
4 | |||
5 | interface StatsCardOptions extends videojs.ComponentOptions { | ||
6 | videoUUID: string | ||
7 | videoIsLive: boolean | ||
8 | mode: 'webtorrent' | 'p2p-media-loader' | ||
9 | } | ||
10 | |||
11 | interface PlayerNetworkInfo { | ||
12 | downloadSpeed?: string | ||
13 | uploadSpeed?: string | ||
14 | totalDownloaded?: string | ||
15 | totalUploaded?: string | ||
16 | numPeers?: number | ||
17 | averageBandwidth?: string | ||
18 | |||
19 | downloadedFromServer?: string | ||
20 | downloadedFromPeers?: string | ||
21 | } | ||
22 | |||
23 | const Component = videojs.getComponent('Component') | ||
24 | class StatsCard extends Component { | ||
25 | options_: StatsCardOptions | ||
26 | |||
27 | container: HTMLDivElement | ||
28 | |||
29 | list: HTMLDivElement | ||
30 | closeButton: HTMLElement | ||
31 | |||
32 | updateInterval: any | ||
33 | |||
34 | mode: 'webtorrent' | 'p2p-media-loader' | ||
35 | |||
36 | metadataStore: any = {} | ||
37 | |||
38 | intervalMs = 300 | ||
39 | playerNetworkInfo: PlayerNetworkInfo = {} | ||
40 | |||
41 | constructor (player: videojs.Player, options: StatsCardOptions) { | ||
42 | super(player, options) | ||
43 | } | ||
44 | |||
45 | createEl () { | ||
46 | const container = super.createEl('div', { | ||
47 | className: 'vjs-stats-content', | ||
48 | innerHTML: this.getMainTemplate() | ||
49 | }) as HTMLDivElement | ||
50 | this.container = container | ||
51 | this.container.style.display = 'none' | ||
52 | |||
53 | this.closeButton = this.container.getElementsByClassName('vjs-stats-close')[0] as HTMLElement | ||
54 | this.closeButton.onclick = () => this.hide() | ||
55 | |||
56 | this.list = this.container.getElementsByClassName('vjs-stats-list')[0] as HTMLDivElement | ||
57 | |||
58 | this.player_.on('p2pInfo', (event: any, data: EventPlayerNetworkInfo) => { | ||
59 | if (!data) return // HTTP fallback | ||
60 | |||
61 | this.mode = data.source | ||
62 | |||
63 | const p2pStats = data.p2p | ||
64 | const httpStats = data.http | ||
65 | |||
66 | this.playerNetworkInfo.downloadSpeed = bytes(p2pStats.downloadSpeed + httpStats.downloadSpeed).join(' ') | ||
67 | this.playerNetworkInfo.uploadSpeed = bytes(p2pStats.uploadSpeed + httpStats.uploadSpeed).join(' ') | ||
68 | this.playerNetworkInfo.totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded).join(' ') | ||
69 | this.playerNetworkInfo.totalUploaded = bytes(p2pStats.uploaded + httpStats.uploaded).join(' ') | ||
70 | this.playerNetworkInfo.numPeers = p2pStats.numPeers | ||
71 | this.playerNetworkInfo.averageBandwidth = bytes(data.bandwidthEstimate).join(' ') + '/s' | ||
72 | |||
73 | if (data.source === 'p2p-media-loader') { | ||
74 | this.playerNetworkInfo.downloadedFromServer = bytes(httpStats.downloaded).join(' ') | ||
75 | this.playerNetworkInfo.downloadedFromPeers = bytes(p2pStats.downloaded).join(' ') | ||
76 | } | ||
77 | }) | ||
78 | |||
79 | return container | ||
80 | } | ||
81 | |||
82 | toggle () { | ||
83 | this.updateInterval | ||
84 | ? this.hide() | ||
85 | : this.show() | ||
86 | } | ||
87 | |||
88 | show () { | ||
89 | this.container.style.display = 'block' | ||
90 | this.updateInterval = setInterval(async () => { | ||
91 | try { | ||
92 | const options = this.mode === 'webtorrent' | ||
93 | ? await this.buildWebTorrentOptions() | ||
94 | : await this.buildHLSOptions() | ||
95 | |||
96 | this.list.innerHTML = this.getListTemplate(options) | ||
97 | } catch (err) { | ||
98 | console.error('Cannot update stats.', err) | ||
99 | clearInterval(this.updateInterval) | ||
100 | } | ||
101 | }, this.intervalMs) | ||
102 | } | ||
103 | |||
104 | hide () { | ||
105 | clearInterval(this.updateInterval) | ||
106 | this.container.style.display = 'none' | ||
107 | } | ||
108 | |||
109 | private async buildHLSOptions () { | ||
110 | const p2pMediaLoader = this.player_.p2pMediaLoader() | ||
111 | const level = p2pMediaLoader.getCurrentLevel() | ||
112 | |||
113 | const codecs = level?.videoCodec || level?.audioCodec | ||
114 | ? `${level?.videoCodec || ''} / ${level?.audioCodec || ''}` | ||
115 | : undefined | ||
116 | |||
117 | const resolution = `${level?.height}p${level?.attrs['FRAME-RATE'] || ''}` | ||
118 | const buffer = this.timeRangesToString(this.player().buffered()) | ||
119 | |||
120 | let progress: number | ||
121 | let latency: string | ||
122 | |||
123 | if (this.options_.videoIsLive) { | ||
124 | latency = secondsToTime(p2pMediaLoader.getLiveLatency()) | ||
125 | } else { | ||
126 | progress = this.player().bufferedPercent() | ||
127 | } | ||
128 | |||
129 | return { | ||
130 | playerNetworkInfo: this.playerNetworkInfo, | ||
131 | resolution, | ||
132 | codecs, | ||
133 | buffer, | ||
134 | latency, | ||
135 | progress | ||
136 | } | ||
137 | } | ||
138 | |||
139 | private async buildWebTorrentOptions () { | ||
140 | const videoFile = this.player_.webtorrent().getCurrentVideoFile() | ||
141 | |||
142 | if (!this.metadataStore[videoFile.fileUrl]) { | ||
143 | this.metadataStore[videoFile.fileUrl] = await fetch(videoFile.metadataUrl).then(res => res.json()) | ||
144 | } | ||
145 | |||
146 | const metadata = this.metadataStore[videoFile.fileUrl] | ||
147 | |||
148 | let colorSpace = 'unknown' | ||
149 | let codecs = 'unknown' | ||
150 | |||
151 | if (metadata?.streams[0]) { | ||
152 | const stream = metadata.streams[0] | ||
153 | |||
154 | colorSpace = stream['color_space'] !== 'unknown' | ||
155 | ? stream['color_space'] | ||
156 | : 'bt709' | ||
157 | |||
158 | codecs = stream['codec_name'] || 'avc1' | ||
159 | } | ||
160 | |||
161 | const resolution = videoFile?.resolution.label + videoFile?.fps | ||
162 | const buffer = this.timeRangesToString(this.player().buffered()) | ||
163 | const progress = this.player_.webtorrent().getTorrent()?.progress | ||
164 | |||
165 | return { | ||
166 | playerNetworkInfo: this.playerNetworkInfo, | ||
167 | progress, | ||
168 | colorSpace, | ||
169 | codecs, | ||
170 | resolution, | ||
171 | buffer | ||
172 | } | ||
173 | } | ||
174 | |||
175 | private getListTemplate (options: { | ||
176 | playerNetworkInfo: PlayerNetworkInfo | ||
177 | progress: number | ||
178 | codecs: string | ||
179 | resolution: string | ||
180 | buffer: string | ||
181 | |||
182 | latency?: string | ||
183 | colorSpace?: string | ||
184 | }) { | ||
185 | const { playerNetworkInfo, progress, colorSpace, codecs, resolution, buffer, latency } = options | ||
186 | const player = this.player() | ||
187 | |||
188 | const videoQuality: VideoPlaybackQuality = player.getVideoPlaybackQuality() | ||
189 | const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) | ||
190 | const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) | ||
191 | const pr = (window.devicePixelRatio || 1).toFixed(2) | ||
192 | const frames = `${vw}x${vh}*${pr} / ${videoQuality.droppedVideoFrames} dropped of ${videoQuality.totalVideoFrames}` | ||
193 | |||
194 | const duration = player.duration() | ||
195 | |||
196 | let volume = `${Math.round(player.volume() * 100)}` | ||
197 | if (player.muted()) volume += ' (muted)' | ||
198 | |||
199 | const networkActivity = playerNetworkInfo.downloadSpeed | ||
200 | ? `${playerNetworkInfo.downloadSpeed} ⇓ / ${playerNetworkInfo.uploadSpeed} ⇑` | ||
201 | : undefined | ||
202 | |||
203 | const totalTransferred = playerNetworkInfo.totalDownloaded | ||
204 | ? `${playerNetworkInfo.totalDownloaded} ⇓ / ${playerNetworkInfo.totalUploaded} ⇑` | ||
205 | : undefined | ||
206 | const downloadBreakdown = playerNetworkInfo.downloadedFromServer | ||
207 | ? `${playerNetworkInfo.downloadedFromServer} from server · ${playerNetworkInfo.downloadedFromPeers} from peers` | ||
208 | : undefined | ||
209 | |||
210 | const bufferProgress = progress !== undefined | ||
211 | ? `${(progress * 100).toFixed(1)}% (${(progress * duration).toFixed(1)}s)` | ||
212 | : undefined | ||
213 | |||
214 | return ` | ||
215 | ${this.buildElement(player.localize('Player mode'), this.options_.mode)} | ||
216 | |||
217 | ${this.buildElement(player.localize('Video UUID'), this.options_.videoUUID)} | ||
218 | |||
219 | ${this.buildElement(player.localize('Viewport / Frames'), frames)} | ||
220 | |||
221 | ${this.buildElement(player.localize('Resolution'), resolution)} | ||
222 | |||
223 | ${this.buildElement(player.localize('Volume'), volume)} | ||
224 | |||
225 | ${this.buildElement(player.localize('Codecs'), codecs)} | ||
226 | ${this.buildElement(player.localize('Color'), colorSpace)} | ||
227 | |||
228 | ${this.buildElement(player.localize('Connection Speed'), playerNetworkInfo.averageBandwidth)} | ||
229 | |||
230 | ${this.buildElement(player.localize('Network Activity'), networkActivity)} | ||
231 | ${this.buildElement(player.localize('Total Transfered'), totalTransferred)} | ||
232 | ${this.buildElement(player.localize('Download Breakdown'), downloadBreakdown)} | ||
233 | |||
234 | ${this.buildElement(player.localize('Buffer Progress'), bufferProgress)} | ||
235 | ${this.buildElement(player.localize('Buffer State'), buffer)} | ||
236 | |||
237 | ${this.buildElement(player.localize('Live Latency'), latency)} | ||
238 | ` | ||
239 | } | ||
240 | |||
241 | private getMainTemplate () { | ||
242 | return ` | ||
243 | <button class="vjs-stats-close" tabindex=0 aria-label="Close stats" title="Close stats">[x]</button> | ||
244 | <div class="vjs-stats-list"></div> | ||
245 | ` | ||
246 | } | ||
247 | |||
248 | private buildElement (label: string, value?: string) { | ||
249 | if (!value) return '' | ||
250 | |||
251 | return `<div><div>${label}</div><span>${value}</span></div>` | ||
252 | } | ||
253 | |||
254 | private timeRangesToString (r: videojs.TimeRange) { | ||
255 | let result = '' | ||
256 | |||
257 | for (let i = 0; i < r.length; i++) { | ||
258 | const start = Math.floor(r.start(i)) | ||
259 | const end = Math.floor(r.end(i)) | ||
260 | |||
261 | result += `[${secondsToTime(start)}, ${secondsToTime(end)}] ` | ||
262 | } | ||
263 | |||
264 | return result | ||
265 | } | ||
266 | } | ||
267 | |||
268 | videojs.registerComponent('StatsCard', StatsCard) | ||
269 | |||
270 | export { | ||
271 | StatsCard, | ||
272 | StatsCardOptions | ||
273 | } | ||
diff --git a/client/src/assets/player/stats/stats-plugin.ts b/client/src/assets/player/stats/stats-plugin.ts new file mode 100644 index 000000000..8aad80e8a --- /dev/null +++ b/client/src/assets/player/stats/stats-plugin.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import { StatsCard, StatsCardOptions } from './stats-card' | ||
3 | |||
4 | const Plugin = videojs.getPlugin('plugin') | ||
5 | |||
6 | class StatsForNerdsPlugin extends Plugin { | ||
7 | private statsCard: StatsCard | ||
8 | |||
9 | constructor (player: videojs.Player, options: StatsCardOptions) { | ||
10 | const settings = { | ||
11 | ...options | ||
12 | } | ||
13 | |||
14 | super(player) | ||
15 | |||
16 | this.player.ready(() => { | ||
17 | player.addClass('vjs-stats-for-nerds') | ||
18 | }) | ||
19 | |||
20 | this.statsCard = new StatsCard(player, options) | ||
21 | |||
22 | player.addChild(this.statsCard, settings) | ||
23 | } | ||
24 | |||
25 | show () { | ||
26 | this.statsCard.show() | ||
27 | } | ||
28 | } | ||
29 | |||
30 | videojs.registerPlugin('stats', StatsForNerdsPlugin) | ||
31 | export { StatsForNerdsPlugin } | ||
diff --git a/client/src/assets/player/videojs-components/settings-menu-button.ts b/client/src/assets/player/videojs-components/settings-menu-button.ts index e67a3da06..74788a897 100644 --- a/client/src/assets/player/videojs-components/settings-menu-button.ts +++ b/client/src/assets/player/videojs-components/settings-menu-button.ts | |||
@@ -95,11 +95,6 @@ class SettingsButton extends Button { | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | document.removeEventListener('click', this.documentClickHandler) | ||
99 | if (this.isInIframe()) { | ||
100 | window.removeEventListener('blur', this.documentClickHandler) | ||
101 | } | ||
102 | |||
103 | this.hideDialog() | 98 | this.hideDialog() |
104 | 99 | ||
105 | if (this.settingsButtonOptions.entries.length === 0) { | 100 | if (this.settingsButtonOptions.entries.length === 0) { |
@@ -107,6 +102,14 @@ class SettingsButton extends Button { | |||
107 | } | 102 | } |
108 | } | 103 | } |
109 | 104 | ||
105 | dispose () { | ||
106 | document.removeEventListener('click', this.documentClickHandler) | ||
107 | |||
108 | if (this.isInIframe()) { | ||
109 | window.removeEventListener('blur', this.documentClickHandler) | ||
110 | } | ||
111 | } | ||
112 | |||
110 | onAddSettingsItem (event: any, data: any) { | 113 | onAddSettingsItem (event: any, data: any) { |
111 | const [ entry, options ] = data | 114 | const [ entry, options ] = data |
112 | 115 | ||
diff --git a/client/src/assets/player/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/webtorrent/webtorrent-plugin.ts index e557fe722..6f5fbe4c9 100644 --- a/client/src/assets/player/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/webtorrent/webtorrent-plugin.ts | |||
@@ -506,7 +506,8 @@ class WebTorrentPlugin extends Plugin { | |||
506 | uploadSpeed: this.torrent.uploadSpeed, | 506 | uploadSpeed: this.torrent.uploadSpeed, |
507 | downloaded: this.torrent.downloaded, | 507 | downloaded: this.torrent.downloaded, |
508 | uploaded: this.torrent.uploaded | 508 | uploaded: this.torrent.uploaded |
509 | } | 509 | }, |
510 | bandwidthEstimate: this.webtorrent.downloadSpeed | ||
510 | } as PlayerNetworkInfo) | 511 | } as PlayerNetworkInfo) |
511 | }, this.CONSTANTS.INFO_SCHEDULER) | 512 | }, this.CONSTANTS.INFO_SCHEDULER) |
512 | } | 513 | } |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index fa9c0d992..89b6f0c4c 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -8,9 +8,9 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
8 | 8 | ||
9 | @import './bootstrap'; | 9 | @import './bootstrap'; |
10 | @import './primeng-custom'; | 10 | @import './primeng-custom'; |
11 | @import './ng-select.scss'; | 11 | @import './ng-select'; |
12 | 12 | ||
13 | @import './classes.scss'; | 13 | @import './classes'; |
14 | 14 | ||
15 | [hidden] { | 15 | [hidden] { |
16 | display: none !important; | 16 | display: none !important; |
@@ -89,14 +89,16 @@ input.readonly { | |||
89 | background-color: pvar(--inputBackgroundColor) !important; | 89 | background-color: pvar(--inputBackgroundColor) !important; |
90 | } | 90 | } |
91 | 91 | ||
92 | input, textarea { | 92 | input, |
93 | textarea { | ||
93 | outline: none; | 94 | outline: none; |
94 | color: pvar(--inputForegroundColor); | 95 | color: pvar(--inputForegroundColor); |
95 | } | 96 | } |
96 | 97 | ||
97 | button { | 98 | button { |
98 | background: unset; | ||
99 | @include disable-outline; | 99 | @include disable-outline; |
100 | |||
101 | background: unset; | ||
100 | } | 102 | } |
101 | 103 | ||
102 | label { | 104 | label { |
@@ -121,12 +123,12 @@ code { | |||
121 | margin-top: 5px; | 123 | margin-top: 5px; |
122 | } | 124 | } |
123 | 125 | ||
124 | .input-error | 126 | .input-error, |
125 | my-input-toggle-hidden ::ng-deep input { | 127 | my-input-toggle-hidden ::ng-deep input { |
126 | border-color: $red !important; | 128 | border-color: $red !important; |
127 | } | 129 | } |
128 | 130 | ||
129 | .fullWidth { | 131 | .full-width { |
130 | width: 100%; | 132 | width: 100%; |
131 | margin-left: auto; | 133 | margin-left: auto; |
132 | margin-right: auto; | 134 | margin-right: auto; |
@@ -134,7 +136,7 @@ my-input-toggle-hidden ::ng-deep input { | |||
134 | } | 136 | } |
135 | 137 | ||
136 | .glyphicon-black { | 138 | .glyphicon-black { |
137 | color: black; | 139 | color: #000; |
138 | } | 140 | } |
139 | 141 | ||
140 | .row { | 142 | .row { |
@@ -184,26 +186,26 @@ my-input-toggle-hidden ::ng-deep input { | |||
184 | width: 100%; | 186 | width: 100%; |
185 | } | 187 | } |
186 | 188 | ||
187 | &.lock-scroll .main-row > router-outlet + * { | 189 | &.lock-scroll .main-row > router-outlet + * { /* stylelint-disable-line selector-max-compound-selectors */ |
188 | // Lock and hide body scrollbars | 190 | // Lock and hide body scrollbars |
189 | position: fixed; | 191 | position: fixed; |
190 | 192 | ||
191 | // Lock and hide sub-menu scrollbars | 193 | // Lock and hide sub-menu scrollbars |
192 | .sub-menu { | 194 | .sub-menu { /* stylelint-disable-line */ |
193 | overflow-x: hidden; | 195 | overflow-x: hidden; |
194 | } | 196 | } |
195 | } | 197 | } |
196 | } | 198 | } |
197 | 199 | ||
198 | .title-page { | 200 | .title-page { |
201 | @include disable-default-a-behaviour; | ||
202 | |||
199 | opacity: 0.6; | 203 | opacity: 0.6; |
200 | color: pvar(--mainForegroundColor); | 204 | color: pvar(--mainForegroundColor); |
201 | font-size: 16px; | 205 | font-size: 16px; |
202 | display: inline-block; | 206 | display: inline-block; |
203 | margin-right: 55px; | 207 | margin-right: 55px; |
204 | font-weight: $font-semibold; | 208 | font-weight: $font-semibold; |
205 | @include disable-default-a-behaviour; | ||
206 | |||
207 | border-bottom: 2px solid transparent; | 209 | border-bottom: 2px solid transparent; |
208 | 210 | ||
209 | &.title-page-single { | 211 | &.title-page-single { |
@@ -219,13 +221,19 @@ my-input-toggle-hidden ::ng-deep input { | |||
219 | font-size: 125%; | 221 | font-size: 125%; |
220 | } | 222 | } |
221 | 223 | ||
222 | &:hover, &:active, &:focus { | 224 | &:hover, |
225 | &:active, | ||
226 | &:focus { | ||
223 | color: pvar(--mainForegroundColor); | 227 | color: pvar(--mainForegroundColor); |
224 | } | 228 | } |
225 | 229 | ||
226 | &.active, &:hover, &:active, &:focus, &.title-page-single { | 230 | &.active, |
231 | &:hover, | ||
232 | &:active, | ||
233 | &:focus, | ||
234 | &.title-page-single { | ||
227 | opacity: 1; | 235 | opacity: 1; |
228 | outline: 0px hidden !important; | 236 | outline: 0 hidden !important; |
229 | } | 237 | } |
230 | 238 | ||
231 | @media screen and (max-width: $mobile-view) { | 239 | @media screen and (max-width: $mobile-view) { |
@@ -262,7 +270,10 @@ my-input-toggle-hidden ::ng-deep input { | |||
262 | background-color: pvar(--submenuBackgroundColor); | 270 | background-color: pvar(--submenuBackgroundColor); |
263 | } | 271 | } |
264 | 272 | ||
265 | &.active, &:hover, &:active, &:focus { | 273 | &.active, |
274 | &:hover, | ||
275 | &:active, | ||
276 | &:focus { | ||
266 | opacity: 1; | 277 | opacity: 1; |
267 | } | 278 | } |
268 | } | 279 | } |
@@ -275,8 +286,13 @@ my-input-toggle-hidden ::ng-deep input { | |||
275 | 286 | ||
276 | // In tables, don't have a hover different background | 287 | // In tables, don't have a hover different background |
277 | table { | 288 | table { |
278 | .action-button-edit, .action-button-delete { | 289 | .action-button-edit, |
279 | &:hover, &:active, &:focus, &[disabled], &.disabled { | 290 | .action-button-delete { |
291 | &:hover, | ||
292 | &:active, | ||
293 | &:focus, | ||
294 | &[disabled], | ||
295 | &.disabled { | ||
280 | background-color: $grey-background-color !important; | 296 | background-color: $grey-background-color !important; |
281 | } | 297 | } |
282 | } | 298 | } |
@@ -329,15 +345,12 @@ ngx-loading-bar { | |||
329 | 345 | ||
330 | @media screen and (max-width: #{breakpoint(xxl)}) { | 346 | @media screen and (max-width: #{breakpoint(xxl)}) { |
331 | .main-col { | 347 | .main-col { |
332 | & { | 348 | --horizontalMarginContent: #{$not-expanded-horizontal-margins / 2}; |
333 | --horizontalMarginContent: #{$not-expanded-horizontal-margins / 2}; | 349 | --videosHorizontalMarginContent: 30px; |
334 | } | ||
335 | 350 | ||
336 | &.expanded { | 351 | &.expanded { |
337 | --horizontalMarginContent: #{$expanded-horizontal-margins / 2}; | 352 | --horizontalMarginContent: #{$expanded-horizontal-margins / 2}; |
338 | } | 353 | } |
339 | |||
340 | --videosHorizontalMarginContent: 30px; | ||
341 | } | 354 | } |
342 | } | 355 | } |
343 | 356 | ||
diff --git a/client/src/sass/bootstrap.scss b/client/src/sass/bootstrap.scss index 0ab6230c8..548e55e1e 100644 --- a/client/src/sass/bootstrap.scss +++ b/client/src/sass/bootstrap.scss | |||
@@ -6,7 +6,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
6 | 6 | ||
7 | // Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d | 7 | // Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d |
8 | .glyphicon-refresh-animate { | 8 | .glyphicon-refresh-animate { |
9 | animation: spin .7s infinite linear; | 9 | animation: spin 0.7s infinite linear; |
10 | } | 10 | } |
11 | 11 | ||
12 | .glyphicon-duplicate { | 12 | .glyphicon-duplicate { |
@@ -25,6 +25,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
25 | from { | 25 | from { |
26 | transform: scale(1) rotate(0deg); | 26 | transform: scale(1) rotate(0deg); |
27 | } | 27 | } |
28 | |||
28 | to { | 29 | to { |
29 | transform: scale(1) rotate(360deg); | 30 | transform: scale(1) rotate(360deg); |
30 | } | 31 | } |
@@ -70,7 +71,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
70 | &.active { | 71 | &.active { |
71 | color: pvar(--mainBackgroundColor) !important; | 72 | color: pvar(--mainBackgroundColor) !important; |
72 | background-color: pvar(--mainHoverColor); | 73 | background-color: pvar(--mainHoverColor); |
73 | opacity: .9; | 74 | opacity: 0.9; |
74 | } | 75 | } |
75 | 76 | ||
76 | &:active { | 77 | &:active { |
@@ -97,9 +98,9 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
97 | } | 98 | } |
98 | 99 | ||
99 | @media screen and (min-width: #{breakpoint(md)}) { | 100 | @media screen and (min-width: #{breakpoint(md)}) { |
100 | .modal:before { | 101 | .modal::before { |
101 | vertical-align: middle; | 102 | vertical-align: middle; |
102 | content: " "; | 103 | content: ' '; |
103 | height: 100%; | 104 | height: 100%; |
104 | } | 105 | } |
105 | 106 | ||
@@ -123,7 +124,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
123 | } | 124 | } |
124 | 125 | ||
125 | .modal-header { | 126 | .modal-header { |
126 | border-bottom: none; | 127 | border-bottom: 0; |
127 | margin-bottom: 5px; | 128 | margin-bottom: 5px; |
128 | 129 | ||
129 | .modal-title { | 130 | .modal-title { |
@@ -140,10 +141,11 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
140 | 141 | ||
141 | margin: 0; | 142 | margin: 0; |
142 | padding: 0; | 143 | padding: 0; |
143 | opacity: .5; | 144 | opacity: 0.5; |
144 | 145 | ||
145 | &[iconName="cross"] { | 146 | &[iconName=cross] { /* stylelint-disable-line selector-max-compound-selectors */ |
146 | @include icon(16px); | 147 | @include icon(16px); |
148 | |||
147 | top: -3px; | 149 | top: -3px; |
148 | } | 150 | } |
149 | } | 151 | } |
@@ -154,7 +156,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
154 | text-align: right; | 156 | text-align: right; |
155 | 157 | ||
156 | > .peertube-button:not(:first-child) { | 158 | > .peertube-button:not(:first-child) { |
157 | margin-left: 10px | 159 | margin-left: 10px; |
158 | } | 160 | } |
159 | } | 161 | } |
160 | } | 162 | } |
@@ -168,7 +170,8 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
168 | 170 | ||
169 | // On touchscreen devices, simply overflow: hidden to avoid detached overlay on scroll | 171 | // On touchscreen devices, simply overflow: hidden to avoid detached overlay on scroll |
170 | @media (hover: none) and (pointer: coarse) { | 172 | @media (hover: none) and (pointer: coarse) { |
171 | .modal-open, .menu-open { | 173 | .modal-open, |
174 | .menu-open { | ||
172 | overflow: hidden !important; | 175 | overflow: hidden !important; |
173 | } | 176 | } |
174 | 177 | ||
@@ -176,7 +179,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
176 | .menu-open { | 179 | .menu-open { |
177 | .main-col { | 180 | .main-col { |
178 | &::before { | 181 | &::before { |
179 | background-color: black; | 182 | background-color: #000; |
180 | width: 100vw; | 183 | width: 100vw; |
181 | height: 100vh; | 184 | height: 100vh; |
182 | opacity: 0.75; | 185 | opacity: 0.75; |
@@ -204,7 +207,10 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
204 | .nav-link { | 207 | .nav-link { |
205 | opacity: 0.6 !important; | 208 | opacity: 0.6 !important; |
206 | 209 | ||
207 | &.active, &:hover, &:active, &:focus { | 210 | &.active, |
211 | &:hover, | ||
212 | &:active, | ||
213 | &:focus { | ||
208 | opacity: 1 !important; | 214 | opacity: 1 !important; |
209 | } | 215 | } |
210 | } | 216 | } |
@@ -221,7 +227,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
221 | 227 | ||
222 | color: pvar(--mainForegroundColor); | 228 | color: pvar(--mainForegroundColor); |
223 | font-weight: $font-semibold; | 229 | font-weight: $font-semibold; |
224 | border: none; | 230 | border: 0; |
225 | border-bottom: 2px solid transparent; | 231 | border-bottom: 2px solid transparent; |
226 | opacity: 0.6; | 232 | opacity: 0.6; |
227 | 233 | ||
@@ -231,7 +237,10 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | |||
231 | border-bottom-color: pvar(--mainColor); | 237 | border-bottom-color: pvar(--mainColor); |
232 | } | 238 | } |
233 | 239 | ||
234 | &.active, &:hover, &:active, &:focus { | 240 | &.active, |
241 | &:hover, | ||
242 | &:active, | ||
243 | &:focus { | ||
235 | opacity: 1; | 244 | opacity: 1; |
236 | } | 245 | } |
237 | } | 246 | } |
@@ -314,9 +323,10 @@ ngb-tooltip-window { | |||
314 | } | 323 | } |
315 | 324 | ||
316 | .input-group { | 325 | .input-group { |
317 | & > .form-control { | 326 | > .form-control { |
318 | flex: initial; | 327 | flex: initial; |
319 | } | 328 | } |
329 | |||
320 | input.form-control { | 330 | input.form-control { |
321 | width: unset !important; | 331 | width: unset !important; |
322 | flex-grow: 1; | 332 | flex-grow: 1; |
@@ -366,7 +376,7 @@ ngb-tooltip-window { | |||
366 | border: 1px solid #eee; | 376 | border: 1px solid #eee; |
367 | border-radius: .25rem; | 377 | border-radius: .25rem; |
368 | 378 | ||
369 | & > label { | 379 | > label { |
370 | position: relative; | 380 | position: relative; |
371 | top: -5px; | 381 | top: -5px; |
372 | left: -10px; | 382 | left: -10px; |
diff --git a/client/src/sass/include/_actor.scss b/client/src/sass/include/_actor.scss index a4798ce1d..38bd90ae6 100644 --- a/client/src/sass/include/_actor.scss +++ b/client/src/sass/include/_actor.scss | |||
@@ -17,7 +17,7 @@ | |||
17 | @mixin show-more-description { | 17 | @mixin show-more-description { |
18 | color: pvar(--mainColor); | 18 | color: pvar(--mainColor); |
19 | cursor: pointer; | 19 | cursor: pointer; |
20 | margin: 10px auto 45px auto; | 20 | margin: 10px auto 45px; |
21 | } | 21 | } |
22 | 22 | ||
23 | @mixin avatar-row-responsive ($img-margin, $grey-font-size) { | 23 | @mixin avatar-row-responsive ($img-margin, $grey-font-size) { |
@@ -25,8 +25,8 @@ | |||
25 | grid-column: 1; | 25 | grid-column: 1; |
26 | margin-bottom: 30px; | 26 | margin-bottom: 30px; |
27 | 27 | ||
28 | .channel-avatar { | 28 | .main-avatar { |
29 | @include channel-avatar(120px); | 29 | @include actor-avatar-size(120px); |
30 | } | 30 | } |
31 | 31 | ||
32 | > div { | 32 | > div { |
@@ -77,12 +77,8 @@ | |||
77 | font-size: 22px; | 77 | font-size: 22px; |
78 | } | 78 | } |
79 | 79 | ||
80 | .channel-avatar { | 80 | .main-avatar { |
81 | @include channel-avatar(80px); | 81 | @include actor-avatar-size(80px); |
82 | } | ||
83 | |||
84 | .account-avatar { | ||
85 | @include avatar(120px); | ||
86 | } | 82 | } |
87 | } | 83 | } |
88 | } | 84 | } |
diff --git a/client/src/sass/include/_bootstrap.scss b/client/src/sass/include/_bootstrap.scss index b1a23be6b..d9e5efc02 100644 --- a/client/src/sass/include/_bootstrap.scss +++ b/client/src/sass/include/_bootstrap.scss | |||
@@ -1,4 +1,4 @@ | |||
1 | @import "./_bootstrap-variables"; | 1 | @import './_bootstrap-variables'; |
2 | 2 | ||
3 | @import '~bootstrap/scss/functions'; | 3 | @import '~bootstrap/scss/functions'; |
4 | @import '~bootstrap/scss/variables'; | 4 | @import '~bootstrap/scss/variables'; |
diff --git a/client/src/sass/include/_fonts.scss b/client/src/sass/include/_fonts.scss index 6313736e0..514261d01 100644 --- a/client/src/sass/include/_fonts.scss +++ b/client/src/sass/include/_fonts.scss | |||
@@ -1,4 +1,4 @@ | |||
1 | @font-face{ | 1 | @font-face { |
2 | font-family: 'Source Sans Pro'; | 2 | font-family: 'Source Sans Pro'; |
3 | font-weight: 200 900; | 3 | font-weight: 200 900; |
4 | font-style: normal; | 4 | font-style: normal; |
@@ -7,7 +7,7 @@ | |||
7 | src: url('../fonts/source-sans/WOFF2/VAR/SourceSans3VF-Roman.ttf.woff2') format('woff2'); | 7 | src: url('../fonts/source-sans/WOFF2/VAR/SourceSans3VF-Roman.ttf.woff2') format('woff2'); |
8 | } | 8 | } |
9 | 9 | ||
10 | @font-face{ | 10 | @font-face { |
11 | font-family: 'Source Sans Pro'; | 11 | font-family: 'Source Sans Pro'; |
12 | font-weight: 200 900; | 12 | font-weight: 200 900; |
13 | font-style: italic; | 13 | font-style: italic; |
diff --git a/client/src/sass/include/_miniature.scss b/client/src/sass/include/_miniature.scss index 3b86f29b4..070aa3398 100644 --- a/client/src/sass/include/_miniature.scss +++ b/client/src/sass/include/_miniature.scss | |||
@@ -3,9 +3,8 @@ | |||
3 | 3 | ||
4 | @mixin miniature-name { | 4 | @mixin miniature-name { |
5 | @include ellipsis-multiline(1.1em, 2); | 5 | @include ellipsis-multiline(1.1em, 2); |
6 | @include peertube-word-wrap(false); | ||
6 | 7 | ||
7 | word-break: break-all; | ||
8 | word-wrap: break-word; | ||
9 | transition: color 0.2s; | 8 | transition: color 0.2s; |
10 | font-weight: $font-semibold; | 9 | font-weight: $font-semibold; |
11 | color: pvar(--mainForegroundColor); | 10 | color: pvar(--mainForegroundColor); |
@@ -21,12 +20,12 @@ | |||
21 | } | 20 | } |
22 | 21 | ||
23 | @mixin miniature-thumbnail { | 22 | @mixin miniature-thumbnail { |
24 | @include disable-outline; | ||
25 | |||
26 | $play-overlay-transition: 0.2s ease; | 23 | $play-overlay-transition: 0.2s ease; |
27 | $play-overlay-height: 26px; | 24 | $play-overlay-height: 26px; |
28 | $play-overlay-width: 18px; | 25 | $play-overlay-width: 18px; |
29 | 26 | ||
27 | @include disable-outline; | ||
28 | |||
30 | display: flex; | 29 | display: flex; |
31 | flex-direction: column; | 30 | flex-direction: column; |
32 | position: relative; | 31 | position: relative; |
@@ -47,7 +46,8 @@ | |||
47 | opacity: 0; | 46 | opacity: 0; |
48 | background-color: rgba(0, 0, 0, 0.3); | 47 | background-color: rgba(0, 0, 0, 0.3); |
49 | 48 | ||
50 | &, .icon { | 49 | &, |
50 | .icon { | ||
51 | transition: all $play-overlay-transition; | 51 | transition: all $play-overlay-transition; |
52 | } | 52 | } |
53 | 53 | ||
@@ -79,7 +79,7 @@ | |||
79 | 79 | ||
80 | &.blur-filter { | 80 | &.blur-filter { |
81 | filter: blur(20px); | 81 | filter: blur(20px); |
82 | transform : scale(1.03); | 82 | transform: scale(1.03); |
83 | } | 83 | } |
84 | } | 84 | } |
85 | } | 85 | } |
@@ -129,10 +129,7 @@ | |||
129 | column-gap: 30px; | 129 | column-gap: 30px; |
130 | grid-template-columns: repeat( | 130 | grid-template-columns: repeat( |
131 | auto-fill, | 131 | auto-fill, |
132 | minmax( | 132 | minmax(var(--miniatureMinWidth), 1fr) |
133 | var(--miniatureMinWidth), | ||
134 | 1fr | ||
135 | ) | ||
136 | ); | 133 | ); |
137 | 134 | ||
138 | .video-wrapper, | 135 | .video-wrapper, |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index e03201cef..b2083e516 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -1,7 +1,9 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | 2 | ||
3 | @mixin disable-default-a-behaviour { | 3 | @mixin disable-default-a-behaviour { |
4 | &:hover, &:focus, &:active { | 4 | &:hover, |
5 | &:focus, | ||
6 | &:active { | ||
5 | text-decoration: none !important; | 7 | text-decoration: none !important; |
6 | outline: none !important; | 8 | outline: none !important; |
7 | } | 9 | } |
@@ -22,7 +24,7 @@ | |||
22 | @mixin ellipsis-multiline($font-size: 16px, $number-of-lines: 2) { | 24 | @mixin ellipsis-multiline($font-size: 16px, $number-of-lines: 2) { |
23 | display: block; | 25 | display: block; |
24 | /* Fallback for non-webkit */ | 26 | /* Fallback for non-webkit */ |
25 | display: -webkit-box; | 27 | display: -webkit-box; /* stylelint-disable-line value-no-vendor-prefix */ |
26 | -webkit-line-clamp: $number-of-lines; | 28 | -webkit-line-clamp: $number-of-lines; |
27 | /* Fallback for non-webkit */ | 29 | /* Fallback for non-webkit */ |
28 | font-size: $font-size; | 30 | font-size: $font-size; |
@@ -36,7 +38,7 @@ | |||
36 | position: relative; | 38 | position: relative; |
37 | overflow: hidden; | 39 | overflow: hidden; |
38 | 40 | ||
39 | &:after { | 41 | &::after { |
40 | content: ''; | 42 | content: ''; |
41 | pointer-events: none; | 43 | pointer-events: none; |
42 | width: 100%; | 44 | width: 100%; |
@@ -48,11 +50,14 @@ | |||
48 | } | 50 | } |
49 | } | 51 | } |
50 | 52 | ||
51 | @mixin peertube-word-wrap { | 53 | @mixin peertube-word-wrap ($with-hyphen: true) { |
52 | word-break: break-word; | 54 | word-break: break-word; |
53 | word-wrap: break-word; | 55 | word-wrap: break-word; |
54 | overflow-wrap: break-word; | 56 | overflow-wrap: break-word; |
55 | hyphens: auto; | 57 | |
58 | @if $with-hyphen { | ||
59 | hyphens: auto; | ||
60 | } | ||
56 | } | 61 | } |
57 | 62 | ||
58 | @mixin apply-svg-color ($color) { | 63 | @mixin apply-svg-color ($color) { |
@@ -109,9 +114,9 @@ | |||
109 | padding-bottom: 0; | 114 | padding-bottom: 0; |
110 | flex-wrap: nowrap; | 115 | flex-wrap: nowrap; |
111 | 116 | ||
112 | .input-group-text{ | 117 | .input-group-text { |
113 | font-size: 14px; | 118 | font-size: 14px; |
114 | color: gray; | 119 | color: #808080; |
115 | } | 120 | } |
116 | } | 121 | } |
117 | 122 | ||
@@ -128,7 +133,9 @@ | |||
128 | @mixin orange-button { | 133 | @mixin orange-button { |
129 | @include button-focus(pvar(--mainColorLightest)); | 134 | @include button-focus(pvar(--mainColorLightest)); |
130 | 135 | ||
131 | &, &:active, &:focus { | 136 | &, |
137 | &:active, | ||
138 | &:focus { | ||
132 | color: #fff; | 139 | color: #fff; |
133 | background-color: pvar(--mainColor); | 140 | background-color: pvar(--mainColor); |
134 | } | 141 | } |
@@ -138,14 +145,15 @@ | |||
138 | background-color: pvar(--mainHoverColor); | 145 | background-color: pvar(--mainHoverColor); |
139 | } | 146 | } |
140 | 147 | ||
141 | &[disabled], &.disabled { | 148 | &[disabled], |
149 | &.disabled { | ||
142 | cursor: default; | 150 | cursor: default; |
143 | color: #fff; | 151 | color: #fff; |
144 | background-color: #C6C6C6; | 152 | background-color: #C6C6C6; |
145 | } | 153 | } |
146 | 154 | ||
147 | my-global-icon { | 155 | my-global-icon { |
148 | @include apply-svg-color(#fff) | 156 | @include apply-svg-color(#fff); |
149 | } | 157 | } |
150 | } | 158 | } |
151 | 159 | ||
@@ -155,7 +163,9 @@ | |||
155 | border: 2px solid pvar(--mainColor); | 163 | border: 2px solid pvar(--mainColor); |
156 | font-weight: $font-semibold; | 164 | font-weight: $font-semibold; |
157 | 165 | ||
158 | &, &:active, &:focus { | 166 | &, |
167 | &:active, | ||
168 | &:focus { | ||
159 | color: pvar(--mainColor); | 169 | color: pvar(--mainColor); |
160 | background-color: pvar(--mainBackgroundColor); | 170 | background-color: pvar(--mainBackgroundColor); |
161 | } | 171 | } |
@@ -165,14 +175,15 @@ | |||
165 | background-color: pvar(--mainColorLightest); | 175 | background-color: pvar(--mainColorLightest); |
166 | } | 176 | } |
167 | 177 | ||
168 | &[disabled], &.disabled { | 178 | &[disabled], |
179 | &.disabled { | ||
169 | cursor: default; | 180 | cursor: default; |
170 | color: pvar(--mainColor); | 181 | color: pvar(--mainColor); |
171 | background-color: #C6C6C6; | 182 | background-color: #C6C6C6; |
172 | } | 183 | } |
173 | 184 | ||
174 | my-global-icon { | 185 | my-global-icon { |
175 | @include apply-svg-color(pvar(--mainColor)) | 186 | @include apply-svg-color(pvar(--mainColor)); |
176 | } | 187 | } |
177 | } | 188 | } |
178 | 189 | ||
@@ -182,12 +193,13 @@ | |||
182 | color: pvar(--greyForegroundColor); | 193 | color: pvar(--greyForegroundColor); |
183 | background-color: transparent; | 194 | background-color: transparent; |
184 | 195 | ||
185 | &[disabled], &.disabled { | 196 | &[disabled], |
197 | .disabled { | ||
186 | cursor: default; | 198 | cursor: default; |
187 | } | 199 | } |
188 | 200 | ||
189 | my-global-icon { | 201 | my-global-icon { |
190 | @include apply-svg-color(transparent) | 202 | @include apply-svg-color(transparent); |
191 | } | 203 | } |
192 | } | 204 | } |
193 | 205 | ||
@@ -197,17 +209,22 @@ | |||
197 | background-color: $grey-background-color; | 209 | background-color: $grey-background-color; |
198 | color: pvar(--greyForegroundColor); | 210 | color: pvar(--greyForegroundColor); |
199 | 211 | ||
200 | &:hover, &:active, &:focus, &[disabled], &.disabled { | 212 | &:hover, |
213 | &:active, | ||
214 | &:focus, | ||
215 | &[disabled], | ||
216 | &.disabled { | ||
201 | color: pvar(--greyForegroundColor); | 217 | color: pvar(--greyForegroundColor); |
202 | background-color: $grey-background-hover-color; | 218 | background-color: $grey-background-hover-color; |
203 | } | 219 | } |
204 | 220 | ||
205 | &[disabled], &.disabled { | 221 | &[disabled], |
222 | &.disabled { | ||
206 | cursor: default; | 223 | cursor: default; |
207 | } | 224 | } |
208 | 225 | ||
209 | my-global-icon { | 226 | my-global-icon { |
210 | @include apply-svg-color(pvar(--greyForegroundColor)) | 227 | @include apply-svg-color(pvar(--greyForegroundColor)); |
211 | } | 228 | } |
212 | } | 229 | } |
213 | 230 | ||
@@ -216,24 +233,30 @@ | |||
216 | $text: #fff6f5; | 233 | $text: #fff6f5; |
217 | 234 | ||
218 | @include button-focus(scale-color($color, $alpha: -95%)); | 235 | @include button-focus(scale-color($color, $alpha: -95%)); |
236 | |||
219 | background-color: $color; | 237 | background-color: $color; |
220 | color: $text; | 238 | color: $text; |
221 | 239 | ||
222 | &:hover, &:active, &:focus, &[disabled], &.disabled { | 240 | &:hover, |
241 | &:active, | ||
242 | &:focus, | ||
243 | &[disabled], | ||
244 | &.disabled { | ||
223 | background-color: lighten($color: $color, $amount: 10); | 245 | background-color: lighten($color: $color, $amount: 10); |
224 | } | 246 | } |
225 | 247 | ||
226 | &[disabled], &.disabled { | 248 | &[disabled], |
249 | &.disabled { | ||
227 | cursor: default; | 250 | cursor: default; |
228 | } | 251 | } |
229 | 252 | ||
230 | my-global-icon { | 253 | my-global-icon { |
231 | @include apply-svg-color($text) | 254 | @include apply-svg-color($text); |
232 | } | 255 | } |
233 | } | 256 | } |
234 | 257 | ||
235 | @mixin peertube-button { | 258 | @mixin peertube-button { |
236 | border: none; | 259 | border: 0; |
237 | font-weight: $font-semibold; | 260 | font-weight: $font-semibold; |
238 | font-size: 15px; | 261 | font-size: 15px; |
239 | height: $button-height; | 262 | height: $button-height; |
@@ -246,18 +269,17 @@ | |||
246 | } | 269 | } |
247 | 270 | ||
248 | @mixin peertube-button-link { | 271 | @mixin peertube-button-link { |
249 | display: inline-block; | ||
250 | |||
251 | @include disable-default-a-behaviour; | 272 | @include disable-default-a-behaviour; |
252 | @include peertube-button; | 273 | @include peertube-button; |
253 | } | ||
254 | 274 | ||
255 | @mixin peertube-button-outline { | ||
256 | display: inline-block; | 275 | display: inline-block; |
276 | } | ||
257 | 277 | ||
278 | @mixin peertube-button-outline { | ||
258 | @include disable-default-a-behaviour; | 279 | @include disable-default-a-behaviour; |
259 | @include peertube-button; | 280 | @include peertube-button; |
260 | 281 | ||
282 | display: inline-block; | ||
261 | border: 1px solid; | 283 | border: 1px solid; |
262 | } | 284 | } |
263 | 285 | ||
@@ -291,17 +313,17 @@ | |||
291 | filter: alpha(opacity=0); | 313 | filter: alpha(opacity=0); |
292 | opacity: 0; | 314 | opacity: 0; |
293 | outline: none; | 315 | outline: none; |
294 | background: white; | 316 | background: #fff; |
295 | cursor: inherit; | 317 | cursor: inherit; |
296 | display: block; | 318 | display: block; |
297 | } | 319 | } |
298 | } | 320 | } |
299 | 321 | ||
300 | @mixin peertube-button-file ($width) { | 322 | @mixin peertube-button-file ($width) { |
301 | width: $width; | ||
302 | |||
303 | @include peertube-file; | 323 | @include peertube-file; |
304 | @include peertube-button; | 324 | @include peertube-button; |
325 | |||
326 | width: $width; | ||
305 | } | 327 | } |
306 | 328 | ||
307 | @mixin icon ($size) { | 329 | @mixin icon ($size) { |
@@ -317,7 +339,7 @@ | |||
317 | @mixin select-arrow-down { | 339 | @mixin select-arrow-down { |
318 | top: 50%; | 340 | top: 50%; |
319 | right: calc(0% + 15px); | 341 | right: calc(0% + 15px); |
320 | content: " "; | 342 | content: ' '; |
321 | height: 0; | 343 | height: 0; |
322 | width: 0; | 344 | width: 0; |
323 | position: absolute; | 345 | position: absolute; |
@@ -358,7 +380,7 @@ | |||
358 | width: 100%; | 380 | width: 100%; |
359 | } | 381 | } |
360 | 382 | ||
361 | &:after { | 383 | &::after { |
362 | @include select-arrow-down; | 384 | @include select-arrow-down; |
363 | } | 385 | } |
364 | 386 | ||
@@ -394,21 +416,21 @@ | |||
394 | option { | 416 | option { |
395 | font-weight: $font-semibold; | 417 | font-weight: $font-semibold; |
396 | color: pvar(--greyForegroundColor); | 418 | color: pvar(--greyForegroundColor); |
397 | border: none; | 419 | border: 0; |
398 | } | 420 | } |
399 | } | 421 | } |
400 | } | 422 | } |
401 | 423 | ||
402 | // Thanks: https://codepen.io/triss90/pen/XNEdRe/ | 424 | // Thanks: https://codepen.io/triss90/pen/XNEdRe/ |
403 | @mixin peertube-radio-container { | 425 | @mixin peertube-radio-container { |
404 | input[type="radio"] { | 426 | input[type=radio] { |
405 | display: none; | 427 | display: none; |
406 | 428 | ||
407 | & + label { | 429 | + label { |
408 | font-weight: $font-regular; | 430 | font-weight: $font-regular; |
409 | cursor: pointer; | 431 | cursor: pointer; |
410 | 432 | ||
411 | &:before { | 433 | &::before { |
412 | position: relative; | 434 | position: relative; |
413 | top: -2px; | 435 | top: -2px; |
414 | content: ''; | 436 | content: ''; |
@@ -425,12 +447,12 @@ | |||
425 | } | 447 | } |
426 | } | 448 | } |
427 | 449 | ||
428 | &:checked + label:before { | 450 | &:checked + label::before { |
429 | background-color: #000; | 451 | background-color: #000; |
430 | box-shadow: inset 0 0 0 4px #fff; | 452 | box-shadow: inset 0 0 0 4px #fff; |
431 | } | 453 | } |
432 | 454 | ||
433 | &:focus + label:before { | 455 | &:focus + label::before { |
434 | outline: none; | 456 | outline: none; |
435 | border-color: #000; | 457 | border-color: #000; |
436 | } | 458 | } |
@@ -445,7 +467,7 @@ | |||
445 | box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest); | 467 | box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest); |
446 | } | 468 | } |
447 | 469 | ||
448 | & + span { | 470 | + span { |
449 | position: relative; | 471 | position: relative; |
450 | width: 18px; | 472 | width: 18px; |
451 | min-width: 18px; | 473 | min-width: 18px; |
@@ -455,7 +477,7 @@ | |||
455 | vertical-align: middle; | 477 | vertical-align: middle; |
456 | cursor: pointer; | 478 | cursor: pointer; |
457 | 479 | ||
458 | &:after { | 480 | &::after { |
459 | content: ''; | 481 | content: ''; |
460 | position: absolute; | 482 | position: absolute; |
461 | top: calc(2px - #{$border-width}); | 483 | top: calc(2px - #{$border-width}); |
@@ -474,13 +496,13 @@ | |||
474 | background: pvar(--mainColor); | 496 | background: pvar(--mainColor); |
475 | animation: jelly 0.6s ease; | 497 | animation: jelly 0.6s ease; |
476 | 498 | ||
477 | &:after { | 499 | &::after { |
478 | opacity: 1; | 500 | opacity: 1; |
479 | transform: rotate(45deg) scale(1); | 501 | transform: rotate(45deg) scale(1); |
480 | } | 502 | } |
481 | } | 503 | } |
482 | 504 | ||
483 | & + span + span { | 505 | + span + span { |
484 | font-size: 15px; | 506 | font-size: 15px; |
485 | font-weight: $font-regular; | 507 | font-weight: $font-regular; |
486 | margin-left: 5px; | 508 | margin-left: 5px; |
@@ -489,7 +511,7 @@ | |||
489 | } | 511 | } |
490 | 512 | ||
491 | &[disabled] + span, | 513 | &[disabled] + span, |
492 | &[disabled] + span + span{ | 514 | &[disabled] + span + span { |
493 | opacity: 0.5; | 515 | opacity: 0.5; |
494 | cursor: default; | 516 | cursor: default; |
495 | } | 517 | } |
@@ -539,21 +561,12 @@ | |||
539 | } | 561 | } |
540 | } | 562 | } |
541 | 563 | ||
542 | @mixin avatar ($size) { | 564 | @mixin actor-avatar-size ($size) { |
543 | object-fit: cover; | 565 | display: inline-block; |
544 | border-radius: 50%; | ||
545 | width: $size; | ||
546 | height: $size; | ||
547 | min-width: $size; | ||
548 | min-height: $size; | ||
549 | } | ||
550 | |||
551 | @mixin channel-avatar ($size) { | ||
552 | width: $size; | 566 | width: $size; |
553 | height: $size; | 567 | height: $size; |
554 | min-width: $size; | 568 | min-width: $size; |
555 | min-height: $size; | 569 | min-height: $size; |
556 | border-radius: 5px; | ||
557 | } | 570 | } |
558 | 571 | ||
559 | @mixin chevron ($size, $border-width) { | 572 | @mixin chevron ($size, $border-width) { |
@@ -595,26 +608,6 @@ | |||
595 | margin-bottom: 10px; | 608 | margin-bottom: 10px; |
596 | } | 609 | } |
597 | 610 | ||
598 | @mixin actor-owner { | ||
599 | @include disable-default-a-behaviour; | ||
600 | |||
601 | font-size: 13px; | ||
602 | margin-top: 4px; | ||
603 | color: pvar(--mainForegroundColor); | ||
604 | |||
605 | span:hover { | ||
606 | opacity: 0.8; | ||
607 | } | ||
608 | |||
609 | img { | ||
610 | @include avatar(18px); | ||
611 | |||
612 | margin-left: 7px; | ||
613 | position: relative; | ||
614 | top: -2px; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | @mixin create-button { | 611 | @mixin create-button { |
619 | @include peertube-button-link; | 612 | @include peertube-button-link; |
620 | @include orange-button; | 613 | @include orange-button; |
@@ -714,13 +707,13 @@ | |||
714 | color: pvar(--mainColor); | 707 | color: pvar(--mainColor); |
715 | } | 708 | } |
716 | 709 | ||
717 | & + .breadcrumb-item { | 710 | + .breadcrumb-item { |
718 | padding-left: 0.5rem; | 711 | padding-left: 0.5rem; |
719 | &::before { | 712 | &::before { |
720 | display: inline-block; | 713 | display: inline-block; |
721 | padding-right: 0.5rem; | 714 | padding-right: 0.5rem; |
722 | color: #6c757d; | 715 | color: #6c757d; |
723 | content: "/"; | 716 | content: '/'; |
724 | } | 717 | } |
725 | } | 718 | } |
726 | 719 | ||
@@ -735,13 +728,13 @@ | |||
735 | flex-wrap: wrap; | 728 | flex-wrap: wrap; |
736 | margin: 0 -5px; | 729 | margin: 0 -5px; |
737 | 730 | ||
738 | & > div { | 731 | > div { |
739 | box-sizing: border-box; | 732 | box-sizing: border-box; |
740 | flex: 0 0 percentage(1/3); | 733 | flex: 0 0 percentage(1/3); |
741 | padding: 0 5px; | 734 | padding: 0 5px; |
742 | margin-bottom: 10px; | 735 | margin-bottom: 10px; |
743 | 736 | ||
744 | & > a { | 737 | > a { |
745 | @include disable-default-a-behaviour; | 738 | @include disable-default-a-behaviour; |
746 | 739 | ||
747 | text-decoration: none; | 740 | text-decoration: none; |
@@ -756,8 +749,8 @@ | |||
756 | } | 749 | } |
757 | } | 750 | } |
758 | 751 | ||
759 | & > a, | 752 | > a, |
760 | & > div { | 753 | > div { |
761 | padding: 20px; | 754 | padding: 20px; |
762 | background: pvar(--submenuBackgroundColor); | 755 | background: pvar(--submenuBackgroundColor); |
763 | border-radius: 4px; | 756 | border-radius: 4px; |
@@ -766,7 +759,8 @@ | |||
766 | } | 759 | } |
767 | } | 760 | } |
768 | 761 | ||
769 | .dashboard-num, .dashboard-text { | 762 | .dashboard-num, |
763 | .dashboard-text { | ||
770 | text-align: center; | 764 | text-align: center; |
771 | font-size: 130%; | 765 | font-size: 130%; |
772 | color: pvar(--mainForegroundColor); | 766 | color: pvar(--mainForegroundColor); |
@@ -830,17 +824,9 @@ | |||
830 | --chip-padding: .2rem .3rem; | 824 | --chip-padding: .2rem .3rem; |
831 | } | 825 | } |
832 | 826 | ||
833 | .avatar { | 827 | my-actor-avatar { |
834 | margin-left: -.4rem; | 828 | margin-left: -.4rem; |
835 | margin-right: .2rem; | 829 | margin-right: .2rem; |
836 | height: $avatar-height; | ||
837 | width: $avatar-height; | ||
838 | |||
839 | border-radius: 50%; | ||
840 | display: inline-block; | ||
841 | line-height: 1.25; | ||
842 | position: relative; | ||
843 | vertical-align: middle; | ||
844 | } | 830 | } |
845 | 831 | ||
846 | &.two-lines { | 832 | &.two-lines { |
@@ -848,9 +834,8 @@ | |||
848 | 834 | ||
849 | height: $avatar-height; | 835 | height: $avatar-height; |
850 | 836 | ||
851 | .avatar { | 837 | my-actor-avatar { |
852 | height: $avatar-height; | 838 | @include actor-avatar-size($avatar-height); |
853 | width: $avatar-height; | ||
854 | } | 839 | } |
855 | 840 | ||
856 | div { | 841 | div { |
@@ -868,7 +853,7 @@ | |||
868 | flex-direction: column; | 853 | flex-direction: column; |
869 | 854 | ||
870 | .form-sub-title { | 855 | .form-sub-title { |
871 | margin-right: 0px !important; | 856 | margin-right: 0 !important; |
872 | margin-bottom: 10px; | 857 | margin-bottom: 10px; |
873 | text-align: center; | 858 | text-align: center; |
874 | } | 859 | } |
@@ -914,15 +899,17 @@ | |||
914 | padding-bottom: 15px; | 899 | padding-bottom: 15px; |
915 | margin-bottom: $sub-menu-margin-bottom; | 900 | margin-bottom: $sub-menu-margin-bottom; |
916 | 901 | ||
902 | > span > my-global-icon, | ||
917 | > my-global-icon { | 903 | > my-global-icon { |
918 | margin-right: 10px; | 904 | margin-right: 10px; |
919 | vertical-align: bottom; | ||
920 | width: 24px; | 905 | width: 24px; |
921 | height: 24px; | 906 | height: 24px; |
907 | vertical-align: top; | ||
922 | } | 908 | } |
923 | 909 | ||
924 | .badge { | 910 | .badge { |
925 | margin-left: 7px; | 911 | margin-left: 7px; |
912 | vertical-align: top; | ||
926 | } | 913 | } |
927 | } | 914 | } |
928 | } | 915 | } |
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index d2a5d2bd9..d54563df6 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -60,7 +60,7 @@ $max-channels-width: 1200px; | |||
60 | $footer-height: 30px; | 60 | $footer-height: 30px; |
61 | $footer-margin: 30px; | 61 | $footer-margin: 30px; |
62 | 62 | ||
63 | $separator-border-color: rgba(0, 0, 0, 0.10); | 63 | $separator-border-color: rgba(0, 0, 0, 0.1); |
64 | 64 | ||
65 | $video-miniature-margin-bottom: 15px; | 65 | $video-miniature-margin-bottom: 15px; |
66 | 66 | ||
@@ -90,7 +90,7 @@ $markdown-textarea-background-color: $grey-background-hover-color; | |||
90 | $sub-menu-margin-bottom: 30px; | 90 | $sub-menu-margin-bottom: 30px; |
91 | $sub-menu-margin-bottom-small-view: 10px; | 91 | $sub-menu-margin-bottom-small-view: 10px; |
92 | 92 | ||
93 | $activated-action-button-color: black; | 93 | $activated-action-button-color: #000; |
94 | 94 | ||
95 | $focus-box-shadow-form: 0 0 0 .2rem; | 95 | $focus-box-shadow-form: 0 0 0 .2rem; |
96 | 96 | ||
@@ -147,7 +147,7 @@ $variables: ( | |||
147 | @if map-has-key($variables, $variable) { | 147 | @if map-has-key($variables, $variable) { |
148 | @return map-get($variables, $variable); | 148 | @return map-get($variables, $variable); |
149 | } @else { | 149 | } @else { |
150 | @error "ERROR: Variable #{$variable} does not exist"; | 150 | @error 'ERROR: Variable #{$variable} does not exist'; |
151 | } | 151 | } |
152 | } | 152 | } |
153 | 153 | ||
diff --git a/client/src/sass/ng-select.scss b/client/src/sass/ng-select.scss index 61da6d266..13b2012b2 100644 --- a/client/src/sass/ng-select.scss +++ b/client/src/sass/ng-select.scss | |||
@@ -14,7 +14,7 @@ $ng-select-height: 30px; | |||
14 | $ng-select-value-padding-left: 15px; | 14 | $ng-select-value-padding-left: 15px; |
15 | $ng-select-value-font-size: 15px; | 15 | $ng-select-value-font-size: 15px; |
16 | 16 | ||
17 | @import "~@ng-select/ng-select/scss/default.theme.scss"; | 17 | @import '~@ng-select/ng-select/scss/default.theme'; |
18 | 18 | ||
19 | .ng-select { | 19 | .ng-select { |
20 | font-size: $ng-select-value-font-size; | 20 | font-size: $ng-select-value-font-size; |
@@ -31,13 +31,13 @@ $ng-select-value-font-size: 15px; | |||
31 | } | 31 | } |
32 | 32 | ||
33 | .ng-arrow-wrapper { | 33 | .ng-arrow-wrapper { |
34 | padding-right: 12px | 34 | padding-right: 12px; |
35 | } | 35 | } |
36 | 36 | ||
37 | &.ng-select-single .ng-value-container .ng-value { | 37 | &.ng-select-single .ng-value-container .ng-value { |
38 | color: pvar(--inputForegroundColor); | 38 | color: pvar(--inputForegroundColor); |
39 | 39 | ||
40 | .ng-value-label { | 40 | .ng-value-label { /* stylelint-disable-line */ |
41 | display: flex; | 41 | display: flex; |
42 | align-items: center; | 42 | align-items: center; |
43 | } | 43 | } |
@@ -45,7 +45,8 @@ $ng-select-value-font-size: 15px; | |||
45 | 45 | ||
46 | &.ng-select-multiple .ng-select-container .ng-value-container { | 46 | &.ng-select-multiple .ng-select-container .ng-value-container { |
47 | padding-left: 12px; | 47 | padding-left: 12px; |
48 | .ng-value { | 48 | |
49 | .ng-value { /* stylelint-disable-line */ | ||
49 | margin-left: 3px; | 50 | margin-left: 3px; |
50 | } | 51 | } |
51 | } | 52 | } |
diff --git a/client/src/sass/player/context-menu.scss b/client/src/sass/player/context-menu.scss index df78916c6..45cee3e77 100644 --- a/client/src/sass/player/context-menu.scss +++ b/client/src/sass/player/context-menu.scss | |||
@@ -8,7 +8,7 @@ $context-menu-width: 350px; | |||
8 | 8 | ||
9 | .video-js .vjs-contextmenu-ui-menu { | 9 | .video-js .vjs-contextmenu-ui-menu { |
10 | position: absolute; | 10 | position: absolute; |
11 | background-color: rgba(0, 0, 0, 0.5); | 11 | background-color: $primary-background-color; |
12 | padding: 8px 0; | 12 | padding: 8px 0; |
13 | border-radius: 4px; | 13 | border-radius: 4px; |
14 | width: $context-menu-width; | 14 | width: $context-menu-width; |
@@ -31,26 +31,26 @@ $context-menu-width: 350px; | |||
31 | background-color: rgba(255, 255, 255, 0.2); | 31 | background-color: rgba(255, 255, 255, 0.2); |
32 | } | 32 | } |
33 | 33 | ||
34 | [class^="vjs-icon-"] { | 34 | [class^='vjs-icon-'] { |
35 | $icons: 'link-2', 'repeat', 'code', 'tick-white', 'info'; | ||
36 | |||
35 | display: inline-flex; | 37 | display: inline-flex; |
36 | position: relative; | 38 | position: relative; |
37 | top: 2px; | 39 | top: 2px; |
38 | cursor: pointer; | 40 | cursor: pointer; |
39 | width: 14px; | 41 | width: 14px; |
40 | height: 14px; | 42 | height: 14px; |
41 | background-color: white; | 43 | background-color: #fff; |
42 | mask-size: cover; | 44 | mask-size: cover; |
43 | margin-right: 0.8rem !important; | 45 | margin-right: 0.8rem !important; |
44 | 46 | ||
45 | $icons: 'link-2', 'repeat', 'code', 'tick-white'; | ||
46 | |||
47 | @each $icon in $icons { | 47 | @each $icon in $icons { |
48 | &[class$="-#{$icon}"] { | 48 | &[class$="-#{$icon}"] { |
49 | mask-image: url('#{$assets-path}/player/images/#{$icon}.svg'); | 49 | mask-image: url('#{$assets-path}/player/images/#{$icon}.svg'); |
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | &[class$="-tick-white"] { | 53 | &[class$='-tick-white'] { |
54 | float: right; | 54 | float: right; |
55 | margin: 0 !important; | 55 | margin: 0 !important; |
56 | } | 56 | } |
diff --git a/client/src/sass/player/index.scss b/client/src/sass/player/index.scss index fe92ce5e0..e674fa2f6 100644 --- a/client/src/sass/player/index.scss +++ b/client/src/sass/player/index.scss | |||
@@ -4,5 +4,6 @@ | |||
4 | @import './settings-menu'; | 4 | @import './settings-menu'; |
5 | @import './spinner'; | 5 | @import './spinner'; |
6 | @import './upnext'; | 6 | @import './upnext'; |
7 | @import './bezels.scss'; | 7 | @import './bezels'; |
8 | @import './playlist.scss'; | 8 | @import './playlist'; |
9 | @import './stats'; | ||
diff --git a/client/src/sass/player/mobile.scss b/client/src/sass/player/mobile.scss index c2fa855ab..26066d218 100644 --- a/client/src/sass/player/mobile.scss +++ b/client/src/sass/player/mobile.scss | |||
@@ -13,4 +13,4 @@ | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | } | 15 | } |
16 | } \ No newline at end of file | 16 | } |
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss index 81aacf1d7..8fe2e054d 100644 --- a/client/src/sass/player/peertube-skin.scss +++ b/client/src/sass/player/peertube-skin.scss | |||
@@ -52,12 +52,12 @@ body { | |||
52 | } | 52 | } |
53 | 53 | ||
54 | .vjs-big-play-button { | 54 | .vjs-big-play-button { |
55 | outline: 0; | ||
56 | font-size: 6em; | ||
57 | |||
58 | $big-play-width: 1.2em; | 55 | $big-play-width: 1.2em; |
59 | $big-play-height: 1.2em; | 56 | $big-play-height: 1.2em; |
60 | 57 | ||
58 | outline: 0; | ||
59 | font-size: 6em; | ||
60 | |||
61 | border: 2px solid #fff; | 61 | border: 2px solid #fff; |
62 | border-radius: 100%; | 62 | border-radius: 100%; |
63 | 63 | ||
@@ -72,7 +72,7 @@ body { | |||
72 | 72 | ||
73 | &::-moz-focus-inner { | 73 | &::-moz-focus-inner { |
74 | border: 0; | 74 | border: 0; |
75 | padding: 0 | 75 | padding: 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | .vjs-icon-placeholder::before { | 78 | .vjs-icon-placeholder::before { |
@@ -82,8 +82,9 @@ body { | |||
82 | background-image: url('#{$assets-path}/player/images/big-play-button.svg'); | 82 | background-image: url('#{$assets-path}/player/images/big-play-button.svg'); |
83 | } | 83 | } |
84 | 84 | ||
85 | &.focus-visible, &:hover { | 85 | &.focus-visible, |
86 | background-color: var(--mainColor, dimgray); | 86 | &:hover { |
87 | background-color: var(--mainColor, #696969); | ||
87 | } | 88 | } |
88 | 89 | ||
89 | } | 90 | } |
@@ -91,16 +92,19 @@ body { | |||
91 | // Small effect when we click on the play button | 92 | // Small effect when we click on the play button |
92 | &.vjs-has-big-play-button-clicked { | 93 | &.vjs-has-big-play-button-clicked { |
93 | 94 | ||
94 | .vjs-big-play-button, .vjs-poster { | 95 | .vjs-big-play-button, |
96 | .vjs-poster { | ||
95 | display: block; | 97 | display: block; |
96 | visibility: hidden; | 98 | visibility: hidden; |
97 | 99 | ||
98 | &.vjs-big-play-button, &.vjs-big-play-button::before { | 100 | &.vjs-big-play-button, |
101 | &.vjs-big-play-button::before { | ||
99 | opacity: 0; | 102 | opacity: 0; |
100 | transition: visibility 0.2s, opacity 0.2s; | 103 | transition: visibility 0.2s, opacity 0.2s; |
101 | } | 104 | } |
102 | 105 | ||
103 | &.vjs-poster, &.vjs-poster::before { | 106 | &.vjs-poster, |
107 | &.vjs-poster::before { | ||
104 | opacity: 0; | 108 | opacity: 0; |
105 | transition: visibility 0.3s, opacity 0.3s; | 109 | transition: visibility 0.3s, opacity 0.3s; |
106 | transition-delay: 0.05s; | 110 | transition-delay: 0.05s; |
@@ -165,8 +169,7 @@ body { | |||
165 | .vjs-fullscreen-control, | 169 | .vjs-fullscreen-control, |
166 | .vjs-peertube-link, | 170 | .vjs-peertube-link, |
167 | .vjs-theater-control, | 171 | .vjs-theater-control, |
168 | .vjs-settings | 172 | .vjs-settings { |
169 | { | ||
170 | color: pvar(--embedForegroundColor) !important; | 173 | color: pvar(--embedForegroundColor) !important; |
171 | 174 | ||
172 | opacity: $primary-foreground-opacity; | 175 | opacity: $primary-foreground-opacity; |
@@ -217,7 +220,8 @@ body { | |||
217 | } | 220 | } |
218 | 221 | ||
219 | .vjs-load-progress { | 222 | .vjs-load-progress { |
220 | &, & div { | 223 | &, |
224 | div { | ||
221 | background: rgba(255, 255, 255, .2); | 225 | background: rgba(255, 255, 255, .2); |
222 | } | 226 | } |
223 | } | 227 | } |
@@ -266,7 +270,7 @@ body { | |||
266 | line-height: calc(#{$control-bar-height} - 1px); | 270 | line-height: calc(#{$control-bar-height} - 1px); |
267 | 271 | ||
268 | &::after { | 272 | &::after { |
269 | content: "/"; | 273 | content: '/'; |
270 | margin: 0 1px 0 2px; | 274 | margin: 0 1px 0 2px; |
271 | } | 275 | } |
272 | } | 276 | } |
@@ -308,11 +312,17 @@ body { | |||
308 | display: none; | 312 | display: none; |
309 | } | 313 | } |
310 | 314 | ||
311 | .download-speed-number, .upload-speed-number, .peers-number, .http-fallback { | 315 | .download-speed-number, |
316 | .upload-speed-number, | ||
317 | .peers-number, | ||
318 | .http-fallback { | ||
312 | font-weight: $font-semibold; | 319 | font-weight: $font-semibold; |
313 | } | 320 | } |
314 | 321 | ||
315 | .download-speed-text, .upload-speed-text, .peers-text, .http-fallback { | 322 | .download-speed-text, |
323 | .upload-speed-text, | ||
324 | .peers-text, | ||
325 | .http-fallback { | ||
316 | margin-right: 15px; | 326 | margin-right: 15px; |
317 | } | 327 | } |
318 | 328 | ||
@@ -336,10 +346,8 @@ body { | |||
336 | &.icon-next, | 346 | &.icon-next, |
337 | &.icon-previous { | 347 | &.icon-previous { |
338 | mask-image: url('#{$assets-path}/player/images/next.svg'); | 348 | mask-image: url('#{$assets-path}/player/images/next.svg'); |
339 | -webkit-mask-image: url('#{$assets-path}/player/images/next.svg'); | 349 | background-color: #fff; |
340 | background-color: white; | ||
341 | mask-size: cover; | 350 | mask-size: cover; |
342 | -webkit-mask-size: cover; | ||
343 | width: 11px; | 351 | width: 11px; |
344 | height: 11px; | 352 | height: 11px; |
345 | margin-top: -2px; | 353 | margin-top: -2px; |
@@ -410,7 +418,7 @@ body { | |||
410 | } | 418 | } |
411 | 419 | ||
412 | .vjs-volume-bar { | 420 | .vjs-volume-bar { |
413 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAcCAQAAACw95UnAAAAMElEQVRIx2NgoBL4n4YKGUYNHkEG4zJg1OCRYDCpBowaPJwMppbLRg0eNXjUYBLEAXWNUA6QNm1lAAAAAElFTkSuQmCC) no-repeat; | 421 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAcCAQAAACw95UnAAAAMElEQVRIx2NgoBL4n4YKGUYNHkEG4zJg1OCRYDCpBowaPJwMppbLRg0eNXjUYBLEAXWNUA6QNm1lAAAAAElFTkSuQmCC') no-repeat; |
414 | background-size: 22px 14px; | 422 | background-size: 22px 14px; |
415 | height: 100%; | 423 | height: 100%; |
416 | width: 100%; | 424 | width: 100%; |
@@ -421,7 +429,7 @@ body { | |||
421 | top: 3px; | 429 | top: 3px; |
422 | 430 | ||
423 | .vjs-volume-level { | 431 | .vjs-volume-level { |
424 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAcAQAAAAAyhWABAAAAAnRSTlMAAHaTzTgAAAAZSURBVHgBYwAB/g9EUv+JokCqiaT+U4MCAPKPS7WUUOc1AAAAAElFTkSuQmCC) no-repeat; | 432 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAcAQAAAAAyhWABAAAAAnRSTlMAAHaTzTgAAAAZSURBVHgBYwAB/g9EUv+JokCqiaT+U4MCAPKPS7WUUOc1AAAAAElFTkSuQmCC') no-repeat; |
425 | background-size: 22px 14px; | 433 | background-size: 22px 14px; |
426 | max-width: 22px; | 434 | max-width: 22px; |
427 | max-height: 14px; | 435 | max-height: 14px; |
diff --git a/client/src/sass/player/playlist.scss b/client/src/sass/player/playlist.scss index ebbed02d9..8558fc837 100644 --- a/client/src/sass/player/playlist.scss +++ b/client/src/sass/player/playlist.scss | |||
@@ -44,10 +44,8 @@ $playlist-menu-width: 350px; | |||
44 | width: 20px; | 44 | width: 20px; |
45 | height: 20px; | 45 | height: 20px; |
46 | mask-image: url('#{$assets-path}/images/feather/x.svg'); | 46 | mask-image: url('#{$assets-path}/images/feather/x.svg'); |
47 | -webkit-mask-image: url('#{$assets-path}/images/feather/x.svg'); | 47 | background-color: #fff; |
48 | background-color: white; | ||
49 | mask-size: cover; | 48 | mask-size: cover; |
50 | -webkit-mask-size: cover; | ||
51 | } | 49 | } |
52 | } | 50 | } |
53 | } | 51 | } |
@@ -90,10 +88,8 @@ $playlist-menu-width: 350px; | |||
90 | width: 22px; | 88 | width: 22px; |
91 | height: 22px; | 89 | height: 22px; |
92 | mask-image: url('#{$assets-path}/images/feather/list.svg'); | 90 | mask-image: url('#{$assets-path}/images/feather/list.svg'); |
93 | -webkit-mask-image: url('#{$assets-path}/images/feather/list.svg'); | 91 | background-color: #fff; |
94 | background-color: white; | ||
95 | mask-size: cover; | 92 | mask-size: cover; |
96 | -webkit-mask-size: cover; | ||
97 | margin-bottom: 3px; | 93 | margin-bottom: 3px; |
98 | } | 94 | } |
99 | 95 | ||
@@ -133,9 +129,9 @@ $playlist-menu-width: 350px; | |||
133 | } | 129 | } |
134 | 130 | ||
135 | .item-player { | 131 | .item-player { |
136 | display: none; | ||
137 | |||
138 | @include play-icon(20px, 16px); | 132 | @include play-icon(20px, 16px); |
133 | |||
134 | display: none; | ||
139 | } | 135 | } |
140 | 136 | ||
141 | &.vjs-selected { | 137 | &.vjs-selected { |
diff --git a/client/src/sass/player/settings-menu.scss b/client/src/sass/player/settings-menu.scss index 09c872ef7..74eee7d64 100644 --- a/client/src/sass/player/settings-menu.scss +++ b/client/src/sass/player/settings-menu.scss | |||
@@ -149,7 +149,7 @@ $setting-transition-easing: ease-out; | |||
149 | background-color: inherit; | 149 | background-color: inherit; |
150 | padding: 8px 8px 13px 12px; | 150 | padding: 8px 8px 13px 12px; |
151 | margin-bottom: 5px; | 151 | margin-bottom: 5px; |
152 | border-bottom: 1px solid grey; | 152 | border-bottom: 1px solid #808080; |
153 | text-align: left; | 153 | text-align: left; |
154 | 154 | ||
155 | &::before { | 155 | &::before { |
diff --git a/client/src/sass/player/spinner.scss b/client/src/sass/player/spinner.scss index a6af8da33..94f4d1008 100644 --- a/client/src/sass/player/spinner.scss +++ b/client/src/sass/player/spinner.scss | |||
@@ -51,4 +51,4 @@ | |||
51 | opacity: 1; | 51 | opacity: 1; |
52 | } | 52 | } |
53 | } | 53 | } |
54 | } \ No newline at end of file | 54 | } |
diff --git a/client/src/sass/player/stats.scss b/client/src/sass/player/stats.scss new file mode 100644 index 000000000..6fcbcd969 --- /dev/null +++ b/client/src/sass/player/stats.scss | |||
@@ -0,0 +1,41 @@ | |||
1 | @import './_player-variables'; | ||
2 | |||
3 | $stats-width: 420px; | ||
4 | $contextmenu-background-color: rgba(0, 0, 0, 0.6); | ||
5 | |||
6 | .video-js { | ||
7 | |||
8 | .vjs-stats-content { | ||
9 | @include transition(opacity 0.1s); | ||
10 | |||
11 | position: absolute; | ||
12 | background-color: $contextmenu-background-color; | ||
13 | padding: 5px 0; | ||
14 | border-radius: 4px; | ||
15 | width: $stats-width; | ||
16 | min-width: 27em; | ||
17 | max-width: calc(100vw - 20px); | ||
18 | left: 10px; | ||
19 | top: 10px; | ||
20 | z-index: 64; | ||
21 | font-size: 12px; | ||
22 | line-height: 1.2; | ||
23 | } | ||
24 | |||
25 | .vjs-stats-close { | ||
26 | cursor: pointer; | ||
27 | position: absolute; | ||
28 | right: 3px; | ||
29 | top: 3px; | ||
30 | padding: 0; | ||
31 | } | ||
32 | |||
33 | .vjs-stats-list > div > div { | ||
34 | display: inline-block; | ||
35 | font-weight: 600; | ||
36 | padding: 0 .5em; | ||
37 | text-align: right; | ||
38 | width: 11.5em; | ||
39 | white-space: nowrap; | ||
40 | } | ||
41 | } | ||
diff --git a/client/src/sass/player/upnext.scss b/client/src/sass/player/upnext.scss index 7614bb3b6..8c9a6f784 100644 --- a/client/src/sass/player/upnext.scss +++ b/client/src/sass/player/upnext.scss | |||
@@ -11,15 +11,15 @@ $browser-context: 16; | |||
11 | .video-js { | 11 | .video-js { |
12 | 12 | ||
13 | .vjs-upnext-content { | 13 | .vjs-upnext-content { |
14 | @include transition(opacity 0.1s); | ||
15 | |||
14 | font-size: 1.8em; | 16 | font-size: 1.8em; |
15 | pointer-events: auto; | 17 | pointer-events: auto; |
16 | position: absolute; | 18 | position: absolute; |
17 | top: 0; | 19 | top: 0; |
18 | bottom: 0; | 20 | bottom: 0; |
19 | background: rgba(0,0,0,0.6); | 21 | background: rgba(0, 0, 0, 0.6); |
20 | width: 100%; | 22 | width: 100%; |
21 | |||
22 | @include transition(opacity 0.1s); | ||
23 | } | 23 | } |
24 | 24 | ||
25 | .vjs-upnext-top { | 25 | .vjs-upnext-top { |
@@ -77,7 +77,7 @@ $browser-context: 16; | |||
77 | float: none; | 77 | float: none; |
78 | padding: 10px !important; | 78 | padding: 10px !important; |
79 | font-size: 16px !important; | 79 | font-size: 16px !important; |
80 | border: none; | 80 | border: 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | .vjs-upnext-cancel-button, | 83 | .vjs-upnext-cancel-button, |
@@ -86,7 +86,7 @@ $browser-context: 16; | |||
86 | } | 86 | } |
87 | 87 | ||
88 | .vjs-upnext-cancel-button:hover { | 88 | .vjs-upnext-cancel-button:hover { |
89 | background-color: rgba(255,255,255,0.25); | 89 | background-color: rgba(255, 255, 255, 0.25); |
90 | border-radius: 2px; | 90 | border-radius: 2px; |
91 | } | 91 | } |
92 | 92 | ||
@@ -95,6 +95,8 @@ $browser-context: 16; | |||
95 | } | 95 | } |
96 | 96 | ||
97 | .vjs-upnext-autoplay-icon { | 97 | .vjs-upnext-autoplay-icon { |
98 | @include transition(stroke-dasharray 0.1s cubic-bezier(0.4,0,1,1)); | ||
99 | |||
98 | position: absolute; | 100 | position: absolute; |
99 | top: 50%; | 101 | top: 50%; |
100 | left: 50%; | 102 | left: 50%; |
@@ -102,8 +104,6 @@ $browser-context: 16; | |||
102 | height: 98px; | 104 | height: 98px; |
103 | margin: -49px 0 0 -49px; | 105 | margin: -49px 0 0 -49px; |
104 | cursor: pointer; | 106 | cursor: pointer; |
105 | |||
106 | @include transition(stroke-dasharray 0.1s cubic-bezier(0.4,0,1,1)); | ||
107 | } | 107 | } |
108 | 108 | ||
109 | } | 109 | } |
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss index 544d0039a..6a4d89dff 100644 --- a/client/src/sass/primeng-custom.scss +++ b/client/src/sass/primeng-custom.scss | |||
@@ -1,13 +1,18 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | /* stylelint-disable */ | ||
4 | @import '~primeng/resources/primeng.css'; | 5 | @import '~primeng/resources/primeng.css'; |
5 | 6 | ||
6 | // Override primeng style we don't want | 7 | // Override primeng style we don't want |
7 | input[type="button"] { | 8 | input[type=button] { |
8 | border-radius: inherit; | 9 | border-radius: inherit; |
9 | } | 10 | } |
10 | 11 | ||
12 | p-table .p-datatable-header .caption { | ||
13 | margin-bottom: 15px; | ||
14 | } | ||
15 | |||
11 | // Taken from old nova light theme | 16 | // Taken from old nova light theme |
12 | 17 | ||
13 | body .p-disabled { | 18 | body .p-disabled { |
@@ -511,10 +516,6 @@ p-table { | |||
511 | .left-buttons { | 516 | .left-buttons { |
512 | padding-left: 15px; | 517 | padding-left: 15px; |
513 | } | 518 | } |
514 | |||
515 | .input-group-text { | ||
516 | background-color: transparent; | ||
517 | } | ||
518 | } | 519 | } |
519 | } | 520 | } |
520 | 521 | ||
diff --git a/client/src/standalone/videos/embed.scss b/client/src/standalone/videos/embed.scss index cbe6bdd01..e32cce54e 100644 --- a/client/src/standalone/videos/embed.scss +++ b/client/src/standalone/videos/embed.scss | |||
@@ -21,7 +21,8 @@ video { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | /* fill the entire space */ | 23 | /* fill the entire space */ |
24 | html, body { | 24 | html, |
25 | body { | ||
25 | height: 100%; | 26 | height: 100%; |
26 | margin: 0; | 27 | margin: 0; |
27 | background-color: #000; | 28 | background-color: #000; |
@@ -70,18 +71,18 @@ html, body { | |||
70 | text-align: center; | 71 | text-align: center; |
71 | width: 100%; | 72 | width: 100%; |
72 | height: 100%; | 73 | height: 100%; |
73 | color: white; | 74 | color: #fff; |
74 | box-sizing: border-box; | 75 | box-sizing: border-box; |
75 | font-family: sans-serif; | 76 | font-family: sans-serif; |
77 | } | ||
76 | 78 | ||
77 | #error-title { | 79 | #error-title { |
78 | font-size: 45px; | 80 | font-size: 45px; |
79 | margin-bottom: 5px; | 81 | margin-bottom: 5px; |
80 | } | 82 | } |
81 | 83 | ||
82 | #error-content { | 84 | #error-content { |
83 | font-size: 24px; | 85 | font-size: 24px; |
84 | } | ||
85 | } | 86 | } |
86 | 87 | ||
87 | #placeholder-preview { | 88 | #placeholder-preview { |
@@ -97,10 +98,10 @@ html, body { | |||
97 | @media screen and (max-width: 300px) { | 98 | @media screen and (max-width: 300px) { |
98 | #error-block { | 99 | #error-block { |
99 | font-size: 36px; | 100 | font-size: 36px; |
101 | } | ||
100 | 102 | ||
101 | #error-content { | 103 | #error-content { |
102 | font-size: 14px; | 104 | font-size: 14px; |
103 | } | ||
104 | } | 105 | } |
105 | } | 106 | } |
106 | 107 | ||
diff --git a/client/src/standalone/videos/test-embed.scss b/client/src/standalone/videos/test-embed.scss index 85ce4e0f7..b9ac3e74e 100644 --- a/client/src/standalone/videos/test-embed.scss +++ b/client/src/standalone/videos/test-embed.scss | |||
@@ -15,7 +15,7 @@ body { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | iframe { | 17 | iframe { |
18 | border: none; | 18 | border: 0; |
19 | border-radius: 8px; | 19 | border-radius: 8px; |
20 | min-width: 200px; | 20 | min-width: 200px; |
21 | width: 100%; | 21 | width: 100%; |
@@ -41,7 +41,7 @@ aside { | |||
41 | .icon { | 41 | .icon { |
42 | height: 100%; | 42 | height: 100%; |
43 | padding: 0 18px 0 32px; | 43 | padding: 0 18px 0 32px; |
44 | background: white; | 44 | background: #fff; |
45 | display: flex; | 45 | display: flex; |
46 | align-items: center; | 46 | align-items: center; |
47 | margin-right: 0.5em; | 47 | margin-right: 0.5em; |
@@ -62,13 +62,13 @@ header { | |||
62 | width: 100%; | 62 | width: 100%; |
63 | height: 3.2em; | 63 | height: 3.2em; |
64 | background-color: #F1680D; | 64 | background-color: #F1680D; |
65 | color: white; | 65 | color: #fff; |
66 | //background-image: url(../../assets/images/backdrop/network-o.png); | 66 | //background-image: url(../../assets/images/backdrop/network-o.png); |
67 | display: flex; | 67 | display: flex; |
68 | flex-direction: row; | 68 | flex-direction: row; |
69 | align-items: center; | 69 | align-items: center; |
70 | margin-bottom: 1em; | 70 | margin-bottom: 1em; |
71 | box-shadow: 1px 0px 10px rgba(0,0,0,0.6); | 71 | box-shadow: 1px 0 10px rgba(0, 0, 0, 0.6); |
72 | background-size: 50%; | 72 | background-size: 50%; |
73 | background-position: top left; | 73 | background-position: top left; |
74 | padding-right: 1em; | 74 | padding-right: 1em; |
@@ -87,13 +87,13 @@ header { | |||
87 | display: flex; | 87 | display: flex; |
88 | flex-wrap: wrap; | 88 | flex-wrap: wrap; |
89 | 89 | ||
90 | & > * { | 90 | > * { |
91 | flex-grow: 0; | 91 | flex-grow: 0; |
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
95 | fieldset { | 95 | fieldset { |
96 | border: none; | 96 | border: 0; |
97 | min-width: 8em; | 97 | min-width: 8em; |
98 | legend { | 98 | legend { |
99 | border-bottom: 1px solid #ccc; | 99 | border-bottom: 1px solid #ccc; |
@@ -103,12 +103,12 @@ fieldset { | |||
103 | 103 | ||
104 | button { | 104 | button { |
105 | background: #F1680D; | 105 | background: #F1680D; |
106 | color: white; | 106 | color: #fff; |
107 | font-weight: bold; | 107 | font-weight: bold; |
108 | border-radius: 5px; | 108 | border-radius: 5px; |
109 | margin: 0; | 109 | margin: 0; |
110 | padding: 1em 1.25em; | 110 | padding: 1em 1.25em; |
111 | border: none; | 111 | border: 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | a { | 114 | a { |
@@ -118,7 +118,11 @@ a { | |||
118 | text-decoration: underline; | 118 | text-decoration: underline; |
119 | } | 119 | } |
120 | 120 | ||
121 | &, &:hover, &:focus, &:visited, &:active { | 121 | &, |
122 | &:hover, | ||
123 | &:focus, | ||
124 | &:visited, | ||
125 | &:active { | ||
122 | color: #F44336; | 126 | color: #F44336; |
123 | } | 127 | } |
124 | } | 128 | } |