added theming support with 3 themes (only 2 selectable for now)

switched from css to scss default style system

cleaned up unused code in app component

upated youtube search results styling

downloading video from home screen now shows local progress bar under that video
This commit is contained in:
Isaac Grynsztein
2020-02-20 10:45:37 -05:00
parent 8545016f1d
commit c58f8a4058
16 changed files with 319 additions and 80 deletions

View File

@@ -16,12 +16,17 @@
},
"Extra": {
"title_top": "Youtube Downloader",
"download_only_mode": false,
"file_manager_enabled": true
"file_manager_enabled": true,
"allow_quality_select": true,
"download_only_mode": false
},
"API": {
"use_youtube_API": false,
"youtube_API_key": ""
},
"Themes": {
"default_theme": "default",
"allow_theme_change": true
}
}
}

View File

@@ -16,12 +16,17 @@
},
"Extra": {
"title_top": "Youtube Downloader",
"download_only_mode": false,
"file_manager_enabled": true
"file_manager_enabled": true,
"allow_quality_select": true,
"download_only_mode": false
},
"API": {
"use_youtube_API": false,
"youtube_API_key": ""
},
"Themes": {
"default_theme": "default",
"allow_theme_change": true
}
}
}

15
src/_palette.scss Normal file
View File

@@ -0,0 +1,15 @@
/* Coolors Exported Palette - coolors.co/e8aeb7-b8e1ff-a9fff7-94fbab-82aba1 */
/* HSL */
$color1: hsla(351%, 56%, 80%, 1);
$softblue: hsla(205%, 100%, 86%, 1);
$color3: hsla(174%, 100%, 83%, 1);
$color4: hsla(133%, 93%, 78%, 1);
$color5: hsla(165%, 20%, 59%, 1);
/* RGB */
$color1: rgba(232, 174, 183, 1);
$softblue: rgba(184, 225, 255, 1);
$color3: rgba(169, 255, 247, 1);
$color4: rgba(148, 251, 171, 1);
$color5: rgba(130, 171, 161, 1);

View File

