aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'client/src')
-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
-rw-r--r--client/src/assets/player/p2p-media-loader/hls-plugin.ts2
-rw-r--r--client/src/hmr.ts24
-rw-r--r--client/src/main.ts13
-rw-r--r--client/src/sass/application.scss2
-rw-r--r--client/src/sass/primeng-custom.scss644
29 files changed, 745 insertions, 279 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}
diff --git a/client/src/assets/player/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/p2p-media-loader/hls-plugin.ts
index 51acad670..cf8cb824d 100644
--- a/client/src/assets/player/p2p-media-loader/hls-plugin.ts
+++ b/client/src/assets/player/p2p-media-loader/hls-plugin.ts
@@ -13,7 +13,7 @@ type Metadata = {
13 levels: Hlsjs.Level[] 13 levels: Hlsjs.Level[]
14} 14}
15 15
16type CustomAudioTrack = Hlsjs.AudioTrack & { name?: string, lang?: string } 16type CustomAudioTrack = Hlsjs.HlsAudioTrack & { name?: string, lang?: string }
17 17
18const registerSourceHandler = function (vjs: typeof videojs) { 18const registerSourceHandler = function (vjs: typeof videojs) {
19 if (!Hlsjs.isSupported()) { 19 if (!Hlsjs.isSupported()) {
diff --git a/client/src/hmr.ts b/client/src/hmr.ts
deleted file mode 100644
index adfbca7d9..000000000
--- a/client/src/hmr.ts
+++ /dev/null
@@ -1,24 +0,0 @@
1import { NgModuleRef, ApplicationRef } from '@angular/core'
2import { createNewHosts } from '@angularclass/hmr'
3import { enableDebugTools } from '@angular/platform-browser'
4
5export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {
6 let ngModule: NgModuleRef<any>
7 module.hot.accept()
8 bootstrap()
9 .then(mod => {
10 ngModule = mod
11
12 const applicationRef = ngModule.injector.get(ApplicationRef)
13 const componentRef = applicationRef.components[ 0 ]
14 // allows to run `ng.profiler.timeChangeDetection();`
15 enableDebugTools(componentRef)
16 })
17 module.hot.dispose(() => {
18 const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef)
19 const elements = appRef.components.map(c => c.location.nativeElement)
20 const makeVisible = createNewHosts(elements)
21 ngModule.destroy()
22 makeVisible()
23 })
24}
diff --git a/client/src/main.ts b/client/src/main.ts
index 3fb9b346e..2d1749c42 100644
--- a/client/src/main.ts
+++ b/client/src/main.ts
@@ -4,8 +4,6 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
4import { AppModule } from './app/app.module' 4import { AppModule } from './app/app.module'
5import { environment } from './environments/environment' 5import { environment } from './environments/environment'
6 6
7import { hmrBootstrap } from './hmr'
8
9if (environment.production) { 7if (environment.production) {
10 enableProdMode() 8 enableProdMode()
11} 9}
@@ -36,13 +34,4 @@ const bootstrap = () => platformBrowserDynamic()
36 return null 34 return null
37 }) 35 })
38 36
39if (environment.hmr) { 37bootstrap()
40 if (module[ 'hot' ]) {
41 hmrBootstrap(module, bootstrap)
42 } else {
43 console.error('HMR is not enabled for webpack-dev-server!')
44 console.log('Are you using the --hmr flag for ng serve?')
45 }
46} else {
47 bootstrap()
48}
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index 1c0d30854..25db91670 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -21,7 +21,7 @@ $assets-path: '../../assets/';
21 21
22body { 22body {
23 /*** theme ***/ 23 /*** theme ***/
24 // now beware node-sass requires interpolation 24 // now beware sass requires interpolation
25 // for css custom properties #{$var} 25 // for css custom properties #{$var}
26 --mainColor: #{$main-color}; 26 --mainColor: #{$main-color};
27 --mainColorLighter: #{$main-color-lighter}; 27 --mainColorLighter: #{$main-color-lighter};
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss
index 2ffa2d3ff..a48f797fc 100644
--- a/client/src/sass/primeng-custom.scss
+++ b/client/src/sass/primeng-custom.scss
@@ -2,7 +2,487 @@
2@import '_mixins'; 2@import '_mixins';
3 3
4@import '~primeng/resources/primeng.css'; 4@import '~primeng/resources/primeng.css';
5@import '~primeng/resources/themes/nova-light/theme.css'; 5
6// Taken from old nova light theme
7
8body .p-disabled {
9 opacity: 0.5;
10}
11
12// Checkbox
13body .p-checkbox {
14 display: inline-block;
15 vertical-align: middle;
16 margin: 0;
17 width: 20px;
18 height: 20px;
19}
20body .p-checkbox .p-checkbox-box {
21 border: 1px solid #a6a6a6;
22 background-color: #ffffff;
23 width: 20px;
24 height: 20px;
25 text-align: center;
26 border-radius: 3px;
27 transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s;
28}
29body .p-checkbox .p-checkbox-box:not(.p-disabled):hover {
30 border-color: #212121;
31}
32body .p-checkbox .p-checkbox-box .p-checkbox-icon {
33 overflow: hidden;
34 position: relative;
35 font-size: 18px;
36}
37
38// Paginator
39body .p-paginator {
40 background-color: #f4f4f4;
41 border: 1px solid #c8c8c8;
42 padding: 0;
43}
44body .p-paginator .p-paginator-first,
45body .p-paginator .p-paginator-prev,
46body .p-paginator .p-paginator-next,
47body .p-paginator .p-paginator-last {
48 color: #848484;
49 height: 2.286em;
50 min-width: 2.286em;
51 border: 0 none;
52 line-height: 2.286em;
53 padding: 0;
54 margin: 0;
55 vertical-align: top;
56 transition: box-shadow 0.2s;
57 border-radius: 0;
58}
59body .p-paginator .p-paginator-first:not(.p-disabled):not(.p-highlight):hover,
60body .p-paginator .p-paginator-prev:not(.p-disabled):not(.p-highlight):hover,
61body .p-paginator .p-paginator-next:not(.p-disabled):not(.p-highlight):hover,
62body .p-paginator .p-paginator-last:not(.p-disabled):not(.p-highlight):hover {
63 background-color: #e0e0e0;
64 color: #333333;
65}
66body .p-paginator .p-paginator-first:focus,
67body .p-paginator .p-paginator-prev:focus,
68body .p-paginator .p-paginator-next:focus,
69body .p-paginator .p-paginator-last:focus {
70 outline: 0 none;
71 outline-offset: 0;
72 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
73}
74body .p-paginator .p-paginator-current {
75 color: #333333;
76 height: 2.286em;
77 min-width: 2.286em;
78 line-height: 2.286em;
79}
80body .p-paginator .p-dropdown {
81 border: 0 none;
82}
83body .p-paginator .p-dropdown .p-dropdown-trigger, body .p-paginator .p-dropdown .p-dropdown-label {
84 color: #848484;
85}
86body .p-paginator .p-dropdown:hover .p-dropdown-trigger, body .p-paginator .p-dropdown:hover .p-dropdown-label {
87 color: #333333;
88}
89body .p-paginator .p-paginator-first:before {
90 position: relative;
91 top: 1px;
92}
93body .p-paginator .p-paginator-prev:before {
94 position: relative;
95 top: 1px;
96}
97body .p-paginator .p-paginator-next:before {
98 position: relative;
99 top: 1px;
100}
101body .p-paginator .p-paginator-last:before {
102 position: relative;
103 top: 1px;
104}
105body .p-paginator .p-paginator-pages {
106 vertical-align: top;
107 display: inline-block;
108 padding: 0;
109}
110body .p-paginator .p-paginator-pages .p-paginator-page {
111 color: #848484;
112 height: 2.286em;
113 min-width: 2.286em;
114 border: 0 none;
115 line-height: 2.286em;
116 padding: 0;
117 margin: 0;
118 vertical-align: top;
119 transition: box-shadow 0.2s;
120 border-radius: 0;
121}
122body .p-paginator .p-paginator-pages .p-paginator-page:not(.p-highlight):hover {
123 background-color: #e0e0e0;
124 color: #333333;
125}
126body .p-paginator .p-paginator-pages .p-paginator-page:focus {
127 outline: 0 none;
128 outline-offset: 0;
129 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
130}
131body .p-paginator .p-dropdown {
132 margin-left: 0.5em;
133 height: 2.286em;
134 min-width: auto;
135}
136
137// Dropdown
138
139body .p-dropdown {
140 background: #ffffff;
141 border: 1px solid #a6a6a6;
142 transition: border-color 0.2s, box-shadow 0.2s;
143}
144body .p-dropdown:not(.p-disabled):hover {
145 border-color: #212121;
146}
147body .p-dropdown:not(.p-disabled).p-focus {
148 outline: 0 none;
149 outline-offset: 0;
150 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
151 border-color: pvar(--mainColor);
152}
153body .p-dropdown .p-dropdown-label {
154 padding-right: 2em;
155}
156body .p-dropdown .p-dropdown-trigger {
157 background-color: #ffffff;
158 width: 2em;
159 line-height: 2em;
160 text-align: center;
161 padding: 0;
162 color: #848484;
163}
164body .p-dropdown .p-dropdown-clear-icon {
165 color: #848484;
166}
167body .p-dropdown.p-dropdown-clearable .p-dropdown-label {
168 padding-right: 4em;
169}
170body .p-dropdown-panel {
171 padding: 0;
172 border: 1px solid #c8c8c8;
173 background-color: #ffffff;
174 box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
175}
176body .p-dropdown-panel .p-dropdown-filter-container {
177 padding: 0.429em 0.857em 0.429em 0.857em;
178 border-bottom: 1px solid #eaeaea;
179 color: #333333;
180 background-color: #ffffff;
181 margin: 0;
182}
183body .p-dropdown-panel .p-dropdown-filter-container .p-dropdown-filter {
184 width: 100%;
185 padding-right: 2em;
186}
187body .p-dropdown-panel .p-dropdown-filter-container .p-dropdown-filter-icon {
188 top: 50%;
189 margin-top: -0.5em;
190 right: 1.357em;
191 color: pvar(--mainColor);
192}
193body .p-dropdown-panel .p-dropdown-items {
194 padding: 0;
195}
196body .p-dropdown-panel .p-dropdown-items .p-dropdown-item, body .p-dropdown-panel .p-dropdown-items .p-dropdown-item-group {
197 margin: 0;
198 padding: 0.429em 0.857em;
199 border: 0 none;
200 color: #333333;
201 background-color: transparent;
202 -moz-border-radius: 0;
203 -webkit-border-radius: 0;
204 border-radius: 0;
205}
206body .p-dropdown-panel .p-dropdown-items .p-dropdown-item.p-highlight,
207body .p-dropdown-panel .p-dropdown-items .p-dropdown-item-group.p-highlight {
208 color: #ffffff;
209 background-color: pvar(--mainColor);
210}
211body .p-dropdown-panel .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover,
212body .p-dropdown-panel .p-dropdown-items .p-dropdown-item-group:not(.p-highlight):not(.p-disabled):hover {
213 color: #333333;
214 background-color: #eaeaea;
215}
216body p-dropdown.ng-dirty.ng-invalid > .p-dropdown {
217 border: 1px solid #a80000;
218}
219
220// p-toast
221body .p-toast .p-toast-message {
222 box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
223 margin: 0 0 1em 0;
224}
225
226// p-calendar
227body .p-datepicker {
228 padding: 0.857em;
229 min-width: 20em;
230 background-color: #ffffff;
231 color: #333333;
232 border: 1px solid #a6a6a6;
233}
234
235body .p-datepicker:not(.p-datepicker-inline) {
236 border: 1px solid #c8c8c8;
237 box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
238}
239body .p-datepicker:not(.p-disabled) .p-datepicker-header .p-datepicker-prev:focus,
240body .p-datepicker:not(.p-disabled) .p-datepicker-header .p-datepicker-next:focus {
241 outline: 0 none;
242 outline-offset: 0;
243 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
244}
245body .p-datepicker:not(.p-disabled) table td a:not(.p-highlight):not(.p-highlight):hover {
246 background-color: #eaeaea;
247}
248body .p-datepicker:not(.p-disabled) .p-monthpicker a.p-monthpicker-month:not(.p-highlight):hover {
249 background-color: #eaeaea;
250}
251body .p-datepicker .p-datepicker-header {
252 padding: 0.429em 0.857em 0.429em 0.857em;
253 background-color: #ffffff;
254 color: #333333;
255 -moz-border-radius: 0;
256 -webkit-border-radius: 0;
257 border-radius: 0;
258}
259body .p-datepicker .p-datepicker-header .p-datepicker-prev,
260body .p-datepicker .p-datepicker-header .p-datepicker-next {
261 cursor: pointer;
262 top: 0;
263 color: #a6a6a6;
264 transition: color 0.2s, box-shadow 0.2s;
265}
266body .p-datepicker .p-datepicker-header .p-datepicker-title {
267 margin: 0;
268 padding: 0;
269 line-height: 1;
270}
271body .p-datepicker .p-datepicker-header .p-datepicker-title select {
272 margin-top: -0.35em;
273 margin-bottom: 0;
274 transition: color 0.2s, box-shadow 0.2s;
275}
276body .p-datepicker .p-datepicker-header .p-datepicker-title select:focus {
277 outline: 0 none;
278 outline-offset: 0;
279 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
280}
281body .p-datepicker table {
282 font-size: 14px;
283 margin: 0.857em 0 0 0;
284}
285body .p-datepicker table th {
286 padding: 0.5em;
287}
288body .p-datepicker table th.p-datepicker-weekheader {
289 border-right: 1px solid #a6a6a6;
290}
291body .p-datepicker table td {
292 padding: 0.5em;
293}
294body .p-datepicker table td > a,
295body .p-datepicker table td > span {
296 display: block;
297 text-align: center;
298 color: #333333;
299 padding: 0.5em;
300 transition: box-shadow 0.2s;
301 border-radius: 3px;
302}
303body .p-datepicker table td > a.p-highlight,
304body .p-datepicker table td > span.p-highlight {
305 color: #ffffff;
306 background-color: pvar(--mainColor);
307}
308body .p-datepicker table td > a {
309 cursor: pointer;
310}
311body .p-datepicker table td > a:focus {
312 outline: 0 none;
313 outline-offset: 0;
314 box-shadow: 0 0 0 0.2em pvar(--mainColorLightest);
315}
316body .p-datepicker table td.p-datepicker-today > a,
317body .p-datepicker table td.p-datepicker-today > span {
318 background-color: #d0d0d0;
319 color: #333333;
320}
321body .p-datepicker table td.p-datepicker-today > a.p-highlight,
322body .p-datepicker table td.p-datepicker-today > span.p-highlight {
323 color: #ffffff;
324 background-color: pvar(--mainColor);
325}
326body .p-datepicker table td.p-datepicker-weeknumber {
327 border-right: 1px solid #a6a6a6;
328}
329body .p-datepicker .p-datepicker-buttonbar {
330 border-top: 1px solid #d8dae2;
331}
332body .p-datepicker .p-timepicker {
333 border: 0 none;
334 border-top: 1px solid #d8dae2;
335 padding: 0.857em;
336}
337body .p-datepicker .p-timepicker a {
338 color: #333333;
339 font-size: 1.286em;
340}
341body .p-datepicker .p-timepicker a:hover {
342 color: pvar(--mainColor);
343}
344body .p-datepicker .p-timepicker span {
345 font-size: 1.286em;
346}
347body .p-datepicker .p-monthpicker .p-monthpicker-month {
348 color: #333333;
349}
350body .p-datepicker .p-monthpicker .p-monthpicker-month.p-highlight {
351 color: #ffffff;
352 background-color: pvar(--mainColor);
353}
354body .p-datepicker.p-datepicker-timeonly {
355 padding: 0;
356}
357body .p-datepicker.p-datepicker-timeonly .p-timepicker {
358 border-top: 0 none;
359}
360body .p-datepicker.p-datepicker-multiple-month .p-datepicker-group {
361 border-right: 1px solid #d8dae2;
362 padding-right: 0.857em;
363 padding-left: 0.857em;
364 padding-top: 0;
365 padding-bottom: 0;
366}
367body .p-datepicker.p-datepicker-multiple-month .p-datepicker-group:first-child {
368 padding-left: 0;
369}
370body .p-datepicker.p-datepicker-multiple-month .p-datepicker-group:last-child {
371 padding-right: 0;
372 border-right: 0 none;
373}
374body .p-calendar.p-calendar-w-btn .p-inputtext {
375 border-top-right-radius: 0;
376 border-bottom-right-radius: 0;
377 border-right: 0 none;
378}
379body .p-calendar.p-calendar-w-btn .p-inputtext:enabled:hover:not(.p-error),
380body .p-calendar.p-calendar-w-btn .p-inputtext:enabled:focus:not(.p-error) {
381 border-right: 0 none;
382}
383body .p-calendar.p-calendar-w-btn .p-datepicker-trigger.p-button {
384 width: 2.357em;
385 border-top-left-radius: 0;
386 border-bottom-left-radius: 0;
387}
388body .ui-fluid .p-calendar.p-calendar-w-btn input.p-inputtext {
389 width: calc(100% - 2.357em);
390}
391body p-calendar.ng-dirty.ng-invalid > .p-calendar > .p-inputtext {
392 border: 1px solid #a80000;
393}
394body .p-timepicker .p-separator {
395 margin-left: 0;
396 min-width: 0.75rem;
397}
398
399// auto complete
400body .p-autocomplete .p-autocomplete-input {
401 padding: 0.429em;
402}
403body .p-autocomplete-panel {
404 padding: 0;
405 border: 1px solid #c8c8c8;
406 background-color: #ffffff;
407 box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
408}
409body .p-autocomplete-panel .p-autocomplete-items {
410 padding: 0;
411}
412body .p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item {
413 margin: 0;
414 padding: 0.429em 0.857em;
415 border: 0 none;
416 color: #333333;
417 background-color: transparent;
418 border-radius: 0;
419}
420body .p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item.p-highlight,
421body .p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item:hover {
422 color: #ffffff;
423 background-color: pvar(--mainColor);
424}
425body .p-autocomplete-panel .p-autocomplete-items .p-autocomplete-group {
426 padding: 0.429em 0.857em;
427 background-color: #d8dae2;
428 color: #333333;
429}
430body p-autocomplete.ng-dirty.ng-invalid > .p-autocomplete > .p-inputtext {
431 border: 1px solid #a80000;
432}
433
434// select button
435body .p-selectbutton .p-button {
436 background-color: #dadada;
437 border: 1px solid #dadada;
438 color: #333333;
439 overflow: hidden;
440 transition: background-color 0.2s, box-shadow 0.2s;
441}
442body .p-selectbutton .p-button .p-button-icon-left {
443 color: #666666;
444}
445body .p-selectbutton .p-button:not(.p-disabled):not(.p-highlight):hover {
446 background-color: #c8c8c8;
447 border-color: #c8c8c8;
448 color: #333333;
449}
450body .p-selectbutton .p-button:not(.p-disabled):not(.p-highlight):hover .p-button-icon-left {
451 color: #212121;
452}
453body .p-selectbutton .p-button:not(.p-disabled):not(.p-highlight).ui-state-focus {
454 box-shadow: 0 0 0 0.2em #8dcdff;
455 z-index: 1;
456}
457body .p-selectbutton .p-button.p-highlight {
458 background-color: pvar(--mainColor);
459 border-color: pvar(--mainColor);
460 color: #ffffff;
461}
462body .p-selectbutton .p-button.p-highlight .p-button-icon-left {
463 color: #ffffff;
464}
465body .p-selectbutton .p-button.p-highlight:not(.p-disabled):hover {
466 background-color: pvar(--mainColorLighter);
467 border-color: pvar(--mainColorLighter);
468 color: #ffffff;
469}
470body .p-selectbutton .p-button.p-highlight:not(.p-disabled):hover .p-button-icon-left {
471 color: #ffffff;
472}
473body .p-selectbutton .p-button:first-child {
474 border-top-left-radius: 3px;
475 border-bottom-left-radius: 3px;
476}
477body .p-selectbutton .p-button:last-child {
478 border-top-right-radius: 3px;
479 border-bottom-right-radius: 3px;
480}
481body p-selectbutton.ng-dirty.ng-invalid .p-button {
482 border: 1px solid #a80000;
483}
484
485//
6 486
7@mixin glyphicon-light { 487@mixin glyphicon-light {
8 font-family: 'Glyphicons Halflings'; 488 font-family: 'Glyphicons Halflings';
@@ -11,20 +491,9 @@
11 font-display: swap; 491 font-display: swap;
12} 492}
13 493
14my-edit-button,
15my-delete-button,
16my-button {
17 height: max-content;
18}
19
20// focus box-shadow for primeng
21.ui-inputtext:enabled:focus:not(.ui-state-error) {
22 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest) !important;
23}
24
25// data table customizations 494// data table customizations
26p-table { 495p-table {
27 .ui-table-caption { 496 .p-datatable-header {
28 border: none !important; 497 border: none !important;
29 background-color: pvar(--mainBackgroundColor) !important; 498 background-color: pvar(--mainBackgroundColor) !important;
30 499
@@ -54,6 +523,10 @@ p-table {
54 td { 523 td {
55 padding-left: 15px !important; 524 padding-left: 15px !important;
56 525
526 &.expand-cell {
527 padding: 10px 15px;
528 }
529
57 &:not(.action-cell):not(.expand-cell):not(.checkbox-cell) { 530 &:not(.action-cell):not(.expand-cell):not(.checkbox-cell) {
58 overflow: hidden !important; 531 overflow: hidden !important;
59 text-overflow: ellipsis !important; 532 text-overflow: ellipsis !important;
@@ -66,7 +539,7 @@ p-table {
66 background-color: pvar(--mainBackgroundColor) !important; 539 background-color: pvar(--mainBackgroundColor) !important;
67 height: 46px; 540 height: 46px;
68 541
69 &.ui-state-highlight { 542 &.p-highlight {
70 background-color: pvar(--submenuColor) !important; 543 background-color: pvar(--submenuColor) !important;
71 544
72 td, td > a { 545 td, td > a {
@@ -75,7 +548,7 @@ p-table {
75 } 548 }
76 } 549 }
77 550
78 .ui-table-tbody { 551 .p-datatable-tbody {
79 tr { 552 tr {
80 &:hover { 553 &:hover {
81 background-color: pvar(--submenuColor) !important; 554 background-color: pvar(--submenuColor) !important;
@@ -115,7 +588,7 @@ p-table {
115 font-weight: $font-semibold !important; 588 font-weight: $font-semibold !important;
116 color: pvar(--mainForegroundColor) !important; 589 color: pvar(--mainForegroundColor) !important;
117 590
118 &.ui-sortable-column:hover { 591 &.p-sortable-column:hover {
119 background-color: pvar(--submenuColor) !important; 592 background-color: pvar(--submenuColor) !important;
120 border: 1px solid !important; 593 border: 1px solid !important;
121 border-color: pvar(--submenuColor) !important; 594 border-color: pvar(--submenuColor) !important;
@@ -126,7 +599,7 @@ p-table {
126 } 599 }
127 } 600 }
128 601
129 &.ui-state-highlight { 602 &.p-highlight {
130 background-color: pvar(--submenuColor) !important; 603 background-color: pvar(--submenuColor) !important;
131 604
132 .pi { 605 .pi {
@@ -170,7 +643,7 @@ p-table {
170 } 643 }
171 644
172 p-paginator { 645 p-paginator {
173 .ui-paginator-bottom { 646 .p-paginator-bottom {
174 background-color: pvar(--mainBackgroundColor) !important; 647 background-color: pvar(--mainBackgroundColor) !important;
175 position: relative; 648 position: relative;
176 border: none; 649 border: none;
@@ -181,30 +654,31 @@ p-table {
181 justify-content: center; 654 justify-content: center;
182 align-items: center; 655 align-items: center;
183 656
184 .ui-dropdown { 657 .p-dropdown {
185 position: absolute; 658 position: absolute;
186 top: 3px; 659 top: 10px;
187 left: 0; 660 left: 0;
188 661
189 &.ui-state-focus { 662 &.p-focus {
190 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest); 663 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
191 } 664 }
192 665
193 .ui-dropdown-label { 666 .p-label {
194 color: pvar(--inputPlaceholderColor); 667 color: pvar(--inputPlaceholderColor);
195 } 668 }
196 } 669 }
197 670
198 .ui-paginator-current { 671 .p-paginator-current {
199 position: absolute; 672 position: absolute;
200 right: 0; 673 right: 0;
201 color: pvar(--inputPlaceholderColor); 674 color: pvar(--inputPlaceholderColor);
675 overflow: visible;
202 } 676 }
203 677
204 .ui-paginator-first, 678 .p-paginator-first,
205 .ui-paginator-prev, 679 .p-paginator-prev,
206 .ui-paginator-next, 680 .p-paginator-next,
207 .ui-paginator-last { 681 .p-paginator-last {
208 @include glyphicon-light; 682 @include glyphicon-light;
209 padding: 5px 2px; 683 padding: 5px 2px;
210 height: auto; 684 height: auto;
@@ -217,42 +691,40 @@ p-table {
217 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest); 691 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
218 } 692 }
219 693
220 &.ui-state-disabled:hover { 694 &.p-disabled:hover {
221 background-color: #fff !important; 695 background-color: #fff !important;
222 } 696 }
223 697
224 &.ui-paginator-first { 698 &.p-paginator-first {
225 @extend .glyphicon-step-backward; 699 @extend .glyphicon-step-backward;
226 } 700 }
227 701
228 &.ui-paginator-prev { 702 &.p-paginator-prev {
229 @extend .glyphicon-chevron-left; 703 @extend .glyphicon-chevron-left;
230 704
231 margin-right: 10px; 705 margin-right: 10px;
232 } 706 }
233 707
234 &.ui-paginator-next { 708 &.p-paginator-next {
235 @extend .glyphicon-chevron-right; 709 @extend .glyphicon-chevron-right;
236 710
237 margin-left: 10px; 711 margin-left: 10px;
238 } 712 }
239 713
240 &.ui-paginator-last { 714 &.p-paginator-last {
241 @extend .glyphicon-step-forward; 715 @extend .glyphicon-step-forward;
242 } 716 }
243 } 717 }
244 718
245 .ui-paginator-pages { 719 .p-paginator-pages {
246 height: auto !important; 720 height: auto !important;
247 721
248 .ui-paginator-page { 722 .p-paginator-page {
249 &.focus-within, 723 &.focus-within,
250 &:focus { 724 &:focus {
251 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest) !important; 725 box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest) !important;
252 } 726 }
253 }
254 727
255 a {
256 color: pvar(--mainForegroundColor) !important; 728 color: pvar(--mainForegroundColor) !important;
257 font-weight: $font-semibold !important; 729 font-weight: $font-semibold !important;
258 margin: 0 5px !important; 730 margin: 0 5px !important;
@@ -262,7 +734,7 @@ p-table {
262 height: auto !important; 734 height: auto !important;
263 line-height: initial !important; 735 line-height: initial !important;
264 736
265 &.ui-state-active { 737 &.p-highlight {
266 &, &:hover, &:active, &:focus { 738 &, &:hover, &:active, &:focus {
267 color: #fff !important; 739 color: #fff !important;
268 background-color: pvar(--mainColor) !important; 740 background-color: pvar(--mainColor) !important;
@@ -277,7 +749,7 @@ p-table {
277// overflow data table 749// overflow data table
278@mixin overflow-datatable ($table-min-width, $horizontal-margins, $mobile-paginator: true) { 750@mixin overflow-datatable ($table-min-width, $horizontal-margins, $mobile-paginator: true) {
279 p-table { 751 p-table {
280 .ui-table-wrapper { 752 .p-datatable-wrapper {
281 overflow-x: auto; 753 overflow-x: auto;
282 max-width: calc(100vw - #{$horizontal-margins * 2}); 754 max-width: calc(100vw - #{$horizontal-margins * 2});
283 755
@@ -287,15 +759,15 @@ p-table {
287 } 759 }
288 760
289 @if $mobile-paginator { 761 @if $mobile-paginator {
290 p-paginator .ui-paginator-bottom { 762 p-paginator .p-paginator-bottom {
291 display: block; 763 display: block;
292 764
293 .ui-paginator-current { 765 .p-paginator-current {
294 position: relative; 766 position: relative;
295 display: block; 767 display: block;
296 } 768 }
297 769
298 a, .ui-paginator-pages { 770 a, .p-paginator-pages {
299 vertical-align: middle; 771 vertical-align: middle;
300 } 772 }
301 } 773 }
@@ -304,18 +776,18 @@ p-table {
304} 776}
305 777
306// PrimeNG calendar tweaks 778// PrimeNG calendar tweaks
307p-calendar .ui-datepicker { 779p-calendar .p-datepicker {
308 a { 780 a {
309 @include disable-default-a-behaviour; 781 @include disable-default-a-behaviour;
310 } 782 }
311 783
312 .ui-datepicker-header { 784 .p-datepicker-header {
313 785
314 .ui-datepicker-year { 786 .p-datepicker-year {
315 margin-left: 5px; 787 margin-left: 5px;
316 } 788 }
317 789
318 .ui-datepicker-next { 790 .p-datepicker-next {
319 @extend .glyphicon-chevron-right; 791 @extend .glyphicon-chevron-right;
320 @include glyphicon-light; 792 @include glyphicon-light;
321 793
@@ -327,7 +799,7 @@ p-calendar .ui-datepicker {
327 } 799 }
328 } 800 }
329 801
330 .ui-datepicker-prev { 802 .p-datepicker-prev {
331 @extend .glyphicon-chevron-left; 803 @extend .glyphicon-chevron-left;
332 @include glyphicon-light; 804 @include glyphicon-light;
333 805
@@ -340,7 +812,7 @@ p-calendar .ui-datepicker {
340 } 812 }
341 } 813 }
342 814
343 .ui-timepicker { 815 .p-timepicker {
344 816
345 .pi.pi-chevron-up { 817 .pi.pi-chevron-up {
346 @extend .glyphicon-chevron-up; 818 @extend .glyphicon-chevron-up;
@@ -358,32 +830,32 @@ p-calendar .ui-datepicker {
358 } 830 }
359} 831}
360 832
361p-tablecheckbox:hover div .ui-chkbox-box { 833p-tablecheckbox:hover div .p-checkbox-box {
362 box-shadow: 0 0 0 .1rem rgba(87, 85, 217, .2); 834 box-shadow: 0 0 0 .1rem rgba(87, 85, 217, .2);
363} 835}
364 836
365.ui-chkbox { 837.p-checkbox {
366 838
367 &, .ui-chkbox-box { 839 &, .p-checkbox-box {
368 width: 18px !important; 840 width: 18px !important;
369 height: 18px !important; 841 height: 18px !important;
370 } 842 }
371 843
372 .ui-chkbox-box { 844 .p-checkbox-box {
373 &.ui-state-active { 845 &.p-highlight {
374 border-color: pvar(--mainColor) !important; 846 border-color: pvar(--mainColor) !important;
375 background-color: pvar(--mainColor) !important; 847 background-color: pvar(--mainColor) !important;
376 } 848 }
377 849
378 .ui-chkbox-icon { 850 .p-checkbox-icon {
379 position: relative; 851 position: relative;
380 overflow: visible !important; 852 overflow: visible !important;
381 853
382 &:after { 854 &:after {
383 content: ''; 855 content: '';
384 position: absolute; 856 position: absolute;
385 top: 1px; 857 bottom: -5px;
386 left: 6px; 858 left: -2px;
387 width: 5px; 859 width: 5px;
388 height: 12px; 860 height: 12px;
389 opacity: 0; 861 opacity: 0;
@@ -400,51 +872,30 @@ p-tablecheckbox:hover div .ui-chkbox-box {
400 } 872 }
401} 873}
402 874
403p-inputswitch {
404 height: 26px;
405
406 .ui-inputswitch-checked .ui-inputswitch-slider {
407 background-color: pvar(--mainColor) !important;
408 }
409
410 &.small {
411 height: 20px;
412
413 .ui-inputswitch {
414 width: 2.5em !important;
415 height: 1.45em !important;
416
417 .ui-inputswitch-slider::before {
418 height: 1em !important;
419 width: 1em !important;
420 }
421 }
422
423 .ui-inputswitch-checked .ui-inputswitch-slider::before {
424 transform: translateX(1em) !important;
425 }
426 }
427}
428
429p-toast { 875p-toast {
430 .ui-toast { 876 .p-toast {
877 width: auto;
878 max-width: 300px;
431 z-index: z(notification) !important; 879 z-index: z(notification) !important;
432 880
433 .ui-toast-close-icon { 881 .p-toast-icon-close {
434 font-family: "Glyphicons Halflings"; 882 font-family: "Glyphicons Halflings";
435 opacity: 0; 883 opacity: 0;
884 position: absolute;
885 right: 5px;
886 top: 5px;
436 887
437 &:after { 888 &:after {
438 content: "\e014"; 889 content: "\e014";
439 } 890 }
440 } 891 }
441 892
442 &:hover .ui-toast-close-icon { 893 &:hover .p-toast-icon-close {
443 opacity: .3; 894 opacity: .3;
444 } 895 }
445 } 896 }
446 897
447 .ui-toast-message { 898 .p-toast-message {
448 font-family: $main-fonts; 899 font-family: $main-fonts;
449 background-color: pvar(--mainBackgroundColor) !important; 900 background-color: pvar(--mainBackgroundColor) !important;
450 color: pvar(--mainForegroundColor) !important; 901 color: pvar(--mainForegroundColor) !important;
@@ -454,29 +905,30 @@ p-toast {
454 box-shadow: 0 2px 12px 0 rgba(0, 0 , 0, .1); 905 box-shadow: 0 2px 12px 0 rgba(0, 0 , 0, .1);
455 overflow: hidden; 906 overflow: hidden;
456 907
457 &.ui-toast-message-success .glyphicon { 908 &.p-toast-message-success .glyphicon {
458 color: #8BC34A !important; 909 color: #8BC34A !important;
459 } 910 }
460 911
461 &.ui-toast-message-error .glyphicon { 912 &.p-toast-message-error .glyphicon {
462 color: #F44336 !important; 913 color: #F44336 !important;
463 } 914 }
464 915
465 &.ui-toast-message-warn .glyphicon { 916 &.p-toast-message-warn .glyphicon {
466 color: #F1680D !important; 917 color: #F1680D !important;
467 } 918 }
468 919
469 &.ui-toast-message-info .glyphicon { 920 &.p-toast-message-info .glyphicon {
470 color: #03A9F4 !important; 921 color: #03A9F4 !important;
471 } 922 }
472 923
473 .notification-block { 924 .notification-block {
474 display: flex; 925 display: flex;
475 align-items: center; 926 align-items: center;
476 padding: 5px; 927 padding: 10px;
477 928
478 .message { 929 .message {
479 flex-grow: 1; 930 flex-grow: 1;
931 margin-right: 20px;
480 932
481 h3 { 933 h3 {
482 font-size: 21px; 934 font-size: 21px;
@@ -496,6 +948,14 @@ p-toast {
496 } 948 }
497} 949}
498 950
499.ui-widget { 951.p-selectbutton {
500 font-family: $main-fonts !important; 952 .p-button:focus {
953 outline: none;
954 }
955
956 .p-button-label {
957 padding: 5px 15px;
958 font-size: 15px;
959 font-weight: 600;
960 }
501} 961}