feat: add dark theme

This commit is contained in:
4gray committed 2021-03-21 13:15:24 +01:00
1 parent 2e6fa1cfa7
commit 0cf010aba3
19 files changed
+201 -45

No files matched your search

+6
View File
@@ -8,6 +8,7 @@ import { ChannelStore } from './state';
import { StorageMap } from '@ngx-pwa/local-storage'; import { StorageMap } from '@ngx-pwa/local-storage';
import { Settings } from './settings/settings.interface'; import { Settings } from './settings/settings.interface';
import { EPG_ERROR, EPG_FETCH, EPG_FETCH_DONE } from '../../ipc-commands'; import { EPG_ERROR, EPG_FETCH, EPG_FETCH_DONE } from '../../ipc-commands';
import { SettingsService } from './services/settings.service';
// create custom title bar // create custom title bar
new Titlebar({ new Titlebar({
@@ -28,6 +29,7 @@ export class AppComponent {
private ngZone: NgZone, private ngZone: NgZone,
private router: Router, private router: Router,
private translate: TranslateService, private translate: TranslateService,
private settingsService: SettingsService,
private snackBar: MatSnackBar, private snackBar: MatSnackBar,
private storage: StorageMap private storage: StorageMap
) { ) {
@@ -115,6 +117,10 @@ export class AppComponent {
horizontalPosition: 'right', horizontalPosition: 'right',
}); });
} }
if (settings.theme) {
this.settingsService.changeTheme(settings.theme);
}
} }
}); });
+2 -6
View File
@@ -3,11 +3,7 @@
text-transform: uppercase; text-transform: uppercase;
} }
.mat-tab-group.mat-background-primary .mat-tab-header {
background: #000 !important;
}
.mat-tab-group.mat-background-primary .mat-tab-header-pagination { .mat-tab-group.mat-background-primary .mat-tab-header-pagination {
display:none; display: none;
} }
} }
@@ -28,7 +28,7 @@
</mat-form-field> </mat-form-field>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button mat-dialog-close cdkFocusInitial color="primary"> <button mat-button mat-dialog-close cdkFocusInitial color="accent">
{{ 'HOME.PLAYLISTS.INFO_DIALOG.CLOSE' | translate }} {{ 'HOME.PLAYLISTS.INFO_DIALOG.CLOSE' | translate }}
</button> </button>
</mat-dialog-actions> </mat-dialog-actions>
@@ -35,7 +35,7 @@
</div> </div>
<button <button
mat-icon-button mat-icon-button
color="primary" color="accent"
(click)="$event.stopPropagation(); openInfoDialog(item)" (click)="$event.stopPropagation(); openInfoDialog(item)"
[matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate" [matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate"
> >
@@ -43,7 +43,7 @@
</button> </button>
<button <button
mat-icon-button mat-icon-button
color="primary" color="accent"
(click)="$event.stopPropagation(); removeClicked.emit(item._id)" (click)="$event.stopPropagation(); removeClicked.emit(item._id)"
[matTooltip]="'HOME.PLAYLISTS.REMOVE' | translate" [matTooltip]="'HOME.PLAYLISTS.REMOVE' | translate"
> >
@@ -16,6 +16,20 @@
.search-bar { .search-bar {
padding: 8px; padding: 8px;
background: #ddd;
border: none;
border-radius: 4px;
}
::ng-deep .dark-theme {
.search-bar {
background: #666;
color: #fff;
}
.search-bar::placeholder {
color: #ccc;
}
} }
::ng-deep { ::ng-deep {
@@ -26,9 +40,10 @@
border-radius: 0 !important; border-radius: 0 !important;
} }
.mat-tab-label, .mat-tab-label-active { .mat-tab-label,
min-width: 0!important; .mat-tab-label-active {
padding: 15px!important; min-width: 0 !important;
margin: 5px!important; padding: 15px !important;
margin: 5px !important;
} }
} }
@@ -1,6 +1,6 @@
<ng-container *ngIf="channel; else noEpg"> <ng-container *ngIf="channel; else noEpg">
<!-- channel info panel --> <!-- channel info panel -->
<div fxFlex="120px" id="channel-info" fxLayout="column"> <div fxFlex="120px" id="channel-info" color="primary" fxLayout="column">
<div fxFlex="79px" fxLayout="row" fxLayoutGap="10px"> <div fxFlex="79px" fxLayout="row" fxLayoutGap="10px">
<div <div
fxFlex="60px" fxFlex="60px"
@@ -22,6 +22,7 @@
</div> </div>
</div> </div>
</div> </div>
<mat-divider></mat-divider>
<div fxFlex="40px" fxLayout="row" id="date-navigator"> <div fxFlex="40px" fxLayout="row" id="date-navigator">
<button <button
fxFlex="40px" fxFlex="40px"
@@ -48,6 +49,7 @@
</button> </button>
</div> </div>
</div> </div>
<mat-divider></mat-divider>
<!-- program list --> <!-- program list -->
<mat-selection-list <mat-selection-list
@@ -14,10 +14,6 @@
} }
#channel-info { #channel-info {
border-bottom: 1px solid #ccc;
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
background-color: #ccc;
.channel-icon { .channel-icon {
overflow: hidden; overflow: hidden;
} }
@@ -40,12 +36,8 @@ mat-selection-list {
overflow: auto; overflow: auto;
} }
#date-navigator { #date-navigator {
border-top: 1px solid #999;
.selected-date { .selected-date {
font-size: 0.9em; font-size: 0.9em;
color: #333;
} }
} }
+19
View File
@@ -0,0 +1,19 @@
import { Theme } from './../settings/theme.enum';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class SettingsService {
/**
* Changes the visual theme of the application
* @param selectedTheme theme to set
*/
changeTheme(selectedTheme: Theme): void {
if (selectedTheme === Theme.LightTheme) {
document.body.classList.remove('dark-theme');
} else if (selectedTheme === Theme.DarkTheme) {
document.body.classList.add('dark-theme');
}
}
}
+26 -2
View File
@@ -95,6 +95,30 @@
</p> </p>
</div> </div>
</mat-list-item> </mat-list-item>
<mat-list-item>
<div matLine fxLayout="row">
<p fxFlex>{{ 'SETTINGS.THEME' | translate }}</p>
<p fxFlex>
<mat-form-field appearance="fill">
<mat-label>{{
'SETTINGS.VIDEO_PLAYER_PLACEHOLDER'
| translate
}}</mat-label>
<mat-select formControlName="theme">
<mat-option
*ngFor="
let theme of themeEnum | keyvalue
"
[value]="theme.value"
>{{
'THEMES.' + theme.value | translate
}}</mat-option
>
</mat-select>
</mat-form-field>
</p>
</div>
</mat-list-item>
<mat-list-item> <mat-list-item>
<div matLine fxLayout="row"> <div matLine fxLayout="row">
<p fxFlex>{{ 'SETTINGS.VERSION' | translate }}</p> <p fxFlex>{{ 'SETTINGS.VERSION' | translate }}</p>
@@ -109,7 +133,7 @@
<mat-card-actions> <mat-card-actions>
<button <button
mat-button mat-button
color="primary" color="accent"
type="submit" type="submit"
[disabled]="settingsForm.pristine" [disabled]="settingsForm.pristine"
> >
@@ -119,7 +143,7 @@
<div fxFlex></div> <div fxFlex></div>
<button <button
mat-button mat-button
color="primary" color="accent"
type="reset" type="reset"
(click)="backToHome()" (click)="backToHome()"
> >
+15
View File
@@ -12,6 +12,8 @@ import { ElectronService } from '../services/electron.service';
import { ChannelQuery } from '../state'; import { ChannelQuery } from '../state';
import { EPG_FETCH } from '../../../ipc-commands'; import { EPG_FETCH } from '../../../ipc-commands';
import { Language } from './language.enum'; import { Language } from './language.enum';
import { Theme } from './theme.enum';
import { SettingsService } from './../services/settings.service';
/** Url of the package.json file in the app repository, required to get the version of the released app */ /** Url of the package.json file in the app repository, required to get the version of the released app */
const PACKAGE_JSON_URL = const PACKAGE_JSON_URL =
@@ -55,6 +57,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
(store) => store.epgAvailable (store) => store.epgAvailable
); );
/** All available visual themes */
themeEnum = Theme;
/** /**
* Creates an instance of SettingsComponent and injects some dependencies into the component * Creates an instance of SettingsComponent and injects some dependencies into the component
* @param channelQuery * @param channelQuery
@@ -62,8 +67,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
* @param formBuilder * @param formBuilder
* @param http * @param http
* @param router * @param router
* @param settingsService
* @param snackBar * @param snackBar
* @param storage * @param storage
* @param translate
*/ */
constructor( constructor(
private channelQuery: ChannelQuery, private channelQuery: ChannelQuery,
@@ -71,6 +78,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private http: HttpClient, private http: HttpClient,
private router: Router, private router: Router,
private settingsService: SettingsService,
private snackBar: MatSnackBar, private snackBar: MatSnackBar,
private storage: StorageMap, private storage: StorageMap,
private translate: TranslateService private translate: TranslateService
@@ -79,6 +87,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
player: ['videojs'], player: ['videojs'],
epgUrl: '', epgUrl: '',
language: Language.ENGLISH, language: Language.ENGLISH,
theme: Theme.LightTheme,
}); });
this.subscription.add( this.subscription.add(
@@ -119,6 +128,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
language: settings.language language: settings.language
? settings.language ? settings.language
: Language.ENGLISH, : Language.ENGLISH,
theme: settings.theme
? settings.theme
: Theme.LightTheme,
}); });
} }
}) })
@@ -139,6 +151,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.fetchEpg(); this.fetchEpg();
} }
this.translate.use(this.settingsForm.value.language); this.translate.use(this.settingsForm.value.language);
this.settingsService.changeTheme(
this.settingsForm.value.theme
);
this.snackBar.open( this.snackBar.open(
this.translate.instant('SETTINGS.SETTINGS_SAVED'), this.translate.instant('SETTINGS.SETTINGS_SAVED'),
null, null,
+2
View File
@@ -1,4 +1,5 @@
import { Language } from './language.enum'; import { Language } from './language.enum';
import { Theme } from './theme.enum';
export type VideoPlayerType = 'html5' | 'videojs'; export type VideoPlayerType = 'html5' | 'videojs';
@@ -9,4 +10,5 @@ export interface Settings {
player: VideoPlayerType; player: VideoPlayerType;
epgUrl: string; epgUrl: string;
language: Language; language: Language;
theme: Theme;
} }
+4
View File
@@ -0,0 +1,4 @@
export enum Theme {
DarkTheme = 'DARK_THEME',
LightTheme = 'LIGHT_THEME',
}
+6 -1
View File
@@ -87,7 +87,12 @@
"VERSION": "Version", "VERSION": "Version",
"VIDEO_PLAYER_LABEL": "Video player", "VIDEO_PLAYER_LABEL": "Video player",
"VIDEO_PLAYER_PLACEHOLDER": "Option auswählen", "VIDEO_PLAYER_PLACEHOLDER": "Option auswählen",
"SETTINGS_SAVED": "Einstellungen wurden erfolgreich gespeichert!" "SETTINGS_SAVED": "Einstellungen wurden erfolgreich gespeichert!",
"THEME": "Farbdesign"
},
"THEMES": {
"DARK_THEME": "Dunkel",
"LIGHT_THEME": "Hell"
}, },
"TOP_MENU": { "TOP_MENU": {
"OPEN_CHANNELS_LIST": "Senderliste öffnen", "OPEN_CHANNELS_LIST": "Senderliste öffnen",
+6 -1
View File
@@ -50,7 +50,12 @@
"NEW_VERSION_AVAILABLE": "There is a new version available", "NEW_VERSION_AVAILABLE": "There is a new version available",
"LATEST_VERSION": "You are using the latest version", "LATEST_VERSION": "You are using the latest version",
"LANGUAGE": "Language", "LANGUAGE": "Language",
"SETTINGS_SAVED": "Success! Configuration was saved." "SETTINGS_SAVED": "Success! Configuration was saved.",
"THEME": "Visual theme"
},
"THEMES": {
"DARK_THEME": "Dark theme",
"LIGHT_THEME": "Light theme"
}, },
"CHANNELS": { "CHANNELS": {
"SEARCH_CHANNEL": "Search channel", "SEARCH_CHANNEL": "Search channel",
+6 -1
View File
@@ -50,7 +50,12 @@
"NEW_VERSION_AVAILABLE": "Доступна новая версия приложения", "NEW_VERSION_AVAILABLE": "Доступна новая версия приложения",
"LATEST_VERSION": "Вы используете последнюю версию приложения", "LATEST_VERSION": "Вы используете последнюю версию приложения",
"LANGUAGE": "Язык", "LANGUAGE": "Язык",
"SETTINGS_SAVED": "Новые настройки были успешно сохранены." "SETTINGS_SAVED": "Новые настройки были успешно сохранены.",
"THEME": "Тема оформления"
},
"THEMES": {
"DARK_THEME": "Тёмная тема",
"LIGHT_THEME": "Светлая тема"
}, },
"CHANNELS": { "CHANNELS": {
"SEARCH_CHANNEL": "Поиск каналов", "SEARCH_CHANNEL": "Поиск каналов",
+11 -11
View File
@@ -1,14 +1,14 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<title>IPTVnator</title> <title>IPTVnator</title>
<base href="/"> <base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico"> <link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico" />
</head> </head>
<body> <body class="mat-app-background">
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>
+7 -5
View File
@@ -1,14 +1,16 @@
$material-icons-font-path: '~material-icons/iconfont/';
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@import '~@angular/material/prebuilt-themes/indigo-pink.css'; @import '~@angular/material/prebuilt-themes/indigo-pink.css';
$material-icons-font-path: '~material-icons/iconfont/';
@import '~material-icons/iconfont/material-icons.scss'; @import '~material-icons/iconfont/material-icons.scss';
@import "~@angular/material/theming";
@include mat-core();
@import 'themes/';
body, body,
html { html {
background: #fff; background: #fff;
font-family: caption; font-family: caption;
user-select: none;
} }
.mat-toolbar.mat-primary { .mat-toolbar.mat-primary {
@@ -70,13 +72,13 @@ html, body {
height: 54px; height: 54px;
} }
:not(input):not(textarea), /* :not(input):not(textarea),
:not(input):not(textarea)::after, :not(input):not(textarea)::after,
:not(input):not(textarea)::before { :not(input):not(textarea)::before {
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
cursor: default; cursor: default;
} } */
input, button, textarea, :focus { input, button, textarea, :focus {
outline: none; outline: none;
} }
+48
View File
@@ -0,0 +1,48 @@
$black: (
50: #000000,
100: #000000,
200: #000000,
300: #000000,
400: #000000,
500: #000000,
600: #000000,
700: #000000,
800: #000000,
900: #000000,
A100: #000000,
A200: #000000,
A400: #000000,
A700: #000000,
contrast: (
50: $light-primary-text,
100: $light-primary-text,
200: $light-primary-text,
300: $light-primary-text,
400: $light-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $light-primary-text,
A200: $light-primary-text,
A400: $light-primary-text,
A700: $light-primary-text,
),
);
$angular-primary: mat-palette($black);
$angular-accent: mat-palette($mat-indigo, 500, 600, 700);
$angular-warn: mat-palette($mat-red);
$angular-default-theme: mat-light-theme(
(
color: (
primary: $angular-primary,
accent: $angular-accent,
warn: $angular-warn,
),
)
);
@include angular-material-theme($angular-default-theme);
@import 'dark';
+16
View File
@@ -0,0 +1,16 @@
$dark-primary: mat-palette($black, A200, A800, A500);
$dark-accent: mat-palette($mat-teal, A400, A100, A400);
$dark-warn: mat-palette($mat-red);
$dark-theme: mat-dark-theme(
(
color: (
primary: $dark-primary,
accent: $dark-accent,
warn: $dark-warn,
),
)
);
.dark-theme {
@include angular-material-color($dark-theme);
}