diff options
Diffstat (limited to 'client/src/app')
147 files changed, 956 insertions, 852 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 6bc1d0448..f16f8bd71 100644 --- a/client/src/app/+about/about-follows/about-follows.component.html +++ b/client/src/app/+about/about-follows/about-follows.component.html | |||
@@ -1,5 +1,6 @@ | |||
1 | <div class="row"> | 1 | <div class="row"> |
2 | <h1 class="sr-only" i18n>Follows</h1> | 2 | <h1 class="visually-hidden" i18n>Follows</h1> |
3 | |||
3 | <div class="col-xl-6 col-md-12"> | 4 | <div class="col-xl-6 col-md-12"> |
4 | <h2 i18n class="subtitle">Follower instances ({{ followersPagination.totalItems }})</h2> | 5 | <h2 i18n class="subtitle">Follower instances ({{ followersPagination.totalItems }})</h2> |
5 | 6 | ||
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 80eb997e4..057d04ced 100644 --- a/client/src/app/+about/about-follows/about-follows.component.scss +++ b/client/src/app/+about/about-follows/about-follows.component.scss | |||
@@ -15,6 +15,7 @@ a { | |||
15 | 15 | ||
16 | .no-results { | 16 | .no-results { |
17 | justify-content: flex-start; | 17 | justify-content: flex-start; |
18 | align-items: flex-start; | ||
18 | } | 19 | } |
19 | 20 | ||
20 | .show-more { | 21 | .show-more { |
diff --git a/client/src/app/+about/about-instance/about-instance.component.html b/client/src/app/+about/about-instance/about-instance.component.html index 7f2a6aa77..b113df82f 100644 --- a/client/src/app/+about/about-instance/about-instance.component.html +++ b/client/src/app/+about/about-instance/about-instance.component.html | |||
@@ -8,9 +8,9 @@ | |||
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <div class="instance-badges" *ngIf="categories.length !== 0 || languages.length !== 0"> | 10 | <div class="instance-badges" *ngIf="categories.length !== 0 || languages.length !== 0"> |
11 | <span *ngFor="let category of categories" class="badge badge-primary category">{{ category }}</span> | 11 | <span *ngFor="let category of categories" class="pt-badge badge-primary">{{ category }}</span> |
12 | 12 | ||
13 | <span *ngFor="let language of languages" class="badge badge-secondary language">{{ language }}</span> | 13 | <span *ngFor="let language of languages" class="pt-badge badge-secondary">{{ language }}</span> |
14 | </div> | 14 | </div> |
15 | 15 | ||
16 | <div class="short-description"> | 16 | <div class="short-description"> |
@@ -204,7 +204,7 @@ | |||
204 | </div> | 204 | </div> |
205 | 205 | ||
206 | <div class="col-md-12 col-xl-6" myPluginSelector pluginSelectorId="about-instance-features"> | 206 | <div class="col-md-12 col-xl-6" myPluginSelector pluginSelectorId="about-instance-features"> |
207 | <h2 class="sr-only" i18n>FEATURES</h2> | 207 | <h2 class="visually-hidden" i18n>FEATURES</h2> |
208 | <my-instance-features-table></my-instance-features-table> | 208 | <my-instance-features-table></my-instance-features-table> |
209 | </div> | 209 | </div> |
210 | 210 | ||
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 965c04b6c..a48783639 100644 --- a/client/src/app/+about/about-instance/about-instance.component.scss +++ b/client/src/app/+about/about-instance/about-instance.component.scss | |||
@@ -19,18 +19,11 @@ | |||
19 | } | 19 | } |
20 | 20 | ||
21 | .instance-badges { | 21 | .instance-badges { |
22 | font-size: 16px; | ||
23 | margin-bottom: 20px; | 22 | margin-bottom: 20px; |
23 | font-size: 16px; | ||
24 | 24 | ||
25 | .badge { | 25 | .pt-badge { |
26 | @include margin-right(5px); | 26 | @include margin-right(5px); |
27 | |||
28 | font-size: 12px; | ||
29 | font-weight: $font-semibold; | ||
30 | |||
31 | &.category { | ||
32 | background-color: pvar(--mainColor); | ||
33 | } | ||
34 | } | 27 | } |
35 | } | 28 | } |
36 | 29 | ||
diff --git a/client/src/app/+about/about.component.html b/client/src/app/+about/about.component.html index 63d429ebf..3b7343a04 100644 --- a/client/src/app/+about/about.component.html +++ b/client/src/app/+about/about.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="row"> | 1 | <div> |
2 | <div class="sub-menu" [ngClass]="{ 'sub-menu-fixed': !isBroadcastMessageDisplayed }"> | 2 | <div class="sub-menu" [ngClass]="{ 'sub-menu-fixed': !isBroadcastMessageDisplayed }"> |
3 | 3 | ||
4 | <div class="links"> | 4 | <div class="links"> |
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 379c0443e..0dfa87074 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 | |||
@@ -1,4 +1,4 @@ | |||
1 | <h1 class="sr-only" i18n>Video channels</h1> | 1 | <h1 class="visually-hidden" i18n>Video channels</h1> |
2 | 2 | ||
3 | <div class="margin-content"> | 3 | <div class="margin-content"> |
4 | 4 | ||
@@ -23,10 +23,10 @@ | |||
23 | </h2> | 23 | </h2> |
24 | 24 | ||
25 | <div class="actor-counters"> | 25 | <div class="actor-counters"> |
26 | <div class="followers" i18n>{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div> | 26 | <div class="followers" i18n>{videoChannel.followersCount, plural, =0 {No subscribers} =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div> |
27 | 27 | ||
28 | <span class="videos-count" *ngIf="getTotalVideosOf(videoChannel) !== undefined" i18n> | 28 | <span class="videos-count" *ngIf="getTotalVideosOf(videoChannel) !== undefined" i18n> |
29 | {getTotalVideosOf(videoChannel), plural, =1 {1 videos} other {{{ getTotalVideosOf(videoChannel) }} videos}} | 29 | {getTotalVideosOf(videoChannel), plural, =0 {No videos} =1 {1 video} other {{{ getTotalVideosOf(videoChannel) }} videos}} |
30 | </span> | 30 | </span> |
31 | </div> | 31 | </div> |
32 | 32 | ||
diff --git a/client/src/app/+accounts/accounts.component.html b/client/src/app/+accounts/accounts.component.html index 8362e6b7e..d92760ff8 100644 --- a/client/src/app/+accounts/accounts.component.html +++ b/client/src/app/+accounts/accounts.component.html | |||
@@ -18,7 +18,7 @@ | |||
18 | (userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()" | 18 | (userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()" |
19 | ></my-user-moderation-dropdown> | 19 | ></my-user-moderation-dropdown> |
20 | 20 | ||
21 | <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="badge badge-danger" i18n>Banned</span> | 21 | <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="pt-badge badge-danger" i18n>Banned</span> |
22 | 22 | ||
23 | <my-account-block-badges [account]="account"></my-account-block-badges> | 23 | <my-account-block-badges [account]="account"></my-account-block-badges> |
24 | </div> | 24 | </div> |
@@ -33,10 +33,10 @@ | |||
33 | </div> | 33 | </div> |
34 | 34 | ||
35 | <div class="actor-counters"> | 35 | <div class="actor-counters"> |
36 | <span i18n>{naiveAggregatedSubscribers(), plural, =1 {1 subscriber} other {{{ naiveAggregatedSubscribers() }} subscribers}}</span> | 36 | <span i18n>{naiveAggregatedSubscribers(), plural, =0 {No subscribers} =1 {1 subscriber} other {{{ naiveAggregatedSubscribers() }} subscribers}}</span> |
37 | 37 | ||
38 | <span class="videos-count" *ngIf="accountVideosCount !== undefined" i18n> | 38 | <span class="videos-count" *ngIf="accountVideosCount !== undefined" i18n> |
39 | {accountVideosCount, plural, =1 {1 videos} other {{{ accountVideosCount }} videos}} | 39 | {accountVideosCount, plural, =0 {No videos} =1 {1 video} other {{{ accountVideosCount }} videos}} |
40 | </span> | 40 | </span> |
41 | </div> | 41 | </div> |
42 | </div> | 42 | </div> |
diff --git a/client/src/app/+accounts/accounts.component.scss b/client/src/app/+accounts/accounts.component.scss index 5043b98c4..a316bd599 100644 --- a/client/src/app/+accounts/accounts.component.scss +++ b/client/src/app/+accounts/accounts.component.scss | |||
@@ -93,6 +93,10 @@ my-user-moderation-dropdown { | |||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | .pt-badge { | ||
97 | @include margin-right(5px); | ||
98 | } | ||
99 | |||
96 | @media screen and (max-width: $small-view) { | 100 | @media screen and (max-width: $small-view) { |
97 | .root { | 101 | .root { |
98 | --myGlobalTopPadding: 45px; | 102 | --myGlobalTopPadding: 45px; |
diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts index 898325492..cf66b817a 100644 --- a/client/src/app/+accounts/accounts.component.ts +++ b/client/src/app/+accounts/accounts.component.ts | |||
@@ -30,8 +30,6 @@ export class AccountsComponent implements OnInit, OnDestroy { | |||
30 | links: ListOverflowItem[] = [] | 30 | links: ListOverflowItem[] = [] |
31 | hideMenu = false | 31 | hideMenu = false |
32 | 32 | ||
33 | accountFollowerTitle = '' | ||
34 | |||
35 | accountVideosCount: number | 33 | accountVideosCount: number |
36 | accountDescriptionHTML = '' | 34 | accountDescriptionHTML = '' |
37 | accountDescriptionExpanded = false | 35 | accountDescriptionExpanded = false |
@@ -121,12 +119,6 @@ export class AccountsComponent implements OnInit, OnDestroy { | |||
121 | this.notifier.success($localize`Username copied`) | 119 | this.notifier.success($localize`Username copied`) |
122 | } | 120 | } |
123 | 121 | ||
124 | subscribersDisplayFor (count: number) { | ||
125 | if (count === 1) return $localize`1 subscriber` | ||
126 | |||
127 | return $localize`${count} subscribers` | ||
128 | } | ||
129 | |||
130 | searchChanged (search: string) { | 122 | searchChanged (search: string) { |
131 | const queryParams = { search } | 123 | const queryParams = { search } |
132 | 124 | ||
@@ -150,8 +142,6 @@ export class AccountsComponent implements OnInit, OnDestroy { | |||
150 | } | 142 | } |
151 | 143 | ||
152 | private async onAccount (account: Account) { | 144 | private async onAccount (account: Account) { |
153 | this.accountFollowerTitle = $localize`${account.followersCount} direct account followers` | ||
154 | |||
155 | this.accountDescriptionHTML = await this.markdown.textMarkdownToHTML(account.description) | 145 | this.accountDescriptionHTML = await this.markdown.textMarkdownToHTML(account.description) |
156 | 146 | ||
157 | // After the markdown renderer to avoid layout changes | 147 | // After the markdown renderer to avoid layout changes |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-advanced-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-advanced-configuration.component.html index 0ab80e5a9..a17b13fdf 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-advanced-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-advanced-configuration.component.html | |||
@@ -1,15 +1,15 @@ | |||
1 | <ng-container [formGroup]="form"> | 1 | <ng-container [formGroup]="form"> |
2 | 2 | ||
3 | <div class="form-row mt-5"> <!-- cache grid --> | 3 | <div class="row mt-5"> <!-- cache grid --> |
4 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 4 | |
5 | <div class="col-12 col-lg-4 col-xl-3"> | ||
5 | <div i18n class="inner-form-title">CACHE</div> | 6 | <div i18n class="inner-form-title">CACHE</div> |
6 | <div i18n class="inner-form-description"> | 7 | <div i18n class="inner-form-description"> |
7 | Some files are not federated, and fetched when necessary. Define their caching policies. | 8 | Some files are not federated, and fetched when necessary. Define their caching policies. |
8 | </div> | 9 | </div> |
9 | </div> | 10 | </div> |
10 | 11 | ||
11 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 12 | <div class="col-12 col-lg-8 col-xl-9"> |
12 | |||
13 | <ng-container formGroupName="cache"> | 13 | <ng-container formGroupName="cache"> |
14 | <div class="form-group" formGroupName="previews"> | 14 | <div class="form-group" formGroupName="previews"> |
15 | <label i18n for="cachePreviewsSize">Number of previews to keep in cache</label> | 15 | <label i18n for="cachePreviewsSize">Number of previews to keep in cache</label> |
@@ -57,8 +57,8 @@ | |||
57 | </div> | 57 | </div> |
58 | </div> | 58 | </div> |
59 | 59 | ||
60 | <div class="form-row mt-4"> <!-- cache grid --> | 60 | <div class="row mt-4"> <!-- cache grid --> |
61 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 61 | <div class="col-12 col-lg-4 col-xl-3"> |
62 | <div class="anchor" id="customizations"></div> <!-- customizations anchor --> | 62 | <div class="anchor" id="customizations"></div> <!-- customizations anchor --> |
63 | <div i18n class="inner-form-title">CUSTOMIZATIONS</div> | 63 | <div i18n class="inner-form-title">CUSTOMIZATIONS</div> |
64 | <div i18n class="inner-form-description"> | 64 | <div i18n class="inner-form-description"> |
@@ -66,8 +66,7 @@ | |||
66 | </div> | 66 | </div> |
67 | </div> | 67 | </div> |
68 | 68 | ||
69 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 69 | <div class="col-12 col-lg-8 col-xl-9"> |
70 | |||
71 | <ng-container formGroupName="instance"> | 70 | <ng-container formGroupName="instance"> |
72 | <ng-container formGroupName="customizations"> | 71 | <ng-container formGroupName="customizations"> |
73 | <div class="form-group"> | 72 | <div class="form-group"> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html index bae9d9775..f225c388d 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html | |||
@@ -1,13 +1,13 @@ | |||
1 | <ng-container [formGroup]="form"> | 1 | <ng-container [formGroup]="form"> |
2 | <div class="form-row mt-5"> <!-- appearance grid --> | 2 | <div class="row mt-5"> <!-- appearance grid --> |
3 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 3 | <div class="col-12 col-lg-4 col-xl-3"> |
4 | <div i18n class="inner-form-title">APPEARANCE</div> | 4 | <div i18n class="inner-form-title">APPEARANCE</div> |
5 | <div i18n class="inner-form-description"> | 5 | <div i18n class="inner-form-description"> |
6 | Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or <a routerLink="/admin/config/edit-custom" fragment="advanced-configuration">add slight customizations</a>. | 6 | Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or <a routerLink="/admin/config/edit-custom" fragment="advanced-configuration">add slight customizations</a>. |
7 | </div> | 7 | </div> |
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 10 | <div class="col-12 col-lg-8 col-xl-9"> |
11 | 11 | ||
12 | <ng-container formGroupName="theme"> | 12 | <ng-container formGroupName="theme"> |
13 | <div class="form-group"> | 13 | <div class="form-group"> |
@@ -88,15 +88,15 @@ | |||
88 | </div> | 88 | </div> |
89 | </div> | 89 | </div> |
90 | 90 | ||
91 | <div class="form-row mt-4"> <!-- broadcast grid --> | 91 | <div class="row mt-4"> <!-- broadcast grid --> |
92 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 92 | <div class="col-12 col-lg-4 col-xl-3"> |
93 | <div i18n class="inner-form-title">BROADCAST MESSAGE</div> | 93 | <div i18n class="inner-form-title">BROADCAST MESSAGE</div> |
94 | <div i18n class="inner-for-description"> | 94 | <div i18n class="inner-for-description"> |
95 | Display a message on your instance | 95 | Display a message on your instance |
96 | </div> | 96 | </div> |
97 | </div> | 97 | </div> |
98 | 98 | ||
99 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 99 | <div class="col-12 col-lg-8 col-xl-9"> |
100 | 100 | ||
101 | <ng-container formGroupName="broadcastMessage"> | 101 | <ng-container formGroupName="broadcastMessage"> |
102 | 102 | ||
@@ -144,15 +144,15 @@ | |||
144 | </div> | 144 | </div> |
145 | </div> | 145 | </div> |
146 | 146 | ||
147 | <div class="form-row mt-4"> <!-- new users grid --> | 147 | <div class="row mt-4"> <!-- new users grid --> |
148 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 148 | <div class="col-12 col-lg-4 col-xl-3"> |
149 | <div i18n class="inner-form-title">NEW USERS</div> | 149 | <div i18n class="inner-form-title">NEW USERS</div> |
150 | <div i18n class="inner-for-description"> | 150 | <div i18n class="inner-for-description"> |
151 | Manage <a routerLink="/admin/users">users</a> to set their quota individually. | 151 | Manage <a routerLink="/admin/users">users</a> to set their quota individually. |
152 | </div> | 152 | </div> |
153 | </div> | 153 | </div> |
154 | 154 | ||
155 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 155 | <div class="col-12 col-lg-8 col-xl-9"> |
156 | 156 | ||
157 | <ng-container formGroupName="signup"> | 157 | <ng-container formGroupName="signup"> |
158 | <div class="form-group"> | 158 | <div class="form-group"> |
@@ -239,20 +239,20 @@ | |||
239 | </div> | 239 | </div> |
240 | </div> | 240 | </div> |
241 | 241 | ||
242 | <div class="form-row mt-4"> <!-- videos grid --> | 242 | <div class="row mt-4"> <!-- videos grid --> |
243 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 243 | <div class="col-12 col-lg-4 col-xl-3"> |
244 | <div i18n class="inner-form-title">VIDEOS</div> | 244 | <div i18n class="inner-form-title">VIDEOS</div> |
245 | </div> | 245 | </div> |
246 | 246 | ||
247 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 247 | <div class="col-12 col-lg-8 col-xl-9"> |
248 | 248 | ||
249 | <ng-container formGroupName="import"> | 249 | <ng-container formGroupName="import"> |
250 | 250 | ||
251 | <ng-container formGroupName="videos"> | 251 | <ng-container formGroupName="videos"> |
252 | 252 | ||
253 | <div class="form-group mt-4"> | 253 | <div class="form-group"> |
254 | <label i18n for="importConcurrency">Import jobs concurrency</label> | 254 | <label i18n for="importConcurrency">Import jobs concurrency</label> |
255 | <span i18n class="muted ml-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span> | 255 | <span i18n class="muted ms-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span> |
256 | 256 | ||
257 | <div class="number-with-unit"> | 257 | <div class="number-with-unit"> |
258 | <input type="number" name="importConcurrency" formControlName="concurrency" /> | 258 | <input type="number" name="importConcurrency" formControlName="concurrency" /> |
@@ -309,12 +309,12 @@ | |||
309 | </div> | 309 | </div> |
310 | </div> | 310 | </div> |
311 | 311 | ||
312 | <div class="form-row mt-4"> <!-- video channels grid --> | 312 | <div class="row mt-4"> <!-- video channels grid --> |
313 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 313 | <div class="col-12 col-lg-4 col-xl-3"> |
314 | <div i18n class="inner-form-title">VIDEO CHANNELS</div> | 314 | <div i18n class="inner-form-title">VIDEO CHANNELS</div> |
315 | </div> | 315 | </div> |
316 | 316 | ||
317 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 317 | <div class="col-12 col-lg-8 col-xl-9"> |
318 | <div class="form-group" formGroupName="videoChannels"> | 318 | <div class="form-group" formGroupName="videoChannels"> |
319 | <label i18n for="videoChannelsMaxPerUser">Max video channels per user</label> | 319 | <label i18n for="videoChannelsMaxPerUser">Max video channels per user</label> |
320 | 320 | ||
@@ -331,12 +331,12 @@ | |||
331 | </div> | 331 | </div> |
332 | </div> | 332 | </div> |
333 | 333 | ||
334 | <div class="form-row mt-4"> <!-- search grid --> | 334 | <div class="row mt-4"> <!-- search grid --> |
335 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 335 | <div class="col-12 col-lg-4 col-xl-3"> |
336 | <div i18n class="inner-form-title">SEARCH</div> | 336 | <div i18n class="inner-form-title">SEARCH</div> |
337 | </div> | 337 | </div> |
338 | 338 | ||
339 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 339 | <div class="col-12 col-lg-8 col-xl-9"> |
340 | 340 | ||
341 | <ng-container formGroupName="search"> | 341 | <ng-container formGroupName="search"> |
342 | <ng-container formGroupName="remoteUri"> | 342 | <ng-container formGroupName="remoteUri"> |
@@ -420,15 +420,15 @@ | |||
420 | </div> | 420 | </div> |
421 | </div> | 421 | </div> |
422 | 422 | ||
423 | <div class="form-row mt-4"> <!-- federation grid --> | 423 | <div class="row mt-4"> <!-- federation grid --> |
424 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 424 | <div class="col-12 col-lg-4 col-xl-3"> |
425 | <div i18n class="inner-form-title">FEDERATION</div> | 425 | <div i18n class="inner-form-title">FEDERATION</div> |
426 | <div i18n class="inner-form-description"> | 426 | <div i18n class="inner-form-description"> |
427 | Manage <a routerLink="/admin/follows">relations</a> with other instances. | 427 | Manage <a routerLink="/admin/follows">relations</a> with other instances. |
428 | </div> | 428 | </div> |
429 | </div> | 429 | </div> |
430 | 430 | ||
431 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 431 | <div class="col-12 col-lg-8 col-xl-9"> |
432 | 432 | ||
433 | <ng-container formGroupName="followers"> | 433 | <ng-container formGroupName="followers"> |
434 | <ng-container formGroupName="instance"> | 434 | <ng-container formGroupName="instance"> |
@@ -499,12 +499,12 @@ | |||
499 | </div> | 499 | </div> |
500 | </div> | 500 | </div> |
501 | 501 | ||
502 | <div class="form-row mt-4"> <!-- administrators grid --> | 502 | <div class="row mt-4"> <!-- administrators grid --> |
503 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 503 | <div class="col-12 col-lg-4 col-xl-3"> |
504 | <div i18n class="inner-form-title">ADMINISTRATORS</div> | 504 | <div i18n class="inner-form-title">ADMINISTRATORS</div> |
505 | </div> | 505 | </div> |
506 | 506 | ||
507 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 507 | <div class="col-12 col-lg-8 col-xl-9"> |
508 | 508 | ||
509 | <div class="form-group" formGroupName="admin"> | 509 | <div class="form-group" formGroupName="admin"> |
510 | <label i18n for="adminEmail">Admin email</label> | 510 | <label i18n for="adminEmail">Admin email</label> |
@@ -527,8 +527,8 @@ | |||
527 | </div> | 527 | </div> |
528 | </div> | 528 | </div> |
529 | 529 | ||
530 | <div class="form-row mt-4"> <!-- Twitter grid --> | 530 | <div class="row mt-4"> <!-- Twitter grid --> |
531 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 531 | <div class="col-12 col-lg-4 col-xl-3"> |
532 | <div i18n class="inner-form-title">TWITTER</div> | 532 | <div i18n class="inner-form-title">TWITTER</div> |
533 | <div i18n class="inner-form-description"> | 533 | <div i18n class="inner-form-description"> |
534 | Provide the Twitter account representing your instance to improve link previews. | 534 | Provide the Twitter account representing your instance to improve link previews. |
@@ -536,7 +536,7 @@ | |||
536 | </div> | 536 | </div> |
537 | </div> | 537 | </div> |
538 | 538 | ||
539 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 539 | <div class="col-12 col-lg-8 col-xl-9"> |
540 | 540 | ||
541 | <ng-container formGroupName="services"> | 541 | <ng-container formGroupName="services"> |
542 | <ng-container formGroupName="twitter"> | 542 | <ng-container formGroupName="twitter"> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-configuration.service.ts b/client/src/app/+admin/config/edit-custom-config/edit-configuration.service.ts index 9b55cb43c..96f5b830e 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-configuration.service.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-configuration.service.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Injectable } from '@angular/core' | 1 | import { Injectable } from '@angular/core' |
2 | import { FormGroup } from '@angular/forms' | 2 | import { FormGroup } from '@angular/forms' |
3 | import { prepareIcu } from '@app/helpers' | ||
3 | 4 | ||
4 | export type ResolutionOption = { | 5 | export type ResolutionOption = { |
5 | id: string | 6 | id: string |
@@ -86,9 +87,10 @@ export class EditConfigurationService { | |||
86 | return { | 87 | return { |
87 | value, | 88 | value, |
88 | atMost: noneOnAuto, // auto switches everything to a least estimation since ffmpeg will take as many threads as possible | 89 | atMost: noneOnAuto, // auto switches everything to a least estimation since ffmpeg will take as many threads as possible |
89 | unit: value > 1 | 90 | unit: prepareIcu($localize`{value, plural, =1 {thread} other {threads}}`)( |
90 | ? $localize`threads` | 91 | { value }, |
91 | : $localize`thread` | 92 | $localize`threads` |
93 | ) | ||
92 | } | 94 | } |
93 | } | 95 | } |
94 | } | 96 | } |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 8fef39b79..cc8e699f3 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <h1 class="sr-only" i18n>Configuration</h1> | 1 | <h1 class="visually-hidden" i18n>Configuration</h1> |
2 | 2 | ||
3 | <div class="alert alert-warning" *ngIf="!isUpdateAllowed()" i18n> | 3 | <div class="alert alert-warning" *ngIf="!isUpdateAllowed()" i18n> |
4 | Updating instance configuration from the web interface is disabled by the system administrator. | 4 | Updating instance configuration from the web interface is disabled by the system administrator. |
@@ -64,7 +64,7 @@ | |||
64 | 64 | ||
65 | <div [ngbNavOutlet]="nav"></div> | 65 | <div [ngbNavOutlet]="nav"></div> |
66 | 66 | ||
67 | <div class="form-row mt-4"> <!-- submit placement block --> | 67 | <div class="row mt-4"> <!-- submit placement block --> |
68 | <div class="col-md-7 col-xl-5"></div> | 68 | <div class="col-md-7 col-xl-5"></div> |
69 | <div class="col-md-5 col-xl-5"> | 69 | <div class="col-md-5 col-xl-5"> |
70 | 70 | ||
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 0458d257f..31dd9f54f 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 | |||
@@ -102,11 +102,6 @@ input[disabled] { | |||
102 | opacity: 0.5; | 102 | opacity: 0.5; |
103 | } | 103 | } |
104 | 104 | ||
105 | |||
106 | .form-group-right { | ||
107 | padding-top: 2px; | ||
108 | } | ||
109 | |||
110 | ngb-tabset:not(.previews) ::ng-deep { | 105 | ngb-tabset:not(.previews) ::ng-deep { |
111 | .nav-link { | 106 | .nav-link { |
112 | font-size: 105%; | 107 | font-size: 105%; |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html index 2286a5a1a..701c3c0c1 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | <ng-container formGroupName="instanceCustomHomepage"> | 3 | <ng-container formGroupName="instanceCustomHomepage"> |
4 | 4 | ||
5 | <div class="form-row mt-5"> <!-- homepage grid --> | 5 | <div class="row mt-5"> <!-- homepage grid --> |
6 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 6 | <div class="col-12 col-lg-4 col-xl-3"> |
7 | <div i18n class="inner-form-title">INSTANCE HOMEPAGE</div> | 7 | <div i18n class="inner-form-title">INSTANCE HOMEPAGE</div> |
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 10 | <div class="col-12 col-lg-8 col-xl-9"> |
11 | 11 | ||
12 | <div class="form-group"> | 12 | <div class="form-group"> |
13 | <label i18n for="instanceCustomHomepageContent">Homepage</label> | 13 | <label i18n for="instanceCustomHomepageContent">Homepage</label> |
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 d806616bd..1c567d962 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 | |||
@@ -2,13 +2,12 @@ | |||
2 | 2 | ||
3 | <ng-container formGroupName="instance"> | 3 | <ng-container formGroupName="instance"> |
4 | 4 | ||
5 | <div class="form-row mt-5"> <!-- instance grid --> | 5 | <div class="row mt-5"> <!-- instance grid --> |
6 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 6 | <div class="col-12 col-lg-4 col-xl-3"> |
7 | <div i18n class="inner-form-title">INSTANCE</div> | 7 | <div i18n class="inner-form-title">INSTANCE</div> |
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 10 | <div class="col-12 col-lg-8 col-xl-9"> |
11 | |||
12 | <div class="form-group"> | 11 | <div class="form-group"> |
13 | <label i18n for="instanceName">Name</label> | 12 | <label i18n for="instanceName">Name</label> |
14 | 13 | ||
@@ -77,16 +76,15 @@ | |||
77 | </div> | 76 | </div> |
78 | </div> | 77 | </div> |
79 | 78 | ||
80 | <div class="form-row mt-4"> <!-- moderation & nsfw grid --> | 79 | <div class="row mt-4"> <!-- moderation & nsfw grid --> |
81 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 80 | <div class="col-12 col-lg-4 col-xl-3"> |
82 | <div i18n class="inner-form-title">MODERATION & NSFW</div> | 81 | <div i18n class="inner-form-title">MODERATION & NSFW</div> |
83 | <div i18n class="inner-for-description"> | 82 | <div i18row="inner-for-description"> |
84 | Manage <a routerLink="/admin/users">users</a> to build a moderation team. | 83 | Manage <a routerLink="/admin/users">users</a> to build a moderation team. |
85 | </div> | 84 | </div> |
86 | </div> | 85 | </div> |
87 | 86 | ||
88 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 87 | <div class="col-12 col-lg-8 col-xl-9"> |
89 | |||
90 | <div class="form-group"> | 88 | <div class="form-group"> |
91 | <my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW"> | 89 | <my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW"> |
92 | <ng-template ptTemplate="label"> | 90 | <ng-template ptTemplate="label"> |
@@ -162,12 +160,12 @@ | |||
162 | </div> | 160 | </div> |
163 | </div> | 161 | </div> |
164 | 162 | ||
165 | <div class="form-row mt-4"> <!-- you and your instance grid --> | 163 | <div class="row mt-4"> <!-- you and your instance grid --> |
166 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 164 | <div class="col-12 col-lg-4 col-xl-3"> |
167 | <div i18n class="inner-form-title">YOU AND YOUR INSTANCE</div> | 165 | <div i18n class="inner-form-title">YOU AND YOUR INSTANCE</div> |
168 | </div> | 166 | </div> |
169 | 167 | ||
170 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 168 | <div class="col-12 col-lg-8 col-xl-9"> |
171 | 169 | ||
172 | <div class="form-group"> | 170 | <div class="form-group"> |
173 | <label i18n for="instanceAdministrator">Who is behind the instance?</label><my-help helpType="markdownText"></my-help> | 171 | <label i18n for="instanceAdministrator">Who is behind the instance?</label><my-help helpType="markdownText"></my-help> |
@@ -220,12 +218,12 @@ | |||
220 | </div> | 218 | </div> |
221 | </div> | 219 | </div> |
222 | 220 | ||
223 | <div class="form-row mt-4"> <!-- other information grid --> | 221 | <div class="row mt-4"> <!-- other information grid --> |
224 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 222 | <div class="col-12 col-lg-4 col-xl-3"> |
225 | <div i18n class="inner-form-title">OTHER INFORMATION</div> | 223 | <div i18n class="inner-form-title">OTHER INFORMATION</div> |
226 | </div> | 224 | </div> |
227 | 225 | ||
228 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 226 | <div class="col-12 col-lg-8 col-xl-9"> |
229 | 227 | ||
230 | <div class="form-group"> | 228 | <div class="form-group"> |
231 | <label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label> | 229 | <label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-live-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-live-configuration.component.html index 71d5d91f0..a970f3df3 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-live-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-live-configuration.component.html | |||
@@ -1,14 +1,14 @@ | |||
1 | <ng-container [formGroup]="form"> | 1 | <ng-container [formGroup]="form"> |
2 | 2 | ||
3 | <div class="form-row mt-5"> | 3 | <div class="row mt-5"> |
4 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 4 | <div class="col-12 col-lg-4 col-xl-3"> |
5 | <div i18n class="inner-form-title">LIVE</div> | 5 | <div i18n class="inner-form-title">LIVE</div> |
6 | <div i18n class="inner-form-description"> | 6 | <div i18n class="inner-form-description"> |
7 | Enable users of your instance to stream live. | 7 | Enable users of your instance to stream live. |
8 | </div> | 8 | </div> |
9 | </div> | 9 | </div> |
10 | 10 | ||
11 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 11 | <div class="col-12 col-lg-8 col-xl-9"> |
12 | 12 | ||
13 | <ng-container formGroupName="live"> | 13 | <ng-container formGroupName="live"> |
14 | 14 | ||
@@ -89,15 +89,15 @@ | |||
89 | </div> | 89 | </div> |
90 | </div> | 90 | </div> |
91 | 91 | ||
92 | <div class="form-row"> <!-- transcoding live streams grid --> | 92 | <div class="row"> <!-- transcoding live streams grid --> |
93 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 93 | <div class="col-12 col-lg-4 col-xl-3"> |
94 | <div i18n class="inner-form-title">TRANSCODING</div> | 94 | <div i18n class="inner-form-title">TRANSCODING</div> |
95 | <div i18n class="inner-form-description"> | 95 | <div i18n class="inner-form-description"> |
96 | Same as VOD transcoding, transcoding live streams so that they are in a streamable form that any device can play. Requires a beefy CPU, and then some. | 96 | Same as VOD transcoding, transcoding live streams so that they are in a streamable form that any device can play. Requires a beefy CPU, and then some. |
97 | </div> | 97 | </div> |
98 | </div> | 98 | </div> |
99 | 99 | ||
100 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 100 | <div class="col-12 col-lg-8 col-xl-9"> |
101 | 101 | ||
102 | <ng-container formGroupName="live"> | 102 | <ng-container formGroupName="live"> |
103 | <ng-container formGroupName="transcoding"> | 103 | <ng-container formGroupName="transcoding"> |
@@ -115,7 +115,7 @@ | |||
115 | <div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()"> | 115 | <div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()"> |
116 | <label i18n for="liveTranscodingThreads">Live resolutions to generate</label> | 116 | <label i18n for="liveTranscodingThreads">Live resolutions to generate</label> |
117 | 117 | ||
118 | <div class="ml-2 mt-2 d-flex flex-column"> | 118 | <div class="ms-2 mt-2 d-flex flex-column"> |
119 | <ng-container formGroupName="resolutions"> | 119 | <ng-container formGroupName="resolutions"> |
120 | 120 | ||
121 | <div class="form-group" *ngFor="let resolution of liveResolutions"> | 121 | <div class="form-group" *ngFor="let resolution of liveResolutions"> |
@@ -136,7 +136,7 @@ | |||
136 | <div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()"> | 136 | <div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()"> |
137 | <label i18n for="liveTranscodingThreads">Live transcoding threads</label> | 137 | <label i18n for="liveTranscodingThreads">Live transcoding threads</label> |
138 | 138 | ||
139 | <span class="muted ml-1"> | 139 | <span class="muted ms-1"> |
140 | <ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n> | 140 | <ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n> |
141 | will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with VOD transcoding | 141 | will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with VOD transcoding |
142 | </ng-container> | 142 | </ng-container> |
@@ -157,7 +157,7 @@ | |||
157 | 157 | ||
158 | <div class="form-group mt-4" [ngClass]="getDisabledLiveTranscodingClass()"> | 158 | <div class="form-group mt-4" [ngClass]="getDisabledLiveTranscodingClass()"> |
159 | <label i18n for="liveTranscodingProfile">Live transcoding profile</label> | 159 | <label i18n for="liveTranscodingProfile">Live transcoding profile</label> |
160 | <span class="muted ml-1" i18n>new live transcoding profiles can be added by PeerTube plugins</span> | 160 | <span class="muted ms-1" i18n>new live transcoding profiles can be added by PeerTube plugins</span> |
161 | 161 | ||
162 | <my-select-options | 162 | <my-select-options |
163 | id="liveTranscodingProfile" | 163 | id="liveTranscodingProfile" |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html index 5c0bea4a5..3d8ab094f 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html | |||
@@ -1,8 +1,8 @@ | |||
1 | <ng-container [formGroup]="form"> | 1 | <ng-container [formGroup]="form"> |
2 | 2 | ||
3 | <div class="form-row mt-4"> <!-- transcoding grid --> | 3 | <div class="row mt-4"> <!-- transcoding grid --> |
4 | <div class="form-group col-12 col-lg-4 col-xl-3"></div> | 4 | <div class="col-12 col-lg-4 col-xl-3"></div> |
5 | <div class="form-group form-group-right col-12 col-lg-8"> | 5 | <div class="col-12 col-lg-8"> |
6 | 6 | ||
7 | <div class="callout callout-info"> | 7 | <div class="callout callout-info"> |
8 | <span i18n> | 8 | <span i18n> |
@@ -21,8 +21,8 @@ | |||
21 | </div> | 21 | </div> |
22 | </div> | 22 | </div> |
23 | 23 | ||
24 | <div class="form-row mt-2"> <!-- transcoding grid --> | 24 | <div class="row mt-4"> <!-- transcoding grid --> |
25 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 25 | <div class="col-12 col-lg-4 col-xl-3"> |
26 | <div i18n class="inner-form-title">TRANSCODING</div> | 26 | <div i18n class="inner-form-title">TRANSCODING</div> |
27 | <div i18n class="inner-form-description"> | 27 | <div i18n class="inner-form-description"> |
28 | Process uploaded videos so that they are in a streamable form that any device can play. Though costly in | 28 | Process uploaded videos so that they are in a streamable form that any device can play. Though costly in |
@@ -30,11 +30,11 @@ | |||
30 | </div> | 30 | </div> |
31 | </div> | 31 | </div> |
32 | 32 | ||
33 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 33 | <div class="col-12 col-lg-8 col-xl-9"> |
34 | 34 | ||
35 | <ng-container formGroupName="transcoding"> | 35 | <ng-container formGroupName="transcoding"> |
36 | 36 | ||
37 | <div class="form-group mb-0 col-12 col-xl-11"> | 37 | <div class="col-12 col-xl-11"> |
38 | <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled" [recommended]="true"> | 38 | <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled" [recommended]="true"> |
39 | <ng-template ptTemplate="label"> | 39 | <ng-template ptTemplate="label"> |
40 | <ng-container i18n>Transcoding enabled</ng-container> | 40 | <ng-container i18n>Transcoding enabled</ng-container> |
@@ -115,7 +115,7 @@ | |||
115 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> | 115 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> |
116 | <label i18n>Resolutions to generate per enabled format</label> | 116 | <label i18n>Resolutions to generate per enabled format</label> |
117 | 117 | ||
118 | <div class="ml-2 mt-2 d-flex flex-column"> | 118 | <div class="ms-2 mt-2 d-flex flex-column"> |
119 | <ng-container formGroupName="resolutions"> | 119 | <ng-container formGroupName="resolutions"> |
120 | <div class="form-group" *ngFor="let resolution of resolutions"> | 120 | <div class="form-group" *ngFor="let resolution of resolutions"> |
121 | <my-peertube-checkbox | 121 | <my-peertube-checkbox |
@@ -142,7 +142,7 @@ | |||
142 | 142 | ||
143 | <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()"> | 143 | <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()"> |
144 | <label i18n for="transcodingThreads">Transcoding threads</label> | 144 | <label i18n for="transcodingThreads">Transcoding threads</label> |
145 | <span class="muted ml-1"> | 145 | <span class="muted ms-1"> |
146 | <ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n> | 146 | <ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n> |
147 | will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with live transcoding | 147 | will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with live transcoding |
148 | </ng-container> | 148 | </ng-container> |
@@ -162,9 +162,9 @@ | |||
162 | <div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div> | 162 | <div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div> |
163 | </div> | 163 | </div> |
164 | 164 | ||
165 | <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()"> | 165 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> |
166 | <label i18n for="transcodingConcurrency">Transcoding jobs concurrency</label> | 166 | <label i18n for="transcodingConcurrency">Transcoding jobs concurrency</label> |
167 | <span class="muted ml-1" i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart</span> | 167 | <span class="muted ms-1" i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart</span> |
168 | 168 | ||
169 | <div class="number-with-unit"> | 169 | <div class="number-with-unit"> |
170 | <input type="number" name="transcodingConcurrency" formControlName="concurrency" /> | 170 | <input type="number" name="transcodingConcurrency" formControlName="concurrency" /> |
@@ -174,9 +174,9 @@ | |||
174 | <div *ngIf="formErrors.transcoding.concurrency" class="form-error">{{ formErrors.transcoding.concurrency }}</div> | 174 | <div *ngIf="formErrors.transcoding.concurrency" class="form-error">{{ formErrors.transcoding.concurrency }}</div> |
175 | </div> | 175 | </div> |
176 | 176 | ||
177 | <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()"> | 177 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> |
178 | <label i18n for="transcodingProfile">Transcoding profile</label> | 178 | <label i18n for="transcodingProfile">Transcoding profile</label> |
179 | <span class="muted ml-1" i18n>new transcoding profiles can be added by PeerTube plugins</span> | 179 | <span class="muted ms-1" i18n>new transcoding profiles can be added by PeerTube plugins</span> |
180 | 180 | ||
181 | <my-select-options | 181 | <my-select-options |
182 | id="transcodingProfile" | 182 | id="transcodingProfile" |
@@ -193,15 +193,15 @@ | |||
193 | </div> | 193 | </div> |
194 | </div> | 194 | </div> |
195 | 195 | ||
196 | <div class="form-row mt-2"> <!-- video studio grid --> | 196 | <div class="row mt-2"> <!-- video studio grid --> |
197 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 197 | <div class="col-12 col-lg-4 col-xl-3"> |
198 | <div i18n class="inner-form-title">VIDEO STUDIO</div> | 198 | <div i18n class="inner-form-title">VIDEO STUDIO</div> |
199 | <div i18n class="inner-form-description"> | 199 | <div i18n class="inner-form-description"> |
200 | Allows your users to edit their video (cut, add intro/outro, add a watermark etc) | 200 | Allows your users to edit their video (cut, add intro/outro, add a watermark etc) |
201 | </div> | 201 | </div> |
202 | </div> | 202 | </div> |
203 | 203 | ||
204 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | 204 | <div class="col-12 col-lg-8 col-xl-9"> |
205 | 205 | ||
206 | <ng-container formGroupName="videoStudio"> | 206 | <ng-container formGroupName="videoStudio"> |
207 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> | 207 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> |
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 1df7bb164..38def2fbb 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 | |||
@@ -12,7 +12,7 @@ | |||
12 | > | 12 | > |
13 | <ng-template pTemplate="caption"> | 13 | <ng-template pTemplate="caption"> |
14 | <div class="caption"> | 14 | <div class="caption"> |
15 | <div class="ml-auto"> | 15 | <div class="ms-auto"> |
16 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 16 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
17 | </div> | 17 | </div> |
18 | </div> | 18 | </div> |
@@ -46,10 +46,10 @@ | |||
46 | </td> | 46 | </td> |
47 | 47 | ||
48 | <td *ngIf="follow.state === 'accepted'"> | 48 | <td *ngIf="follow.state === 'accepted'"> |
49 | <span class="badge badge-green" i18n>Accepted</span> | 49 | <span class="pt-badge badge-green" i18n>Accepted</span> |
50 | </td> | 50 | </td> |
51 | <td *ngIf="follow.state === 'pending'"> | 51 | <td *ngIf="follow.state === 'pending'"> |
52 | <span class="badge badge-yellow" i18n>Pending</span> | 52 | <span class="pt-badge badge-yellow" i18n>Pending</span> |
53 | </td> | 53 | </td> |
54 | 54 | ||
55 | <td>{{ follow.score }}</td> | 55 | <td>{{ follow.score }}</td> |
diff --git a/client/src/app/+admin/follows/following-list/follow-modal.component.ts b/client/src/app/+admin/follows/following-list/follow-modal.component.ts index c40b36e10..bac7b2b01 100644 --- a/client/src/app/+admin/follows/following-list/follow-modal.component.ts +++ b/client/src/app/+admin/follows/following-list/follow-modal.component.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { prepareIcu } from '@app/helpers' | ||
3 | import { splitAndGetNotEmpty, UNIQUE_HOSTS_OR_HANDLE_VALIDATOR } from '@app/shared/form-validators/host-validators' | 4 | import { splitAndGetNotEmpty, UNIQUE_HOSTS_OR_HANDLE_VALIDATOR } from '@app/shared/form-validators/host-validators' |
4 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' |
5 | import { InstanceFollowService } from '@app/shared/shared-instance' | 6 | import { InstanceFollowService } from '@app/shared/shared-instance' |
@@ -60,7 +61,13 @@ export class FollowModalComponent extends FormReactive implements OnInit { | |||
60 | this.followService.follow(hostsOrHandles) | 61 | this.followService.follow(hostsOrHandles) |
61 | .subscribe({ | 62 | .subscribe({ |
62 | next: () => { | 63 | next: () => { |
63 | this.notifier.success($localize`Follow request(s) sent!`) | 64 | this.notifier.success( |
65 | prepareIcu($localize`{count, plural, =1 {Follow request} other {Follow requests}} sent!`)( | ||
66 | { count: hostsOrHandles.length }, | ||
67 | $localize`Follow request(s) sent!` | ||
68 | ) | ||
69 | ) | ||
70 | |||
64 | this.newFollow.emit() | 71 | this.newFollow.emit() |
65 | }, | 72 | }, |
66 | 73 | ||
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 767e92d18..207ca81a4 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 | |||
@@ -19,7 +19,7 @@ | |||
19 | </a> | 19 | </a> |
20 | </div> | 20 | </div> |
21 | 21 | ||
22 | <div class="ml-auto"> | 22 | <div class="ms-auto"> |
23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
24 | </div> | 24 | </div> |
25 | </div> | 25 | </div> |
@@ -48,10 +48,10 @@ | |||
48 | </td> | 48 | </td> |
49 | 49 | ||
50 | <td *ngIf="follow.state === 'accepted'"> | 50 | <td *ngIf="follow.state === 'accepted'"> |
51 | <span class="badge badge-green" i18n>Accepted</span> | 51 | <span class="pt-badge badge-green" i18n>Accepted</span> |
52 | </td> | 52 | </td> |
53 | <td *ngIf="follow.state === 'pending'"> | 53 | <td *ngIf="follow.state === 'pending'"> |
54 | <span class="badge badge-yellow" i18n>Pending</span> | 54 | <span class="pt-badge badge-yellow" i18n>Pending</span> |
55 | </td> | 55 | </td> |
56 | 56 | ||
57 | <td>{{ follow.createdAt | date: 'short' }}</td> | 57 | <td>{{ follow.createdAt | date: 'short' }}</td> |
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 3634951c9..b302014b6 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 | |||
@@ -13,7 +13,7 @@ | |||
13 | > | 13 | > |
14 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
15 | <div class="caption"> | 15 | <div class="caption"> |
16 | <div class="ml-auto"> | 16 | <div class="ms-auto"> |
17 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 17 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
18 | </div> | 18 | </div> |
19 | </div> | 19 | </div> |
@@ -53,11 +53,11 @@ | |||
53 | </td> | 53 | </td> |
54 | 54 | ||
55 | <td> | 55 | <td> |
56 | <span *ngIf="videoBlock.video.nsfw" class="badge badge-red" i18n>NSFW</span> | 56 | <span *ngIf="videoBlock.video.nsfw" class="pt-badge badge-red" i18n>NSFW</span> |
57 | </td> | 57 | </td> |
58 | 58 | ||
59 | <td> | 59 | <td> |
60 | <span *ngIf="videoBlock.unfederated" class="badge badge-blue" i18n>Unfederated</span> | 60 | <span *ngIf="videoBlock.unfederated" class="pt-badge badge-blue" i18n>Unfederated</span> |
61 | </td> | 61 | </td> |
62 | 62 | ||
63 | <td> | 63 | <td> |
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.html b/client/src/app/+admin/overview/comments/video-comment-list.component.html index 27a5d82ff..6fdefbfe2 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.html +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.html | |||
@@ -25,7 +25,7 @@ | |||
25 | </my-action-dropdown> | 25 | </my-action-dropdown> |
26 | </div> | 26 | </div> |
27 | 27 | ||
28 | <div class="ml-auto right-form"> | 28 | <div class="ms-auto right-form"> |
29 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 29 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
30 | 30 | ||
31 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> | 31 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> |
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.ts b/client/src/app/+admin/overview/comments/video-comment-list.component.ts index f3f43a900..f1b27d846 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.ts +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.ts | |||
@@ -7,6 +7,7 @@ import { DropdownAction } from '@app/shared/shared-main' | |||
7 | import { BulkService } from '@app/shared/shared-moderation' | 7 | import { BulkService } from '@app/shared/shared-moderation' |
8 | import { VideoCommentAdmin, VideoCommentService } from '@app/shared/shared-video-comment' | 8 | import { VideoCommentAdmin, VideoCommentService } from '@app/shared/shared-video-comment' |
9 | import { FeedFormat, UserRight } from '@shared/models' | 9 | import { FeedFormat, UserRight } from '@shared/models' |
10 | import { prepareIcu } from '@app/helpers' | ||
10 | 11 | ||
11 | @Component({ | 12 | @Component({ |
12 | selector: 'my-video-comment-list', | 13 | selector: 'my-video-comment-list', |
@@ -145,7 +146,13 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
145 | this.videoCommentService.deleteVideoComments(commentArgs) | 146 | this.videoCommentService.deleteVideoComments(commentArgs) |
146 | .subscribe({ | 147 | .subscribe({ |
147 | next: () => { | 148 | next: () => { |
148 | this.notifier.success($localize`${commentArgs.length} comments deleted.`) | 149 | this.notifier.success( |
150 | prepareIcu($localize`{count, plural, =1 {1 comment} other {{count} comments}} deleted.`)( | ||
151 | { count: commentArgs.length }, | ||
152 | $localize`${commentArgs.length} comment(s) deleted.` | ||
153 | ) | ||
154 | ) | ||
155 | |||
149 | this.reloadData() | 156 | this.reloadData() |
150 | }, | 157 | }, |
151 | 158 | ||
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.component.html b/client/src/app/+admin/overview/users/user-edit/user-edit.component.html index 772ebf272..7e0eaf280 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.component.html +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.component.html | |||
@@ -57,7 +57,7 @@ | |||
57 | </div> | 57 | </div> |
58 | </ng-template> | 58 | </ng-template> |
59 | 59 | ||
60 | <div class="form-row" *ngIf="!isInBigView()"> <!-- hidden on large screens, as it is then displayed on the right side of the form --> | 60 | <div class="row d-xxl-none"> <!-- hidden on large screens, as it is then displayed on the right side of the form --> |
61 | <div class="col-12 col-xl-3"></div> | 61 | <div class="col-12 col-xl-3"></div> |
62 | 62 | ||
63 | <div class="col-12 col-xl-9"> | 63 | <div class="col-12 col-xl-9"> |
@@ -67,8 +67,8 @@ | |||
67 | 67 | ||
68 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | 68 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> |
69 | 69 | ||
70 | <div class="form-row mt-4"> <!-- user grid --> | 70 | <div class="row mt-4"> <!-- user grid --> |
71 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 71 | <div class="col-12 col-lg-4 col-xl-3"> |
72 | <div class="anchor" id="user"></div> <!-- user anchor --> | 72 | <div class="anchor" id="user"></div> <!-- user anchor --> |
73 | <div *ngIf="isCreation()" class="account-title" i18n>NEW USER</div> | 73 | <div *ngIf="isCreation()" class="account-title" i18n>NEW USER</div> |
74 | <div *ngIf="!isCreation() && user" class="account-title"> | 74 | <div *ngIf="!isCreation() && user" class="account-title"> |
@@ -76,150 +76,150 @@ | |||
76 | </div> | 76 | </div> |
77 | </div> | 77 | </div> |
78 | 78 | ||
79 | <div class="form-group col-12 col-lg-8 col-xl-9" [ngClass]="{ 'form-row': isInBigView() }"> | 79 | <div class="col-12 col-lg-8 col-xl-9"> |
80 | 80 | <div class="row"> | |
81 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form" [ngClass]="{ 'col-5': isInBigView() }"> | 81 | <form class="col" role="form" (ngSubmit)="formValidated()" [formGroup]="form"> |
82 | <div class="form-group" *ngIf="isCreation()"> | 82 | <div class="form-group" *ngIf="isCreation()"> |
83 | <label i18n for="username">Username</label> | 83 | <label i18n for="username">Username</label> |
84 | <input | 84 | <input |
85 | type="text" id="username" i18n-placeholder placeholder="john" class="form-control" | 85 | type="text" id="username" i18n-placeholder placeholder="john" class="form-control" |
86 | formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }" | 86 | formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }" |
87 | > | 87 | > |
88 | <div *ngIf="formErrors.username" class="form-error"> | 88 | <div *ngIf="formErrors.username" class="form-error"> |
89 | {{ formErrors.username }} | 89 | {{ formErrors.username }} |
90 | </div> | ||
90 | </div> | 91 | </div> |
91 | </div> | ||
92 | 92 | ||
93 | <div class="form-group" *ngIf="isCreation()"> | 93 | <div class="form-group" *ngIf="isCreation()"> |
94 | <label i18n for="channelName">Channel name</label> | 94 | <label i18n for="channelName">Channel name</label> |
95 | <input | 95 | <input |
96 | type="text" id="channelName" i18n-placeholder placeholder="john_channel" class="form-control" | 96 | type="text" id="channelName" i18n-placeholder placeholder="john_channel" class="form-control" |
97 | formControlName="channelName" [ngClass]="{ 'input-error': formErrors['channelName'] }" | 97 | formControlName="channelName" [ngClass]="{ 'input-error': formErrors['channelName'] }" |
98 | > | 98 | > |
99 | <div *ngIf="formErrors.channelName" class="form-error"> | 99 | <div *ngIf="formErrors.channelName" class="form-error"> |
100 | {{ formErrors.channelName }} | 100 | {{ formErrors.channelName }} |
101 | </div> | ||
101 | </div> | 102 | </div> |
102 | </div> | ||
103 | 103 | ||
104 | <div class="form-group"> | 104 | <div class="form-group"> |
105 | <label i18n for="email">Email</label> | 105 | <label i18n for="email">Email</label> |
106 | <input | 106 | <input |
107 | type="text" id="email" i18n-placeholder placeholder="mail@example.com" class="form-control" | 107 | type="text" id="email" i18n-placeholder placeholder="mail@example.com" class="form-control" |
108 | formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }" | 108 | formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }" |
109 | autocomplete="off" [readonly]="user && user.pluginAuth !== null" | 109 | autocomplete="off" [readonly]="user && user.pluginAuth !== null" |
110 | > | 110 | > |
111 | <div *ngIf="formErrors.email" class="form-error"> | 111 | <div *ngIf="formErrors.email" class="form-error"> |
112 | {{ formErrors.email }} | 112 | {{ formErrors.email }} |
113 | </div> | ||
113 | </div> | 114 | </div> |
114 | </div> | ||
115 | 115 | ||
116 | <div class="form-group" *ngIf="isCreation()"> | 116 | <div class="form-group" *ngIf="isCreation()"> |
117 | <label i18n for="password">Password</label> | 117 | <label i18n for="password">Password</label> |
118 | <my-help *ngIf="isPasswordOptional()"> | 118 | <my-help *ngIf="isPasswordOptional()"> |
119 | <ng-template ptTemplate="customHtml"> | 119 | <ng-template ptTemplate="customHtml"> |
120 | <ng-container i18n> | 120 | <ng-container i18n> |
121 | If you leave the password empty, an email will be sent to the user. | 121 | If you leave the password empty, an email will be sent to the user. |
122 | </ng-container> | 122 | </ng-container> |
123 | </ng-template> | 123 | </ng-template> |
124 | </my-help> | 124 | </my-help> |
125 | 125 | ||
126 | <my-input-toggle-hidden | 126 | <my-input-toggle-hidden |
127 | formControlName="password" inputId="password" [ngClass]="{ 'input-error': formErrors['password'] }" autocomplete="new-password" | 127 | formControlName="password" inputId="password" [ngClass]="{ 'input-error': formErrors['password'] }" autocomplete="new-password" |
128 | ></my-input-toggle-hidden> | 128 | ></my-input-toggle-hidden> |
129 | 129 | ||
130 | <div *ngIf="formErrors.password" class="form-error"> | 130 | <div *ngIf="formErrors.password" class="form-error"> |
131 | {{ formErrors.password }} | 131 | {{ formErrors.password }} |
132 | </div> | ||
132 | </div> | 133 | </div> |
133 | </div> | ||
134 | 134 | ||
135 | <div class="form-group"> | 135 | <div class="form-group"> |
136 | <label i18n for="role">Role</label> | 136 | <label i18n for="role">Role</label> |
137 | <div class="peertube-select-container"> | 137 | <div class="peertube-select-container"> |
138 | <select id="role" formControlName="role" class="form-control"> | 138 | <select id="role" formControlName="role" class="form-control"> |
139 | <option *ngFor="let role of roles" [value]="role.value"> | 139 | <option *ngFor="let role of roles" [value]="role.value"> |
140 | {{ role.label }} | 140 | {{ role.label }} |
141 | </option> | 141 | </option> |
142 | </select> | 142 | </select> |
143 | </div> | ||
144 | |||
145 | <div *ngIf="formErrors.role" class="form-error"> | ||
146 | {{ formErrors.role }} | ||
147 | </div> | ||
143 | </div> | 148 | </div> |
144 | 149 | ||
145 | <div *ngIf="formErrors.role" class="form-error"> | 150 | <div class="form-group"> |
146 | {{ formErrors.role }} | 151 | <label i18n for="videoQuota">Video quota</label> |
152 | |||
153 | <my-select-custom-value | ||
154 | id="videoQuota" | ||
155 | [items]="videoQuotaOptions" | ||
156 | formControlName="videoQuota" | ||
157 | i18n-inputSuffix inputSuffix="bytes" inputType="number" | ||
158 | [clearable]="false" | ||
159 | ></my-select-custom-value> | ||
160 | |||
161 | <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> | ||
162 | Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br /> | ||
163 | At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}. | ||
164 | </div> | ||
165 | |||
166 | <div *ngIf="formErrors.videoQuota" class="form-error"> | ||
167 | {{ formErrors.videoQuota }} | ||
168 | </div> | ||
147 | </div> | 169 | </div> |
148 | </div> | ||
149 | 170 | ||
150 | <div class="form-group"> | 171 | <div class="form-group"> |
151 | <label i18n for="videoQuota">Video quota</label> | 172 | <label i18n for="videoQuotaDaily">Daily video quota</label> |
152 | |||
153 | <my-select-custom-value | ||
154 | id="videoQuota" | ||
155 | [items]="videoQuotaOptions" | ||
156 | formControlName="videoQuota" | ||
157 | i18n-inputSuffix inputSuffix="bytes" inputType="number" | ||
158 | [clearable]="false" | ||
159 | ></my-select-custom-value> | ||
160 | |||
161 | <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> | ||
162 | Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br /> | ||
163 | At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}. | ||
164 | </div> | ||
165 | 173 | ||
166 | <div *ngIf="formErrors.videoQuota" class="form-error"> | 174 | <my-select-custom-value |
167 | {{ formErrors.videoQuota }} | 175 | id="videoQuotaDaily" |
168 | </div> | 176 | [items]="videoQuotaDailyOptions" |
169 | </div> | 177 | formControlName="videoQuotaDaily" |
178 | i18n-inputSuffix inputSuffix="bytes" inputType="number" | ||
179 | [clearable]="false" | ||
180 | ></my-select-custom-value> | ||
170 | 181 | ||
171 | <div class="form-group"> | 182 | <div *ngIf="formErrors.videoQuotaDaily" class="form-error"> |
172 | <label i18n for="videoQuotaDaily">Daily video quota</label> | 183 | {{ formErrors.videoQuotaDaily }} |
173 | 184 | </div> | |
174 | <my-select-custom-value | ||
175 | id="videoQuotaDaily" | ||
176 | [items]="videoQuotaDailyOptions" | ||
177 | formControlName="videoQuotaDaily" | ||
178 | i18n-inputSuffix inputSuffix="bytes" inputType="number" | ||
179 | [clearable]="false" | ||
180 | ></my-select-custom-value> | ||
181 | |||
182 | <div *ngIf="formErrors.videoQuotaDaily" class="form-error"> | ||
183 | {{ formErrors.videoQuotaDaily }} | ||
184 | </div> | 185 | </div> |
185 | </div> | ||
186 | 186 | ||
187 | <div class="form-group" *ngIf="!isCreation() && getAuthPlugins().length !== 0"> | 187 | <div class="form-group" *ngIf="!isCreation() && getAuthPlugins().length !== 0"> |
188 | <label i18n for="pluginAuth">Auth plugin</label> | 188 | <label i18n for="pluginAuth">Auth plugin</label> |
189 | 189 | ||
190 | <div class="peertube-select-container"> | 190 | <div class="peertube-select-container"> |
191 | <select id="pluginAuth" formControlName="pluginAuth" class="form-control"> | 191 | <select id="pluginAuth" formControlName="pluginAuth" class="form-control"> |
192 | <option [value]="null" i18n>None (local authentication)</option> | 192 | <option [value]="null" i18n>None (local authentication)</option> |
193 | <option *ngFor="let authPlugin of getAuthPlugins()" [value]="authPlugin">{{ authPlugin }}</option> | 193 | <option *ngFor="let authPlugin of getAuthPlugins()" [value]="authPlugin">{{ authPlugin }}</option> |
194 | </select> | 194 | </select> |
195 | </div> | ||
195 | </div> | 196 | </div> |
196 | </div> | ||
197 | 197 | ||
198 | <div class="form-group"> | 198 | <div class="form-group"> |
199 | <my-peertube-checkbox | 199 | <my-peertube-checkbox |
200 | inputName="byPassAutoBlock" formControlName="byPassAutoBlock" | 200 | inputName="byPassAutoBlock" formControlName="byPassAutoBlock" |
201 | i18n-labelText labelText="Doesn't need review before a video goes public" | 201 | i18n-labelText labelText="Doesn't need review before a video goes public" |
202 | ></my-peertube-checkbox> | 202 | ></my-peertube-checkbox> |
203 | </div> | 203 | </div> |
204 | 204 | ||
205 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> | 205 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> |
206 | </form> | 206 | </form> |
207 | 207 | ||
208 | <div *ngIf="isInBigView()" class="col-7"> | 208 | <div class="d-none d-xxl-block col-7"> |
209 | <ng-template *ngTemplateOutlet="dashboard"></ng-template> | 209 | <ng-template *ngTemplateOutlet="dashboard"></ng-template> |
210 | </div> | ||
210 | </div> | 211 | </div> |
211 | |||
212 | </div> | 212 | </div> |
213 | </div> | 213 | </div> |
214 | 214 | ||
215 | 215 | ||
216 | <div *ngIf="!isCreation() && user && user.pluginAuth === null" class="form-row mt-4"> <!-- danger zone grid --> | 216 | <div *ngIf="!isCreation() && user && user.pluginAuth === null" class="row mt-4"> <!-- danger zone grid --> |
217 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 217 | <div class="col-12 col-lg-4 col-xl-3"> |
218 | <div class="anchor" id="danger"></div> <!-- danger zone anchor --> | 218 | <div class="anchor" id="danger"></div> <!-- danger zone anchor --> |
219 | <div i18n class="account-title account-title-danger">DANGER ZONE</div> | 219 | <div i18n class="account-title account-title-danger">DANGER ZONE</div> |
220 | </div> | 220 | </div> |
221 | 221 | ||
222 | <div class="form-group col-12 col-lg-8 col-xl-9" [ngClass]="{ 'form-row': isInBigView() }"> | 222 | <div class="col-12 col-lg-8 col-xl-9"> |
223 | 223 | ||
224 | <div class="danger-zone"> | 224 | <div class="danger-zone"> |
225 | <div class="form-group reset-password-email"> | 225 | <div class="form-group reset-password-email"> |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.ts b/client/src/app/+admin/overview/users/user-edit/user-edit.ts index 069b62a53..395d07423 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.ts | |||
@@ -46,10 +46,6 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
46 | .concat(this.serverConfig.plugin.registeredExternalAuths.map(p => p.npmName)) | 46 | .concat(this.serverConfig.plugin.registeredExternalAuths.map(p => p.npmName)) |
47 | } | 47 | } |
48 | 48 | ||
49 | isInBigView () { | ||
50 | return this.screenService.getWindowInnerWidth() > 1600 | ||
51 | } | ||
52 | |||
53 | buildRoles () { | 49 | buildRoles () { |
54 | const authUser = this.auth.getUser() | 50 | const authUser = this.auth.getUser() |
55 | 51 | ||
diff --git a/client/src/app/+admin/overview/users/user-edit/user-password.component.html b/client/src/app/+admin/overview/users/user-edit/user-password.component.html index 1238d1839..35f36e465 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-password.component.html +++ b/client/src/app/+admin/overview/users/user-edit/user-password.component.html | |||
@@ -1,20 +1,16 @@ | |||
1 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> | 1 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> |
2 | <div class="form-group"> | 2 | <div class="input-group"> |
3 | <input id="password" [attr.type]="showPassword ? 'text' : 'password'" class="form-control" | ||
4 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" | ||
5 | > | ||
6 | <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button"> | ||
7 | <ng-container *ngIf="!showPassword" i18n>Show</ng-container> | ||
8 | <ng-container *ngIf="!!showPassword" i18n>Hide</ng-container> | ||
9 | </button> | ||
10 | </div> | ||
3 | 11 | ||
4 | <div class="input-group"> | 12 | <div *ngIf="formErrors.password" class="form-error"> |
5 | <input id="password" [attr.type]="showPassword ? 'text' : 'password'" class="form-control" | 13 | {{ formErrors.password }} |
6 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" | ||
7 | > | ||
8 | <div class="input-group-append"> | ||
9 | <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button"> | ||
10 | <ng-container *ngIf="!showPassword" i18n>Show</ng-container> | ||
11 | <ng-container *ngIf="!!showPassword" i18n>Hide</ng-container> | ||
12 | </button> | ||
13 | </div> | ||
14 | </div> | ||
15 | <div *ngIf="formErrors.password" class="form-error"> | ||
16 | {{ formErrors.password }} | ||
17 | </div> | ||
18 | </div> | 14 | </div> |
19 | 15 | ||
20 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> | 16 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-password.component.scss b/client/src/app/+admin/overview/users/user-edit/user-password.component.scss index acb680682..54f782086 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-password.component.scss +++ b/client/src/app/+admin/overview/users/user-edit/user-password.component.scss | |||
@@ -1,13 +1,9 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | 3 | ||
4 | input:not([type=submit]):not([type=checkbox]) { | 4 | input[type=text], |
5 | input[type=password] { | ||
5 | @include peertube-input-text(340px); | 6 | @include peertube-input-text(340px); |
6 | |||
7 | display: block; | ||
8 | border-top-right-radius: 0; | ||
9 | border-bottom-right-radius: 0; | ||
10 | border-right: 0; | ||
11 | } | 7 | } |
12 | 8 | ||
13 | input[type=submit] { | 9 | input[type=submit] { |
@@ -17,7 +13,3 @@ input[type=submit] { | |||
17 | 13 | ||
18 | margin-top: 10px; | 14 | margin-top: 10px; |
19 | } | 15 | } |
20 | |||
21 | .input-group-append { | ||
22 | height: 30px; | ||
23 | } | ||
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index 30d10e3cf..f6915ae9a 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | <p-table | 6 | <p-table |
7 | [value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 7 | [value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
8 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedUsers" | 8 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedUsers" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" | 9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" |
@@ -26,7 +26,7 @@ | |||
26 | </a> | 26 | </a> |
27 | </div> | 27 | </div> |
28 | 28 | ||
29 | <div class="ml-auto"> | 29 | <div class="ms-auto"> |
30 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 30 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
31 | </div> | 31 | </div> |
32 | 32 | ||
@@ -90,7 +90,7 @@ | |||
90 | </my-user-moderation-dropdown> | 90 | </my-user-moderation-dropdown> |
91 | </td> | 91 | </td> |
92 | 92 | ||
93 | <td *ngIf="isSelected('username')"> | 93 | <td *ngIf="isSelected('username')" class="cell-username"> |
94 | <a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/a/' + user.username ]"> | 94 | <a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/a/' + user.username ]"> |
95 | <div class="chip two-lines"> | 95 | <div class="chip two-lines"> |
96 | <my-actor-avatar [account]="user?.account" size="32"></my-actor-avatar> | 96 | <my-actor-avatar [account]="user?.account" size="32"></my-actor-avatar> |
@@ -101,13 +101,13 @@ | |||
101 | </div> | 101 | </div> |
102 | </a> | 102 | </a> |
103 | 103 | ||
104 | <div *ngIf="user.accountMutedStatus.mutedByInstance" class="badges-username badge badge-red" i18n>Muted</div> | 104 | <div *ngIf="user.accountMutedStatus.mutedByInstance" class="pt-badge badge-red" i18n>Muted</div> |
105 | <div *ngIf="user.blocked" class="badges-username badge badge-red" i18n>Banned</div> | 105 | <div *ngIf="user.blocked" class="pt-badge badge-red" i18n>Banned</div> |
106 | </td> | 106 | </td> |
107 | 107 | ||
108 | <td *ngIf="isSelected('role')"> | 108 | <td *ngIf="isSelected('role')"> |
109 | <span *ngIf="user.blocked" class="badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> | 109 | <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> |
110 | <span *ngIf="!user.blocked" class="badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> | 110 | <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> |
111 | </td> | 111 | </td> |
112 | 112 | ||
113 | <td *ngIf="isSelected('email')" [title]="user.email"> | 113 | <td *ngIf="isSelected('email')" [title]="user.email"> |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.scss b/client/src/app/+admin/overview/users/user-list/user-list.component.scss index 8160703f0..6449f5064 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.scss | |||
@@ -1,5 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | @use '~bootstrap/scss/functions' as *; | ||
3 | 4 | ||
4 | .add-button { | 5 | .add-button { |
5 | @include create-button; | 6 | @include create-button; |
@@ -23,8 +24,8 @@ tr.banned > td { | |||
23 | font-weight: $font-semibold; | 24 | font-weight: $font-semibold; |
24 | } | 25 | } |
25 | 26 | ||
26 | .badges-username { | 27 | .cell-username .pt-badge { |
27 | margin-left: 15px; | 28 | @include margin-left(15px); |
28 | } | 29 | } |
29 | 30 | ||
30 | .user-table-primary-text .glyphicon { | 31 | .user-table-primary-text .glyphicon { |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.ts b/client/src/app/+admin/overview/users/user-list/user-list.component.ts index d22e1355e..f7dc22256 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.ts | |||
@@ -1,8 +1,8 @@ | |||
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, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 4 | import { AuthService, ConfirmService, LocalStorageService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
5 | import { getAPIHost } from '@app/helpers' | 5 | import { prepareIcu, getAPIHost } from '@app/helpers' |
6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
7 | import { Actor, DropdownAction } from '@app/shared/shared-main' | 7 | import { Actor, DropdownAction } from '@app/shared/shared-main' |
8 | import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' | 8 | import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' |
@@ -22,6 +22,8 @@ type UserForList = User & { | |||
22 | styleUrls: [ './user-list.component.scss' ] | 22 | styleUrls: [ './user-list.component.scss' ] |
23 | }) | 23 | }) |
24 | export class UserListComponent extends RestTable implements OnInit { | 24 | export class UserListComponent extends RestTable implements OnInit { |
25 | private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns' | ||
26 | |||
25 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent | 27 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent |
26 | 28 | ||
27 | users: (User & { accountMutedStatus: AccountMutedStatus })[] = [] | 29 | users: (User & { accountMutedStatus: AccountMutedStatus })[] = [] |
@@ -56,7 +58,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
56 | 58 | ||
57 | requiresEmailVerification = false | 59 | requiresEmailVerification = false |
58 | 60 | ||
59 | private _selectedColumns: string[] | 61 | private _selectedColumns: string[] = [] |
60 | 62 | ||
61 | constructor ( | 63 | constructor ( |
62 | protected route: ActivatedRoute, | 64 | protected route: ActivatedRoute, |
@@ -66,7 +68,8 @@ export class UserListComponent extends RestTable implements OnInit { | |||
66 | private serverService: ServerService, | 68 | private serverService: ServerService, |
67 | private auth: AuthService, | 69 | private auth: AuthService, |
68 | private blocklist: BlocklistService, | 70 | private blocklist: BlocklistService, |
69 | private userAdminService: UserAdminService | 71 | private userAdminService: UserAdminService, |
72 | private peertubeLocalStorage: LocalStorageService | ||
70 | ) { | 73 | ) { |
71 | super() | 74 | super() |
72 | } | 75 | } |
@@ -76,11 +79,13 @@ export class UserListComponent extends RestTable implements OnInit { | |||
76 | } | 79 | } |
77 | 80 | ||
78 | get selectedColumns () { | 81 | get selectedColumns () { |
79 | return this._selectedColumns | 82 | return this._selectedColumns || [] |
80 | } | 83 | } |
81 | 84 | ||
82 | set selectedColumns (val: string[]) { | 85 | set selectedColumns (val: string[]) { |
83 | this._selectedColumns = val | 86 | this._selectedColumns = val |
87 | |||
88 | this.saveSelectedColumns() | ||
84 | } | 89 | } |
85 | 90 | ||
86 | ngOnInit () { | 91 | ngOnInit () { |
@@ -126,14 +131,35 @@ export class UserListComponent extends RestTable implements OnInit { | |||
126 | { id: 'role', label: $localize`Role` }, | 131 | { id: 'role', label: $localize`Role` }, |
127 | { id: 'email', label: $localize`Email` }, | 132 | { id: 'email', label: $localize`Email` }, |
128 | { id: 'quota', label: $localize`Video quota` }, | 133 | { id: 'quota', label: $localize`Video quota` }, |
129 | { id: 'createdAt', label: $localize`Created` } | 134 | { id: 'createdAt', label: $localize`Created` }, |
135 | { id: 'lastLoginDate', label: $localize`Last login` }, | ||
136 | |||
137 | { id: 'quotaDaily', label: $localize`Daily quota` }, | ||
138 | { id: 'pluginAuth', label: $localize`Auth plugin` } | ||
130 | ] | 139 | ] |
131 | 140 | ||
132 | this.selectedColumns = this.columns.map(c => c.id) | 141 | this.loadSelectedColumns() |
142 | } | ||
143 | |||
144 | loadSelectedColumns () { | ||
145 | const result = this.peertubeLocalStorage.getItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY) | ||
133 | 146 | ||
134 | this.columns.push({ id: 'quotaDaily', label: $localize`Daily quota` }) | 147 | if (result) { |
135 | this.columns.push({ id: 'pluginAuth', label: $localize`Auth plugin` }) | 148 | try { |
136 | this.columns.push({ id: 'lastLoginDate', label: $localize`Last login` }) | 149 | this.selectedColumns = JSON.parse(result) |
150 | return | ||
151 | } catch (err) { | ||
152 | console.error('Cannot load selected columns.', err) | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Default behaviour | ||
157 | this.selectedColumns = [ 'username', 'role', 'email', 'quota', 'createdAt', 'lastLoginDate' ] | ||
158 | return | ||
159 | } | ||
160 | |||
161 | saveSelectedColumns () { | ||
162 | this.peertubeLocalStorage.setItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY, JSON.stringify(this.selectedColumns)) | ||
137 | } | 163 | } |
138 | 164 | ||
139 | getIdentifier () { | 165 | getIdentifier () { |
@@ -183,13 +209,25 @@ export class UserListComponent extends RestTable implements OnInit { | |||
183 | } | 209 | } |
184 | 210 | ||
185 | async unbanUsers (users: User[]) { | 211 | async unbanUsers (users: User[]) { |
186 | const res = await this.confirmService.confirm($localize`Do you really want to unban ${users.length} users?`, $localize`Unban`) | 212 | const res = await this.confirmService.confirm( |
213 | prepareIcu($localize`Do you really want to unban {count, plural, =1 {1 user} other {{count} users}}?`)( | ||
214 | { count: users.length }, | ||
215 | $localize`Do you really want to unban ${users.length} users?` | ||
216 | ), | ||
217 | $localize`Unban` | ||
218 | ) | ||
219 | |||
187 | if (res === false) return | 220 | if (res === false) return |
188 | 221 | ||
189 | this.userAdminService.unbanUsers(users) | 222 | this.userAdminService.unbanUsers(users) |
190 | .subscribe({ | 223 | .subscribe({ |
191 | next: () => { | 224 | next: () => { |
192 | this.notifier.success($localize`${users.length} users unbanned.`) | 225 | this.notifier.success( |
226 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} unbanned.`)( | ||
227 | { count: users.length }, | ||
228 | $localize`${users.length} users unbanned.` | ||
229 | ) | ||
230 | ) | ||
193 | this.reloadData() | 231 | this.reloadData() |
194 | }, | 232 | }, |
195 | 233 | ||
@@ -198,21 +236,28 @@ export class UserListComponent extends RestTable implements OnInit { | |||
198 | } | 236 | } |
199 | 237 | ||
200 | async removeUsers (users: User[]) { | 238 | async removeUsers (users: User[]) { |
201 | for (const user of users) { | 239 | if (users.some(u => u.username === 'root')) { |
202 | if (user.username === 'root') { | 240 | this.notifier.error($localize`You cannot delete root.`) |
203 | this.notifier.error($localize`You cannot delete root.`) | 241 | return |
204 | return | ||
205 | } | ||
206 | } | 242 | } |
207 | 243 | ||
208 | const message = $localize`If you remove these users, you will not be able to create others with the same username!` | 244 | const message = $localize`<p>You can't create users or channels with a username that already used by a deleted user/channel.</p>` + |
245 | $localize`It means the following usernames will be permanently deleted and cannot be recovered:` + | ||
246 | '<ul>' + users.map(u => '<li>' + u.username + '</li>').join('') + '</ul>' | ||
247 | |||
209 | const res = await this.confirmService.confirm(message, $localize`Delete`) | 248 | const res = await this.confirmService.confirm(message, $localize`Delete`) |
210 | if (res === false) return | 249 | if (res === false) return |
211 | 250 | ||
212 | this.userAdminService.removeUser(users) | 251 | this.userAdminService.removeUser(users) |
213 | .subscribe({ | 252 | .subscribe({ |
214 | next: () => { | 253 | next: () => { |
215 | this.notifier.success($localize`${users.length} users deleted.`) | 254 | this.notifier.success( |
255 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} deleted.`)( | ||
256 | { count: users.length }, | ||
257 | $localize`${users.length} users deleted.` | ||
258 | ) | ||
259 | ) | ||
260 | |||
216 | this.reloadData() | 261 | this.reloadData() |
217 | }, | 262 | }, |
218 | 263 | ||
@@ -224,7 +269,13 @@ export class UserListComponent extends RestTable implements OnInit { | |||
224 | this.userAdminService.updateUsers(users, { emailVerified: true }) | 269 | this.userAdminService.updateUsers(users, { emailVerified: true }) |
225 | .subscribe({ | 270 | .subscribe({ |
226 | next: () => { | 271 | next: () => { |
227 | this.notifier.success($localize`${users.length} users email set as verified.`) | 272 | this.notifier.success( |
273 | prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} email set as verified.`)( | ||
274 | { count: users.length }, | ||
275 | $localize`${users.length} users email set as verified.` | ||
276 | ) | ||
277 | ) | ||
278 | |||
228 | this.reloadData() | 279 | this.reloadData() |
229 | }, | 280 | }, |
230 | 281 | ||
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index 75d9be5f1..2f36c27b7 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | </my-action-dropdown> | 21 | </my-action-dropdown> |
22 | </div> | 22 | </div> |
23 | 23 | ||
24 | <div class="ml-auto right-form"> | 24 | <div class="ms-auto right-form"> |
25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
26 | 26 | ||
27 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> | 27 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> |
@@ -67,25 +67,25 @@ | |||
67 | </td> | 67 | </td> |
68 | 68 | ||
69 | <td> | 69 | <td> |
70 | <span class="badge badge-blue" *ngIf="video.isLocal">Local</span> | 70 | <span class="pt-badge badge-blue" *ngIf="video.isLocal">Local</span> |
71 | <span class="badge badge-purple" *ngIf="!video.isLocal">Remote</span> | 71 | <span class="pt-badge badge-purple" *ngIf="!video.isLocal">Remote</span> |
72 | 72 | ||
73 | <span [ngClass]="getPrivacyBadgeClass(video)" class="badge">{{ video.privacy.label }}</span> | 73 | <span [ngClass]="getPrivacyBadgeClass(video)" class="pt-badge">{{ video.privacy.label }}</span> |
74 | 74 | ||
75 | <span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span> | 75 | <span *ngIf="video.nsfw" class="pt-badge badge-red" i18n>NSFW</span> |
76 | 76 | ||
77 | <span *ngIf="isUnpublished(video)" class="badge badge-yellow" i18n>{{ video.state.label }}</span> | 77 | <span *ngIf="isUnpublished(video)" class="pt-badge badge-yellow" i18n>{{ video.state.label }}</span> |
78 | 78 | ||
79 | <span *ngIf="isAccountBlocked(video)" class="badge badge-red" i18n>Account muted</span> | 79 | <span *ngIf="isAccountBlocked(video)" class="pt-badge badge-red" i18n>Account muted</span> |
80 | <span *ngIf="isServerBlocked(video)" class="badge badge-red" i18n>Server muted</span> | 80 | <span *ngIf="isServerBlocked(video)" class="pt-badge badge-red" i18n>Server muted</span> |
81 | 81 | ||
82 | <span *ngIf="isVideoBlocked(video)" class="badge badge-red" i18n>Blocked</span> | 82 | <span *ngIf="isVideoBlocked(video)" class="pt-badge badge-red" i18n>Blocked</span> |
83 | </td> | 83 | </td> |
84 | 84 | ||
85 | <td> | 85 | <td> |
86 | <span *ngIf="isHLS(video)" class="badge badge-blue">HLS</span> | 86 | <span *ngIf="isHLS(video)" class="pt-badge badge-blue">HLS</span> |
87 | <span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent ({{ video.files.length }})</span> | 87 | <span *ngIf="isWebTorrent(video)" class="pt-badge badge-blue">WebTorrent ({{ video.files.length }})</span> |
88 | <span *ngIf="video.isLive" class="badge badge-blue">Live</span> | 88 | <span *ngIf="video.isLive" class="pt-badge badge-blue">Live</span> |
89 | 89 | ||
90 | <span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span> | 90 | <span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span> |
91 | </td> | 91 | </td> |
@@ -121,7 +121,7 @@ | |||
121 | </ul> | 121 | </ul> |
122 | </div> | 122 | </div> |
123 | 123 | ||
124 | <my-embed class="ml-auto" [video]="video"></my-embed> | 124 | <my-embed class="ms-auto" [video]="video"></my-embed> |
125 | </div> | 125 | </div> |
126 | </td> | 126 | </td> |
127 | </tr> | 127 | </tr> |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.scss b/client/src/app/+admin/overview/videos/video-list.component.scss index cb47b6548..dcd41a1b4 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.scss +++ b/client/src/app/+admin/overview/videos/video-list.component.scss | |||
@@ -7,10 +7,8 @@ my-embed { | |||
7 | width: 50%; | 7 | width: 50%; |
8 | } | 8 | } |
9 | 9 | ||
10 | .badge { | 10 | .pt-badge { |
11 | @include peertube-badge; | 11 | @include margin-right(5px); |
12 | |||
13 | margin-right: 5px; | ||
14 | } | 12 | } |
15 | 13 | ||
16 | .video-info > div { | 14 | .video-info > div { |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index 82ff372aa..67e52d100 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -3,6 +3,7 @@ import { finalize } 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, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' | 5 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' |
6 | import { prepareIcu } from '@app/helpers' | ||
6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 7 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
7 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 8 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
8 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' | 9 | import { VideoBlockComponent, VideoBlockService } from '@app/shared/shared-moderation' |
@@ -196,14 +197,24 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
196 | } | 197 | } |
197 | 198 | ||
198 | private async removeVideos (videos: Video[]) { | 199 | private async removeVideos (videos: Video[]) { |
199 | const message = $localize`Are you sure you want to delete these ${videos.length} videos?` | 200 | const message = prepareIcu($localize`Are you sure you want to delete {count, plural, =1 {this video} other {these {count} videos}}?`)( |
201 | { count: videos.length }, | ||
202 | $localize`Are you sure you want to delete these ${videos.length} videos?` | ||
203 | ) | ||
204 | |||
200 | const res = await this.confirmService.confirm(message, $localize`Delete`) | 205 | const res = await this.confirmService.confirm(message, $localize`Delete`) |
201 | if (res === false) return | 206 | if (res === false) return |
202 | 207 | ||
203 | this.videoService.removeVideo(videos.map(v => v.id)) | 208 | this.videoService.removeVideo(videos.map(v => v.id)) |
204 | .subscribe({ | 209 | .subscribe({ |
205 | next: () => { | 210 | next: () => { |
206 | this.notifier.success($localize`Deleted ${videos.length} videos.`) | 211 | this.notifier.success( |
212 | prepareIcu($localize`Deleted {count, plural, =1 {1 video} other {{count} videos}}.`)( | ||
213 | { count: videos.length }, | ||
214 | $localize`Deleted ${videos.length} videos.` | ||
215 | ) | ||
216 | ) | ||
217 | |||
207 | this.reloadData() | 218 | this.reloadData() |
208 | }, | 219 | }, |
209 | 220 | ||
@@ -215,7 +226,13 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
215 | this.videoBlockService.unblockVideo(videos.map(v => v.id)) | 226 | this.videoBlockService.unblockVideo(videos.map(v => v.id)) |
216 | .subscribe({ | 227 | .subscribe({ |
217 | next: () => { | 228 | next: () => { |
218 | this.notifier.success($localize`Unblocked ${videos.length} videos.`) | 229 | this.notifier.success( |
230 | prepareIcu($localize`Unblocked {count, plural, =1 {1 video} other {{count} videos}}.`)( | ||
231 | { count: videos.length }, | ||
232 | $localize`Unblocked ${videos.length} videos.` | ||
233 | ) | ||
234 | ) | ||
235 | |||
219 | this.reloadData() | 236 | this.reloadData() |
220 | }, | 237 | }, |
221 | 238 | ||
@@ -224,9 +241,21 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
224 | } | 241 | } |
225 | 242 | ||
226 | private async removeVideoFiles (videos: Video[], type: 'hls' | 'webtorrent') { | 243 | private async removeVideoFiles (videos: Video[], type: 'hls' | 'webtorrent') { |
227 | const message = type === 'hls' | 244 | let message: string |
228 | ? $localize`Are you sure you want to delete ${videos.length} HLS streaming playlists?` | 245 | |
229 | : $localize`Are you sure you want to delete WebTorrent files of ${videos.length} videos?` | 246 | if (type === 'hls') { |
247 | // eslint-disable-next-line max-len | ||
248 | message = prepareIcu($localize`Are you sure you want to delete {count, plural, =1 {1 HLS streaming playlist} other {{count} HLS streaming playlists}}?`)( | ||
249 | { count: videos.length }, | ||
250 | $localize`Are you sure you want to delete ${videos.length} HLS streaming playlists?` | ||
251 | ) | ||
252 | } else { | ||
253 | // eslint-disable-next-line max-len | ||
254 | message = prepareIcu($localize`Are you sure you want to delete WebTorrent files of {count, plural, =1 {1 video} other {{count} videos}}?`)( | ||
255 | { count: videos.length }, | ||
256 | $localize`Are you sure you want to delete WebTorrent files of ${videos.length} videos?` | ||
257 | ) | ||
258 | } | ||
230 | 259 | ||
231 | const res = await this.confirmService.confirm(message, $localize`Delete`) | 260 | const res = await this.confirmService.confirm(message, $localize`Delete`) |
232 | if (res === false) return | 261 | if (res === false) return |
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 33575ef52..23dde86b4 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 | |||
@@ -32,9 +32,9 @@ | |||
32 | <ng-container *ngFor="let plugin of plugins" > | 32 | <ng-container *ngFor="let plugin of plugins" > |
33 | <my-plugin-card [plugin]="plugin" [version]="plugin.latestVersion" [pluginType]="pluginType"> | 33 | <my-plugin-card [plugin]="plugin" [version]="plugin.latestVersion" [pluginType]="pluginType"> |
34 | <div ngProjectAs="badges"> | 34 | <div ngProjectAs="badges"> |
35 | <span i18n *ngIf="plugin.installed" class="badge badge-success">Installed</span> | 35 | <span i18n *ngIf="plugin.installed" class="pt-badge badge-success">Installed</span> |
36 | 36 | ||
37 | <span *ngIf="plugin.official" class="badge badge-primary" i18n i18n-title title="This plugin is developed by Framasoft"> | 37 | <span *ngIf="plugin.official" class="pt-badge badge-primary" i18n i18n-title title="This plugin is developed by Framasoft"> |
38 | Official | 38 | Official |
39 | </span> | 39 | </span> |
40 | </div> | 40 | </div> |
diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss index 10401e9df..55baa038f 100644 --- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss | |||
@@ -22,11 +22,10 @@ | |||
22 | } | 22 | } |
23 | } | 23 | } |
24 | 24 | ||
25 | .badge { | 25 | .pt-badge { |
26 | @include margin-left(15px); | 26 | @include margin-left(15px); |
27 | 27 | ||
28 | font-size: 13px; | 28 | font-size: 13px; |
29 | font-weight: $font-semibold; | ||
30 | } | 29 | } |
31 | 30 | ||
32 | .alert { | 31 | .alert { |
diff --git a/client/src/app/+admin/system/jobs/jobs.component.html b/client/src/app/+admin/system/jobs/jobs.component.html index 301591786..8068fe626 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.html +++ b/client/src/app/+admin/system/jobs/jobs.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | <span i18n="Selector for the list displaying jobs, filtering by their state">any</span> | 21 | <span i18n="Selector for the list displaying jobs, filtering by their state">any</span> |
22 | </ng-option> | 22 | </ng-option> |
23 | <ng-option *ngFor="let state of jobStates" [value]="state"> | 23 | <ng-option *ngFor="let state of jobStates" [value]="state"> |
24 | <span class="badge" [ngClass]="getJobStateClass(state)">{{ state }}</span> | 24 | <span class="pt-badge" [ngClass]="getJobStateClass(state)">{{ state }}</span> |
25 | </ng-option> | 25 | </ng-option> |
26 | </ng-select> | 26 | </ng-select> |
27 | </div> | 27 | </div> |
@@ -62,7 +62,7 @@ | |||
62 | <td class="job-priority c-hand" [pRowToggler]="job">{{ job.priority }}</td> | 62 | <td class="job-priority c-hand" [pRowToggler]="job">{{ job.priority }}</td> |
63 | 63 | ||
64 | <td class="job-state c-hand" [pRowToggler]="job" *ngIf="jobState === 'all'"> | 64 | <td class="job-state c-hand" [pRowToggler]="job" *ngIf="jobState === 'all'"> |
65 | <span class="badge" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span> | 65 | <span class="pt-badge" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span> |
66 | </td> | 66 | </td> |
67 | 67 | ||
68 | <td *ngIf="hasGlobalProgress()" class="job-progress c-hand" [pRowToggler]="job"> | 68 | <td *ngIf="hasGlobalProgress()" class="job-progress c-hand" [pRowToggler]="job"> |
@@ -107,8 +107,8 @@ | |||
107 | </ng-container> | 107 | </ng-container> |
108 | 108 | ||
109 | <ng-container *ngIf="jobState !== 'all'"> | 109 | <ng-container *ngIf="jobState !== 'all'"> |
110 | <ng-container *ngIf="jobType === 'all'" i18n>No <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container> | 110 | <ng-container *ngIf="jobType === 'all'" i18n>No <span class="pt-badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container> |
111 | <ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container> | 111 | <ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="pt-badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container> |
112 | </ng-container> | 112 | </ng-container> |
113 | </div> | 113 | </div> |
114 | </div> | 114 | </div> |
diff --git a/client/src/app/+admin/system/jobs/jobs.component.scss b/client/src/app/+admin/system/jobs/jobs.component.scss index a9e5e8d4b..eadaf7904 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.scss +++ b/client/src/app/+admin/system/jobs/jobs.component.scss | |||
@@ -55,7 +55,3 @@ pre { | |||
55 | .job-error { | 55 | .job-error { |
56 | color: #ff0000; | 56 | color: #ff0000; |
57 | } | 57 | } |
58 | |||
59 | .select-filter-block .badge { | ||
60 | @include peertube-badge; | ||
61 | } | ||
diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html index 3751747a9..61b89082c 100644 --- a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html | |||
@@ -3,42 +3,41 @@ | |||
3 | <div class="margin-content"> | 3 | <div class="margin-content"> |
4 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> | 4 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> |
5 | 5 | ||
6 | <div class="form-row"> <!-- channel grid --> | 6 | <div class="row"> <!-- channel grid --> |
7 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 7 | <div class="col-12 col-lg-4 col-xl-3"> |
8 | <div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div> | 8 | <div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div> |
9 | <div *ngIf="!isCreation() && videoChannel" class="video-channel-title" i18n>CHANNEL</div> | 9 | <div *ngIf="!isCreation() && videoChannel" class="video-channel-title" i18n>CHANNEL</div> |
10 | </div> | 10 | </div> |
11 | 11 | ||
12 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 12 | <div class="col-12 col-lg-8 col-xl-9"> |
13 | <h6 i18n>Banner image of the channel</h6> | 13 | <h6 i18n>Banner image of the channel</h6> |
14 | 14 | ||
15 | <my-actor-banner-edit | 15 | <my-actor-banner-edit |
16 | *ngIf="videoChannel" [previewImage]="isCreation()" | 16 | *ngIf="videoChannel" [previewImage]="isCreation()" |
17 | [actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()" | 17 | [actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()" |
18 | ></my-actor-banner-edit> | 18 | ></my-actor-banner-edit> |
19 | 19 | ||
20 | <my-actor-avatar-edit | 20 | <my-actor-avatar-edit |
21 | *ngIf="videoChannel" [previewImage]="isCreation()" | 21 | *ngIf="videoChannel" [previewImage]="isCreation()" |
22 | [actor]="videoChannel" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()" | 22 | [actor]="videoChannel" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()" |
23 | [displayUsername]="!isCreation()" [displaySubscribers]="!isCreation()" | 23 | [displayUsername]="!isCreation()" [displaySubscribers]="!isCreation()" |
24 | ></my-actor-avatar-edit> | 24 | ></my-actor-avatar-edit> |
25 | 25 | ||
26 | <div class="form-group" *ngIf="isCreation()"> | 26 | <div class="form-group" *ngIf="isCreation()"> |
27 | <label i18n for="name">Name</label> | 27 | <label i18n for="name">Name</label> |
28 | |||
28 | <div class="input-group"> | 29 | <div class="input-group"> |
29 | <input | 30 | <input |
30 | type="text" id="name" i18n-placeholder placeholder="Example: my_channel" | 31 | type="text" id="name" i18n-placeholder placeholder="Example: my_channel" |
31 | formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control" | 32 | formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control" |
32 | > | 33 | > |
33 | <div class="input-group-append"> | 34 | <div class="input-group-text">@{{ instanceHost }}</div> |
34 | <span class="input-group-text">@{{ instanceHost }}</span> | ||
35 | </div> | ||
36 | </div> | 35 | </div> |
37 | <div *ngIf="formErrors['name']" class="form-error"> | 36 | <div *ngIf="formErrors['name']" class="form-error"> |
38 | {{ formErrors['name'] }} | 37 | {{ formErrors['name'] }} |
39 | </div> | 38 | </div> |
40 | </div> | 39 | </div> |
41 | 40 | ||
42 | <div class="form-group"> | 41 | <div class="form-group"> |
43 | <label i18n for="display-name">Display name</label> | 42 | <label i18n for="display-name">Display name</label> |
44 | <input | 43 | <input |
@@ -49,7 +48,7 @@ | |||
49 | {{ formErrors['display-name'] }} | 48 | {{ formErrors['display-name'] }} |
50 | </div> | 49 | </div> |
51 | </div> | 50 | </div> |
52 | 51 | ||
53 | <div class="form-group"> | 52 | <div class="form-group"> |
54 | <label i18n for="description">Description</label> | 53 | <label i18n for="description">Description</label> |
55 | <textarea | 54 | <textarea |
@@ -60,7 +59,7 @@ | |||
60 | {{ formErrors.description }} | 59 | {{ formErrors.description }} |
61 | </div> | 60 | </div> |
62 | </div> | 61 | </div> |
63 | 62 | ||
64 | <div class="form-group"> | 63 | <div class="form-group"> |
65 | <label for="support">Support</label> | 64 | <label for="support">Support</label> |
66 | <my-help | 65 | <my-help |
@@ -75,22 +74,22 @@ | |||
75 | {{ formErrors.support }} | 74 | {{ formErrors.support }} |
76 | </div> | 75 | </div> |
77 | </div> | 76 | </div> |
78 | 77 | ||
79 | <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()"> | 78 | <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()"> |
80 | <my-peertube-checkbox | 79 | <my-peertube-checkbox |
81 | inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate" | 80 | inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate" |
82 | i18n-labelText labelText="Overwrite support field of all videos of this channel" | 81 | i18n-labelText labelText="Overwrite support field of all videos of this channel" |
83 | ></my-peertube-checkbox> | 82 | ></my-peertube-checkbox> |
84 | </div> | 83 | </div> |
85 | 84 | ||
86 | </div> | 85 | </div> |
87 | </div> | 86 | </div> |
88 | 87 | ||
89 | <div class="form-row"> <!-- submit placement block --> | 88 | <div class="row"> <!-- submit placement block --> |
90 | <div class="col-md-7 col-xl-5"></div> | 89 | <div class="col-md-7 col-xl-5"></div> |
91 | <div class="col-md-5 col-xl-5 d-inline-flex"> | 90 | <div class="col-md-5 col-xl-5 d-inline-flex"> |
92 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> | 91 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> |
93 | </div> | 92 | </div> |
94 | </div> | 93 | </div> |
95 | </form> | 94 | </form> |
96 | </div> \ No newline at end of file | 95 | </div> |
diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss index d010d6277..2c720314a 100644 --- a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss | |||
@@ -24,31 +24,21 @@ my-actor-banner-edit { | |||
24 | max-width: 500px; | 24 | max-width: 500px; |
25 | } | 25 | } |
26 | 26 | ||
27 | .input-group { | 27 | input[type=text] { |
28 | @include peertube-input-group(fit-content); | 28 | @include peertube-input-text(340px); |
29 | } | ||
30 | |||
31 | .input-group-append { | ||
32 | height: 30px; | ||
33 | } | ||
34 | |||
35 | input { | ||
36 | &[type=text] { | ||
37 | @include peertube-input-text(340px); | ||
38 | 29 | ||
39 | display: block; | 30 | display: block; |
40 | 31 | ||
41 | &#name { | 32 | &#name { |
42 | width: auto; | 33 | width: auto; |
43 | flex-grow: 1; | 34 | flex-grow: 1; |
44 | } | ||
45 | } | 35 | } |
36 | } | ||
46 | 37 | ||
47 | &[type=submit] { | 38 | input[type=submit] { |
48 | @include peertube-button; | 39 | @include peertube-button; |
49 | @include orange-button; | 40 | @include orange-button; |
50 | @include margin-left(auto); | 41 | @include margin-left(auto); |
51 | } | ||
52 | } | 42 | } |
53 | 43 | ||
54 | textarea { | 44 | textarea { |
diff --git a/client/src/app/+my-account/my-account-applications/my-account-applications.component.html b/client/src/app/+my-account/my-account-applications/my-account-applications.component.html index 68d094a4f..8f3a55be5 100644 --- a/client/src/app/+my-account/my-account-applications/my-account-applications.component.html +++ b/client/src/app/+my-account/my-account-applications/my-account-applications.component.html | |||
@@ -3,8 +3,9 @@ | |||
3 | <ng-container i18n>Applications</ng-container> | 3 | <ng-container i18n>Applications</ng-container> |
4 | </h1> | 4 | </h1> |
5 | 5 | ||
6 | <div class="form-row"> <!-- built-in token grid --> | 6 | <div class="row"> <!-- built-in token grid --> |
7 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 7 | |
8 | <div class="group col-12 col-lg-4 col-xl-3"> | ||
8 | <h2 i18n class="applications-title">SUBSCRIPTION FEED</h2> | 9 | <h2 i18n class="applications-title">SUBSCRIPTION FEED</h2> |
9 | <div i18n class="applications-description"> | 10 | <div i18n class="applications-description"> |
10 | Use third-party feed aggregators to retrieve the list of videos from | 11 | Use third-party feed aggregators to retrieve the list of videos from |
@@ -12,7 +13,7 @@ | |||
12 | </div> | 13 | </div> |
13 | </div> | 14 | </div> |
14 | 15 | ||
15 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 16 | <div class="col-12 col-lg-8 col-xl-9"> |
16 | 17 | ||
17 | <div class="form-group"> | 18 | <div class="form-group"> |
18 | <label i18n for="feed-url">Feed URL</label> | 19 | <label i18n for="feed-url">Feed URL</label> |
@@ -29,7 +30,7 @@ | |||
29 | </div> | 30 | </div> |
30 | </div> | 31 | </div> |
31 | 32 | ||
32 | <div class="form-row mt-4"> <!-- submit placement block --> | 33 | <div class="row mt-4"> <!-- submit placement block --> |
33 | <div class="col-md-7 col-xl-5"></div> | 34 | <div class="col-md-7 col-xl-5"></div> |
34 | <div class="col-md-5 col-xl-5"> | 35 | <div class="col-md-5 col-xl-5"> |
35 | <input (click)="renewToken()" type="submit" i18n-value value="Renew token"> | 36 | <input (click)="renewToken()" type="submit" i18n-value value="Renew token"> |
diff --git a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html index f0e9f4010..b98cd1156 100644 --- a/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html +++ b/client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html | |||
@@ -1,11 +1,11 @@ | |||
1 | <h1 class="sr-only" i18n>Notifications</h1> | 1 | <h1 class="visually-hidden" i18n>Notifications</h1> |
2 | <div class="header"> | 2 | <div class="header"> |
3 | <a routerLink="/my-account/settings" fragment="notifications" i18n> | 3 | <a routerLink="/my-account/settings" fragment="notifications" i18n> |
4 | <my-global-icon iconName="cog" aria-hidden="true"></my-global-icon> | 4 | <my-global-icon iconName="cog" aria-hidden="true"></my-global-icon> |
5 | Notification preferences | 5 | Notification preferences |
6 | </a> | 6 | </a> |
7 | 7 | ||
8 | <div class="peertube-select-container peertube-select-button ml-2 mr-2"> | 8 | <div class="peertube-select-container peertube-select-button ms-2 me-2"> |
9 | <select [(ngModel)]="notificationSortType" (ngModelChange)="onChangeSortColumn()" class="form-control"> | 9 | <select [(ngModel)]="notificationSortType" (ngModelChange)="onChangeSortColumn()" class="form-control"> |
10 | <option value="undefined" disabled>Sort by</option> | 10 | <option value="undefined" disabled>Sort by</option> |
11 | <option value="createdAt" i18n>Newest first</option> | 11 | <option value="createdAt" i18n>Newest first</option> |
@@ -13,7 +13,7 @@ | |||
13 | </select> | 13 | </select> |
14 | </div> | 14 | </div> |
15 | 15 | ||
16 | <button class="btn ml-auto" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()"> | 16 | <button class="btn ms-auto" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()"> |
17 | <ng-container *ngIf="hasUnreadNotifications()"> | 17 | <ng-container *ngIf="hasUnreadNotifications()"> |
18 | <my-global-icon iconName="tick" aria-hidden="true"></my-global-icon> | 18 | <my-global-icon iconName="tick" aria-hidden="true"></my-global-icon> |
19 | 19 | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts index 7c13282fa..769ab647a 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts | |||
@@ -37,7 +37,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit { | |||
37 | myVideoPublished: $localize`Video published (after transcoding/scheduled update)`, | 37 | myVideoPublished: $localize`Video published (after transcoding/scheduled update)`, |
38 | myVideoImportFinished: $localize`Video import finished`, | 38 | myVideoImportFinished: $localize`Video import finished`, |
39 | newUserRegistration: $localize`A new user registered on your instance`, | 39 | newUserRegistration: $localize`A new user registered on your instance`, |
40 | newFollow: $localize`You or your channel(s) has a new follower`, | 40 | newFollow: $localize`You or one of your channels has a new follower`, |
41 | commentMention: $localize`Someone mentioned you in video comments`, | 41 | commentMention: $localize`Someone mentioned you in video comments`, |
42 | newInstanceFollower: $localize`Your instance has a new follower`, | 42 | newInstanceFollower: $localize`Your instance has a new follower`, |
43 | autoInstanceFollowing: $localize`Your instance automatically followed another instance`, | 43 | autoInstanceFollowing: $localize`Your instance automatically followed another instance`, |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.scss b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.scss index cbac81d01..78f7ef1d5 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.scss +++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.scss | |||
@@ -6,10 +6,6 @@ label { | |||
6 | font-size: 100%; | 6 | font-size: 100%; |
7 | } | 7 | } |
8 | 8 | ||
9 | .form-group:first-child { | ||
10 | margin-bottom: 15px; | ||
11 | } | ||
12 | |||
13 | input#username + .muted { | 9 | input#username + .muted { |
14 | margin-top: 5px; | 10 | margin-top: 5px; |
15 | } | 11 | } |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index 8ca197fd4..abcfe54a6 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html | |||
@@ -1,18 +1,19 @@ | |||
1 | <h1 class="sr-only" i18n>Settings</h1> | 1 | <h1 class="visually-hidden" i18n>Settings</h1> |
2 | <div class="form-row"> <!-- preview --> | ||
3 | <div class="form-group col-12 col-lg-4 col-xl-3"></div> | ||
4 | 2 | ||
5 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 3 | <div class="row"> <!-- preview --> |
4 | <div class="col-12 col-lg-4 col-xl-3"></div> | ||
5 | |||
6 | <div class="col-12 col-lg-8 col-xl-9"> | ||
6 | <my-actor-avatar-edit [actor]="user.account" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"></my-actor-avatar-edit> | 7 | <my-actor-avatar-edit [actor]="user.account" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"></my-actor-avatar-edit> |
7 | </div> | 8 | </div> |
8 | </div> | 9 | </div> |
9 | 10 | ||
10 | <div class="form-row"> <!-- profile settings grid --> | 11 | <div class="row mt-3"> <!-- profile settings grid --> |
11 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 12 | <div class="col-12 col-lg-4 col-xl-3"> |
12 | <h2 i18n class="account-title">PROFILE SETTINGS</h2> | 13 | <h2 i18n class="account-title">PROFILE SETTINGS</h2> |
13 | </div> | 14 | </div> |
14 | 15 | ||
15 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 16 | <div class="col-12 col-lg-8 col-xl-9"> |
16 | 17 | ||
17 | <my-user-quota [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-quota> | 18 | <my-user-quota [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-quota> |
18 | 19 | ||
@@ -20,64 +21,64 @@ | |||
20 | </div> | 21 | </div> |
21 | </div> | 22 | </div> |
22 | 23 | ||
23 | <div class="form-row mt-5"> <!-- interface grid --> | 24 | <div class="row mt-5"> <!-- interface grid --> |
24 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 25 | <div class="col-12 col-lg-4 col-xl-3"> |
25 | <h2 i18n class="account-title">INTERFACE</h2> | 26 | <h2 i18n class="account-title">INTERFACE</h2> |
26 | </div> | 27 | </div> |
27 | 28 | ||
28 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 29 | <div class="col-12 col-lg-8 col-xl-9"> |
29 | <my-user-interface-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-interface-settings> | 30 | <my-user-interface-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-interface-settings> |
30 | </div> | 31 | </div> |
31 | </div> | 32 | </div> |
32 | 33 | ||
33 | <div class="form-row mt-5"> <!-- video settings grid --> | 34 | <div class="row mt-5"> <!-- video settings grid --> |
34 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 35 | <div class="col-12 col-lg-4 col-xl-3"> |
35 | <div class="anchor" id="video-settings"></div> <!-- video settings anchor --> | 36 | <div class="anchor" id="video-settings"></div> <!-- video settings anchor --> |
36 | <h2 i18n class="account-title">VIDEO SETTINGS</h2> | 37 | <h2 i18n class="account-title">VIDEO SETTINGS</h2> |
37 | </div> | 38 | </div> |
38 | 39 | ||
39 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 40 | <div class="col-12 col-lg-8 col-xl-9"> |
40 | <my-user-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-video-settings> | 41 | <my-user-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-video-settings> |
41 | </div> | 42 | </div> |
42 | </div> | 43 | </div> |
43 | 44 | ||
44 | <div class="form-row mt-5"> <!-- notifications grid --> | 45 | <div class="row mt-5"> <!-- notifications grid --> |
45 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 46 | <div class="col-12 col-lg-4 col-xl-3"> |
46 | <div class="anchor" id="notifications"></div> <!-- notifications anchor --> | 47 | <div class="anchor" id="notifications"></div> <!-- notifications anchor --> |
47 | <h2 i18n class="account-title">NOTIFICATIONS</h2> | 48 | <h2 i18n class="account-title">NOTIFICATIONS</h2> |
48 | </div> | 49 | </div> |
49 | 50 | ||
50 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 51 | <div class="col-12 col-lg-8 col-xl-9"> |
51 | <my-account-notification-preferences [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-notification-preferences> | 52 | <my-account-notification-preferences [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-notification-preferences> |
52 | </div> | 53 | </div> |
53 | </div> | 54 | </div> |
54 | 55 | ||
55 | <div class="form-row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid --> | 56 | <div class="row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid --> |
56 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 57 | <div class="col-12 col-lg-4 col-xl-3"> |
57 | <h2 i18n class="account-title">PASSWORD</h2> | 58 | <h2 i18n class="account-title">PASSWORD</h2> |
58 | </div> | 59 | </div> |
59 | 60 | ||
60 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 61 | <div class="col-12 col-lg-8 col-xl-9"> |
61 | <my-account-change-password></my-account-change-password> | 62 | <my-account-change-password></my-account-change-password> |
62 | </div> | 63 | </div> |
63 | </div> | 64 | </div> |
64 | 65 | ||
65 | <div class="form-row mt-5"> <!-- email grid --> | 66 | <div class="row mt-5"> <!-- email grid --> |
66 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 67 | <div class="col-12 col-lg-4 col-xl-3"> |
67 | <h2 i18n class="account-title">EMAIL</h2> | 68 | <h2 i18n class="account-title">EMAIL</h2> |
68 | </div> | 69 | </div> |
69 | 70 | ||
70 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 71 | <div class="col-12 col-lg-8 col-xl-9"> |
71 | <my-account-change-email></my-account-change-email> | 72 | <my-account-change-email></my-account-change-email> |
72 | </div> | 73 | </div> |
73 | </div> | 74 | </div> |
74 | 75 | ||
75 | <div class="form-row mt-5"> <!-- danger zone grid --> | 76 | <div class="row mt-5"> <!-- danger zone grid --> |
76 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 77 | <div class="col-12 col-lg-4 col-xl-3"> |
77 | <h2 i18n class="account-title account-title-danger">DANGER ZONE</h2> | 78 | <h2 i18n class="account-title account-title-danger">DANGER ZONE</h2> |
78 | </div> | 79 | </div> |
79 | 80 | ||
80 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 81 | <div class="col-12 col-lg-8 col-xl-9"> |
81 | <my-account-danger-zone [user]="user"></my-account-danger-zone> | 82 | <my-account-danger-zone [user]="user"></my-account-danger-zone> |
82 | </div> | 83 | </div> |
83 | </div> | 84 | </div> |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss b/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss index 1c216d79d..8206f4dd8 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.scss | |||
@@ -1,5 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | @use '~bootstrap/scss/functions' as *; | ||
3 | 4 | ||
4 | .account-title { | 5 | .account-title { |
5 | @include settings-big-title; | 6 | @include settings-big-title; |
@@ -9,6 +10,6 @@ | |||
9 | } | 10 | } |
10 | } | 11 | } |
11 | 12 | ||
12 | .form-group { | 13 | .row > div { |
13 | max-width: 500px; | 14 | max-width: 500px; |
14 | } | 15 | } |
diff --git a/client/src/app/+my-account/my-account.component.html b/client/src/app/+my-account/my-account.component.html index b465d0156..1c44c8472 100644 --- a/client/src/app/+my-account/my-account.component.html +++ b/client/src/app/+my-account/my-account.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="row"> | 1 | <div class="root"> |
2 | <my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown> | 2 | <my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown> |
3 | 3 | ||
4 | <div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }"> | 4 | <div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }"> |
diff --git a/client/src/app/+my-account/my-account.component.scss b/client/src/app/+my-account/my-account.component.scss index 1ec25315a..6275b7ac2 100644 --- a/client/src/app/+my-account/my-account.component.scss +++ b/client/src/app/+my-account/my-account.component.scss | |||
@@ -1,7 +1,7 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | 3 | ||
4 | .row { | 4 | .root { |
5 | @include sub-menu-h1; | 5 | @include sub-menu-h1; |
6 | 6 | ||
7 | flex-direction: column; | 7 | flex-direction: column; |
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 89327b065..aa51764be 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,7 +1,7 @@ | |||
1 | <h1> | 1 | <h1> |
2 | <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> | 2 | <my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> |
3 | <ng-container i18n>My channels</ng-container> | 3 | <ng-container i18n>My channels</ng-container> |
4 | <span class="badge badge-secondary">{{ totalItems }}</span> | 4 | <span *ngIf="totalItems" class="pt-badge badge-secondary">{{ totalItems }}</span> |
5 | </h1> | 5 | </h1> |
6 | 6 | ||
7 | <my-channels-setup-message [hideLink]="true"></my-channels-setup-message> | 7 | <my-channels-setup-message [hideLink]="true"></my-channels-setup-message> |
@@ -31,11 +31,13 @@ | |||
31 | i18n class="video-channel-followers" | 31 | i18n class="video-channel-followers" |
32 | [routerLink]="[ '/my-library', 'followers' ]" [queryParams]="{ search: 'channel:' + videoChannel.name }" | 32 | [routerLink]="[ '/my-library', 'followers' ]" [queryParams]="{ search: 'channel:' + videoChannel.name }" |
33 | > | 33 | > |
34 | {videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}} | 34 | {videoChannel.followersCount, plural, =0 {No subscribers} =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}} |
35 | </a> | 35 | </a> |
36 | 36 | ||
37 | <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div> | 37 | <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div> |
38 | 38 | ||
39 | <div i18n class="video-channel-views">{videoChannel.totalViews, plural, =0 {No views} =1 {1 view} other {{{ videoChannel.totalViews }} views}}</div> | ||
40 | |||
39 | <div class="video-channel-buttons"> | 41 | <div class="video-channel-buttons"> |
40 | <my-edit-button label [routerLink]="[ '/manage/update', videoChannel.nameWithHost ]"></my-edit-button> | 42 | <my-edit-button label [routerLink]="[ '/manage/update', videoChannel.nameWithHost ]"></my-edit-button> |
41 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> | 43 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> |
diff --git a/client/src/app/+my-library/my-follows/my-followers.component.html b/client/src/app/+my-library/my-follows/my-followers.component.html index a8a3da863..2827f8c41 100644 --- a/client/src/app/+my-library/my-follows/my-followers.component.html +++ b/client/src/app/+my-library/my-follows/my-followers.component.html | |||
@@ -2,7 +2,7 @@ | |||
2 | <span> | 2 | <span> |
3 | <my-global-icon iconName="follower" aria-hidden="true"></my-global-icon> | 3 | <my-global-icon iconName="follower" aria-hidden="true"></my-global-icon> |
4 | <ng-container i18n>My followers</ng-container> | 4 | <ng-container i18n>My followers</ng-container> |
5 | <span class="badge badge-secondary"> {{ pagination.totalItems }}</span> | 5 | <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span> |
6 | </span> | 6 | </span> |
7 | </h1> | 7 | </h1> |
8 | 8 | ||
diff --git a/client/src/app/+my-library/my-follows/my-subscriptions.component.html b/client/src/app/+my-library/my-follows/my-subscriptions.component.html index 391c4d3be..11d460b19 100644 --- a/client/src/app/+my-library/my-follows/my-subscriptions.component.html +++ b/client/src/app/+my-library/my-follows/my-subscriptions.component.html | |||
@@ -2,7 +2,7 @@ | |||
2 | <span> | 2 | <span> |
3 | <my-global-icon iconName="subscriptions" aria-hidden="true"></my-global-icon> | 3 | <my-global-icon iconName="subscriptions" aria-hidden="true"></my-global-icon> |
4 | <ng-container i18n>My subscriptions</ng-container> | 4 | <ng-container i18n>My subscriptions</ng-container> |
5 | <span class="badge badge-secondary"> {{ pagination.totalItems }}</span> | 5 | <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span> |
6 | </span> | 6 | </span> |
7 | </h1> | 7 | </h1> |
8 | 8 | ||
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 14bf01804..76367c029 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 | |||
@@ -1,6 +1,7 @@ | |||
1 | <h1> | 1 | <h1> |
2 | <my-global-icon iconName="history" aria-hidden="true"></my-global-icon> | 2 | <my-global-icon iconName="history" aria-hidden="true"></my-global-icon> |
3 | <ng-container i18n>My watch history</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span> | 3 | <ng-container i18n>My watch history</ng-container> |
4 | <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary">{{ pagination.totalItems }}</span> | ||
4 | </h1> | 5 | </h1> |
5 | 6 | ||
6 | <div class="top-buttons"> | 7 | <div class="top-buttons"> |
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 f6b712908..766869637 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 | |||
@@ -93,8 +93,8 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook { | |||
93 | .subscribe({ | 93 | .subscribe({ |
94 | next: () => { | 94 | next: () => { |
95 | const message = this.videosHistoryEnabled === true | 95 | const message = this.videosHistoryEnabled === true |
96 | ? $localize`Videos history is enabled` | 96 | ? $localize`Video history is enabled` |
97 | : $localize`Videos history is disabled` | 97 | : $localize`Video history is disabled` |
98 | 98 | ||
99 | this.notifier.success(message) | 99 | this.notifier.success(message) |
100 | 100 | ||
@@ -117,8 +117,8 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | async clearAllHistory () { | 119 | async clearAllHistory () { |
120 | const title = $localize`Delete videos history` | 120 | const title = $localize`Delete video history` |
121 | const message = $localize`Are you sure you want to delete all your videos history?` | 121 | const message = $localize`Are you sure you want to delete all your video history?` |
122 | 122 | ||
123 | const res = await this.confirmService.confirm(message, title) | 123 | const res = await this.confirmService.confirm(message, title) |
124 | if (res !== true) return | 124 | if (res !== true) return |
@@ -126,7 +126,7 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook { | |||
126 | this.userHistoryService.clearAll() | 126 | this.userHistoryService.clearAll() |
127 | .subscribe({ | 127 | .subscribe({ |
128 | next: () => { | 128 | next: () => { |
129 | this.notifier.success($localize`Videos history deleted`) | 129 | this.notifier.success($localize`Video history deleted`) |
130 | 130 | ||
131 | this.reloadData() | 131 | this.reloadData() |
132 | }, | 132 | }, |
diff --git a/client/src/app/+my-library/my-library.component.html b/client/src/app/+my-library/my-library.component.html index b465d0156..1c44c8472 100644 --- a/client/src/app/+my-library/my-library.component.html +++ b/client/src/app/+my-library/my-library.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="row"> | 1 | <div class="root"> |
2 | <my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown> | 2 | <my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown> |
3 | 3 | ||
4 | <div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }"> | 4 | <div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }"> |
diff --git a/client/src/app/+my-library/my-library.component.scss b/client/src/app/+my-library/my-library.component.scss index 1ec25315a..6275b7ac2 100644 --- a/client/src/app/+my-library/my-library.component.scss +++ b/client/src/app/+my-library/my-library.component.scss | |||
@@ -1,7 +1,7 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | 3 | ||
4 | .row { | 4 | .root { |
5 | @include sub-menu-h1; | 5 | @include sub-menu-h1; |
6 | 6 | ||
7 | flex-direction: column; | 7 | flex-direction: column; |
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 c29c71c0a..01470e46f 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 | |||
@@ -65,7 +65,7 @@ | |||
65 | <td>{{ videoChangeOwnership.createdAt | date: 'short' }}</td> | 65 | <td>{{ videoChangeOwnership.createdAt | date: 'short' }}</td> |
66 | 66 | ||
67 | <td> | 67 | <td> |
68 | <span class="badge" | 68 | <span class="pt-badge" |
69 | [ngClass]="getStatusClass(videoChangeOwnership.status)">{{ videoChangeOwnership.status }}</span> | 69 | [ngClass]="getStatusClass(videoChangeOwnership.status)">{{ videoChangeOwnership.status }}</span> |
70 | </td> | 70 | </td> |
71 | </tr> | 71 | </tr> |
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.html b/client/src/app/+my-library/my-video-imports/my-video-imports.component.html index 1525d0bd1..79fb4da26 100644 --- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.html +++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.html | |||
@@ -50,7 +50,7 @@ | |||
50 | </td> | 50 | </td> |
51 | 51 | ||
52 | <td> | 52 | <td> |
53 | <span class="badge" [ngClass]="getVideoImportStateClass(videoImport.state.id)"> | 53 | <span class="pt-badge" [ngClass]="getVideoImportStateClass(videoImport.state.id)"> |
54 | {{ videoImport.state.label }} | 54 | {{ videoImport.state.label }} |
55 | </span> | 55 | </span> |
56 | </td> | 56 | </td> |
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html index c39e90a1e..35682cf81 100644 --- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html +++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html | |||
@@ -20,13 +20,13 @@ | |||
20 | 20 | ||
21 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> | 21 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> |
22 | 22 | ||
23 | <div class="form-row"> <!-- playlist grid --> | 23 | <div class="row"> <!-- playlist grid --> |
24 | <div class="form-group col-12 col-lg-4 col-xl-3"> | 24 | <div class="col-12 col-lg-4 col-xl-3"> |
25 | <div *ngIf="isCreation()" class="video-playlist-title" i18n>NEW PLAYLIST</div> | 25 | <div *ngIf="isCreation()" class="video-playlist-title" i18n>NEW PLAYLIST</div> |
26 | <div *ngIf="!isCreation() && videoPlaylistToUpdate" class="video-playlist-title" i18n>PLAYLIST</div> | 26 | <div *ngIf="!isCreation() && videoPlaylistToUpdate" class="video-playlist-title" i18n>PLAYLIST</div> |
27 | </div> | 27 | </div> |
28 | 28 | ||
29 | <div class="form-group col-12 col-lg-8 col-xl-9"> | 29 | <div class="col-12 col-lg-8 col-xl-9"> |
30 | 30 | ||
31 | <div class="col-md-12 col-xl-6"> | 31 | <div class="col-md-12 col-xl-6"> |
32 | <div class="form-group"> | 32 | <div class="form-group"> |
@@ -88,7 +88,7 @@ | |||
88 | </div> | 88 | </div> |
89 | </div> | 89 | </div> |
90 | 90 | ||
91 | <div class="form-row"> <!-- submit placement block --> | 91 | <div class="row"> <!-- submit placement block --> |
92 | <div class="col-md-7 col-xl-5"></div> | 92 | <div class="col-md-7 col-xl-5"></div> |
93 | <div class="col-md-5 col-xl-5 d-inline-flex"> | 93 | <div class="col-md-5 col-xl-5 d-inline-flex"> |
94 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> | 94 | <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> |
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 25b742bff..0091f70be 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 | |||
@@ -1,6 +1,7 @@ | |||
1 | <h1> | 1 | <h1> |
2 | <my-global-icon iconName="playlists" aria-hidden="true"></my-global-icon> | 2 | <my-global-icon iconName="playlists" aria-hidden="true"></my-global-icon> |
3 | <ng-container i18n>My playlists</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span> | 3 | <ng-container i18n>My playlists</ng-container> |
4 | <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary">{{ pagination.totalItems }}</span> | ||
4 | </h1> | 5 | </h1> |
5 | 6 | ||
6 | <my-channels-setup-message></my-channels-setup-message> | 7 | <my-channels-setup-message></my-channels-setup-message> |
diff --git a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.html b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.html index 955fd4884..56ff0e788 100644 --- a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.html +++ b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.html | |||
@@ -17,7 +17,7 @@ | |||
17 | </div> | 17 | </div> |
18 | 18 | ||
19 | <div class="modal-footer"> | 19 | <div class="modal-footer"> |
20 | <div class="form-group inputs"> | 20 | <div class="inputs"> |
21 | <input | 21 | <input |
22 | type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button" | 22 | type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button" |
23 | (click)="dismiss()" (key.enter)="dismiss()" | 23 | (click)="dismiss()" (key.enter)="dismiss()" |
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 0eb694162..48c073192 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 | |||
@@ -4,7 +4,3 @@ | |||
4 | p-autocomplete { | 4 | p-autocomplete { |
5 | display: block; | 5 | display: block; |
6 | } | 6 | } |
7 | |||
8 | .form-group { | ||
9 | margin: 20px 0; | ||
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 7f12e2c71..146dcf41e 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 | |||
@@ -2,7 +2,7 @@ | |||
2 | <span> | 2 | <span> |
3 | <my-global-icon iconName="videos" aria-hidden="true"></my-global-icon> | 3 | <my-global-icon iconName="videos" aria-hidden="true"></my-global-icon> |
4 | <ng-container i18n>My videos</ng-container> | 4 | <ng-container i18n>My videos</ng-container> |
5 | <span class="badge badge-secondary"> {{ pagination.totalItems }}</span> | 5 | <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span> |
6 | </span> | 6 | </span> |
7 | 7 | ||
8 | <div> | 8 | <div> |
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 91cc06702..2f1eb84ba 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 | |||
@@ -4,7 +4,7 @@ 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 { prepareIcu, immutableAssign } from '@app/helpers' |
8 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 8 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
9 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 9 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
10 | import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' | 10 | import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' |
@@ -167,7 +167,10 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
167 | .map(k => parseInt(k, 10)) | 167 | .map(k => parseInt(k, 10)) |
168 | 168 | ||
169 | const res = await this.confirmService.confirm( | 169 | const res = await this.confirmService.confirm( |
170 | $localize`Do you really want to delete ${toDeleteVideosIds.length} videos?`, | 170 | prepareIcu($localize`Do you really want to delete {length, plural, =1 {this video} other {{length} videos}}?`)( |
171 | { length: toDeleteVideosIds.length }, | ||
172 | $localize`Do you really want to delete ${toDeleteVideosIds.length} videos?` | ||
173 | ), | ||
171 | $localize`Delete` | 174 | $localize`Delete` |
172 | ) | 175 | ) |
173 | if (res === false) return | 176 | if (res === false) return |
@@ -184,7 +187,13 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
184 | .pipe(toArray()) | 187 | .pipe(toArray()) |
185 | .subscribe({ | 188 | .subscribe({ |
186 | next: () => { | 189 | next: () => { |
187 | this.notifier.success($localize`${toDeleteVideosIds.length} videos deleted.`) | 190 | this.notifier.success( |
191 | prepareIcu($localize`{length, plural, =1 {Video has been deleted} other {{length} videos have been deleted}}`)( | ||
192 | { length: toDeleteVideosIds.length }, | ||
193 | $localize`${toDeleteVideosIds.length} have been deleted.` | ||
194 | ) | ||
195 | ) | ||
196 | |||
188 | this.selection = {} | 197 | this.selection = {} |
189 | }, | 198 | }, |
190 | 199 | ||
diff --git a/client/src/app/+page-not-found/page-not-found.component.html b/client/src/app/+page-not-found/page-not-found.component.html index 0333f9550..70ede26e8 100644 --- a/client/src/app/+page-not-found/page-not-found.component.html +++ b/client/src/app/+page-not-found/page-not-found.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <div class="root"> | 1 | <div class="root"> |
2 | <div *ngIf="status !== 403 && status !== 418" class="box"> | 2 | <div *ngIf="status !== 403 && status !== 418" class="box"> |
3 | <strong>{{ status }}.</strong> | 3 | <strong>{{ status }}.</strong> |
4 | <span class="ml-1 muted" i18n>That's an error.</span> | 4 | <span class="ms-1 muted" i18n>That's an error.</span> |
5 | 5 | ||
6 | <div class="text mt-4"> | 6 | <div class="text mt-4"> |
7 | <ng-container *ngIf="type === 'video'" i18n>We couldn't find any video tied to the URL {{ pathname }} you were looking for.</ng-container> | 7 | <ng-container *ngIf="type === 'video'" i18n>We couldn't find any video tied to the URL {{ pathname }} you were looking for.</ng-container> |
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | <div *ngIf="status === 403" class="box"> | 25 | <div *ngIf="status === 403" class="box"> |
26 | <strong>{{ status }}.</strong> | 26 | <strong>{{ status }}.</strong> |
27 | <span class="ml-1 muted" i18n>You are not authorized here.</span> | 27 | <span class="ms-1 muted" i18n>You are not authorized here.</span> |
28 | 28 | ||
29 | <div class="text mt-4"> | 29 | <div class="text mt-4"> |
30 | <ng-container *ngIf="type === 'video'" i18n>You might need to check your account is allowed by the video or instance owner.</ng-container> | 30 | <ng-container *ngIf="type === 'video'" i18n>You might need to check your account is allowed by the video or instance owner.</ng-container> |
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | <div *ngIf="status === 418" class="box"> | 35 | <div *ngIf="status === 418" class="box"> |
36 | <strong>{{ status }}.</strong> | 36 | <strong>{{ status }}.</strong> |
37 | <span class="ml-1 muted">I'm a teapot.</span> | 37 | <span class="ms-1 muted">I'm a teapot.</span> |
38 | 38 | ||
39 | <div class="text mt-4" i18n="Description of a tea flavour, keeping the 'requested entity body' as a technical expression referring to a web request"> | 39 | <div class="text mt-4" i18n="Description of a tea flavour, keeping the 'requested entity body' as a technical expression referring to a web request"> |
40 | The requested entity body blends sweet bits with a mellow earthiness. | 40 | The requested entity body blends sweet bits with a mellow earthiness. |
diff --git a/client/src/app/+search/search-filters.component.html b/client/src/app/+search/search-filters.component.html index c4861e8c4..5bce009d5 100644 --- a/client/src/app/+search/search-filters.component.html +++ b/client/src/app/+search/search-filters.component.html | |||
@@ -77,7 +77,7 @@ | |||
77 | </div> | 77 | </div> |
78 | 78 | ||
79 | <div class="row"> | 79 | <div class="row"> |
80 | <div class="pl-0 col-sm-6"> | 80 | <div class="ps-0 col-sm-6"> |
81 | <input | 81 | <input |
82 | (change)="onDurationOrPublishedUpdated()" | 82 | (change)="onDurationOrPublishedUpdated()" |
83 | (keydown.enter)="$event.preventDefault()" | 83 | (keydown.enter)="$event.preventDefault()" |
@@ -87,7 +87,7 @@ | |||
87 | class="form-control" | 87 | class="form-control" |
88 | > | 88 | > |
89 | </div> | 89 | </div> |
90 | <div class="pr-0 col-sm-6"> | 90 | <div class="pe-0 col-sm-6"> |
91 | <input | 91 | <input |
92 | (change)="onDurationOrPublishedUpdated()" | 92 | (change)="onDurationOrPublishedUpdated()" |
93 | (keydown.enter)="$event.preventDefault()" | 93 | (keydown.enter)="$event.preventDefault()" |
diff --git a/client/src/app/+search/search-filters.component.scss b/client/src/app/+search/search-filters.component.scss index ece4ba5b5..5fd1764d3 100644 --- a/client/src/app/+search/search-filters.component.scss +++ b/client/src/app/+search/search-filters.component.scss | |||
@@ -22,10 +22,6 @@ form { | |||
22 | margin-bottom: 1rem; | 22 | margin-bottom: 1rem; |
23 | } | 23 | } |
24 | 24 | ||
25 | .form-group { | ||
26 | margin-bottom: 25px; | ||
27 | } | ||
28 | |||
29 | input[type=text] { | 25 | input[type=text] { |
30 | @include peertube-input-text(100%); | 26 | @include peertube-input-text(100%); |
31 | display: block; | 27 | display: block; |
diff --git a/client/src/app/+search/search.component.html b/client/src/app/+search/search.component.html index 2c84dd930..247dfb56a 100644 --- a/client/src/app/+search/search.component.html +++ b/client/src/app/+search/search.component.html | |||
@@ -2,22 +2,22 @@ | |||
2 | <div class="results-header"> | 2 | <div class="results-header"> |
3 | <div class="first-line"> | 3 | <div class="first-line"> |
4 | <div class="results-counter" *ngIf="pagination.totalItems"> | 4 | <div class="results-counter" *ngIf="pagination.totalItems"> |
5 | <span class="mr-1" i18n>{{ pagination.totalItems | myNumberFormatter }} {pagination.totalItems, plural, =1 {result} other {results}}</span> | 5 | <span class="me-1" i18n>{{ pagination.totalItems | myNumberFormatter }} {pagination.totalItems, plural, =1 {result} other {results}}</span> |
6 | 6 | ||
7 | <span class="mr-1" i18n *ngIf="advancedSearch.searchTarget === 'local'">on this instance</span> | 7 | <span class="me-1" i18n *ngIf="advancedSearch.searchTarget === 'local'">on this instance</span> |
8 | <span class="mr-1" i18n *ngIf="advancedSearch.searchTarget === 'search-index'">on the vidiverse</span> | 8 | <span class="me-1" i18n *ngIf="advancedSearch.searchTarget === 'search-index'">on the vidiverse</span> |
9 | 9 | ||
10 | <span *ngIf="currentSearch" i18n>for <span class="search-value">{{ currentSearch }}</span></span> | 10 | <span *ngIf="currentSearch" i18n>for <span class="search-value">{{ currentSearch }}</span></span> |
11 | </div> | 11 | </div> |
12 | 12 | ||
13 | <div | 13 | <div |
14 | class="results-filter-button ml-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed" role="button" | 14 | class="results-filter-button ms-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed" role="button" |
15 | [attr.aria-expanded]="!isSearchFilterCollapsed" aria-controls="collapseBasic" | 15 | [attr.aria-expanded]="!isSearchFilterCollapsed" aria-controls="collapseBasic" |
16 | > | 16 | > |
17 | <span class="icon icon-filter"></span> | 17 | <span class="icon icon-filter"></span> |
18 | <ng-container i18n> | 18 | <ng-container i18n> |
19 | Filters | 19 | Filters |
20 | <span *ngIf="numberOfFilters() > 0" class="badge badge-secondary">{{ numberOfFilters() }}</span> | 20 | <span *ngIf="numberOfFilters() > 0" class="pt-badge badge-secondary">{{ numberOfFilters() }}</span> |
21 | </ng-container> | 21 | </ng-container> |
22 | </div> | 22 | </div> |
23 | </div> | 23 | </div> |
diff --git a/client/src/app/+search/search.component.ts b/client/src/app/+search/search.component.ts index b9ec6dbcc..62b1c4446 100644 --- a/client/src/app/+search/search.component.ts +++ b/client/src/app/+search/search.component.ts | |||
@@ -248,11 +248,11 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
248 | } | 248 | } |
249 | 249 | ||
250 | private updateTitle () { | 250 | private updateTitle () { |
251 | const suffix = this.currentSearch | 251 | const title = this.currentSearch |
252 | ? ' ' + this.currentSearch | 252 | ? $localize`Search ${this.currentSearch}` |
253 | : '' | 253 | : $localize`Search` |
254 | 254 | ||
255 | this.metaService.setTitle($localize`Search` + suffix) | 255 | this.metaService.setTitle(title) |
256 | } | 256 | } |
257 | 257 | ||
258 | private updateUrlFromAdvancedSearch () { | 258 | private updateUrlFromAdvancedSearch () { |
diff --git a/client/src/app/+signup/+register/custom-stepper.component.html b/client/src/app/+signup/+register/custom-stepper.component.html index aad2f31d3..a07e2fca3 100644 --- a/client/src/app/+signup/+register/custom-stepper.component.html +++ b/client/src/app/+signup/+register/custom-stepper.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | (click)="onClick(i)" | 6 | (click)="onClick(i)" |
7 | > | 7 | > |
8 | <div class="step-index"> | 8 | <div class="step-index"> |
9 | <ng-container *ngIf="!isCompleted(step)"><span class="sr-only" i18n>Step</span> {{ i + 1 }}</ng-container> | 9 | <ng-container *ngIf="!isCompleted(step)"><span class="visually-hidden" i18n>Step</span> {{ i + 1 }}</ng-container> |
10 | <my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon> | 10 | <my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon> |
11 | </div> | 11 | </div> |
12 | 12 | ||
diff --git a/client/src/app/+signup/+register/register-step-channel.component.html b/client/src/app/+signup/+register/register-step-channel.component.html index 67f332409..888e3245d 100644 --- a/client/src/app/+signup/+register/register-step-channel.component.html +++ b/client/src/app/+signup/+register/register-step-channel.component.html | |||
@@ -34,9 +34,7 @@ | |||
34 | type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel" | 34 | type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel" |
35 | formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" | 35 | formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" |
36 | > | 36 | > |
37 | <div class="input-group-append"> | 37 | <div class="input-group-text">@{{ instanceHost }}</div> |
38 | <span class="input-group-text">@{{ instanceHost }}</span> | ||
39 | </div> | ||
40 | </div> | 38 | </div> |
41 | 39 | ||
42 | <div class="name-information" i18n> | 40 | <div class="name-information" i18n> |
diff --git a/client/src/app/+signup/+register/register-step-terms.component.html b/client/src/app/+signup/+register/register-step-terms.component.html index 28a6e0021..717a289e6 100644 --- a/client/src/app/+signup/+register/register-step-terms.component.html +++ b/client/src/app/+signup/+register/register-step-terms.component.html | |||
@@ -1,8 +1,8 @@ | |||
1 | <form role="form" [formGroup]="form"> | 1 | <form role="form" [formGroup]="form"> |
2 | <div class="form-group form-group-terms"> | 2 | <div class="form-group"> |
3 | <my-peertube-checkbox inputName="terms" formControlName="terms"> | 3 | <my-peertube-checkbox inputName="terms" formControlName="terms"> |
4 | <ng-template ptTemplate="label"> | 4 | <ng-template ptTemplate="label"> |
5 | <ng-container i18n> | 5 | <ng-container i18n> |
6 | I am at least {{ minimumAge }} years old and agree | 6 | I am at least {{ minimumAge }} years old and agree |
7 | to the <a class="terms-anchor" (click)="onTermsClick($event)" href='#'>Terms</a> | 7 | to the <a class="terms-anchor" (click)="onTermsClick($event)" href='#'>Terms</a> |
8 | <ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container> | 8 | <ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container> |
diff --git a/client/src/app/+signup/+register/register-step-user.component.html b/client/src/app/+signup/+register/register-step-user.component.html index cab21c655..745b37c10 100644 --- a/client/src/app/+signup/+register/register-step-user.component.html +++ b/client/src/app/+signup/+register/register-step-user.component.html | |||
@@ -27,9 +27,7 @@ | |||
27 | type="text" id="username" i18n-placeholder="Username choice placeholder in the registration form" placeholder="e.g. jane_doe" | 27 | type="text" id="username" i18n-placeholder="Username choice placeholder in the registration form" placeholder="e.g. jane_doe" |
28 | formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" | 28 | formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" |
29 | > | 29 | > |
30 | <div class="input-group-append"> | 30 | <span class="input-group-text">@{{ instanceHost }}</span> |
31 | <span class="input-group-text">@{{ instanceHost }}</span> | ||
32 | </div> | ||
33 | </div> | 31 | </div> |
34 | 32 | ||
35 | <div class="name-information" i18n> | 33 | <div class="name-information" i18n> |
diff --git a/client/src/app/+signup/+register/register.component.html b/client/src/app/+signup/+register/register.component.html index 2d0e6e865..5c4fe5f0b 100644 --- a/client/src/app/+signup/+register/register.component.html +++ b/client/src/app/+signup/+register/register.component.html | |||
@@ -32,7 +32,7 @@ | |||
32 | <button cdkStepperNext [disabled]="!formStepTerms || !formStepTerms.valid">{{ defaultNextStepButtonLabel }}</button> | 32 | <button cdkStepperNext [disabled]="!formStepTerms || !formStepTerms.valid">{{ defaultNextStepButtonLabel }}</button> |
33 | </cdk-step> | 33 | </cdk-step> |
34 | 34 | ||
35 | <cdk-step [stepControl]="formStepUser" i18n-label="Stepper label for the registration page asking user informations" label="User"> | 35 | <cdk-step [stepControl]="formStepUser" i18n-label="Stepper label for the registration page asking user information" label="User"> |
36 | <my-register-step-user (formBuilt)="onUserFormBuilt($event)" [videoUploadDisabled]="videoUploadDisabled"></my-register-step-user> | 36 | <my-register-step-user (formBuilt)="onUserFormBuilt($event)" [videoUploadDisabled]="videoUploadDisabled"></my-register-step-user> |
37 | 37 | ||
38 | <button cdkStepperPrevious>{{ defaultPreviousStepButtonLabel }}</button> | 38 | <button cdkStepperPrevious>{{ defaultPreviousStepButtonLabel }}</button> |
diff --git a/client/src/app/+signup/+register/register.component.scss b/client/src/app/+signup/+register/register.component.scss index 4be67a858..53093a81a 100644 --- a/client/src/app/+signup/+register/register.component.scss +++ b/client/src/app/+signup/+register/register.component.scss | |||
@@ -29,22 +29,6 @@ | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | .form-group-terms { | ||
33 | margin: 30px 0; | ||
34 | } | ||
35 | |||
36 | .input-group { | ||
37 | @include peertube-input-group(100%); | ||
38 | } | ||
39 | |||
40 | .input-group-append { | ||
41 | height: 30px; | ||
42 | } | ||
43 | |||
44 | .form-group-terms { | ||
45 | width: 100% !important; | ||
46 | } | ||
47 | |||
48 | input:not([type=submit]) { | 32 | input:not([type=submit]) { |
49 | @include peertube-input-text(100%); | 33 | @include peertube-input-text(100%); |
50 | display: block; | 34 | display: block; |
diff --git a/client/src/app/+video-channels/video-channels.component.html b/client/src/app/+video-channels/video-channels.component.html index 212e2f867..780db79b0 100644 --- a/client/src/app/+video-channels/video-channels.component.html +++ b/client/src/app/+video-channels/video-channels.component.html | |||
@@ -72,10 +72,10 @@ | |||
72 | </div> | 72 | </div> |
73 | 73 | ||
74 | <div class="actor-counters"> | 74 | <div class="actor-counters"> |
75 | <span i18n>{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</span> | 75 | <span i18n>{videoChannel.followersCount, plural, =0 {No subscribers} =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</span> |
76 | 76 | ||
77 | <span class="videos-count" *ngIf="channelVideosCount !== undefined" i18n> | 77 | <span class="videos-count" *ngIf="channelVideosCount !== undefined" i18n> |
78 | {channelVideosCount, plural, =1 {1 videos} other {{{ channelVideosCount }} videos}} | 78 | {channelVideosCount, plural, =0 {No videos} =1 {1 video} other {{{ channelVideosCount }} videos}} |
79 | </span> | 79 | </span> |
80 | </div> | 80 | </div> |
81 | </div> | 81 | </div> |
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 5344e5431..7add71886 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 | |||
@@ -33,10 +33,6 @@ my-peertube-checkbox { | |||
33 | height: 100%; | 33 | height: 100%; |
34 | min-height: 300px; | 34 | min-height: 300px; |
35 | 35 | ||
36 | .form-group { | ||
37 | margin-bottom: 25px; | ||
38 | } | ||
39 | |||
40 | input { | 36 | input { |
41 | @include peertube-input-text(100%); | 37 | @include peertube-input-text(100%); |
42 | display: block; | 38 | display: block; |
@@ -45,10 +41,6 @@ my-peertube-checkbox { | |||
45 | .label-tags + span { | 41 | .label-tags + span { |
46 | font-size: 15px; | 42 | font-size: 15px; |
47 | } | 43 | } |
48 | |||
49 | .advanced-settings .form-group { | ||
50 | margin-bottom: 20px; | ||
51 | } | ||
52 | } | 44 | } |
53 | 45 | ||
54 | .captions-header { | 46 | .captions-header { |
diff --git a/client/src/app/+videos/+video-edit/video-update.component.html b/client/src/app/+videos/+video-edit/video-update.component.html index 4376f6fe4..446406d1a 100644 --- a/client/src/app/+videos/+video-edit/video-update.component.html +++ b/client/src/app/+videos/+video-edit/video-update.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div class="margin-content"> | 1 | <div class="margin-content"> |
2 | <div class="title-page title-page-single"> | 2 | <div class="title-page title-page-single"> |
3 | <span class="mr-1" i18n>Update</span> | 3 | <span class="me-1" i18n>Update</span> |
4 | <a [routerLink]="getVideoUrl()">{{ video?.name }}</a> | 4 | <a [routerLink]="getVideoUrl()">{{ video?.name }}</a> |
5 | </div> | 5 | </div> |
6 | 6 | ||
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.html b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.html index 3ee818c8b..95d117eec 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.html +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.html | |||
@@ -2,7 +2,7 @@ | |||
2 | <div class="avatar-and-textarea"> | 2 | <div class="avatar-and-textarea"> |
3 | <my-actor-avatar [account]="user?.account" size="25"></my-actor-avatar> | 3 | <my-actor-avatar [account]="user?.account" size="25"></my-actor-avatar> |
4 | 4 | ||
5 | <div class="form-group"> | 5 | <div class="textarea-wrapper"> |
6 | <textarea i18n-placeholder placeholder="Add comment..." myAutoResize | 6 | <textarea i18n-placeholder placeholder="Add comment..." myAutoResize |
7 | [readonly]="(user === null) ? true : false" | 7 | [readonly]="(user === null) ? true : false" |
8 | (click)="openVisitorModal($event)" | 8 | (click)="openVisitorModal($event)" |
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.scss b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.scss index ae889dd38..023d625e9 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.scss +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.scss | |||
@@ -17,9 +17,8 @@ form { | |||
17 | @include margin-right(10px); | 17 | @include margin-right(10px); |
18 | } | 18 | } |
19 | 19 | ||
20 | .form-group { | 20 | .textarea-wrapper { |
21 | flex-grow: 1; | 21 | flex-grow: 1; |
22 | margin: 0; | ||
23 | position: relative; | 22 | position: relative; |
24 | } | 23 | } |
25 | 24 | ||
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.html b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.html index 5014b9692..160865519 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.html +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.html | |||
@@ -16,7 +16,7 @@ | |||
16 | {{ comment.account.displayName }} | 16 | {{ comment.account.displayName }} |
17 | </span> | 17 | </span> |
18 | 18 | ||
19 | <span class="comment-account-fid ml-1">{{ comment.by }}</span> | 19 | <span class="comment-account-fid ms-1">{{ comment.by }}</span> |
20 | </a> | 20 | </a> |
21 | </div> | 21 | </div> |
22 | 22 | ||
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html index 0e00c9c0e..a76379924 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | <my-feed [syndicationItems]="syndicationItems"></my-feed> | 7 | <my-feed [syndicationItems]="syndicationItems"></my-feed> |
8 | 8 | ||
9 | <div ngbDropdown class="d-inline-block ml-4 dropdown-root"> | 9 | <div ngbDropdown class="d-inline-block ms-4 dropdown-root"> |
10 | <button class="btn btn-sm btn-outline-secondary" id="dropdown-sort-comments" ngbDropdownToggle i18n> | 10 | <button class="btn btn-sm btn-outline-secondary" id="dropdown-sort-comments" ngbDropdownToggle i18n> |
11 | SORT BY | 11 | SORT BY |
12 | </button> | 12 | </button> |
@@ -80,7 +80,7 @@ | |||
80 | 80 | ||
81 | <ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template> | 81 | <ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template> |
82 | 82 | ||
83 | <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> | 83 | <my-small-loader class="comment-thread-loading ms-1" [loading]="threadLoading[comment.id]"></my-small-loader> |
84 | </div> | 84 | </div> |
85 | </my-video-comment> | 85 | </my-video-comment> |
86 | 86 | ||
diff --git a/client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.html b/client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.html index d579aaddb..b64d45564 100644 --- a/client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.html +++ b/client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div class="privacy-concerns" *ngIf="display"> | 1 | <div class="privacy-concerns" *ngIf="display"> |
2 | <div class="privacy-concerns-text"> | 2 | <div class="privacy-concerns-text"> |
3 | <span class="mr-2"> | 3 | <span class="me-2"> |
4 | <strong i18n>Friendly Reminder: </strong> | 4 | <strong i18n>Friendly Reminder: </strong> |
5 | <ng-container i18n> | 5 | <ng-container i18n> |
6 | the sharing system used for this video implies that some technical information about your system (such as a public IP address) can be sent to other peers. | 6 | the sharing system used for this video implies that some technical information about your system (such as a public IP address) can be sent to other peers. |
diff --git a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html index f5dd352a3..b04bd3548 100644 --- a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html +++ b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.html | |||
@@ -6,9 +6,9 @@ | |||
6 | <div class="playlist-display-name"> | 6 | <div class="playlist-display-name"> |
7 | {{ playlist.displayName }} | 7 | {{ playlist.displayName }} |
8 | 8 | ||
9 | <span *ngIf="isUnlistedPlaylist()" class="badge badge-warning" i18n>Unlisted</span> | 9 | <span *ngIf="isUnlistedPlaylist()" class="pt-badge badge-warning" i18n>Unlisted</span> |
10 | <span *ngIf="isPrivatePlaylist()" class="badge badge-danger" i18n>Private</span> | 10 | <span *ngIf="isPrivatePlaylist()" class="pt-badge badge-danger" i18n>Private</span> |
11 | <span *ngIf="isPublicPlaylist()" class="badge badge-info" i18n>Public</span> | 11 | <span *ngIf="isPublicPlaylist()" class="pt-badge badge-info" i18n>Public</span> |
12 | </div> | 12 | </div> |
13 | 13 | ||
14 | <div class="playlist-by-index"> | 14 | <div class="playlist-by-index"> |
diff --git a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss index 5c3453e4b..0f0ac1979 100644 --- a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss +++ b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.scss | |||
@@ -15,43 +15,47 @@ | |||
15 | .playlist-info { | 15 | .playlist-info { |
16 | padding: 5px 30px; | 16 | padding: 5px 30px; |
17 | background-color: pvar(--greyBackgroundColor); | 17 | background-color: pvar(--greyBackgroundColor); |
18 | } | ||
19 | |||
20 | .playlist-display-name { | ||
21 | font-size: 18px; | ||
22 | font-weight: $font-semibold; | ||
23 | margin-bottom: 5px; | ||
18 | 24 | ||
19 | .playlist-display-name { | 25 | .pt-badge { |
20 | font-size: 18px; | 26 | @include margin-left(5px); |
21 | font-weight: $font-semibold; | ||
22 | margin-bottom: 5px; | ||
23 | } | 27 | } |
28 | } | ||
24 | 29 | ||
25 | .playlist-by-index { | 30 | .playlist-by-index { |
26 | color: pvar(--greyForegroundColor); | 31 | color: pvar(--greyForegroundColor); |
27 | display: flex; | 32 | display: flex; |
28 | 33 | ||
29 | .playlist-by { | 34 | .playlist-by { |
30 | @include margin-right(5px); | 35 | @include margin-right(5px); |
31 | } | 36 | } |
32 | 37 | ||
33 | .playlist-index span:first-child::after { | 38 | .playlist-index span:first-child::after { |
34 | content: '/'; | 39 | content: '/'; |
35 | margin: 0 3px; | 40 | margin: 0 3px; |
36 | } | ||
37 | } | 41 | } |
42 | } | ||
38 | 43 | ||
39 | .playlist-controls { | 44 | .playlist-controls { |
40 | display: flex; | 45 | display: flex; |
41 | margin: 10px 0; | 46 | margin: 10px 0; |
42 | 47 | ||
43 | my-global-icon:not(:last-child) { | 48 | my-global-icon:not(:last-child) { |
44 | @include margin-right(.5rem); | 49 | @include margin-right(.5rem); |
45 | } | 50 | } |
46 | 51 | ||
47 | my-global-icon { | 52 | my-global-icon { |
48 | &:not(.active) { | 53 | &:not(.active) { |
49 | opacity: .5; | 54 | opacity: .5; |
50 | } | 55 | } |
51 | 56 | ||
52 | ::ng-deep { | 57 | ::ng-deep { |
53 | cursor: pointer; | 58 | cursor: pointer; |
54 | } | ||
55 | } | 59 | } |
56 | } | 60 | } |
57 | } | 61 | } |
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 1ea0cf6b8..461891779 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.html +++ b/client/src/app/+videos/+video-watch/video-watch.component.html | |||
@@ -61,7 +61,7 @@ | |||
61 | <div class="video-info-channel-left d-flex"> | 61 | <div class="video-info-channel-left d-flex"> |
62 | <my-video-avatar-channel [video]="video" [showChannel]="!isChannelDisplayNameGeneric()"></my-video-avatar-channel> | 62 | <my-video-avatar-channel [video]="video" [showChannel]="!isChannelDisplayNameGeneric()"></my-video-avatar-channel> |
63 | 63 | ||
64 | <div class="video-info-channel-left-links ml-1"> | 64 | <div class="video-info-channel-left-links ms-1"> |
65 | <ng-container *ngIf="!isChannelDisplayNameGeneric()"> | 65 | <ng-container *ngIf="!isChannelDisplayNameGeneric()"> |
66 | <a [routerLink]="[ '/c', video.byVideoChannel ]" i18n-title title="Channel page"> | 66 | <a [routerLink]="[ '/c', video.byVideoChannel ]" i18n-title title="Channel page"> |
67 | {{ video.channel.displayName }} | 67 | {{ video.channel.displayName }} |
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 f250c2407..1d5131092 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 | |||
@@ -1,4 +1,4 @@ | |||
1 | <h1 class="sr-only" i18n>Discover</h1> | 1 | <h1 class="visually-hidden" i18n>Discover</h1> |
2 | <div class="margin-content"> | 2 | <div class="margin-content"> |
3 | 3 | ||
4 | <div class="no-results" i18n *ngIf="notResults">No results.</div> | 4 | <div class="no-results" i18n *ngIf="notResults">No results.</div> |
diff --git a/client/src/app/+videos/video-list/videos-list-common-page.component.ts b/client/src/app/+videos/video-list/videos-list-common-page.component.ts index d2782036b..c8fa8ef30 100644 --- a/client/src/app/+videos/video-list/videos-list-common-page.component.ts +++ b/client/src/app/+videos/video-list/videos-list-common-page.component.ts | |||
@@ -204,13 +204,28 @@ export class VideosListCommonPageComponent implements OnInit, OnDestroy, Disable | |||
204 | if ([ 'hot', 'trending', 'likes', 'views' ].includes(sanitizedSort)) { | 204 | if ([ 'hot', 'trending', 'likes', 'views' ].includes(sanitizedSort)) { |
205 | this.title = $localize`Trending` | 205 | this.title = $localize`Trending` |
206 | 206 | ||
207 | if (sanitizedSort === 'hot') this.titleTooltip = $localize`Videos with the most interactions for recent videos` | 207 | if (sanitizedSort === 'hot') { |
208 | if (sanitizedSort === 'likes') this.titleTooltip = $localize`Videos that have the most likes` | 208 | this.titleTooltip = $localize`Videos with the most interactions for recent videos` |
209 | if (sanitizedSort === 'views') this.titleTooltip = undefined | 209 | return |
210 | } | ||
211 | |||
212 | if (sanitizedSort === 'likes') { | ||
213 | this.titleTooltip = $localize`Videos that have the most likes` | ||
214 | return | ||
215 | } | ||
216 | |||
217 | if (sanitizedSort === 'views') { | ||
218 | this.titleTooltip = undefined | ||
219 | return | ||
220 | } | ||
210 | 221 | ||
211 | if (sanitizedSort === 'trending') { | 222 | if (sanitizedSort === 'trending') { |
212 | if (this.trendingDays === 1) this.titleTooltip = $localize`Videos with the most views during the last 24 hours` | 223 | if (this.trendingDays === 1) { |
213 | else this.titleTooltip = $localize`Videos with the most views during the last ${this.trendingDays} days` | 224 | this.titleTooltip = $localize`Videos with the most views during the last 24 hours` |
225 | return | ||
226 | } | ||
227 | |||
228 | this.titleTooltip = $localize`Videos with the most views during the last ${this.trendingDays} days` | ||
214 | } | 229 | } |
215 | 230 | ||
216 | return | 231 | return |
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index d80f95ed6..4a4c2321b 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts | |||
@@ -41,7 +41,9 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra | |||
41 | ToastModule, | 41 | ToastModule, |
42 | 42 | ||
43 | HotkeyModule.forRoot({ | 43 | HotkeyModule.forRoot({ |
44 | cheatSheetCloseEsc: true | 44 | cheatSheetCloseEsc: true, |
45 | cheatSheetDescription: $localize`Show/hide this help menu`, | ||
46 | cheatSheetCloseEscDescription: $localize`Hide this help menu` | ||
45 | }) | 47 | }) |
46 | ], | 48 | ], |
47 | 49 | ||
diff --git a/client/src/app/core/rest/rest-extractor.service.ts b/client/src/app/core/rest/rest-extractor.service.ts index 17053811c..86c7484a5 100644 --- a/client/src/app/core/rest/rest-extractor.service.ts +++ b/client/src/app/core/rest/rest-extractor.service.ts | |||
@@ -34,49 +34,17 @@ export class RestExtractor { | |||
34 | return target | 34 | return target |
35 | } | 35 | } |
36 | 36 | ||
37 | handleError (err: any) { | 37 | redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) { |
38 | let errorMessage | 38 | if (obj?.status && status.includes(obj.status)) { |
39 | // Do not use redirectService to avoid circular dependencies | ||
40 | this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true }) | ||
41 | } | ||
39 | 42 | ||
40 | if (err.error instanceof Error) { | 43 | return observableThrowError(() => obj) |
41 | // A client-side or network error occurred. Handle it accordingly. | 44 | } |
42 | errorMessage = err.error.detail || err.error.title | ||
43 | console.error('An error occurred:', errorMessage) | ||
44 | } else if (typeof err.error === 'string') { | ||
45 | errorMessage = err.error | ||
46 | } else if (err.status !== undefined) { | ||
47 | // A server-side error occurred. | ||
48 | if (err.error?.errors) { | ||
49 | const errors = err.error.errors | ||
50 | const errorsArray: string[] = [] | ||
51 | |||
52 | Object.keys(errors).forEach(key => { | ||
53 | errorsArray.push(errors[key].msg) | ||
54 | }) | ||
55 | |||
56 | errorMessage = errorsArray.join('. ') | ||
57 | } else if (err.error?.error) { | ||
58 | errorMessage = err.error.error | ||
59 | } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { | ||
60 | // eslint-disable-next-line max-len | ||
61 | errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.` | ||
62 | } else if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) { | ||
63 | const secondsLeft = err.headers.get('retry-after') | ||
64 | if (secondsLeft) { | ||
65 | const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60) | ||
66 | errorMessage = $localize`Too many attempts, please try again after ${minutesLeft} minutes.` | ||
67 | } else { | ||
68 | errorMessage = $localize`Too many attempts, please try again later.` | ||
69 | } | ||
70 | } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { | ||
71 | errorMessage = $localize`Server error. Please retry later.` | ||
72 | } | ||
73 | 45 | ||
74 | errorMessage = errorMessage || 'Unknown error.' | 46 | handleError (err: any) { |
75 | console.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`) | 47 | const errorMessage = this.buildErrorMessage(err) |
76 | } else { | ||
77 | console.error(err) | ||
78 | errorMessage = err | ||
79 | } | ||
80 | 48 | ||
81 | const errorObj: { message: string, status: string, body: string } = { | 49 | const errorObj: { message: string, status: string, body: string } = { |
82 | message: errorMessage, | 50 | message: errorMessage, |
@@ -92,12 +60,63 @@ export class RestExtractor { | |||
92 | return observableThrowError(() => errorObj) | 60 | return observableThrowError(() => errorObj) |
93 | } | 61 | } |
94 | 62 | ||
95 | redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) { | 63 | private buildErrorMessage (err: any) { |
96 | if (obj?.status && status.includes(obj.status)) { | 64 | if (err.error instanceof Error) { |
97 | // Do not use redirectService to avoid circular dependencies | 65 | // A client-side or network error occurred. Handle it accordingly. |
98 | this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true }) | 66 | const errorMessage = err.error.detail || err.error.title |
67 | console.error('An error occurred:', errorMessage) | ||
68 | |||
69 | return errorMessage | ||
99 | } | 70 | } |
100 | 71 | ||
101 | return observableThrowError(() => obj) | 72 | if (typeof err.error === 'string') { |
73 | return err.error | ||
74 | } | ||
75 | |||
76 | if (err.status !== undefined) { | ||
77 | const errorMessage = this.buildServerErrorMessage(err) | ||
78 | console.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`) | ||
79 | |||
80 | return errorMessage | ||
81 | } | ||
82 | |||
83 | console.error(err) | ||
84 | return err | ||
85 | } | ||
86 | |||
87 | private buildServerErrorMessage (err: any) { | ||
88 | // A server-side error occurred. | ||
89 | if (err.error?.errors) { | ||
90 | const errors = err.error.errors | ||
91 | |||
92 | return Object.keys(errors) | ||
93 | .map(key => errors[key].msg) | ||
94 | .join('. ') | ||
95 | } | ||
96 | |||
97 | if (err.error?.error) { | ||
98 | return err.error.error | ||
99 | } | ||
100 | |||
101 | if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { | ||
102 | return $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.` | ||
103 | } | ||
104 | |||
105 | if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) { | ||
106 | const secondsLeft = err.headers.get('retry-after') | ||
107 | |||
108 | if (secondsLeft) { | ||
109 | const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60) | ||
110 | return $localize`Too many attempts, please try again after ${minutesLeft} minutes.` | ||
111 | } | ||
112 | |||
113 | return $localize`Too many attempts, please try again later.` | ||
114 | } | ||
115 | |||
116 | if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { | ||
117 | return $localize`Server error. Please retry later.` | ||
118 | } | ||
119 | |||
120 | return $localize`Unknown server error` | ||
102 | } | 121 | } |
103 | } | 122 | } |
diff --git a/client/src/app/core/rest/rest-table.ts b/client/src/app/core/rest/rest-table.ts index d8b039187..7b765f7fc 100644 --- a/client/src/app/core/rest/rest-table.ts +++ b/client/src/app/core/rest/rest-table.ts | |||
@@ -39,6 +39,10 @@ export abstract class RestTable { | |||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | saveSort () { | ||
43 | peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort)) | ||
44 | } | ||
45 | |||
42 | loadLazy (event: LazyLoadEvent) { | 46 | loadLazy (event: LazyLoadEvent) { |
43 | logger('Load lazy %o.', event) | 47 | logger('Load lazy %o.', event) |
44 | 48 | ||
@@ -60,10 +64,6 @@ export abstract class RestTable { | |||
60 | this.saveSort() | 64 | this.saveSort() |
61 | } | 65 | } |
62 | 66 | ||
63 | saveSort () { | ||
64 | peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort)) | ||
65 | } | ||
66 | |||
67 | onSearch (search: string) { | 67 | onSearch (search: string) { |
68 | this.search = search | 68 | this.search = search |
69 | this.reloadData() | 69 | this.reloadData() |
diff --git a/client/src/app/header/search-typeahead.component.html b/client/src/app/header/search-typeahead.component.html index 7a9b6c51f..d08e2f0fb 100644 --- a/client/src/app/header/search-typeahead.component.html +++ b/client/src/app/header/search-typeahead.component.html | |||
@@ -25,7 +25,7 @@ | |||
25 | <div class="d-flex justify-content-between"> | 25 | <div class="d-flex justify-content-between"> |
26 | <label class="small-title" i18n>GLOBAL SEARCH</label> | 26 | <label class="small-title" i18n>GLOBAL SEARCH</label> |
27 | <div class="advanced-search-status muted"> | 27 | <div class="advanced-search-status muted"> |
28 | <span *ngIf="serverConfig" class="mr-1" i18n>using {{ serverConfig.search.searchIndex.url }}</span> | 28 | <span *ngIf="serverConfig" class="me-1" i18n>using {{ serverConfig.search.searchIndex.url }}</span> |
29 | <i class="glyphicon glyphicon-globe"></i> | 29 | <i class="glyphicon glyphicon-globe"></i> |
30 | </div> | 30 | </div> |
31 | </div> | 31 | </div> |
@@ -39,8 +39,8 @@ | |||
39 | <label class="small-title" i18n>ADVANCED SEARCH</label> | 39 | <label class="small-title" i18n>ADVANCED SEARCH</label> |
40 | <div class="advanced-search-status c-help"> | 40 | <div class="advanced-search-status c-help"> |
41 | <span [ngClass]="canSearchAnyURI ? 'text-success' : 'muted'" i18n-title title="Determines whether you can resolve any distant content, or if this instance only allows doing so for instances it follows."> | 41 | <span [ngClass]="canSearchAnyURI ? 'text-success' : 'muted'" i18n-title title="Determines whether you can resolve any distant content, or if this instance only allows doing so for instances it follows."> |
42 | <span *ngIf="canSearchAnyURI()" class="mr-1" i18n>any instance</span> | 42 | <span *ngIf="canSearchAnyURI()" class="me-1" i18n>any instance</span> |
43 | <span *ngIf="!canSearchAnyURI()" class="mr-1" i18n>only followed instances</span> | 43 | <span *ngIf="!canSearchAnyURI()" class="me-1" i18n>only followed instances</span> |
44 | <i [ngClass]="canSearchAnyURI() ? 'glyphicon glyphicon-ok-sign' : 'glyphicon glyphicon-exclamation-sign'"></i> | 44 | <i [ngClass]="canSearchAnyURI() ? 'glyphicon glyphicon-ok-sign' : 'glyphicon glyphicon-exclamation-sign'"></i> |
45 | </span> | 45 | </span> |
46 | </div> | 46 | </div> |
diff --git a/client/src/app/header/suggestion.component.html b/client/src/app/header/suggestion.component.html index 4ac9809e1..3f85ed6ae 100644 --- a/client/src/app/header/suggestion.component.html +++ b/client/src/app/header/suggestion.component.html | |||
@@ -1,16 +1,16 @@ | |||
1 | <a tabindex="-1" class="d-flex flex-auto flex-items-center p-2" [class.focus-visible]="active"> | 1 | <a tabindex="-1" class="d-flex flex-auto flex-items-center p-2" [class.focus-visible]="active"> |
2 | <div class="flex-shrink-0 mr-2 text-center"> | 2 | <div class="flex-shrink-0 me-2 text-center"> |
3 | <my-global-icon iconName="search"></my-global-icon> | 3 | <my-global-icon iconName="search"></my-global-icon> |
4 | </div> | 4 | </div> |
5 | 5 | ||
6 | <img class="avatar mr-2 flex-shrink-0 d-none" alt="" aria-label="Team" src="" width="28" height="28"> | 6 | <img class="avatar me-2 flex-shrink-0 d-none" alt="" aria-label="Team" src="" width="28" height="28"> |
7 | 7 | ||
8 | <div | 8 | <div |
9 | class="flex-auto overflow-hidden text-left no-wrap css-truncate css-truncate-target" | 9 | class="flex-auto overflow-hidden text-start no-wrap css-truncate css-truncate-target" |
10 | [attr.aria-label]="result.text" [innerHTML]="result.text | highlight : highlight" | 10 | [attr.aria-label]="result.text" [innerHTML]="result.text | highlight : highlight" |
11 | ></div> | 11 | ></div> |
12 | 12 | ||
13 | <div class="border rounded flex-shrink-0 px-1 bg-gray text-gray-light ml-1 f6"> | 13 | <div class="border rounded flex-shrink-0 px-1 bg-gray text-gray-light ms-1 f6"> |
14 | <span *ngIf="result.type === 'search-instance'" i18n>In this instance's network</span> | 14 | <span *ngIf="result.type === 'search-instance'" i18n>In this instance's network</span> |
15 | <span *ngIf="result.type === 'search-index'" i18n>In the vidiverse</span> | 15 | <span *ngIf="result.type === 'search-index'" i18n>In the vidiverse</span> |
16 | </div> | 16 | </div> |
diff --git a/client/src/app/helpers/i18n-utils.ts b/client/src/app/helpers/i18n-utils.ts index bbfb12959..2017a31ea 100644 --- a/client/src/app/helpers/i18n-utils.ts +++ b/client/src/app/helpers/i18n-utils.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { environment } from '../../environments/environment' | 1 | import { environment } from '../../environments/environment' |
2 | import IntlMessageFormat from 'intl-messageformat' | ||
2 | 3 | ||
3 | function isOnDevLocale () { | 4 | function isOnDevLocale () { |
4 | return environment.production === false && window.location.search === '?lang=fr' | 5 | return environment.production === false && window.location.search === '?lang=fr' |
@@ -8,7 +9,31 @@ function getDevLocale () { | |||
8 | return 'fr-FR' | 9 | return 'fr-FR' |
9 | } | 10 | } |
10 | 11 | ||
12 | function prepareIcu (icu: string) { | ||
13 | let alreadyWarned = false | ||
14 | |||
15 | try { | ||
16 | const msg = new IntlMessageFormat(icu, $localize.locale) | ||
17 | |||
18 | return (context: { [id: string]: number | string }, fallback: string) => { | ||
19 | try { | ||
20 | return msg.format(context) as string | ||
21 | } catch (err) { | ||
22 | if (!alreadyWarned) console.warn('Cannot format ICU %s.', icu, err) | ||
23 | |||
24 | alreadyWarned = true | ||
25 | return fallback | ||
26 | } | ||
27 | } | ||
28 | } catch (err) { | ||
29 | console.warn('Cannot build intl message %s.', icu, err) | ||
30 | |||
31 | return (_context: unknown, fallback: string) => fallback | ||
32 | } | ||
33 | } | ||
34 | |||
11 | export { | 35 | export { |
12 | getDevLocale, | 36 | getDevLocale, |
37 | prepareIcu, | ||
13 | isOnDevLocale | 38 | isOnDevLocale |
14 | } | 39 | } |
diff --git a/client/src/app/helpers/utils/upload.ts b/client/src/app/helpers/utils/upload.ts index a3fce7fee..5c2600a0d 100644 --- a/client/src/app/helpers/utils/upload.ts +++ b/client/src/app/helpers/utils/upload.ts | |||
@@ -2,36 +2,43 @@ import { HttpErrorResponse } from '@angular/common/http' | |||
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { HttpStatusCode } from '@shared/models' | 3 | import { HttpStatusCode } from '@shared/models' |
4 | 4 | ||
5 | function genericUploadErrorHandler (parameters: { | 5 | function genericUploadErrorHandler (options: { |
6 | err: Pick<HttpErrorResponse, 'message' | 'status' | 'headers'> | 6 | err: Pick<HttpErrorResponse, 'message' | 'status' | 'headers'> |
7 | name: string | 7 | name: string |
8 | notifier: Notifier | 8 | notifier: Notifier |
9 | sticky?: boolean | 9 | sticky?: boolean |
10 | }) { | 10 | }) { |
11 | const { err, name, notifier, sticky } = { sticky: false, ...parameters } | 11 | const { err, name, notifier, sticky = false } = options |
12 | const title = $localize`The upload failed` | 12 | const title = $localize`Upload failed` |
13 | let message = err.message | 13 | const message = buildMessage(name, err) |
14 | |||
15 | if (err instanceof ErrorEvent) { // network error | ||
16 | message = $localize`The connection was interrupted` | ||
17 | notifier.error(message, title, null, sticky) | ||
18 | } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { | ||
19 | message = $localize`The server encountered an error` | ||
20 | notifier.error(message, title, null, sticky) | ||
21 | } else if (err.status === HttpStatusCode.REQUEST_TIMEOUT_408) { | ||
22 | message = $localize`Your ${name} file couldn't be transferred before the set timeout (usually 10min)` | ||
23 | notifier.error(message, title, null, sticky) | ||
24 | } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { | ||
25 | const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G' | ||
26 | message = $localize`Your ${name} file was too large (max. size: ${maxFileSize})` | ||
27 | notifier.error(message, title, null, sticky) | ||
28 | } else { | ||
29 | notifier.error(err.message, title) | ||
30 | } | ||
31 | 14 | ||
15 | notifier.error(message, title, null, sticky) | ||
32 | return message | 16 | return message |
33 | } | 17 | } |
34 | 18 | ||
35 | export { | 19 | export { |
36 | genericUploadErrorHandler | 20 | genericUploadErrorHandler |
37 | } | 21 | } |
22 | |||
23 | // --------------------------------------------------------------------------- | ||
24 | |||
25 | function buildMessage (name: string, err: Pick<HttpErrorResponse, 'message' | 'status' | 'headers'>) { | ||
26 | if (err instanceof ErrorEvent) { // network error | ||
27 | return $localize`The connection was interrupted` | ||
28 | } | ||
29 | |||
30 | if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { | ||
31 | return $localize`The server encountered an error` | ||
32 | } | ||
33 | |||
34 | if (err.status === HttpStatusCode.REQUEST_TIMEOUT_408) { | ||
35 | return $localize`Your ${name} file couldn't be transferred before the server proxy timeout` | ||
36 | } | ||
37 | |||
38 | if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { | ||
39 | const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G' | ||
40 | return $localize`Your ${name} file was too large (max. size: ${maxFileSize})` | ||
41 | } | ||
42 | |||
43 | return err.message | ||
44 | } | ||
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index b8f8d68ab..2961daaa3 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -36,14 +36,14 @@ | |||
36 | > | 36 | > |
37 | <my-global-icon iconName="language" aria-hidden="true"></my-global-icon> | 37 | <my-global-icon iconName="language" aria-hidden="true"></my-global-icon> |
38 | <span i18n>Interface:</span> | 38 | <span i18n>Interface:</span> |
39 | <span class="ml-auto muted">{{ currentInterfaceLanguage }}</span> | 39 | <span class="ms-auto muted">{{ currentInterfaceLanguage }}</span> |
40 | </a> | 40 | </a> |
41 | 41 | ||
42 | <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles" | 42 | <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles" |
43 | #settingsLanguagesSubtitles (click)="onActiveLinkScrollToAnchor(settingsLanguagesSubtitles)"> | 43 | #settingsLanguagesSubtitles (click)="onActiveLinkScrollToAnchor(settingsLanguagesSubtitles)"> |
44 | <my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon> | 44 | <my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon> |
45 | <span i18n>Videos:</span> | 45 | <span i18n>Videos:</span> |
46 | <span class="ml-auto muted">{{ videoLanguages.join(', ') }}</span> | 46 | <span class="ms-auto muted">{{ videoLanguages.join(', ') }}</span> |
47 | </a> | 47 | </a> |
48 | 48 | ||
49 | <a ngbDropdownItem ngbDropdownToggle class="dropdown-item settings-sensitive" routerLink="/my-account/settings" | 49 | <a ngbDropdownItem ngbDropdownToggle class="dropdown-item settings-sensitive" routerLink="/my-account/settings" |
@@ -53,14 +53,14 @@ | |||
53 | <my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy === 'display'" iconName="sensitive" aria-hidden="true"></my-global-icon> | 53 | <my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy === 'display'" iconName="sensitive" aria-hidden="true"></my-global-icon> |
54 | <my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy !== 'display'" iconName="unsensitive" aria-hidden="true"></my-global-icon> | 54 | <my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy !== 'display'" iconName="unsensitive" aria-hidden="true"></my-global-icon> |
55 | <span i18n>Sensitive:</span> | 55 | <span i18n>Sensitive:</span> |
56 | <span class="ml-auto muted">{{ nsfwPolicy }}</span> | 56 | <span class="ms-auto muted">{{ nsfwPolicy }}</span> |
57 | </a> | 57 | </a> |
58 | 58 | ||
59 | <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()"> | 59 | <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()"> |
60 | <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon> | 60 | <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon> |
61 | <ng-container i18n>Help share videos</ng-container> | 61 | <ng-container i18n>Help share videos</ng-container> |
62 | 62 | ||
63 | <my-input-switch class="ml-auto" [checked]="user.p2pEnabled"></my-input-switch> | 63 | <my-input-switch class="ms-auto" [checked]="user.p2pEnabled"></my-input-switch> |
64 | </a> | 64 | </a> |
65 | 65 | ||
66 | <div class="dropdown-divider"></div> | 66 | <div class="dropdown-divider"></div> |
@@ -149,7 +149,7 @@ | |||
149 | 149 | ||
150 | <div class="footer-copyleft"> | 150 | <div class="footer-copyleft"> |
151 | <small class="d-inline" i18n-title title="powered by PeerTube - CopyLeft 2015-2022"> | 151 | <small class="d-inline" i18n-title title="powered by PeerTube - CopyLeft 2015-2022"> |
152 | <a href="https://joinpeertube.org" class="mr-1" target="_blank" rel="noopener noreferrer" i18n>powered by PeerTube</a> | 152 | <a href="https://joinpeertube.org" class="me-1" target="_blank" rel="noopener noreferrer" i18n>powered by PeerTube</a> |
153 | 153 | ||
154 | <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/LICENSE" target="_blank" rel="noopener noreferrer"> | 154 | <a href="https://github.com/Chocobozzz/PeerTube/blob/develop/LICENSE" target="_blank" rel="noopener noreferrer"> |
155 | <span aria-label="copyleft" class="d-inline-block" style="transform: rotateY(180deg)">©</span> 2015-2022 | 155 | <span aria-label="copyleft" class="d-inline-block" style="transform: rotateY(180deg)">©</span> 2015-2022 |
diff --git a/client/src/app/menu/notification.component.html b/client/src/app/menu/notification.component.html index beda1c43c..2bd11c6f7 100644 --- a/client/src/app/menu/notification.component.html +++ b/client/src/app/menu/notification.component.html | |||
@@ -24,7 +24,7 @@ | |||
24 | <div> | 24 | <div> |
25 | <button | 25 | <button |
26 | *ngIf="unreadNotifications" | 26 | *ngIf="unreadNotifications" |
27 | i18n-title title="Mark all as read" class="glyphicon glyphicon-ok mr-2" | 27 | i18n-title title="Mark all as read" class="glyphicon glyphicon-ok me-2" |
28 | (click)="markAllAsRead()" | 28 | (click)="markAllAsRead()" |
29 | ></button> | 29 | ></button> |
30 | <a | 30 | <a |
@@ -45,7 +45,7 @@ | |||
45 | ></my-user-notifications> | 45 | ></my-user-notifications> |
46 | 46 | ||
47 | <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)"> | 47 | <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)"> |
48 | <my-global-icon class="mr-1" iconName="bell" aria-hidden="true"></my-global-icon> | 48 | <my-global-icon class="me-1" iconName="bell" aria-hidden="true"></my-global-icon> |
49 | <span i18n>See all your notifications</span> | 49 | <span i18n>See all your notifications</span> |
50 | </a> | 50 | </a> |
51 | </div> | 51 | </div> |
diff --git a/client/src/app/modal/confirm.component.html b/client/src/app/modal/confirm.component.html index f07501726..c59c25770 100644 --- a/client/src/app/modal/confirm.component.html +++ b/client/src/app/modal/confirm.component.html | |||
@@ -9,7 +9,7 @@ | |||
9 | <div class="modal-body" > | 9 | <div class="modal-body" > |
10 | <div [innerHtml]="message"></div> | 10 | <div [innerHtml]="message"></div> |
11 | 11 | ||
12 | <div *ngIf="inputLabel && expectedInputValue" class="form-group"> | 12 | <div *ngIf="inputLabel && expectedInputValue" class="form-group mt-3"> |
13 | <label for="confirmInput">{{ inputLabel }}</label> | 13 | <label for="confirmInput">{{ inputLabel }}</label> |
14 | <input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" /> | 14 | <input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" /> |
15 | </div> | 15 | </div> |
diff --git a/client/src/app/modal/confirm.component.scss b/client/src/app/modal/confirm.component.scss index 77ea4d307..21aa81eeb 100644 --- a/client/src/app/modal/confirm.component.scss +++ b/client/src/app/modal/confirm.component.scss | |||
@@ -13,7 +13,3 @@ input[type=text] { | |||
13 | @include peertube-input-text(100%); | 13 | @include peertube-input-text(100%); |
14 | display: block; | 14 | display: block; |
15 | } | 15 | } |
16 | |||
17 | .form-group { | ||
18 | margin: 20px 0; | ||
19 | } | ||
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 986de15ed..bb87279d7 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 | |||
@@ -17,9 +17,9 @@ | |||
17 | </a> | 17 | </a> |
18 | 18 | ||
19 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" | 19 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }" |
20 | class="ml-auto muted abuse-details-links" i18n | 20 | class="ms-auto 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="ms-1 glyphicon glyphicon-flag"></span> |
23 | </a> | 23 | </a> |
24 | </span> | 24 | </span> |
25 | </div> | 25 | </div> |
@@ -37,9 +37,9 @@ | |||
37 | </a> | 37 | </a> |
38 | 38 | ||
39 | <a *ngIf="isAdminView" [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" | 39 | <a *ngIf="isAdminView" [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }" |
40 | class="ml-auto muted abuse-details-links" i18n | 40 | class="ms-auto 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="ms-1 glyphicon glyphicon-flag"></span> |
43 | </a> | 43 | </a> |
44 | </span> | 44 | </span> |
45 | </div> | 45 | </div> |
@@ -53,7 +53,7 @@ | |||
53 | <div class="mt-3 d-flex"> | 53 | <div class="mt-3 d-flex"> |
54 | <span class="moderation-expanded-label"> | 54 | <span class="moderation-expanded-label"> |
55 | <ng-container i18n>Report</ng-container> | 55 | <ng-container i18n>Report</ng-container> |
56 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ml-1 muted">#{{ abuse.id }}</a> | 56 | <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ms-1 muted">#{{ abuse.id }}</a> |
57 | </span> | 57 | </span> |
58 | <span class="moderation-expanded-text" [innerHTML]="abuse.reasonHtml"></span> | 58 | <span class="moderation-expanded-text" [innerHTML]="abuse.reasonHtml"></span> |
59 | </div> | 59 | </div> |
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 f0a27c6e2..6d1de808d 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 | |||
@@ -8,7 +8,7 @@ | |||
8 | > | 8 | > |
9 | <ng-template pTemplate="caption"> | 9 | <ng-template pTemplate="caption"> |
10 | <div class="caption"> | 10 | <div class="caption"> |
11 | <div class="ml-auto"> | 11 | <div class="ms-auto"> |
12 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 12 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
13 | </div> | 13 | </div> |
14 | </div> | 14 | </div> |
diff --git a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html index e9c5fadcf..b63bf1f92 100644 --- a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | <div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body"> | 7 | <div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body"> |
8 | <my-global-icon iconName="upload"></my-global-icon> | 8 | <my-global-icon iconName="upload"></my-global-icon> |
9 | <label class="sr-only" for="avatarfile" i18n>Upload a new avatar</label> | 9 | <label class="visually-hidden" for="avatarfile" i18n>Upload a new avatar</label> |
10 | <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> | 10 | <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> |
11 | </div> | 11 | </div> |
12 | 12 | ||
@@ -15,7 +15,7 @@ | |||
15 | #avatarPopover="ngbPopover" [ngbPopover]="avatarEditContent" popoverClass="popover-image-info" autoClose="outside" placement="right" | 15 | #avatarPopover="ngbPopover" [ngbPopover]="avatarEditContent" popoverClass="popover-image-info" autoClose="outside" placement="right" |
16 | > | 16 | > |
17 | <my-global-icon iconName="edit"></my-global-icon> | 17 | <my-global-icon iconName="edit"></my-global-icon> |
18 | <label class="sr-only" for="avatarMenu" i18n>Change your avatar</label> | 18 | <label class="visually-hidden" for="avatarMenu" i18n>Change your avatar</label> |
19 | </div> | 19 | </div> |
20 | 20 | ||
21 | </div> | 21 | </div> |
diff --git a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss index cc5e36a32..a50a2bb0e 100644 --- a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss | |||
@@ -3,37 +3,37 @@ | |||
3 | 3 | ||
4 | .actor { | 4 | .actor { |
5 | display: flex; | 5 | display: flex; |
6 | } | ||
6 | 7 | ||
7 | my-actor-avatar { | 8 | my-actor-avatar { |
8 | @include margin-right(15px); | 9 | @include margin-right(15px); |
9 | } | 10 | } |
11 | |||
12 | .actor-info { | ||
13 | display: inline-flex; | ||
14 | flex-direction: column; | ||
15 | } | ||
16 | |||
17 | .actor-info-display-name { | ||
18 | font-size: 20px; | ||
19 | font-weight: $font-bold; | ||
10 | 20 | ||
11 | .actor-info { | 21 | @media screen and (max-width: $small-view) { |
12 | display: inline-flex; | 22 | font-size: 16px; |
13 | flex-direction: column; | ||
14 | |||
15 | .actor-info-display-name { | ||
16 | font-size: 20px; | ||
17 | font-weight: $font-bold; | ||
18 | |||
19 | @media screen and (max-width: $small-view) { | ||
20 | font-size: 16px; | ||
21 | } | ||
22 | } | ||
23 | |||
24 | .actor-info-username { | ||
25 | position: relative; | ||
26 | font-size: 14px; | ||
27 | color: pvar(--greyForegroundColor); | ||
28 | } | ||
29 | |||
30 | .actor-info-followers { | ||
31 | font-size: 15px; | ||
32 | padding-bottom: .5rem; | ||
33 | } | ||
34 | } | 23 | } |
35 | } | 24 | } |
36 | 25 | ||
26 | .actor-info-username { | ||
27 | position: relative; | ||
28 | font-size: 14px; | ||
29 | color: pvar(--greyForegroundColor); | ||
30 | } | ||
31 | |||
32 | .actor-info-followers { | ||
33 | font-size: 15px; | ||
34 | padding-bottom: .5rem; | ||
35 | } | ||
36 | |||
37 | .actor-img-edit-container { | 37 | .actor-img-edit-container { |
38 | position: relative; | 38 | position: relative; |
39 | width: 0; | 39 | width: 0; |
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts index 0e4d5fb12..7d3498d4c 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts | |||
@@ -7,7 +7,7 @@ import { MiniatureDisplayOptions } from '../../shared-video-miniature' | |||
7 | import { CustomMarkupComponent } from './shared' | 7 | import { CustomMarkupComponent } from './shared' |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * Markup component list videos depending on criterias | 10 | * Markup component list videos depending on criteria |
11 | */ | 11 | */ |
12 | 12 | ||
13 | @Component({ | 13 | @Component({ |
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 index 7031cb53b..1d6b3df7e 100644 --- a/client/src/app/shared/shared-forms/advanced-input-filter.component.html +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.html | |||
@@ -1,6 +1,7 @@ | |||
1 | <div class="input-group has-feedback has-clear"> | 1 | <div class="input-group has-clear" ngbDropdown placement="bottom-left auto" container="body"> |
2 | <div *ngIf="hasFilters()" class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | 2 | |
3 | <div class="input-group-text" ngbDropdownToggle> | 3 | <ng-container *ngIf="hasFilters()"> |
4 | <div class="input-group-text c-hand" ngbDropdownToggle> | ||
4 | <span class="caret" aria-haspopup="menu" role="button"></span> | 5 | <span class="caret" aria-haspopup="menu" role="button"></span> |
5 | </div> | 6 | </div> |
6 | 7 | ||
@@ -15,14 +16,14 @@ | |||
15 | </button> | 16 | </button> |
16 | </ng-container> | 17 | </ng-container> |
17 | </div> | 18 | </div> |
18 | </div> | 19 | </ng-container> |
19 | 20 | ||
20 | <input | 21 | <input |
21 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | 22 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." |
23 | class="last-in-group" | ||
22 | [(ngModel)]="searchValue" | 24 | [(ngModel)]="searchValue" |
23 | (keyup)="onInputSearch($event)" | 25 | (keyup)="onInputSearch($event)" |
24 | > | 26 | > |
25 | 27 | ||
26 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="onResetTableFilter()"></a> | 28 | <a class="glyphicon glyphicon-remove-sign form-control-clear" title="Clear filter" i18n-title (click)="onResetTableFilter()"></a> |
27 | <span class="sr-only" i18n>Clear filters</span> | ||
28 | </div> | 29 | </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 index ee1b3b508..ed85385fd 100644 --- a/client/src/app/shared/shared-forms/advanced-input-filter.component.scss +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.scss | |||
@@ -23,7 +23,6 @@ my-global-icon { | |||
23 | width: 18px; | 23 | width: 18px; |
24 | height: 18px; | 24 | height: 18px; |
25 | 25 | ||
26 | |||
27 | &.no-visible { | 26 | &.no-visible { |
28 | @include margin-right($size + $margin); | 27 | @include margin-right($size + $margin); |
29 | 28 | ||
diff --git a/client/src/app/shared/shared-forms/input-switch.component.html b/client/src/app/shared/shared-forms/input-switch.component.html index ce1dee470..9a466055a 100644 --- a/client/src/app/shared/shared-forms/input-switch.component.html +++ b/client/src/app/shared/shared-forms/input-switch.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div (click)="update()"> | 1 | <div (click)="update()"> |
2 | <input type="checkbox" [checked]="checked"/> | 2 | <input type="checkbox" [checked]="checked"/> |
3 | <label class="ml-auto">Toggle</label> | 3 | <label class="ms-auto">Toggle</label> |
4 | </div> | 4 | </div> |
diff --git a/client/src/app/shared/shared-forms/input-toggle-hidden.component.html b/client/src/app/shared/shared-forms/input-toggle-hidden.component.html index dfe646d2f..e5edb6c97 100644 --- a/client/src/app/shared/shared-forms/input-toggle-hidden.component.html +++ b/client/src/app/shared/shared-forms/input-toggle-hidden.component.html | |||
@@ -1,21 +1,19 @@ | |||
1 | <div class="input-group input-group-sm"> | 1 | <div class="input-group"> |
2 | <input | 2 | <input |
3 | [id]="inputId" [autocomplete]="autocomplete" [value]="value" [placeholder]="placeholder" [tabindex]="tabindex" | 3 | [id]="inputId" [autocomplete]="autocomplete" [value]="value" [placeholder]="placeholder" [tabindex]="tabindex" |
4 | [(ngModel)]="value" (ngModelChange)="update()" [readonly]="readonly" | 4 | [(ngModel)]="value" (ngModelChange)="update()" [readonly]="readonly" |
5 | #input (click)="input.select()" (input)="update()" (change)="update()" [type]="inputType" class="form-control" | 5 | #input (click)="input.select()" (input)="update()" (change)="update()" [type]="inputType" class="form-control" |
6 | /> | 6 | /> |
7 | 7 | ||
8 | <div *ngIf="withToggle || withCopy" class="input-group-append"> | 8 | <button *ngIf="withToggle" (click)="toggle()" type="button" class="btn btn-outline-secondary eye-button" [title]="toggleTitle"> |
9 | <button *ngIf="withToggle" (click)="toggle()" type="button" class="btn btn-outline-secondary eye-button" [title]="toggleTitle"> | 9 | <span class="glyphicon glyphicon-eye-{{ show ? 'open' : 'close' }}"></span> |
10 | <span class="glyphicon glyphicon-eye-{{ show ? 'open' : 'close' }}"></span> | 10 | </button> |
11 | </button> | ||
12 | 11 | ||
13 | <button | 12 | <button |
14 | *ngIf="withCopy" [cdkCopyToClipboard]="input.value" (click)="activateCopiedMessage()" type="button" | 13 | *ngIf="withCopy" [cdkCopyToClipboard]="input.value" (click)="activateCopiedMessage()" type="button" |
15 | class="btn btn-outline-secondary text-uppercase" i18n-title title="Copy" | 14 | class="btn btn-outline-secondary text-uppercase" i18n-title title="Copy" |
16 | > | 15 | > |
17 | <span class="glyphicon glyphicon-duplicate"></span> | 16 | <span class="glyphicon glyphicon-duplicate"></span> |
18 | Copy | 17 | <span class="copy-text">Copy</span> |
19 | </button> | 18 | </button> |
20 | </div> | ||
21 | </div> | 19 | </div> |
diff --git a/client/src/app/shared/shared-forms/input-toggle-hidden.component.scss b/client/src/app/shared/shared-forms/input-toggle-hidden.component.scss index ef4236ebc..02a8d7d0e 100644 --- a/client/src/app/shared/shared-forms/input-toggle-hidden.component.scss +++ b/client/src/app/shared/shared-forms/input-toggle-hidden.component.scss | |||
@@ -5,11 +5,14 @@ input { | |||
5 | @include peertube-input-text(auto); | 5 | @include peertube-input-text(auto); |
6 | @include padding-left(15px !important); | 6 | @include padding-left(15px !important); |
7 | @include padding-right(15px !important); | 7 | @include padding-right(15px !important); |
8 | } | ||
8 | 9 | ||
9 | // set again properties of peertube-input-text that are overriden by .input-group | 10 | .btn { |
10 | font-size: 15px !important; | 11 | font-size: 15px; |
11 | } | 12 | } |
12 | 13 | ||
13 | .eye-button { | 14 | .copy-text { |
14 | line-height: 1 !important; | 15 | font-size: 14px; |
16 | margin-left: 5px; | ||
17 | vertical-align: top; | ||
15 | } | 18 | } |
diff --git a/client/src/app/shared/shared-forms/peertube-checkbox.component.html b/client/src/app/shared/shared-forms/peertube-checkbox.component.html index c679e1403..38a48a2a5 100644 --- a/client/src/app/shared/shared-forms/peertube-checkbox.component.html +++ b/client/src/app/shared/shared-forms/peertube-checkbox.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div class="root flex-column"> | 1 | <div class="root flex-column"> |
2 | <div class="d-flex"> | 2 | <div class="d-flex"> |
3 | <label class="form-group-checkbox"> | 3 | <label> |
4 | <input | 4 | <input |
5 | type="checkbox" | 5 | type="checkbox" |
6 | [(ngModel)]="checked" | 6 | [(ngModel)]="checked" |
@@ -33,7 +33,7 @@ | |||
33 | <div *ngIf="recommended" class="recommended" i18n>Recommended</div> | 33 | <div *ngIf="recommended" class="recommended" i18n>Recommended</div> |
34 | </div> | 34 | </div> |
35 | 35 | ||
36 | <div class="ml-4 d-flex flex-column"> | 36 | <div class="ms-4 d-flex flex-column"> |
37 | <small class="wrapper mt-2 muted"> | 37 | <small class="wrapper mt-2 muted"> |
38 | <ng-content select="description"></ng-content> | 38 | <ng-content select="description"></ng-content> |
39 | </small> | 39 | </small> |
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 4e384e7e0..5fe20c3a5 100644 --- a/client/src/app/shared/shared-forms/peertube-checkbox.component.scss +++ b/client/src/app/shared/shared-forms/peertube-checkbox.component.scss | |||
@@ -4,7 +4,7 @@ | |||
4 | .root { | 4 | .root { |
5 | display: flex; | 5 | display: flex; |
6 | 6 | ||
7 | .form-group-checkbox { | 7 | label { |
8 | display: flex; | 8 | display: flex; |
9 | align-items: center; | 9 | align-items: center; |
10 | 10 | ||
diff --git a/client/src/app/shared/shared-forms/reactive-file.component.ts b/client/src/app/shared/shared-forms/reactive-file.component.ts index 50b7d4c3e..48055a51c 100644 --- a/client/src/app/shared/shared-forms/reactive-file.component.ts +++ b/client/src/app/shared/shared-forms/reactive-file.component.ts | |||
@@ -57,7 +57,7 @@ export class ReactiveFileComponent implements OnInit, ControlValueAccessor { | |||
57 | 57 | ||
58 | const extension = '.' + file.name.split('.').pop() | 58 | const extension = '.' + file.name.split('.').pop() |
59 | if (this.extensions.includes(extension.toLowerCase()) === false) { | 59 | if (this.extensions.includes(extension.toLowerCase()) === false) { |
60 | const message = $localize`PeerTube cannot handle this kind of file. Accepted extensions are ${this.allowedExtensionsMessage}}.` | 60 | const message = $localize`PeerTube cannot handle this kind of file. Accepted extensions are ${this.allowedExtensionsMessage}.` |
61 | this.notifier.error(message) | 61 | this.notifier.error(message) |
62 | 62 | ||
63 | return | 63 | return |
diff --git a/client/src/app/shared/shared-forms/select/select-channel.component.html b/client/src/app/shared/shared-forms/select/select-channel.component.html index f83f17a16..b49fd36fa 100644 --- a/client/src/app/shared/shared-forms/select/select-channel.component.html +++ b/client/src/app/shared/shared-forms/select/select-channel.component.html | |||
@@ -7,7 +7,7 @@ | |||
7 | [searchable]="searchable" | 7 | [searchable]="searchable" |
8 | > | 8 | > |
9 | <ng-option *ngFor="let channel of channels" [value]="channel.id"> | 9 | <ng-option *ngFor="let channel of channels" [value]="channel.id"> |
10 | <img alt="" class="avatar mr-1" [src]="channel.avatarPath" /> | 10 | <img alt="" class="avatar me-1" [src]="channel.avatarPath" /> |
11 | {{ channel.label }} | 11 | {{ channel.label }} |
12 | </ng-option> | 12 | </ng-option> |
13 | </ng-select> | 13 | </ng-select> |
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts b/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts index ebf7b77a6..2c3226f68 100644 --- a/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts +++ b/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Component, forwardRef, Input } from '@angular/core' | 1 | import { Component, forwardRef, Input } from '@angular/core' |
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' |
3 | import { Notifier } from '@app/core' | 3 | import { Notifier } from '@app/core' |
4 | import { prepareIcu } from '@app/helpers' | ||
4 | import { SelectOptionsItem } from '../../../../types/select-options-item.model' | 5 | import { SelectOptionsItem } from '../../../../types/select-options-item.model' |
5 | import { ItemSelectCheckboxValue } from './select-checkbox.component' | 6 | import { ItemSelectCheckboxValue } from './select-checkbox.component' |
6 | 7 | ||
@@ -78,7 +79,12 @@ export class SelectCheckboxAllComponent implements ControlValueAccessor { | |||
78 | if (!outputItems) return true | 79 | if (!outputItems) return true |
79 | 80 | ||
80 | if (outputItems.length >= this.maxItems) { | 81 | if (outputItems.length >= this.maxItems) { |
81 | this.notifier.error($localize`You can't select more than ${this.maxItems} items`) | 82 | this.notifier.error( |
83 | prepareIcu($localize`You can't select more than {maxItems, plural, =1 {1 item} other {{maxItems} items}}`)( | ||
84 | { maxItems: this.maxItems }, | ||
85 | $localize`You can't select more than ${this.maxItems} items` | ||
86 | ) | ||
87 | ) | ||
82 | 88 | ||
83 | return false | 89 | return false |
84 | } | 90 | } |
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.html b/client/src/app/shared/shared-forms/select/select-checkbox.component.html index 03db2875b..2799ccdcc 100644 --- a/client/src/app/shared/shared-forms/select/select-checkbox.component.html +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.html | |||
@@ -22,7 +22,7 @@ | |||
22 | > | 22 | > |
23 | 23 | ||
24 | <ng-template ng-optgroup-tmp let-item="item" let-item$="item$" let-index="index"> | 24 | <ng-template ng-optgroup-tmp let-item="item" let-item$="item$" let-index="index"> |
25 | <div class="form-group-checkbox"> | 25 | <div class="checkbox-wrapper"> |
26 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> | 26 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> |
27 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> | 27 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> |
28 | <span>{{ item.group }}</span> | 28 | <span>{{ item.group }}</span> |
@@ -30,7 +30,7 @@ | |||
30 | </ng-template> | 30 | </ng-template> |
31 | 31 | ||
32 | <ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index"> | 32 | <ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index"> |
33 | <div class="form-group-checkbox"> | 33 | <div class="checkbox-wrapper"> |
34 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> | 34 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> |
35 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> | 35 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> |
36 | <span>{{ item.label }}</span> | 36 | <span>{{ item.label }}</span> |
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.scss b/client/src/app/shared/shared-forms/select/select-checkbox.component.scss index d47c4f9da..892f22dff 100644 --- a/client/src/app/shared/shared-forms/select/select-checkbox.component.scss +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.scss | |||
@@ -7,7 +7,7 @@ ng-select ::ng-deep { | |||
7 | align-items: center; | 7 | align-items: center; |
8 | } | 8 | } |
9 | 9 | ||
10 | .form-group-checkbox { | 10 | .checkbox-wrapper { |
11 | display: flex; | 11 | display: flex; |
12 | align-items: center; | 12 | align-items: center; |
13 | 13 | ||
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 be6099a97..8e5dfb064 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 | |||
@@ -16,26 +16,3 @@ | |||
16 | font-size: 15px; | 16 | font-size: 15px; |
17 | margin-bottom: 15px; | 17 | margin-bottom: 15px; |
18 | } | 18 | } |
19 | |||
20 | ngb-accordion ::ng-deep { | ||
21 | .card { | ||
22 | border-color: var(--mainBackgroundColor); | ||
23 | |||
24 | .card-header { | ||
25 | background-color: unset; | ||
26 | padding: 0; | ||
27 | |||
28 | + .collapse.show { | ||
29 | background-color: var(--submenuBackgroundColor); | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | .btn { | ||
35 | @include peertube-button; | ||
36 | @include grey-button; | ||
37 | |||
38 | border-radius: unset; | ||
39 | width: 100%; | ||
40 | } | ||
41 | } | ||
diff --git a/client/src/app/shared/shared-instance/instance-features-table.component.html b/client/src/app/shared/shared-instance/instance-features-table.component.html index 1fdef95ff..761243bfe 100644 --- a/client/src/app/shared/shared-instance/instance-features-table.component.html +++ b/client/src/app/shared/shared-instance/instance-features-table.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <div *ngIf="serverConfig" class="feature-table"> | 1 | <div *ngIf="serverConfig" class="feature-table"> |
2 | 2 | ||
3 | <table class="table" *ngIf="serverConfig"> | 3 | <table *ngIf="serverConfig"> |
4 | <caption i18n>Features found on this instance</caption> | 4 | <caption i18n>Features found on this instance</caption> |
5 | <tr> | 5 | <tr> |
6 | <th i18n class="label" scope="row">PeerTube version</th> | 6 | <th i18n class="label" scope="row">PeerTube version</th> |
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 56ca105f4..105a7681f 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 | |||
@@ -4,6 +4,7 @@ | |||
4 | table { | 4 | table { |
5 | font-size: 14px; | 5 | font-size: 14px; |
6 | color: pvar(--mainForegroundColor); | 6 | color: pvar(--mainForegroundColor); |
7 | width: 100%; | ||
7 | 8 | ||
8 | .label, | 9 | .label, |
9 | .sub-label { | 10 | .sub-label { |
@@ -24,8 +25,10 @@ table { | |||
24 | } | 25 | } |
25 | } | 26 | } |
26 | 27 | ||
28 | th, | ||
27 | td { | 29 | td { |
28 | vertical-align: middle; | 30 | padding: 0.75rem; |
31 | border-top: 1px solid #dee2e6; | ||
29 | } | 32 | } |
30 | 33 | ||
31 | caption { | 34 | caption { |
diff --git a/client/src/app/shared/shared-instance/instance-features-table.component.ts b/client/src/app/shared/shared-instance/instance-features-table.component.ts index 6335de450..e405c5790 100644 --- a/client/src/app/shared/shared-instance/instance-features-table.component.ts +++ b/client/src/app/shared/shared-instance/instance-features-table.component.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { ServerService } from '@app/core' | 2 | import { ServerService } from '@app/core' |
3 | import { prepareIcu } from '@app/helpers' | ||
3 | import { ServerConfig } from '@shared/models' | 4 | import { ServerConfig } from '@shared/models' |
4 | import { PeertubeModalService } from '../shared-main/peertube-modal/peertube-modal.service' | 5 | import { PeertubeModalService } from '../shared-main/peertube-modal/peertube-modal.service' |
5 | 6 | ||
@@ -65,15 +66,20 @@ export class InstanceFeaturesTableComponent implements OnInit { | |||
65 | 66 | ||
66 | private getApproximateTime (seconds: number) { | 67 | private getApproximateTime (seconds: number) { |
67 | const hours = Math.floor(seconds / 3600) | 68 | const hours = Math.floor(seconds / 3600) |
68 | let pluralSuffix = '' | ||
69 | if (hours > 1) pluralSuffix = 's' | ||
70 | if (hours > 0) return `~ ${hours} hour${pluralSuffix}` | ||
71 | 69 | ||
72 | const minutes = Math.floor(seconds % 3600 / 60) | 70 | if (hours !== 0) { |
71 | return prepareIcu($localize`~ {hours, plural, =1 {1 hour} other {{hours} hours}}`)( | ||
72 | { hours }, | ||
73 | $localize`~ ${hours} hours` | ||
74 | ) | ||
75 | } | ||
73 | 76 | ||
74 | if (minutes === 1) return $localize`~ 1 minute` | 77 | const minutes = Math.floor(seconds % 3600 / 60) |
75 | 78 | ||
76 | return $localize`~ ${minutes} minutes` | 79 | return prepareIcu($localize`~ {minutes, plural, =1 {1 minute} other {{minutes} minutes}}`)( |
80 | { minutes }, | ||
81 | $localize`~ ${minutes} minutes` | ||
82 | ) | ||
77 | } | 83 | } |
78 | 84 | ||
79 | private buildQuotaHelpIndication () { | 85 | private buildQuotaHelpIndication () { |
diff --git a/client/src/app/shared/shared-main/angular/from-now.pipe.ts b/client/src/app/shared/shared-main/angular/from-now.pipe.ts index d62c1f88e..dc6a25e83 100644 --- a/client/src/app/shared/shared-main/angular/from-now.pipe.ts +++ b/client/src/app/shared/shared-main/angular/from-now.pipe.ts | |||
@@ -1,37 +1,51 @@ | |||
1 | import { Pipe, PipeTransform } from '@angular/core' | 1 | import { Pipe, PipeTransform } from '@angular/core' |
2 | import { prepareIcu } from '@app/helpers' | ||
2 | 3 | ||
3 | // Thanks: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site | 4 | // Thanks: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site |
4 | @Pipe({ name: 'myFromNow' }) | 5 | @Pipe({ name: 'myFromNow' }) |
5 | export class FromNowPipe implements PipeTransform { | 6 | export class FromNowPipe implements PipeTransform { |
7 | private yearICU = prepareIcu($localize`{interval, plural, =1 {1 year ago} other {{interval} years ago}}`) | ||
8 | private monthICU = prepareIcu($localize`{interval, plural, =1 {1 month ago} other {{interval} months ago}}`) | ||
9 | private weekICU = prepareIcu($localize`{interval, plural, =1 {1 week ago} other {{interval} weeks ago}}`) | ||
10 | private dayICU = prepareIcu($localize`{interval, plural, =1 {1 day ago} other {{interval} days ago}}`) | ||
11 | private hourICU = prepareIcu($localize`{interval, plural, =1 {1 hour ago} other {{interval} hours ago}}`) | ||
12 | |||
6 | transform (arg: number | Date | string) { | 13 | transform (arg: number | Date | string) { |
7 | const argDate = new Date(arg) | 14 | const argDate = new Date(arg) |
8 | const seconds = Math.floor((Date.now() - argDate.getTime()) / 1000) | 15 | const seconds = Math.floor((Date.now() - argDate.getTime()) / 1000) |
9 | 16 | ||
10 | let interval = Math.floor(seconds / 31536000) | 17 | let interval = Math.floor(seconds / 31536000) |
11 | if (interval > 1) return $localize`${interval} years ago` | 18 | if (interval >= 1) { |
12 | if (interval === 1) return $localize`1 year ago` | 19 | return this.yearICU({ interval }, $localize`${interval} year(s) ago`) |
20 | } | ||
13 | 21 | ||
14 | interval = Math.floor(seconds / 2419200) | 22 | interval = Math.floor(seconds / 2419200) |
15 | // 12 months = 360 days, but a year ~ 365 days | 23 | // 12 months = 360 days, but a year ~ 365 days |
16 | // Display "1 year ago" rather than "12 months ago" | 24 | // Display "1 year ago" rather than "12 months ago" |
17 | if (interval >= 12) return $localize`1 year ago` | 25 | if (interval >= 12) return $localize`1 year ago` |
18 | if (interval > 1) return $localize`${interval} months ago` | 26 | |
19 | if (interval === 1) return $localize`1 month ago` | 27 | if (interval >= 1) { |
28 | return this.monthICU({ interval }, $localize`${interval} month(s) ago`) | ||
29 | } | ||
20 | 30 | ||
21 | interval = Math.floor(seconds / 604800) | 31 | interval = Math.floor(seconds / 604800) |
22 | // 4 weeks ~ 28 days, but our month is 30 days | 32 | // 4 weeks ~ 28 days, but our month is 30 days |
23 | // Display "1 month ago" rather than "4 weeks ago" | 33 | // Display "1 month ago" rather than "4 weeks ago" |
24 | if (interval >= 4) return $localize`1 month ago` | 34 | if (interval >= 4) return $localize`1 month ago` |
25 | if (interval > 1) return $localize`${interval} weeks ago` | 35 | |
26 | if (interval === 1) return $localize`1 week ago` | 36 | if (interval >= 1) { |
37 | return this.weekICU({ interval }, $localize`${interval} week(s) ago`) | ||
38 | } | ||
27 | 39 | ||
28 | interval = Math.floor(seconds / 86400) | 40 | interval = Math.floor(seconds / 86400) |
29 | if (interval > 1) return $localize`${interval} days ago` | 41 | if (interval >= 1) { |
30 | if (interval === 1) return $localize`1 day ago` | 42 | return this.dayICU({ interval }, $localize`${interval} day(s) ago`) |
43 | } | ||
31 | 44 | ||
32 | interval = Math.floor(seconds / 3600) | 45 | interval = Math.floor(seconds / 3600) |
33 | if (interval > 1) return $localize`${interval} hours ago` | 46 | if (interval >= 1) { |
34 | if (interval === 1) return $localize`1 hour ago` | 47 | return this.hourICU({ interval }, $localize`${interval} hour(s) ago`) |
48 | } | ||
35 | 49 | ||
36 | interval = Math.floor(seconds / 60) | 50 | interval = Math.floor(seconds / 60) |
37 | if (interval >= 1) return $localize`${interval} min ago` | 51 | if (interval >= 1) return $localize`${interval} min ago` |
diff --git a/client/src/app/shared/shared-main/misc/simple-search-input.component.html b/client/src/app/shared/shared-main/misc/simple-search-input.component.html index 1e2f6c6a9..11f5a1ab0 100644 --- a/client/src/app/shared/shared-main/misc/simple-search-input.component.html +++ b/client/src/app/shared/shared-main/misc/simple-search-input.component.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <div class="root"> | 1 | <div class="root"> |
2 | <div class="input-group has-feedback has-clear"> | 2 | <div class="input-group has-clear"> |
3 | <input | 3 | <input |
4 | #ref | 4 | #ref |
5 | type="text" | 5 | type="text" |
@@ -10,8 +10,7 @@ | |||
10 | [placeholder]="placeholder" | 10 | [placeholder]="placeholder" |
11 | > | 11 | > |
12 | 12 | ||
13 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="onResetFilter()"></a> | 13 | <a class="glyphicon glyphicon-remove-sign form-control-clear" title="Clear filter" i18n-title (click)="onResetFilter()"></a> |
14 | <span class="sr-only" i18n>Clear filters</span> | ||
15 | </div> | 14 | </div> |
16 | 15 | ||
17 | <my-global-icon iconName="search" aria-label="Search" role="button" (click)="onIconClick()" [title]="iconTitle"></my-global-icon> | 16 | <my-global-icon iconName="search" aria-label="Search" role="button" (click)="onIconClick()" [title]="iconTitle"></my-global-icon> |
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 32376bf62..62bd94349 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 | |||
@@ -27,6 +27,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
27 | videosCount?: number | 27 | videosCount?: number |
28 | 28 | ||
29 | viewsPerDay?: ViewsPerDate[] | 29 | viewsPerDay?: ViewsPerDate[] |
30 | totalViews?: number | ||
30 | 31 | ||
31 | static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { | 32 | static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { |
32 | return Actor.GET_ACTOR_AVATAR_URL(actor, size) | 33 | return Actor.GET_ACTOR_AVATAR_URL(actor, size) |
@@ -74,6 +75,10 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
74 | this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) | 75 | this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) |
75 | } | 76 | } |
76 | 77 | ||
78 | if (hash.totalViews !== null && hash.totalViews !== undefined) { | ||
79 | this.totalViews = hash.totalViews | ||
80 | } | ||
81 | |||
77 | if (hash.ownerAccount) { | 82 | if (hash.ownerAccount) { |
78 | this.ownerAccount = hash.ownerAccount | 83 | this.ownerAccount = hash.ownerAccount |
79 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) | 84 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) |
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 022bb95ad..2e4ab87d7 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { AuthUser } from '@app/core' | 1 | import { AuthUser } from '@app/core' |
2 | import { User } from '@app/core/users/user.model' | 2 | import { User } from '@app/core/users/user.model' |
3 | import { durationToString, getAbsoluteAPIUrl, getAbsoluteEmbedUrl } from '@app/helpers' | 3 | import { durationToString, prepareIcu, getAbsoluteAPIUrl, getAbsoluteEmbedUrl } from '@app/helpers' |
4 | import { Actor } from '@app/shared/shared-main/account/actor.model' | 4 | import { Actor } from '@app/shared/shared-main/account/actor.model' |
5 | import { buildVideoWatchPath } from '@shared/core-utils' | 5 | import { buildVideoWatchPath } from '@shared/core-utils' |
6 | import { peertubeTranslate } from '@shared/core-utils/i18n' | 6 | import { peertubeTranslate } from '@shared/core-utils/i18n' |
@@ -19,6 +19,9 @@ import { | |||
19 | } from '@shared/models' | 19 | } from '@shared/models' |
20 | 20 | ||
21 | export class Video implements VideoServerModel { | 21 | export class Video implements VideoServerModel { |
22 | private static readonly viewsICU = prepareIcu($localize`{views, plural, =0 {No view} =1 {1 view} other {{views} views}}`) | ||
23 | private static readonly viewersICU = prepareIcu($localize`{viewers, plural, =0 {No viewers} =1 {1 viewer} other {{viewers} viewers}}`) | ||
24 | |||
22 | byVideoChannel: string | 25 | byVideoChannel: string |
23 | byAccount: string | 26 | byAccount: string |
24 | 27 | ||
@@ -269,12 +272,10 @@ export class Video implements VideoServerModel { | |||
269 | } | 272 | } |
270 | 273 | ||
271 | getExactNumberOfViews () { | 274 | getExactNumberOfViews () { |
272 | if (this.views < 1000) return '' | ||
273 | |||
274 | if (this.isLive) { | 275 | if (this.isLive) { |
275 | return $localize`${this.views} viewers` | 276 | return Video.viewersICU({ viewers: this.viewers }, $localize`${this.viewers} viewer(s)`) |
276 | } | 277 | } |
277 | 278 | ||
278 | return $localize`${this.views} views` | 279 | return Video.viewsICU({ views: this.views }, $localize`{${this.views} view(s)}`) |
279 | } | 280 | } |
280 | } | 281 | } |
diff --git a/client/src/app/shared/shared-moderation/account-block-badges.component.html b/client/src/app/shared/shared-moderation/account-block-badges.component.html index feac707c2..fd3709676 100644 --- a/client/src/app/shared/shared-moderation/account-block-badges.component.html +++ b/client/src/app/shared/shared-moderation/account-block-badges.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <span *ngIf="account.mutedByUser" class="badge badge-danger" i18n>Muted</span> | 1 | <span *ngIf="account.mutedByUser" class="pt-badge badge-danger" i18n>Muted</span> |
2 | <span *ngIf="account.mutedServerByUser" class="badge badge-danger" i18n>Instance muted</span> | 2 | <span *ngIf="account.mutedServerByUser" class="pt-badge badge-danger" i18n>Instance muted</span> |
3 | <span *ngIf="account.mutedByInstance" class="badge badge-danger" i18n>Muted by your instance</span> | 3 | <span *ngIf="account.mutedByInstance" class="pt-badge badge-danger" i18n>Muted by your instance</span> |
4 | <span *ngIf="account.mutedServerByInstance" class="badge badge-danger" i18n>Instance muted by your instance</span> | 4 | <span *ngIf="account.mutedServerByInstance" class="pt-badge badge-danger" i18n>Instance muted by your instance</span> |
diff --git a/client/src/app/shared/shared-moderation/account-block-badges.component.scss b/client/src/app/shared/shared-moderation/account-block-badges.component.scss index ccc3666aa..301d8305e 100644 --- a/client/src/app/shared/shared-moderation/account-block-badges.component.scss +++ b/client/src/app/shared/shared-moderation/account-block-badges.component.scss | |||
@@ -1,9 +1,8 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | 3 | ||
4 | .badge { | 4 | .pt-badge { |
5 | @include margin-right(10px); | 5 | @include margin-right(10px); |
6 | 6 | ||
7 | height: fit-content; | ||
8 | font-size: 12px; | 7 | font-size: 12px; |
9 | } | 8 | } |
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 a4f81d824..15632f654 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.html +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.html | |||
@@ -11,7 +11,7 @@ | |||
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"> | 14 | <div class="ms-auto"> |
15 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 15 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
16 | </div> | 16 | </div> |
17 | </div> | 17 | </div> |
diff --git a/client/src/app/shared/shared-moderation/report-modals/report.component.html b/client/src/app/shared/shared-moderation/report-modals/report.component.html index 6c99180ef..8e0b0993c 100644 --- a/client/src/app/shared/shared-moderation/report-modals/report.component.html +++ b/client/src/app/shared/shared-moderation/report-modals/report.component.html | |||
@@ -8,11 +8,11 @@ | |||
8 | <form novalidate [formGroup]="form" (ngSubmit)="report()"> | 8 | <form novalidate [formGroup]="form" (ngSubmit)="report()"> |
9 | 9 | ||
10 | <div class="row"> | 10 | <div class="row"> |
11 | <div class="col-5 form-group"> | 11 | <div class="col-5"> |
12 | 12 | ||
13 | <label i18n for="reportPredefinedReasons">What is the issue?</label> | 13 | <label i18n for="reportPredefinedReasons">What is the issue?</label> |
14 | 14 | ||
15 | <div class="ml-2 mt-2 d-flex flex-column"> | 15 | <div class="ms-2 mt-2 d-flex flex-column"> |
16 | <ng-container formGroupName="predefinedReasons"> | 16 | <ng-container formGroupName="predefinedReasons"> |
17 | 17 | ||
18 | <div class="form-group" *ngFor="let reason of predefinedReasons"> | 18 | <div class="form-group" *ngFor="let reason of predefinedReasons"> |
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | </ng-container> | 30 | </ng-container> |
31 | </div> | 31 | </div> |
32 | |||
33 | </div> | 32 | </div> |
34 | 33 | ||
35 | <div class="col-7"> | 34 | <div class="col-7"> |
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.html b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html index afac108fc..51ca0b9d6 100644 --- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.html +++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html | |||
@@ -8,38 +8,32 @@ | |||
8 | <form novalidate [formGroup]="form" (ngSubmit)="report()"> | 8 | <form novalidate [formGroup]="form" (ngSubmit)="report()"> |
9 | 9 | ||
10 | <div class="row"> | 10 | <div class="row"> |
11 | <div class="col-5 form-group"> | 11 | <div class="col-12 col-md-5"> |
12 | <label i18n for="reportPredefinedReasons">What is the issue?</label> | ||
12 | 13 | ||
13 | <label i18n for="reportPredefinedReasons">What is the issue?</label> | 14 | <div class="ms-2 mt-2 d-flex flex-column"> |
15 | <ng-container formGroupName="predefinedReasons"> | ||
14 | 16 | ||
15 | <div class="ml-2 mt-2 d-flex flex-column"> | 17 | <div class="form-group" *ngFor="let reason of predefinedReasons"> |
16 | <ng-container formGroupName="predefinedReasons"> | 18 | <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label"> |
19 | <ng-template *ngIf="reason.help" ptTemplate="help"> | ||
20 | <div [innerHTML]="reason.help"></div> | ||
21 | </ng-template> | ||
17 | 22 | ||
18 | <div class="form-group" *ngFor="let reason of predefinedReasons"> | 23 | <ng-container *ngIf="reason.description" ngProjectAs="description"> |
19 | <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label"> | 24 | <div [innerHTML]="reason.description"></div> |
20 | <ng-template *ngIf="reason.help" ptTemplate="help"> | 25 | </ng-container> |
21 | <div [innerHTML]="reason.help"></div> | 26 | </my-peertube-checkbox> |
22 | </ng-template> | 27 | </div> |
23 | |||
24 | <ng-container *ngIf="reason.description" ngProjectAs="description"> | ||
25 | <div [innerHTML]="reason.description"></div> | ||
26 | </ng-container> | ||
27 | </my-peertube-checkbox> | ||
28 | </div> | ||
29 | |||
30 | </ng-container> | ||
31 | </div> | ||
32 | 28 | ||
29 | </ng-container> | ||
30 | </div> | ||
33 | </div> | 31 | </div> |
34 | 32 | ||
35 | <div class="col-7"> | 33 | <div class="col-12 col-md-7"> |
36 | <div class="row justify-content-center"> | 34 | <my-embed [video]="video"></my-embed> |
37 | <div class="col-12 col-lg-9 mb-2"> | ||
38 | <my-embed [video]="video"></my-embed> | ||
39 | </div> | ||
40 | </div> | ||
41 | 35 | ||
42 | <div class="mb-1 start-at" formGroupName="timestamp"> | 36 | <div class="mb-1 mt-3 start-at" formGroupName="timestamp"> |
43 | <my-peertube-checkbox | 37 | <my-peertube-checkbox |
44 | formControlName="hasStart" | 38 | formControlName="hasStart" |
45 | i18n-labelText labelText="Start at" | 39 | i18n-labelText labelText="Start at" |
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 1a320e9a4..ba4336e2e 100644 --- a/client/src/app/shared/shared-moderation/server-blocklist.component.html +++ b/client/src/app/shared/shared-moderation/server-blocklist.component.html | |||
@@ -19,7 +19,7 @@ | |||
19 | </a> | 19 | </a> |
20 | </div> | 20 | </div> |
21 | 21 | ||
22 | <div class="ml-auto"> | 22 | <div class="ms-auto"> |
23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 23 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
24 | </div> | 24 | </div> |
25 | </div> | 25 | </div> |
diff --git a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts index 9edfac388..8b483499a 100644 --- a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts +++ b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { forkJoin } from 'rxjs' | 1 | import { forkJoin } from 'rxjs' |
2 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | 2 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' |
3 | import { Notifier } from '@app/core' | 3 | import { Notifier } from '@app/core' |
4 | import { prepareIcu } from '@app/helpers' | ||
4 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' |
5 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
6 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | 7 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' |
@@ -63,9 +64,16 @@ export class UserBanModalComponent extends FormReactive implements OnInit { | |||
63 | forkJoin(observables) | 64 | forkJoin(observables) |
64 | .subscribe({ | 65 | .subscribe({ |
65 | next: () => { | 66 | next: () => { |
66 | const message = Array.isArray(this.usersToBan) | 67 | let message: string |
67 | ? $localize`${this.usersToBan.length} users banned.` | 68 | |
68 | : $localize`User ${this.usersToBan.username} banned.` | 69 | if (Array.isArray(this.usersToBan)) { |
70 | message = prepareIcu($localize`{count, plural, =1 {1 user} other {{count} users}} banned.`)( | ||
71 | { count: this.usersToBan.length }, | ||
72 | $localize`${this.usersToBan.length} users banned.` | ||
73 | ) | ||
74 | } else { | ||
75 | message = $localize`User ${this.usersToBan.username} banned.` | ||
76 | } | ||
69 | 77 | ||
70 | this.notifier.success(message) | 78 | this.notifier.success(message) |
71 | 79 | ||
@@ -79,7 +87,12 @@ export class UserBanModalComponent extends FormReactive implements OnInit { | |||
79 | } | 87 | } |
80 | 88 | ||
81 | getModalTitle () { | 89 | getModalTitle () { |
82 | if (Array.isArray(this.usersToBan)) return $localize`Ban ${this.usersToBan.length} users` | 90 | if (Array.isArray(this.usersToBan)) { |
91 | return prepareIcu($localize`Ban {count, plural, =1 {1 user} other {{count} users}}`)( | ||
92 | { count: this.usersToBan.length }, | ||
93 | $localize`Ban ${this.usersToBan.length} users` | ||
94 | ) | ||
95 | } | ||
83 | 96 | ||
84 | return $localize`Ban "${this.usersToBan.username}"` | 97 | return $localize`Ban "${this.usersToBan.username}"` |
85 | } | 98 | } |
diff --git a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts index 787318c2c..c69a45c25 100644 --- a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts +++ b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts | |||
@@ -100,7 +100,8 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
100 | return | 100 | return |
101 | } | 101 | } |
102 | 102 | ||
103 | const message = $localize`If you remove user ${user.username}, you won't be able to create another with the same username!` | 103 | // eslint-disable-next-line max-len |
104 | const message = $localize`If you remove this user, you won't be able to create another user or channel with <strong>${user.username}</strong> username!` | ||
104 | const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`) | 105 | const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`) |
105 | if (res === false) return | 106 | if (res === false) return |
106 | 107 | ||
diff --git a/client/src/app/shared/shared-moderation/video-block.component.ts b/client/src/app/shared/shared-moderation/video-block.component.ts index 400913f02..e14473b89 100644 --- a/client/src/app/shared/shared-moderation/video-block.component.ts +++ b/client/src/app/shared/shared-moderation/video-block.component.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { prepareIcu } from '@app/helpers' | ||
3 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 4 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' |
4 | import { Video } from '@app/shared/shared-main' | 5 | import { Video } from '@app/shared/shared-main' |
5 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
@@ -80,9 +81,10 @@ export class VideoBlockComponent extends FormReactive implements OnInit { | |||
80 | this.videoBlocklistService.blockVideo(options) | 81 | this.videoBlocklistService.blockVideo(options) |
81 | .subscribe({ | 82 | .subscribe({ |
82 | next: () => { | 83 | next: () => { |
83 | const message = this.isMultiple | 84 | const message = prepareIcu($localize`{count, plural, =1 {Blocked {videoName}} other {Blocked {count} videos}}.`)( |
84 | ? $localize`Blocked ${this.videos.length} videos.` | 85 | { count: this.videos.length, videoName: this.getSingleVideo().name }, |
85 | : $localize`Blocked ${this.getSingleVideo().name}` | 86 | $localize`Blocked ${this.videos.length} videos.` |
87 | ) | ||
86 | 88 | ||
87 | this.notifier.success(message) | 89 | this.notifier.success(message) |
88 | this.hide() | 90 | this.hide() |
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.html b/client/src/app/shared/shared-share-modal/video-share.component.html index 67ca56516..a6b8576a1 100644 --- a/client/src/app/shared/shared-share-modal/video-share.component.html +++ b/client/src/app/shared/shared-share-modal/video-share.component.html | |||
@@ -171,9 +171,8 @@ | |||
171 | </div> | 171 | </div> |
172 | </div> | 172 | </div> |
173 | 173 | ||
174 | <div class="form-group"> | 174 | <div class="form-group" *ngIf="isInVideoEmbedTab()"> |
175 | <my-peertube-checkbox | 175 | <my-peertube-checkbox |
176 | *ngIf="isInVideoEmbedTab()" | ||
177 | inputName="onlyEmbedUrl" [(ngModel)]="customizations.onlyEmbedUrl" | 176 | inputName="onlyEmbedUrl" [(ngModel)]="customizations.onlyEmbedUrl" |
178 | i18n-labelText labelText="Only display embed URL" | 177 | i18n-labelText labelText="Only display embed URL" |
179 | ></my-peertube-checkbox> | 178 | ></my-peertube-checkbox> |
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.scss b/client/src/app/shared/shared-share-modal/video-share.component.scss index 44ebb13f4..abb78b09b 100644 --- a/client/src/app/shared/shared-share-modal/video-share.component.scss +++ b/client/src/app/shared/shared-share-modal/video-share.component.scss | |||
@@ -55,13 +55,6 @@ my-input-toggle-hidden { | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | .form-group { | ||
59 | margin-bottom: 0; | ||
60 | height: 34px; | ||
61 | display: flex; | ||
62 | align-items: center; | ||
63 | } | ||
64 | |||
65 | .video-caption-block { | 58 | .video-caption-block { |
66 | display: flex; | 59 | display: flex; |
67 | align-items: center; | 60 | align-items: center; |
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 446ade445..ccd7f8f4b 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 | |||
@@ -1,5 +1,5 @@ | |||
1 | <form role="form" (ngSubmit)="updateDetails()" [formGroup]="form"> | 1 | <form role="form" (ngSubmit)="updateDetails()" [formGroup]="form"> |
2 | <div class="form-group form-group-select"> | 2 | <div class="form-group"> |
3 | <div class="anchor" id="video-sensitive-content-policy"></div> <!-- video-sensitive-content-policy anchor --> | 3 | <div class="anchor" id="video-sensitive-content-policy"></div> <!-- video-sensitive-content-policy anchor --> |
4 | <label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label> | 4 | <label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label> |
5 | <my-help> | 5 | <my-help> |
@@ -20,7 +20,7 @@ | |||
20 | </div> | 20 | </div> |
21 | </div> | 21 | </div> |
22 | 22 | ||
23 | <div class="form-group form-group-select"> | 23 | <div class="form-group"> |
24 | <div class="anchor" id="video-languages-subtitles"></div> <!-- video-languages-subtitles anchor --> | 24 | <div class="anchor" id="video-languages-subtitles"></div> <!-- video-languages-subtitles anchor --> |
25 | <label i18n for="videoLanguages">Only display videos in the following languages/subtitles</label> | 25 | <label i18n for="videoLanguages">Only display videos in the following languages/subtitles</label> |
26 | <my-help> | 26 | <my-help> |
@@ -30,7 +30,7 @@ | |||
30 | </my-help> | 30 | </my-help> |
31 | 31 | ||
32 | <div> | 32 | <div> |
33 | <my-select-languages formControlName="videoLanguages"></my-select-languages> | 33 | <my-select-languages [maxLanguages]="20" formControlName="videoLanguages"></my-select-languages> |
34 | </div> | 34 | </div> |
35 | </div> | 35 | </div> |
36 | 36 | ||
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.scss b/client/src/app/shared/shared-user-settings/user-video-settings.component.scss index c4f6020d4..a39e7cf1f 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.scss +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.scss | |||
@@ -15,8 +15,6 @@ input[type=submit] { | |||
15 | 15 | ||
16 | .peertube-select-container { | 16 | .peertube-select-container { |
17 | @include peertube-select-container(340px); | 17 | @include peertube-select-container(340px); |
18 | |||
19 | margin-bottom: 30px; | ||
20 | } | 18 | } |
21 | 19 | ||
22 | my-select-languages { | 20 | my-select-languages { |
@@ -24,7 +22,3 @@ my-select-languages { | |||
24 | 22 | ||
25 | display: block; | 23 | display: block; |
26 | } | 24 | } |
27 | |||
28 | .form-group-select { | ||
29 | margin-bottom: 30px; | ||
30 | } | ||
diff --git a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.html b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.html index a00c3d1c7..656d1beb3 100644 --- a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.html +++ b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <form novalidate [formGroup]="form" (ngSubmit)="formValidated()"> | 1 | <form novalidate [formGroup]="form" (ngSubmit)="formValidated()"> |
2 | <div class="form-group mb-2"> | 2 | <div class="form-group"> |
3 | <input type="email" | 3 | <input type="email" |
4 | formControlName="text" | 4 | formControlName="text" |
5 | class="form-control" | 5 | class="form-control" |
diff --git a/client/src/app/shared/shared-video-live/live-stream-information.component.html b/client/src/app/shared/shared-video-live/live-stream-information.component.html index 01e305938..28396915a 100644 --- a/client/src/app/shared/shared-video-live/live-stream-information.component.html +++ b/client/src/app/shared/shared-video-live/live-stream-information.component.html | |||
@@ -7,8 +7,8 @@ | |||
7 | 7 | ||
8 | <div class="modal-body" *ngIf="live"> | 8 | <div class="modal-body" *ngIf="live"> |
9 | <div> | 9 | <div> |
10 | <div class="badge badge-info" *ngIf="live.permanentLive" i18n>Permanent/Recurring live</div> | 10 | <div class="pt-badge badge-blue" *ngIf="live.permanentLive" i18n>Permanent/Recurring live</div> |
11 | <div class="badge badge-info" *ngIf="live.saveReplay" i18n>Replay will be saved</div> | 11 | <div class="pt-badge badge-blue" *ngIf="live.saveReplay" i18n>Replay will be saved</div> |
12 | </div> | 12 | </div> |
13 | 13 | ||
14 | <div class="alert alert-info"> | 14 | <div class="alert alert-info"> |
@@ -36,8 +36,8 @@ | |||
36 | <label i18n>Latest live sessions</label> | 36 | <label i18n>Latest live sessions</label> |
37 | 37 | ||
38 | <div class="journal-session" *ngFor="let session of latestLiveSessions"> | 38 | <div class="journal-session" *ngFor="let session of latestLiveSessions"> |
39 | <span i18n class="badge badge-success" *ngIf="!getErrorLabel(session)">Success</span> | 39 | <span i18n class="pt-badge badge-success" *ngIf="!getErrorLabel(session)">Success</span> |
40 | <span class="badge badge-danger" *ngIf="getErrorLabel(session)">{{ getErrorLabel(session) }}</span> | 40 | <span class="pt-badge badge-danger" *ngIf="getErrorLabel(session)">{{ getErrorLabel(session) }}</span> |
41 | 41 | ||
42 | <span i18n>Started on {{ session.startDate | date:'medium' }}</span> | 42 | <span i18n>Started on {{ session.startDate | date:'medium' }}</span> |
43 | <span i18n *ngIf="session.endDate">Ended on {{ session.endDate | date:'medium' }}</span> | 43 | <span i18n *ngIf="session.endDate">Ended on {{ session.endDate | date:'medium' }}</span> |
diff --git a/client/src/app/shared/shared-video-live/live-stream-information.component.scss b/client/src/app/shared/shared-video-live/live-stream-information.component.scss index 9c8ad12bd..fc0b1cea2 100644 --- a/client/src/app/shared/shared-video-live/live-stream-information.component.scss +++ b/client/src/app/shared/shared-video-live/live-stream-information.component.scss | |||
@@ -13,15 +13,16 @@ p-autocomplete { | |||
13 | margin: 1rem 0; | 13 | margin: 1rem 0; |
14 | } | 14 | } |
15 | 15 | ||
16 | .badge { | 16 | .pt-badge { |
17 | @include margin-right(5px); | ||
18 | |||
17 | font-size: 13px; | 19 | font-size: 13px; |
18 | margin-right: 5px; | ||
19 | } | 20 | } |
20 | 21 | ||
21 | .journal-session { | 22 | .journal-session { |
22 | margin-bottom: 5px; | 23 | margin-bottom: 5px; |
23 | 24 | ||
24 | span:not(.badge, :last-child)::after { | 25 | span:not(.pt-badge, :last-child)::after { |
25 | margin: 3px; | 26 | margin: 3px; |
26 | content: '•'; | 27 | content: '•'; |
27 | } | 28 | } |
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.html b/client/src/app/shared/shared-video-miniature/video-download.component.html index b50544057..9123d2a5a 100644 --- a/client/src/app/shared/shared-video-miniature/video-download.component.html +++ b/client/src/app/shared/shared-video-miniature/video-download.component.html | |||
@@ -28,14 +28,15 @@ | |||
28 | 28 | ||
29 | <ng-template ngbNavContent> | 29 | <ng-template ngbNavContent> |
30 | <div class="nav-content"> | 30 | <div class="nav-content"> |
31 | <div class="input-group input-group-sm"> | 31 | <div class="input-group"> |
32 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> | 32 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getLink()" /> |
33 | 33 | ||
34 | <div class="input-group-append" *ngIf="!isConfidentialVideo()"> | 34 | <button |
35 | <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | 35 | *ngIf="!isConfidentialVideo()" type="button" class="btn btn-outline-secondary" |
36 | <span class="glyphicon glyphicon-duplicate"></span> | 36 | [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" |
37 | </button> | 37 | > |
38 | </div> | 38 | <span class="glyphicon glyphicon-duplicate"></span> |
39 | </button> | ||
39 | </div> | 40 | </div> |
40 | </div> | 41 | </div> |
41 | </ng-template> | 42 | </ng-template> |
@@ -53,13 +54,15 @@ | |||
53 | 54 | ||
54 | <ng-template ngbNavContent> | 55 | <ng-template ngbNavContent> |
55 | <div class="nav-content"> | 56 | <div class="nav-content"> |
56 | <div class="input-group input-group-sm"> | 57 | <div class="input-group"> |
57 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> | 58 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getLink()" /> |
58 | <div class="input-group-append" *ngIf="!isConfidentialVideo()"> | 59 | |
59 | <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | 60 | <button |
60 | <span class="glyphicon glyphicon-duplicate"></span> | 61 | *ngIf="!isConfidentialVideo()" type="button" class="btn btn-outline-secondary" |
61 | </button> | 62 | [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" |
62 | </div> | 63 | > |
64 | <span class="glyphicon glyphicon-duplicate"></span> | ||
65 | </button> | ||
63 | </div> | 66 | </div> |
64 | </div> | 67 | </div> |
65 | </ng-template> | 68 | </ng-template> |
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 bd42f4813..04d5eb560 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 | |||
@@ -5,6 +5,13 @@ | |||
5 | margin-top: 30px; | 5 | margin-top: 30px; |
6 | } | 6 | } |
7 | 7 | ||
8 | .input-group > input { | ||
9 | @include peertube-input-text(auto); | ||
10 | |||
11 | font-size: 14px; | ||
12 | padding: 0 5px; | ||
13 | } | ||
14 | |||
8 | .advanced-filters-button { | 15 | .advanced-filters-button { |
9 | display: flex; | 16 | display: flex; |
10 | justify-content: center; | 17 | justify-content: center; |
diff --git a/client/src/app/shared/shared-video-miniature/video-filters-header.component.html b/client/src/app/shared/shared-video-miniature/video-filters-header.component.html index a07b8b5ee..fe7a59bdb 100644 --- a/client/src/app/shared/shared-video-miniature/video-filters-header.component.html +++ b/client/src/app/shared/shared-video-miniature/video-filters-header.component.html | |||
@@ -44,6 +44,7 @@ | |||
44 | [searchable]="false" | 44 | [searchable]="false" |
45 | > | 45 | > |
46 | <ng-option i18n value="-publishedAt">Sort by <strong>"Recently Added"</strong></ng-option> | 46 | <ng-option i18n value="-publishedAt">Sort by <strong>"Recently Added"</strong></ng-option> |
47 | <ng-option i18n value="-originallyPublishedAt">Sort by <strong>"Original Publication Date"</strong></ng-option> | ||
47 | 48 | ||
48 | <ng-option i18n *ngIf="isTrendingSortEnabled('most-viewed')" value="-trending">Sort by <strong>"Recent Views"</strong></ng-option> | 49 | <ng-option i18n *ngIf="isTrendingSortEnabled('most-viewed')" value="-trending">Sort by <strong>"Recent Views"</strong></ng-option> |
49 | <ng-option i18n *ngIf="isTrendingSortEnabled('hot')" value="-hot">Sort by <strong>"Hot"</strong></ng-option> | 50 | <ng-option i18n *ngIf="isTrendingSortEnabled('hot')" value="-hot">Sort by <strong>"Hot"</strong></ng-option> |
diff --git a/client/src/app/shared/shared-video-miniature/video-filters-header.component.scss b/client/src/app/shared/shared-video-miniature/video-filters-header.component.scss index 8cb1ff5b8..6a968ed5c 100644 --- a/client/src/app/shared/shared-video-miniature/video-filters-header.component.scss +++ b/client/src/app/shared/shared-video-miniature/video-filters-header.component.scss | |||
@@ -101,7 +101,7 @@ | |||
101 | } | 101 | } |
102 | 102 | ||
103 | .sort { | 103 | .sort { |
104 | min-width: 200px; | 104 | min-width: 250px; |
105 | max-width: 300px; | 105 | max-width: 300px; |
106 | height: min-content; | 106 | height: min-content; |
107 | 107 | ||
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 42c472579..534a78b3f 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 | |||
@@ -175,7 +175,7 @@ export class VideoMiniatureComponent implements OnInit { | |||
175 | 175 | ||
176 | if (video.scheduledUpdate) { | 176 | if (video.scheduledUpdate) { |
177 | const updateAt = new Date(video.scheduledUpdate.updateAt.toString()).toLocaleString(this.localeId) | 177 | const updateAt = new Date(video.scheduledUpdate.updateAt.toString()).toLocaleString(this.localeId) |
178 | return $localize`Publication scheduled on ` + updateAt | 178 | return $localize`Publication scheduled on ${updateAt}` |
179 | } | 179 | } |
180 | 180 | ||
181 | if (video.state.id === VideoState.TRANSCODING_FAILED) { | 181 | if (video.state.id === VideoState.TRANSCODING_FAILED) { |
diff --git a/client/src/app/shared/shared-video-miniature/videos-list.component.html b/client/src/app/shared/shared-video-miniature/videos-list.component.html index 2b554517f..c220f61f1 100644 --- a/client/src/app/shared/shared-video-miniature/videos-list.component.html +++ b/client/src/app/shared/shared-video-miniature/videos-list.component.html | |||
@@ -12,15 +12,15 @@ | |||
12 | 12 | ||
13 | <div class="action-block"> | 13 | <div class="action-block"> |
14 | <ng-container *ngFor="let action of headerActions"> | 14 | <ng-container *ngFor="let action of headerActions"> |
15 | <a *ngIf="action.routerLink" class="ml-2" [routerLink]="action.routerLink" routerLinkActive="active"> | 15 | <a *ngIf="action.routerLink" class="ms-2" [routerLink]="action.routerLink" routerLinkActive="active"> |
16 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> | 16 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> |
17 | </a> | 17 | </a> |
18 | 18 | ||
19 | <a *ngIf="!action.routerLink && !action.href && action.click" class="ml-2" (click)="action.click($event)" (key.enter)="action.click($event)"> | 19 | <a *ngIf="!action.routerLink && !action.href && action.click" class="ms-2" (click)="action.click($event)" (key.enter)="action.click($event)"> |
20 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> | 20 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> |
21 | </a> | 21 | </a> |
22 | 22 | ||
23 | <a *ngIf="!action.routerLink && action.href && action.click" class="ml-2" (click)="action.click($event)" (key.enter)="action.click($event)" [href]="action.href"> | 23 | <a *ngIf="!action.routerLink && action.href && action.click" class="ms-2" (click)="action.click($event)" (key.enter)="action.click($event)" [href]="action.href"> |
24 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> | 24 | <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container> |
25 | </a> | 25 | </a> |
26 | 26 | ||
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.html b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.html index 2400a4c25..f58d5f7f6 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.html +++ b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | [attr.title]="playlistElement.video.name" | 21 | [attr.title]="playlistElement.video.name" |
22 | >{{ playlistElement.video.name }}</a> | 22 | >{{ playlistElement.video.name }}</a> |
23 | 23 | ||
24 | <span *ngIf="isVideoPrivate()" class="badge badge-yellow">Private</span> | 24 | <span *ngIf="isVideoPrivate()" class="pt-badge badge-yellow">Private</span> |
25 | </div> | 25 | </div> |
26 | 26 | ||
27 | <span class="video-miniature-created-at-views"> | 27 | <span class="video-miniature-created-at-views"> |
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 fbf67e892..c0cf2d1da 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 | |||
@@ -91,9 +91,8 @@ my-video-thumbnail, | |||
91 | padding-right: 5px; | 91 | padding-right: 5px; |
92 | } | 92 | } |
93 | 93 | ||
94 | .badge { | 94 | .pt-badge { |
95 | @include peertube-badge; | 95 | @include margin-right(5px); |
96 | margin-right: 5px; | ||
97 | } | 96 | } |
98 | } | 97 | } |
99 | 98 | ||