aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/+admin/admin.component.html2
-rw-r--r--client/src/app/+admin/admin.component.scss4
-rw-r--r--client/src/app/+admin/follows/following-list/following-list.component.ts1
-rw-r--r--client/src/app/+admin/plugins/shared/toggle-plugin-type.scss28
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.html10
-rw-r--r--client/src/app/+my-account/my-account.module.ts2
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.html2
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts103
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.html2
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.ts6
-rw-r--r--client/src/app/+my-library/my-library.module.ts2
-rw-r--r--client/src/app/+videos/+video-edit/shared/video-edit.component.scss5
-rw-r--r--client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts7
-rw-r--r--client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html2
-rw-r--r--client/src/app/app.component.ts7
-rw-r--r--client/src/app/core/notification/peertube-socket.service.ts9
-rw-r--r--client/src/app/menu/menu.component.html3
-rw-r--r--client/src/app/menu/menu.component.scss42
-rw-r--r--client/src/app/shared/shared-forms/index.ts1
-rw-r--r--client/src/app/shared/shared-forms/input-switch.component.html4
-rw-r--r--client/src/app/shared/shared-forms/input-switch.component.scss44
-rw-r--r--client/src/app/shared/shared-forms/input-switch.component.ts38
-rw-r--r--client/src/app/shared/shared-forms/shared-form.module.ts10
-rw-r--r--client/src/app/shared/shared-forms/timestamp-input.component.scss5
24 files changed, 190 insertions, 149 deletions
diff --git a/client/src/app/+admin/admin.component.html b/client/src/app/+admin/admin.component.html
index aca4d9b0c..f1531f3ef 100644
--- a/client/src/app/+admin/admin.component.html
+++ b/client/src/app/+admin/admin.component.html
@@ -1,4 +1,4 @@
1<div> 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" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }"> 4 <div class="margin-content" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }">
diff --git a/client/src/app/+admin/admin.component.scss b/client/src/app/+admin/admin.component.scss
index 61a2744ba..c98cc9be5 100644
--- a/client/src/app/+admin/admin.component.scss
+++ b/client/src/app/+admin/admin.component.scss
@@ -5,4 +5,6 @@ my-top-menu-dropdown {
5 flex-grow: 1; 5 flex-grow: 1;
6} 6}
7 7
8@include sub-menu-h1; 8.root {
9 @include sub-menu-h1;
10}
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts
index 5f71f1238..f34490cc8 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.ts
+++ b/client/src/app/+admin/follows/following-list/following-list.component.ts
@@ -6,7 +6,6 @@ import { BatchDomainsModalComponent } from '@app/shared/shared-moderation'
6import { ActorFollow } from '@shared/models' 6import { ActorFollow } from '@shared/models'
7 7
8@Component({ 8@Component({
9 selector: 'my-followers-list',
10 templateUrl: './following-list.component.html', 9 templateUrl: './following-list.component.html',
11 styleUrls: [ '../follows.component.scss', './following-list.component.scss' ] 10 styleUrls: [ '../follows.component.scss', './following-list.component.scss' ]
12}) 11})
diff --git a/client/src/app/+admin/plugins/shared/toggle-plugin-type.scss b/client/src/app/+admin/plugins/shared/toggle-plugin-type.scss
index b653abfaa..9e98fcd34 100644
--- a/client/src/app/+admin/plugins/shared/toggle-plugin-type.scss
+++ b/client/src/app/+admin/plugins/shared/toggle-plugin-type.scss
@@ -5,32 +5,4 @@
5 display: flex; 5 display: flex;
6 justify-content: center; 6 justify-content: center;
7 margin-bottom: 30px; 7 margin-bottom: 30px;
8
9 p-selectButton {
10 ::ng-deep {
11 .ui-button-text {
12 font-size: 15px;
13 font-weight: 600;
14 }
15
16 .ui-button.ui-state-default {
17 background-color: #f0f0f0;
18 border: 1px solid #f0f0f0;
19 }
20
21 .ui-button.ui-state-active {
22 background-color: pvar(--mainColor);
23 border-color: pvar(--mainColor);
24
25 &:hover {
26 background-color: pvar(--mainHoverColor);
27 border-color: pvar(--mainHoverColor);
28 }
29 }
30
31 .ui-button:not(.ui-state-active).ui-state-focus {
32 box-shadow: 0 0 0 .1rem rgba(87, 85, 217, .2);
33 }
34 }
35 }
36} 8}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.html b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.html
index 93e294a96..75951006d 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.html
+++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.html
@@ -9,11 +9,17 @@
9 <div>{{ labelNotifications[notificationType] }}</div> 9 <div>{{ labelNotifications[notificationType] }}</div>
10 10
11 <div> 11 <div>
12 <p-inputSwitch [(ngModel)]="webNotifications[notificationType]" (onChange)="updateWebSetting(notificationType, $event.checked)"></p-inputSwitch> 12 <my-input-switch
13 [(ngModel)]="webNotifications[notificationType]"
14 (ngModelChange)="updateWebSetting(notificationType, webNotifications[notificationType])"
15 ></my-input-switch>
13 </div> 16 </div>
14 17
15 <div *ngIf="emailEnabled"> 18 <div *ngIf="emailEnabled">
16 <p-inputSwitch [(ngModel)]="emailNotifications[notificationType]" (onChange)="updateEmailSetting(notificationType, $event.checked)"></p-inputSwitch> 19 <my-input-switch
20 [(ngModel)]="emailNotifications[notificationType]"
21 (ngModelChange)="updateEmailSetting(notificationType, emailNotifications[notificationType])"
22 ></my-input-switch>
17 </div> 23 </div>
18 </div> 24 </div>
19</ng-container> 25</ng-container>
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts
index d3b6a9fa3..9e3fbcf65 100644
--- a/client/src/app/+my-account/my-account.module.ts
+++ b/client/src/app/+my-account/my-account.module.ts
@@ -1,5 +1,4 @@
1import { AutoCompleteModule } from 'primeng/autocomplete' 1import { AutoCompleteModule } from 'primeng/autocomplete'
2import { InputSwitchModule } from 'primeng/inputswitch'
3import { TableModule } from 'primeng/table' 2import { TableModule } from 'primeng/table'
4import { DragDropModule } from '@angular/cdk/drag-drop' 3import { DragDropModule } from '@angular/cdk/drag-drop'
5import { NgModule } from '@angular/core' 4import { NgModule } from '@angular/core'
@@ -29,7 +28,6 @@ import { MyAccountComponent } from './my-account.component'
29 28
30 AutoCompleteModule, 29 AutoCompleteModule,
31 TableModule, 30 TableModule,
32 InputSwitchModule,
33 DragDropModule, 31 DragDropModule,
34 32
35 SharedMainModule, 33 SharedMainModule,
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 205d23cd5..b704a1cc6 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
@@ -42,7 +42,7 @@
42 </div> 42 </div>
43 43
44 <div *ngIf="!isInSmallView" class="w-100 d-flex justify-content-end"> 44 <div *ngIf="!isInSmallView" class="w-100 d-flex justify-content-end">
45 <p-chart *ngIf="videoChannelsChartData && videoChannelsChartData[i]" type="line" [data]="videoChannelsChartData[i]" [options]="chartOptions" width="40vw" height="100px"></p-chart> 45 <p-chart *ngIf="chartOptions && videoChannelsChartData && videoChannelsChartData[i]" type="line" [data]="videoChannelsChartData[i]" [options]="chartOptions" width="40vw" height="100px"></p-chart>
46 </div> 46 </div>
47 </div> 47 </div>
48 </div> 48 </div>
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
index a63e98a51..f6ba50a48 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
@@ -21,6 +21,8 @@ export class MyVideoChannelsComponent implements OnInit {
21 channelsSearch: string 21 channelsSearch: string
22 channelsSearchChanged = new Subject<string>() 22 channelsSearchChanged = new Subject<string>()
23 23
24 chartOptions: any
25
24 private user: User 26 private user: User
25 27
26 constructor ( 28 constructor (
@@ -47,55 +49,6 @@ export class MyVideoChannelsComponent implements OnInit {
47 return this.screenService.isInSmallView() 49 return this.screenService.isInSmallView()
48 } 50 }
49 51
50 get chartOptions () {
51 return {
52 legend: {
53 display: false
54 },
55 scales: {
56 xAxes: [{
57 display: false
58 }],
59 yAxes: [{
60 display: false,
61 ticks: {
62 min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)),
63 max: Math.max(1, this.videoChannelsMaximumDailyViews)
64 }
65 }]
66 },
67 layout: {
68 padding: {
69 left: 15,
70 right: 15,
71 top: 10,
72 bottom: 0
73 }
74 },
75 elements: {
76 point: {
77 radius: 0
78 }
79 },
80 tooltips: {
81 mode: 'index',
82 intersect: false,
83 custom: function (tooltip: any) {
84 if (!tooltip) return
85 // disable displaying the color box
86 tooltip.displayColors = false
87 },
88 callbacks: {
89 label: (tooltip: any, data: any) => `${tooltip.value} views`
90 }
91 },
92 hover: {
93 mode: 'index',
94 intersect: false
95 }
96 }
97 }
98
99 resetSearch () { 52 resetSearch () {
100 this.channelsSearch = '' 53 this.channelsSearch = ''
101 this.onChannelsSearchChanged() 54 this.onChannelsSearchChanged()
@@ -159,6 +112,7 @@ channel with the same name (${videoChannel.name})!`,
159 day => day.views 112 day => day.views
160 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute 113 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
161 ) 114 )
115
162 this.videoChannelsMaximumDailyViews = max( 116 this.videoChannelsMaximumDailyViews = max(
163 // compute local maximum daily views for each channel, by their "views" attribute 117 // compute local maximum daily views for each channel, by their "views" attribute
164 this.videoChannels.map(v => maxBy( 118 this.videoChannels.map(v => maxBy(
@@ -166,6 +120,57 @@ channel with the same name (${videoChannel.name})!`,
166 day => day.views 120 day => day.views
167 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute 121 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
168 ) 122 )
123
124 this.buildChartOptions()
169 }) 125 })
170 } 126 }
127
128 private buildChartOptions () {
129 this.chartOptions = {
130 legend: {
131 display: false
132 },
133 scales: {
134 xAxes: [{
135 display: false
136 }],
137 yAxes: [{
138 display: false,
139 ticks: {
140 min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)),
141 max: Math.max(1, this.videoChannelsMaximumDailyViews)
142 }
143 }]
144 },
145 layout: {
146 padding: {
147 left: 15,
148 right: 15,
149 top: 10,
150 bottom: 0
151 }
152 },
153 elements: {
154 point: {
155 radius: 0
156 }
157 },
158 tooltips: {
159 mode: 'index',
160 intersect: false,
161 custom: function (tooltip: any) {
162 if (!tooltip) return
163 // disable displaying the color box
164 tooltip.displayColors = false
165 },
166 callbacks: {
167 label: (tooltip: any, data: any) => `${tooltip.value} views`
168 }
169 },
170 hover: {
171 mode: 'index',
172 intersect: false
173 }
174 }
175 }
171} 176}
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 cff46a41d..05e016e55 100644
--- a/client/src/app/+my-library/my-history/my-history.component.html
+++ b/client/src/app/+my-library/my-history/my-history.component.html
@@ -5,7 +5,7 @@
5 5
6<div class="top-buttons"> 6<div class="top-buttons">
7 <div class="history-switch"> 7 <div class="history-switch">
8 <p-inputSwitch [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></p-inputSwitch> 8 <my-input-switch [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></my-input-switch>
9 <label i18n>Video history</label> 9 <label i18n>Video history</label>
10 </div> 10 </div>
11 11
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 e11f05c47..4ba95124d 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
@@ -47,7 +47,11 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD
47 ngOnInit () { 47 ngOnInit () {
48 super.ngOnInit() 48 super.ngOnInit()
49 49
50 this.videosHistoryEnabled = this.authService.getUser().videosHistoryEnabled 50 this.authService.userInformationLoaded
51 .subscribe(() => {
52 this.videosHistoryEnabled = this.authService.getUser().videosHistoryEnabled
53 })
54
51 } 55 }
52 56
53 ngOnDestroy () { 57 ngOnDestroy () {
diff --git a/client/src/app/+my-library/my-library.module.ts b/client/src/app/+my-library/my-library.module.ts
index bf791952c..5518cfd98 100644
--- a/client/src/app/+my-library/my-library.module.ts
+++ b/client/src/app/+my-library/my-library.module.ts
@@ -1,5 +1,4 @@
1import { AutoCompleteModule } from 'primeng/autocomplete' 1import { AutoCompleteModule } from 'primeng/autocomplete'
2import { InputSwitchModule } from 'primeng/inputswitch'
3import { TableModule } from 'primeng/table' 2import { TableModule } from 'primeng/table'
4import { DragDropModule } from '@angular/cdk/drag-drop' 3import { DragDropModule } from '@angular/cdk/drag-drop'
5import { NgModule } from '@angular/core' 4import { NgModule } from '@angular/core'
@@ -34,7 +33,6 @@ import { MyVideosComponent } from './my-videos/my-videos.component'
34 33
35 AutoCompleteModule, 34 AutoCompleteModule,
36 TableModule, 35 TableModule,
37 InputSwitchModule,
38 DragDropModule, 36 DragDropModule,
39 37
40 SharedMainModule, 38 SharedMainModule,
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 3082a4f72..c2fbb46f9 100644
--- a/client/src/app/+videos/+video-edit/shared/video-edit.component.scss
+++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.scss
@@ -150,12 +150,11 @@ p-calendar {
150 display: block; 150 display: block;
151 151
152 ::ng-deep { 152 ::ng-deep {
153 input, 153 .p-calendar {
154 .ui-calendar {
155 width: 100%; 154 width: 100%;
156 } 155 }
157 156
158 input { 157 .p-inputtext {
159 @include peertube-input-text(100%); 158 @include peertube-input-text(100%);
160 color: #000; 159 color: #000;
161 } 160 }
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts b/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts
index 259afb196..1417f3e2a 100644
--- a/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts
+++ b/client/src/app/+videos/+video-watch/recommendations/recommendations.module.ts
@@ -1,6 +1,7 @@
1import { InputSwitchModule } from 'primeng/inputswitch' 1
2import { CommonModule } from '@angular/common' 2import { CommonModule } from '@angular/common'
3import { NgModule } from '@angular/core' 3import { NgModule } from '@angular/core'
4import { SharedFormModule } from '@app/shared/shared-forms'
4import { SharedMainModule } from '@app/shared/shared-main' 5import { SharedMainModule } from '@app/shared/shared-main'
5import { SharedSearchModule } from '@app/shared/shared-search' 6import { SharedSearchModule } from '@app/shared/shared-search'
6import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' 7import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature'
@@ -12,12 +13,12 @@ import { RecommendedVideosStore } from './recommended-videos.store'
12@NgModule({ 13@NgModule({
13 imports: [ 14 imports: [
14 CommonModule, 15 CommonModule,
15 InputSwitchModule,
16 16
17 SharedMainModule, 17 SharedMainModule,
18 SharedSearchModule, 18 SharedSearchModule,
19 SharedVideoPlaylistModule, 19 SharedVideoPlaylistModule,
20 SharedVideoMiniatureModule 20 SharedVideoMiniatureModule,
21 SharedFormModule
21 ], 22 ],
22 declarations: [ 23 declarations: [
23 RecommendedVideosComponent 24 RecommendedVideosComponent
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
index 1ab1b7343..3c7c679b8 100644
--- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
+++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
@@ -8,7 +8,7 @@
8 [ngbTooltip]="autoPlayNextVideoTooltip" placement="bottom-right auto" 8 [ngbTooltip]="autoPlayNextVideoTooltip" placement="bottom-right auto"
9 > 9 >
10 <span i18n>AUTOPLAY</span> 10 <span i18n>AUTOPLAY</span>
11 <p-inputSwitch class="small" [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></p-inputSwitch> 11 <my-input-switch class="small" [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></my-input-switch>
12 </div> 12 </div>
13 </div> 13 </div>
14 14
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index da51040ad..75f4bdfe6 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -11,7 +11,7 @@ import { PluginService } from '@app/core/plugins/plugin.service'
11import { CustomModalComponent } from '@app/modal/custom-modal.component' 11import { CustomModalComponent } from '@app/modal/custom-modal.component'
12import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component' 12import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
13import { WelcomeModalComponent } from '@app/modal/welcome-modal.component' 13import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
14import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 14import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
15import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' 15import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
16import { getShortLocale, is18nPath } from '@shared/core-utils/i18n' 16import { getShortLocale, is18nPath } from '@shared/core-utils/i18n'
17import { BroadcastMessageLevel, ServerConfig, UserRole } from '@shared/models' 17import { BroadcastMessageLevel, ServerConfig, UserRole } from '@shared/models'
@@ -54,8 +54,11 @@ export class AppComponent implements OnInit, AfterViewInit {
54 private location: PlatformLocation, 54 private location: PlatformLocation,
55 private modalService: NgbModal, 55 private modalService: NgbModal,
56 private markdownService: MarkdownService, 56 private markdownService: MarkdownService,
57 private ngbConfig: NgbConfig,
57 public menu: MenuService 58 public menu: MenuService
58 ) { } 59 ) {
60 this.ngbConfig.animation = false
61 }
59 62
60 get instanceName () { 63 get instanceName () {
61 return this.serverConfig.instance.name 64 return this.serverConfig.instance.name
diff --git a/client/src/app/core/notification/peertube-socket.service.ts b/client/src/app/core/notification/peertube-socket.service.ts
index 8668c44a8..2f17fd709 100644
--- a/client/src/app/core/notification/peertube-socket.service.ts
+++ b/client/src/app/core/notification/peertube-socket.service.ts
@@ -3,18 +3,19 @@ import { Injectable, NgZone } from '@angular/core'
3import { LiveVideoEventPayload, LiveVideoEventType, UserNotification as UserNotificationServer } from '@shared/models' 3import { LiveVideoEventPayload, LiveVideoEventType, UserNotification as UserNotificationServer } from '@shared/models'
4import { environment } from '../../../environments/environment' 4import { environment } from '../../../environments/environment'
5import { AuthService } from '../auth' 5import { AuthService } from '../auth'
6import { io, Socket } from 'socket.io-client'
6 7
7export type NotificationEvent = 'new' | 'read' | 'read-all' 8export type NotificationEvent = 'new' | 'read' | 'read-all'
8 9
9@Injectable() 10@Injectable()
10export class PeerTubeSocket { 11export class PeerTubeSocket {
11 private io: typeof import ('socket.io-client') 12 private io: typeof io
12 13
13 private notificationSubject = new Subject<{ type: NotificationEvent, notification?: UserNotificationServer }>() 14 private notificationSubject = new Subject<{ type: NotificationEvent, notification?: UserNotificationServer }>()
14 private liveVideosSubject = new Subject<{ type: LiveVideoEventType, payload: LiveVideoEventPayload }>() 15 private liveVideosSubject = new Subject<{ type: LiveVideoEventType, payload: LiveVideoEventPayload }>()
15 16
16 private notificationSocket: SocketIOClient.Socket 17 private notificationSocket: Socket
17 private liveVideosSocket: SocketIOClient.Socket 18 private liveVideosSocket: Socket
18 19
19 constructor ( 20 constructor (
20 private auth: AuthService, 21 private auth: AuthService,
@@ -77,7 +78,7 @@ export class PeerTubeSocket {
77 private async importIOIfNeeded () { 78 private async importIOIfNeeded () {
78 if (this.io) return 79 if (this.io) return
79 80
80 this.io = (await import('socket.io-client') as any).default 81 this.io = (await import('socket.io-client')).io
81 } 82 }
82 83
83 private dispatchLiveVideoEvent (type: LiveVideoEventType, payload: LiveVideoEventPayload) { 84 private dispatchLiveVideoEvent (type: LiveVideoEventType, payload: LiveVideoEventPayload) {
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index 88e3d60db..810466a72 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -54,7 +54,8 @@
54 <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()"> 54 <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()">
55 <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon> 55 <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon>
56 <ng-container i18n>Help share videos</ng-container> 56 <ng-container i18n>Help share videos</ng-container>
57 <input type="checkbox" [checked]="user.webTorrentEnabled"/><label class="ml-auto" for="switch">Toggle p2p</label> 57
58 <my-input-switch class="ml-auto" [checked]="user.webTorrentEnabled"></my-input-switch>
58 </a> 59 </a>
59 60
60 <div class="dropdown-divider"></div> 61 <div class="dropdown-divider"></div>
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index 3ca4e47a1..8a8094fbb 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -352,48 +352,6 @@ menu {
352 color: #6c757d; 352 color: #6c757d;
353} 353}
354 354
355input[type=checkbox]{
356 position: absolute;
357 visibility: hidden;
358}
359
360label {
361 cursor: pointer;
362 text-indent: -9999px;
363 width: 35px;
364 height: 20px;
365 background: #cccccc;
366 display: block;
367 border-radius: 100px;
368 position: relative;
369 margin: 0;
370
371 &:after {
372 content: '';
373 position: absolute;
374 top: 3px;
375 left: 3px;
376 width: 14px;
377 height: 14px;
378 background: pvar(--mainBackgroundColor);
379 border-radius: 50%;
380 transition: 0.3s ease-out;
381 }
382
383 &:active:after {
384 width: 40px;
385 }
386}
387
388input:checked + label {
389 background: pvar(--mainColor);
390
391 &:after {
392 left: calc(100% - 3px);
393 transform: translateX(-100%);
394 }
395}
396
397@media screen and (max-width: $mobile-view) { 355@media screen and (max-width: $mobile-view) {
398 .menu-wrapper { 356 .menu-wrapper {
399 width: 100% !important; 357 width: 100% !important;
diff --git a/client/src/app/shared/shared-forms/index.ts b/client/src/app/shared/shared-forms/index.ts
index b2c7fa9ba..66b426191 100644
--- a/client/src/app/shared/shared-forms/index.ts
+++ b/client/src/app/shared/shared-forms/index.ts
@@ -2,6 +2,7 @@ export * from './form-validator.service'
2export * from './form-reactive' 2export * from './form-reactive'
3export * from './select' 3export * from './select'
4export * from './input-readonly-copy.component' 4export * from './input-readonly-copy.component'
5export * from './input-switch.component'
5export * from './markdown-textarea.component' 6export * from './markdown-textarea.component'
6export * from './peertube-checkbox.component' 7export * from './peertube-checkbox.component'
7export * from './preview-upload.component' 8export * from './preview-upload.component'
diff --git a/client/src/app/shared/shared-forms/input-switch.component.html b/client/src/app/shared/shared-forms/input-switch.component.html
new file mode 100644
index 000000000..ce1dee470
--- /dev/null
+++ b/client/src/app/shared/shared-forms/input-switch.component.html
@@ -0,0 +1,4 @@
1<div (click)="update()">
2 <input type="checkbox" [checked]="checked"/>
3 <label class="ml-auto">Toggle</label>
4</div>
diff --git a/client/src/app/shared/shared-forms/input-switch.component.scss b/client/src/app/shared/shared-forms/input-switch.component.scss
new file mode 100644
index 000000000..c14950bd7
--- /dev/null
+++ b/client/src/app/shared/shared-forms/input-switch.component.scss
@@ -0,0 +1,44 @@
1@import '_variables';
2@import '_mixins';
3
4input {
5 position: absolute;
6 visibility: hidden;
7
8 & + label {
9 cursor: pointer;
10 text-indent: -9999px;
11 width: 35px;
12 height: 20px;
13 background: #cccccc;
14 display: block;
15 border-radius: 100px;
16 position: relative;
17 margin: 0;
18
19 &:after {
20 content: '';
21 position: absolute;
22 top: 3px;
23 left: 3px;
24 width: 14px;
25 height: 14px;
26 background: pvar(--mainBackgroundColor);
27 border-radius: 50%;
28 transition: 0.3s ease-out;
29 }
30
31 &:active:after {
32 width: 40px;
33 }
34 }
35
36 &:checked + label {
37 background: pvar(--mainColor);
38
39 &:after {
40 left: calc(100% - 3px);
41 transform: translateX(-100%);
42 }
43 }
44}
diff --git a/client/src/app/shared/shared-forms/input-switch.component.ts b/client/src/app/shared/shared-forms/input-switch.component.ts
new file mode 100644
index 000000000..abb96de62
--- /dev/null
+++ b/client/src/app/shared/shared-forms/input-switch.component.ts
@@ -0,0 +1,38 @@
1import { Component, forwardRef, Input } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3
4@Component({
5 selector: 'my-input-switch',
6 styleUrls: [ './input-switch.component.scss' ],
7 templateUrl: './input-switch.component.html',
8 providers: [
9 {
10 provide: NG_VALUE_ACCESSOR,
11 useExisting: forwardRef(() => InputSwitchComponent),
12 multi: true
13 }
14 ]
15})
16export class InputSwitchComponent implements ControlValueAccessor {
17 @Input() checked = false
18 @Input() inputName: string
19
20 propagateChange = (_: any) => { /* empty */ }
21
22 writeValue (checked: boolean) {
23 this.checked = checked
24 }
25
26 registerOnChange (fn: (_: any) => void) {
27 this.propagateChange = fn
28 }
29
30 registerOnTouched () {
31 // Unused
32 }
33
34 update () {
35 this.checked = !this.checked
36 this.propagateChange(this.checked)
37 }
38}
diff --git a/client/src/app/shared/shared-forms/shared-form.module.ts b/client/src/app/shared/shared-forms/shared-form.module.ts
index a28988f87..060abc995 100644
--- a/client/src/app/shared/shared-forms/shared-form.module.ts
+++ b/client/src/app/shared/shared-forms/shared-form.module.ts
@@ -1,13 +1,14 @@
1 1
2import { InputMaskModule } from 'primeng/inputmask' 2import { InputMaskModule } from 'primeng/inputmask'
3import { InputSwitchModule } from 'primeng/inputswitch'
4import { NgModule } from '@angular/core' 3import { NgModule } from '@angular/core'
5import { FormsModule, ReactiveFormsModule } from '@angular/forms' 4import { FormsModule, ReactiveFormsModule } from '@angular/forms'
6import { NgSelectModule } from '@ng-select/ng-select' 5import { NgSelectModule } from '@ng-select/ng-select'
7import { SharedGlobalIconModule } from '../shared-icons' 6import { SharedGlobalIconModule } from '../shared-icons'
8import { SharedMainModule } from '../shared-main/shared-main.module' 7import { SharedMainModule } from '../shared-main/shared-main.module'
8import { DynamicFormFieldComponent } from './dynamic-form-field.component'
9import { FormValidatorService } from './form-validator.service' 9import { FormValidatorService } from './form-validator.service'
10import { InputReadonlyCopyComponent } from './input-readonly-copy.component' 10import { InputReadonlyCopyComponent } from './input-readonly-copy.component'
11import { InputSwitchComponent } from './input-switch.component'
11import { MarkdownTextareaComponent } from './markdown-textarea.component' 12import { MarkdownTextareaComponent } from './markdown-textarea.component'
12import { PeertubeCheckboxComponent } from './peertube-checkbox.component' 13import { PeertubeCheckboxComponent } from './peertube-checkbox.component'
13import { PreviewUploadComponent } from './preview-upload.component' 14import { PreviewUploadComponent } from './preview-upload.component'
@@ -15,7 +16,6 @@ import { ReactiveFileComponent } from './reactive-file.component'
15import { SelectChannelComponent, SelectCheckboxComponent, SelectOptionsComponent, SelectTagsComponent } from './select' 16import { SelectChannelComponent, SelectCheckboxComponent, SelectOptionsComponent, SelectTagsComponent } from './select'
16import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' 17import { TextareaAutoResizeDirective } from './textarea-autoresize.directive'
17import { TimestampInputComponent } from './timestamp-input.component' 18import { TimestampInputComponent } from './timestamp-input.component'
18import { DynamicFormFieldComponent } from './dynamic-form-field.component'
19 19
20@NgModule({ 20@NgModule({
21 imports: [ 21 imports: [
@@ -23,7 +23,6 @@ import { DynamicFormFieldComponent } from './dynamic-form-field.component'
23 ReactiveFormsModule, 23 ReactiveFormsModule,
24 24
25 InputMaskModule, 25 InputMaskModule,
26 InputSwitchModule,
27 NgSelectModule, 26 NgSelectModule,
28 27
29 SharedMainModule, 28 SharedMainModule,
@@ -39,6 +38,8 @@ import { DynamicFormFieldComponent } from './dynamic-form-field.component'
39 TextareaAutoResizeDirective, 38 TextareaAutoResizeDirective,
40 TimestampInputComponent, 39 TimestampInputComponent,
41 40
41 InputSwitchComponent,
42
42 SelectChannelComponent, 43 SelectChannelComponent,
43 SelectOptionsComponent, 44 SelectOptionsComponent,
44 SelectTagsComponent, 45 SelectTagsComponent,
@@ -52,7 +53,6 @@ import { DynamicFormFieldComponent } from './dynamic-form-field.component'
52 ReactiveFormsModule, 53 ReactiveFormsModule,
53 54
54 InputMaskModule, 55 InputMaskModule,
55 InputSwitchModule,
56 NgSelectModule, 56 NgSelectModule,
57 57
58 InputReadonlyCopyComponent, 58 InputReadonlyCopyComponent,
@@ -63,6 +63,8 @@ import { DynamicFormFieldComponent } from './dynamic-form-field.component'
63 TextareaAutoResizeDirective, 63 TextareaAutoResizeDirective,
64 TimestampInputComponent, 64 TimestampInputComponent,
65 65
66 InputSwitchComponent,
67
66 SelectChannelComponent, 68 SelectChannelComponent,
67 SelectOptionsComponent, 69 SelectOptionsComponent,
68 SelectTagsComponent, 70 SelectTagsComponent,
diff --git a/client/src/app/shared/shared-forms/timestamp-input.component.scss b/client/src/app/shared/shared-forms/timestamp-input.component.scss
index 8092b095b..66e9aa032 100644
--- a/client/src/app/shared/shared-forms/timestamp-input.component.scss
+++ b/client/src/app/shared/shared-forms/timestamp-input.component.scss
@@ -11,5 +11,10 @@ p-inputmask {
11 &:focus { 11 &:focus {
12 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest); 12 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
13 } 13 }
14
15 &:disabled {
16 background: pvar(--mainBackgroundColor);
17 opacity: 0.5;
18 }
14 } 19 }
15} 20}