@@ -1,15 +1,17 @@
<mat-toolbar color="primary" class="top">
<div class="flex-row" width="100%" height="100%">
<div class="flex-column" style="text-align: left; margin-top: 1px;">
<button (click)="goBack()" *ngIf="router.url.split(';')[0] === '/player'" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
<div [style.background]="postsService.theme.background_color" style="width: 100%; height: 100%;">
<mat-toolbar color="primary" class="top">
<div class="flex-row" width="100%" height="100%">
<div class="flex-column" style="text-align: left; margin-top: 1px;">
<button (click)="goBack()" *ngIf="router.url.split(';')[0] === '/player'" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
</div>
<div class="flex-column" style="text-align: center; margin-top: 5px;">
<div>{{topBarTitle}}</div>
</div>
<div class="flex-column" style="text-align: right; align-items: flex-end;">
<button *ngIf="allowThemeChange" mat-icon-button (click)="flipTheme()"><mat-icon>{{(postsService.theme.key === 'default') ? 'brightness_5' : 'brightness_2'}}</mat-icon></button>
</div>
</div>
<div class="flex-column" style="text-align: center; margin-top: 5px;">
<div>{{topBarTitle}}</div>
</div>
<div class="flex-column" style="text-align: right">
</mat-toolbar>
</div>
</div>
</mat-toolbar>
<router-outlet></router-outlet>
<router-outlet></router-outlet>
</div>

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { Component, OnInit, ElementRef, ViewChild, HostBinding } from '@angular/core';
import {PostsService} from './posts.services';
import {FileCardComponent} from './file-card/file-card.component';
import { Observable } from 'rxjs/Observable';
@@ -16,6 +16,8 @@ import 'rxjs/add/operator/do'
import 'rxjs/add/operator/switch'
import { YoutubeSearchService, Result } from './youtube-search.service';
import { Router } from '@angular/router';
import { OverlayContainer } from '@angular/cdk/overlay';
import { THEMES_CONFIG } from '../themes';
@Component({
selector: 'app-root',
@@ -23,56 +25,93 @@ import { Router } from '@angular/router';
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
iOS = false;
determinateProgress = false;
downloadingfile = false;
audioOnly: boolean;
urlError = false;
path = '';
url = '';
exists = '';
@HostBinding('class') componentCssClass;
THEMES_CONFIG = THEMES_CONFIG;
// config items
topBarTitle = 'Youtube Downloader';
percentDownloaded: number;
fileManagerEnabled = false;
downloadOnlyMode = false;
baseStreamPath;
audioFolderPath;
videoFolderPath;
// youtube api
youtubeSearchEnabled = false;
youtubeAPIKey = null;
results_loading = false;
results_showing = true;
results = [];
mp3s: any[] = [];
mp4s: any[] = [];
files_cols = (window.innerWidth <= 450) ? 2 : 4;
urlForm = new FormControl('', [Validators.required]);
defaultTheme = null;
allowThemeChange = null;
@ViewChild('urlinput', { read: ElementRef, static: false }) urlInput: ElementRef;
constructor(private postsService: PostsService, private youtubeSearch: YoutubeSearchService, public snackBar: MatSnackBar,
public router: Router) {
this.audioOnly = false;
public router: Router, public overlayContainer: OverlayContainer) {
// loading config
this.postsService.loadNavItems().subscribe(result => { // loads settings
this.topBarTitle = result['YoutubeDLMaterial']['Extra']['title_top'];
const themingExists = result['YoutubeDLMaterial']['Themes'];
this.defaultTheme = themingExists ? result['YoutubeDLMaterial']['Themes']['default_theme'] : 'default';
this.allowThemeChange = themingExists ? result['YoutubeDLMaterial']['Themes']['allow_theme_change'] : true;
// sets theme to config default if it doesn't exist
if (!localStorage.getItem('theme')) {
this.setTheme(themingExists ? this.defaultTheme : 'default');
}
}, error => {
console.log(error);
});
}
ngOnInit() {
// theme stuff
setTheme(theme) {
// theme is registered, so set it to the stored cookie variable
let old_theme = null;
if (this.THEMES_CONFIG[theme]) {
if (localStorage.getItem('theme')) {
old_theme = localStorage.getItem('theme');
if (!this.THEMES_CONFIG[old_theme]) {
console.log('bad theme found, setting to default');
if (this.defaultTheme === null) {
// means it hasn't loaded yet
console.error('No default theme detected');
} else {
localStorage.setItem('theme', this.defaultTheme);
old_theme = localStorage.getItem('theme'); // updates old_theme
}
}
}
localStorage.setItem('theme', theme);
} else {
console.error('Invalid theme: ' + theme);
return;
}
this.postsService.setTheme(theme);
this.onSetTheme(this.THEMES_CONFIG[theme]['css_label'], old_theme ? this.THEMES_CONFIG[old_theme]['css_label'] : old_theme);
}
onSetTheme(theme, old_theme) {
if (old_theme) {
document.body.classList.remove(old_theme);
this.overlayContainer.getContainerElement().classList.remove(old_theme);
}
this.overlayContainer.getContainerElement().classList.add(theme);
this.componentCssClass = theme;
}
flipTheme() {
if (this.postsService.theme.key === 'default') {
this.setTheme('dark');
} else if (this.postsService.theme.key === 'dark') {
this.setTheme('default');
}
}
ngOnInit() {
if (localStorage.getItem('theme')) {
this.setTheme(localStorage.getItem('theme'));
} else {
//
}
}
goBack() {
this.router.navigate(['/home']);
}

View File

@@ -1,4 +1,4 @@
<mat-card class="example-card">
<mat-card class="example-card mat-elevation-z6">
<button (click)="deleteFile()" class="deleteButton" mat-icon-button><mat-icon>delete_forever</mat-icon></button>
<div style="padding:5px">
<b><a href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>

View File

@@ -1,7 +1,7 @@
<h4 mat-dialog-title>{{inputTitle}}</h4>
<mat-dialog-content>
<div>
<mat-form-field>
<mat-form-field color="accent">
<input matInput (keyup.enter)="enterPressed()" [(ngModel)]="inputText" [placeholder]="inputPlaceholder">
</mat-form-field>
</div>

View File

@@ -81,4 +81,34 @@ mat-form-field.mat-form-field {
.margined {
margin-left: 20px;
margin-right: 20px;
}
.results-div {
position: relative;
top: -15px;
}
.first-result-card {
border-radius: 4px 4px 0px 0px !important;
}
.last-result-card {
border-radius: 0px 0px 4px 4px !important;
}
.only-result-card {
border-radius: 4px !important;
}
.result-card {
height: 120px;
border-radius: 0px;
padding-bottom: 5px;
}
.download-progress-bar {
z-index: 999;
position: absolute;
bottom: 0px;
width: 150px;
}

View File

@@ -9,15 +9,15 @@
<form class="example-form">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-sm-9">
<mat-form-field class="example-full-width">
<div [ngClass]="allowQualitySelect ? 'col-sm-9' : null" class="col-12">
<mat-form-field color="accent" class="example-full-width">
<input style="padding-right: 25px;" matInput (ngModelChange)="inputChanged($event)" [(ngModel)]="url" [placeholder]="'URL' + (youtubeSearchEnabled ? ' or search' : '')" type="url" name="url" [formControl]="urlForm" required #urlinput>
<mat-error *ngIf="urlError || urlForm.invalid">Please enter a valid URL!</mat-error>
<button class="input-clear-button" mat-icon-button (click)="clearInput()"><mat-icon>clear</mat-icon></button>
</mat-form-field>
</div>
<div class="col-7 col-sm-3">
<mat-form-field style="display: inline-block; width: inherit; min-width: 120px;">
<div *ngIf="allowQualitySelect" class="col-7 col-sm-3">
<mat-form-field color="accent" style="display: inline-block; width: inherit; min-width: 120px;">
<mat-label>Quality</mat-label>
<mat-select [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality">
<ng-container *ngFor="let option of qualityOptions[(audioOnly) ? 'audio' : 'video']">
@@ -33,21 +33,20 @@
</div>
</div>
</div>
<span *ngIf="results_showing">
<span *ngFor="let result of results">
<mat-card style="height: 120px; border-radius: 0px">
<div class="results-div" *ngIf="results_showing">
<span *ngFor="let result of results; let i = index">
<mat-card class="result-card mat-elevation-z7" [ngClass]="[(i === 0 && results.length > 1) ? 'first-result-card' : '', ((i === results.length-1) && results.length > 1) ? 'last-result-card' : '', (results.length === 1) ? 'only-result-card' : '']">
<div class="search-card-title">
{{result.title}}
</div>
<div style="font-size: 12px">
<div style="font-size: 12px; margin-bottom: 10px;">
{{result.uploaded}}
</div>
<br/>
<button mat-flat-button color="primary" style="float: left;" (click)="useURL(result.videoUrl)">Use URL</button>
<button mat-stroked-button color="primary" (click)="visitURL(result.videoUrl)" style="float: right">View</button>
</mat-card>
</span>
</span>
</div>
</form>
<br/>
<mat-checkbox (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">Only Audio</mat-checkbox>
@@ -56,7 +55,7 @@
</mat-card-content>
<mat-card-actions>
<button style="margin-left: 8px; margin-bottom: 8px" (click)="downloadClicked()" [disabled]="downloadingfile" type="submit" mat-stroked-button
color="primary">Download</button>
color="accent">Download</button>
</mat-card-actions>
</mat-card>
</div>
@@ -95,13 +94,18 @@
<mat-grid-tile *ngFor="let file of mp3s; index as i;">
<app-file-card (removeFile)="removeFromMp3($event)" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
[length]="file.duration" [isAudio]="true"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['audio'][file.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>
</mat-grid-list>
<mat-divider *ngIf="playlists.audio.length > 0"></mat-divider>
<div style="width: 100%; text-align: center; margin-top: 10px;" *ngIf="playlists.audio.length > 0">
<h6>Playlists</h6>
</div>
<mat-grid-list *ngIf="playlists.audio.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let playlist of playlists.audio; let i = index;">
<app-file-card (removeFile)="removePlaylistMp3(playlist.id, i)" [title]="playlist.name" [name]="playlist.id" [thumbnailURL]="playlist_thumbnails[playlist.id]"
[length]="null" [isAudio]="true" [isPlaylist]="true" [count]="playlist.fileNames.length"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['audio'][playlist.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>
</mat-grid-list>
</div>
@@ -121,13 +125,19 @@
<mat-grid-tile *ngFor="let file of mp4s; index as i;">
<app-file-card (removeFile)="removeFromMp4($event)" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
[length]="file.duration" [isAudio]="false"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['video'][file.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>
</mat-grid-list>
<mat-divider *ngIf="playlists.video.length > 0"></mat-divider>
<div style="width: 100%; text-align: center; margin-top: 10px;" *ngIf="playlists.video.length > 0">
<h6>Playlists</h6>
</div>
<mat-grid-list *ngIf="playlists.video.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let playlist of playlists.video; let i = index;">
<app-file-card (removeFile)="removePlaylistMp4(playlist.id, i)" [title]="playlist.name" [name]="playlist.id" [thumbnailURL]="playlist_thumbnails[playlist.id]"
[length]="null" [isAudio]="false" [isPlaylist]="true" [count]="playlist.fileNames.length"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['video'][playlist.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>
</mat-grid-list>
</div>

View File

@@ -33,7 +33,10 @@ export class MainComponent implements OnInit {
url = '';
exists = '';
percentDownloaded: number;
// settings
fileManagerEnabled = false;
allowQualitySelect = false;
downloadOnlyMode = false;
baseStreamPath;
audioFolderPath;
@@ -53,6 +56,7 @@ export class MainComponent implements OnInit {
files_cols = (window.innerWidth <= 450) ? 2 : 4;
playlists = {'audio': [], 'video': []};
playlist_thumbnails = {};
downloading_content = {'audio': {}, 'video': {}};
urlForm = new FormControl('', [Validators.required]);
@@ -171,6 +175,7 @@ export class MainComponent implements OnInit {
this.youtubeSearchEnabled = result['YoutubeDLMaterial']['API'] && result['YoutubeDLMaterial']['API']['use_youtube_API'] &&
result['YoutubeDLMaterial']['API']['youtube_API_key'];
this.youtubeAPIKey = this.youtubeSearchEnabled ? result['YoutubeDLMaterial']['API']['youtube_API_key'] : null;
this.allowQualitySelect = result['YoutubeDLMaterial']['Extra']['allow_quality_select'];
this.postsService.path = backendUrl;
this.postsService.startPath = backendUrl;
@@ -246,23 +251,38 @@ export class MainComponent implements OnInit {
public goToFile(name, isAudio) {
if (isAudio) {
this.downloadHelperMp3(name, false, true);
this.downloadHelperMp3(name, false, false);
} else {
this.downloadHelperMp4(name, false, true);
this.downloadHelperMp4(name, false, false);
}
}
public goToPlaylist(playlistID, type) {
for (let i = 0; i < this.playlists[type].length; i++) {
const playlist = this.playlists[type][i];
if (playlist.id === playlistID) {
// found the playlist, now go to it
const playlist = this.getPlaylistObjectByID(playlistID, type);
if (playlist) {
if (this.downloadOnlyMode) {
this.downloading_content[type][playlistID] = true;
this.downloadPlaylist(playlist.fileNames, type, playlist.name, playlistID);
} else {
const fileNames = playlist.fileNames;
this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID}]);
}
} else {
// playlist not found
console.error(`Playlist with ID ${playlistID} not found!`);
}
}
getPlaylistObjectByID(playlistID, type) {
for (let i = 0; i < this.playlists[type].length; i++) {
const playlist = this.playlists[type][i];
if (playlist.id === playlistID) {
return playlist;
}
}
return null;
}
public removeFromMp3(name: string) {
for (let i = 0; i < this.mp3s.length; i++) {
if (this.mp3s[i].id === name) {
@@ -275,6 +295,7 @@ export class MainComponent implements OnInit {
this.postsService.removePlaylist(playlistID, 'audio').subscribe(res => {
if (res['success']) {
this.playlists.audio.splice(index, 1);
this.openSnackBar('Playlist successfully removed.', '');
}
this.getMp3s();
});
@@ -292,6 +313,7 @@ export class MainComponent implements OnInit {
this.postsService.removePlaylist(playlistID, 'video').subscribe(res => {
if (res['success']) {
this.playlists.video.splice(index, 1);
this.openSnackBar('Playlist successfully removed.', '');
}
this.getMp4s();
});
@@ -315,9 +337,8 @@ export class MainComponent implements OnInit {
// if download only mode, just download the file. no redirect
if (forceView === false && this.downloadOnlyMode && !this.iOS) {
if (is_playlist) {
for (let i = 0; i < name.length; i++) {
this.downloadAudioFile(decodeURI(name[i]));
}
const zipName = name[0].split(' ')[0] + name[1].split(' ')[0];
this.downloadPlaylist(name, 'audio', zipName);
} else {
this.downloadAudioFile(decodeURI(name));
}
@@ -343,9 +364,8 @@ export class MainComponent implements OnInit {
// if download only mode, just download the file. no redirect
if (forceView === false && this.downloadOnlyMode) {
if (is_playlist) {
for (let i = 0; i < name.length; i++) {
this.downloadVideoFile(decodeURI(name[i]));
}
const zipName = name[0].split(' ')[0] + name[1].split(' ')[0];
this.downloadPlaylist(name, 'video', zipName);
} else {
this.downloadVideoFile(decodeURI(name));
}
@@ -422,7 +442,9 @@ export class MainComponent implements OnInit {
}
downloadAudioFile(name) {
this.downloading_content['audio'][name] = true;
this.postsService.downloadFileFromServer(name, 'audio').subscribe(res => {
this.downloading_content['audio'][name] = false;
const blob: Blob = res;
saveAs(blob, name + '.mp3');
@@ -437,7 +459,9 @@ export class MainComponent implements OnInit {
}
downloadVideoFile(name) {
this.downloading_content['video'][name] = true;
this.postsService.downloadFileFromServer(name, 'video').subscribe(res => {
this.downloading_content['video'][name] = false;
const blob: Blob = res;
saveAs(blob, name + '.mp4');
@@ -451,6 +475,15 @@ export class MainComponent implements OnInit {
});
}
downloadPlaylist(fileNames, type, zipName = null, playlistID = null) {
this.postsService.downloadFileFromServer(fileNames, type, zipName).subscribe(res => {
if (playlistID) { this.downloading_content[type][playlistID] = false };
const blob: Blob = res;
saveAs(blob, zipName + '.zip');
});
}
clearInput() {
this.url = '';
this.results_showing = false;
@@ -493,7 +526,7 @@ export class MainComponent implements OnInit {
const reYT = new RegExp(youtubeStrRegex);
const ytValid = reYT.test(str);
if (valid && ytValid && Date.now() - this.last_url_check > 1000) {
if (str !== this.last_valid_url) {
if (str !== this.last_valid_url && this.allowQualitySelect) {
// get info
this.getURLInfo(str);
}

View File

@@ -205,7 +205,6 @@ export class PlayerComponent implements OnInit {
// changes the route without moving from the current view or
// triggering a navigation event
this.id = playlistID;
console.log(this.router.url);
this.router.navigateByUrl(this.router.url + ';id=' + playlistID);
}

View File

@@ -6,6 +6,7 @@ import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { THEMES_CONFIG } from '../themes';
@Injectable()
export class PostsService {
@@ -15,11 +16,17 @@ export class PostsService {
startPath = 'http://localhost:17442/';
startPathSSL = 'https://localhost:17442/'
handShakeComplete = false;
THEMES_CONFIG = THEMES_CONFIG;
theme;
constructor(private http: HttpClient) {
console.log('PostsService Initialized...');
}
setTheme(theme) {
this.theme = this.THEMES_CONFIG[theme];
}
startHandshake(url: string) {
return this.http.get(url + 'geturl');
}

View File

@@ -17,11 +17,16 @@
"Extra": {
"title_top": "Youtube Downloader",
"file_manager_enabled": true,
"allow_quality_select": true,
"download_only_mode": false
},
"API": {
"use_youtube_API": false,
"youtube_API_key": ""
},
"Themes": {
"default_theme": "default",
"allow_theme_change": true
}
}
}

View File

@@ -1,3 +0,0 @@
/* You can add global styles to this file, and also import other style files */
@import '@angular/material/prebuilt-themes/indigo-pink.css';

70
src/styles.scss Normal file
View File

@@ -0,0 +1,70 @@
/* You can add global styles to this file, and also import other style files */
@import '@angular/material/prebuilt-themes/indigo-pink.css';
//@import './app-theme';
/* You can add global styles to this file, and also import other style files */
// @import "../node_modules/@angular/material/prebuilt-themes/purple-green.css";
@import "palette.scss";
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
@import '~@angular/material/theming';
// Plus imports for other components in your app.
/*// Typography
$custom-typography: mat-typography-config(
$font-family: Raleway,
$headline: mat-typography-level(24px, 48px, 400),
$body-1: mat-typography-level(16px, 24px, 400)
);
@include angular-material-typography($custom-typography);
*/
// Default colors
$my-app-primary: mat-palette($mat-light-blue, 700, 100, 800);
$my-app-accent: mat-palette($mat-blue, 700, 100, 800);
$my-app-warn: mat-palette($mat-red, 700, 100, 800);
$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn);
@include angular-material-theme($my-app-theme);
// Dark theme
$dark-primary: mat-palette($mat-indigo);
$dark-accent: mat-palette($mat-blue);
$dark-warn: mat-palette($mat-deep-orange);
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
.dark-theme {
@include angular-material-theme($dark-theme);
}
// Light theme
$light-primary: mat-palette($mat-grey, 200, 500, 300);
$light-accent: mat-palette($mat-brown, 200);
$light-warn: mat-palette($mat-deep-orange, 200);
$light-theme: mat-light-theme($light-primary, $light-accent, $light-warn);
.light-theme {
@include angular-material-theme($light-theme)
}
.no-outline {
outline: none;
}
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();
// @import '../node_modules/@angular/material/theming';
.centered {
margin: 0 auto;
left: 50%;
top: 50%;
}

22
src/themes.ts Normal file
View File

@@ -0,0 +1,22 @@
const THEMES_CONFIG = {
'default': {
'key': 'default',
'background_color': 'ghostwhite',
'css_label': 'default-theme',
'social_theme': 'material-light'
},
'dark': {
'key': 'dark',
'background_color': '#757575',
'css_label': 'dark-theme',
'social_theme': 'material-dark'
},
'light': {
'key': 'light',
'background_color': 'white',
'css_label': 'light-theme',
'social_theme': 'material-light'
}
};
export {THEMES_CONFIG};