mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-22 18:47:06 +00:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43b85ca3b6 | ||
|
|
99696cabf7 | ||
|
|
f246fab1f4 | ||
|
|
b0101a1f8c | ||
|
|
8f5e947c28 | ||
|
|
dfd430712d | ||
|
|
8431c19133 | ||
|
|
6ee6934e0d | ||
|
|
3253fbfaf4 | ||
|
|
985a8dd3a9 | ||
|
|
0c99c075f3 | ||
|
|
c79db27092 | ||
|
|
a92cb8b7b6 | ||
|
|
bb3d6d4839 | ||
|
|
9c06622efb | ||
|
|
8b590408b0 | ||
|
|
18b2bdf5ab | ||
|
|
ba49621e79 | ||
|
|
416f1997a9 | ||
|
|
fcfbedfd74 | ||
|
|
35f3512e89 | ||
|
|
2288905cbd | ||
|
|
5a40116c7b | ||
|
|
b7c10a515c | ||
|
|
65e637eeb9 | ||
|
|
b56088948c | ||
|
|
0c5066e7d0 | ||
|
|
751497556a | ||
|
|
5f2372cc08 | ||
|
|
6f315aa38e | ||
|
|
0653b5f36b | ||
|
|
f13120bc01 | ||
|
|
a6c56518bc | ||
|
|
ecae48f3d0 | ||
|
|
c74751e0f4 | ||
|
|
2b755fa669 | ||
|
|
ca0f46b414 | ||
|
|
528fa31df6 | ||
|
|
abfb2a6706 | ||
|
|
b1ab11393e | ||
|
|
786883eb10 | ||
|
|
e477f797d0 | ||
|
|
fb196c3864 | ||
|
|
5cf44962fc | ||
|
|
06b0c3775a | ||
|
|
26690990f0 | ||
|
|
377092d9ec | ||
|
|
abede386c8 | ||
|
|
242feaa169 | ||
|
|
7c2494a82c | ||
|
|
5c2e717a40 | ||
|
|
6ae0a9760d | ||
|
|
2a10f3e443 | ||
|
|
db7a00440c | ||
|
|
0e1c589399 | ||
|
|
2f419b1af5 | ||
|
|
effd3cefcb | ||
|
|
21fd488a8e | ||
|
|
37a5c69269 | ||
|
|
9f440b1bf2 | ||
|
|
a65f61cce4 | ||
|
|
0d8fe0be72 | ||
|
|
2bbc90af64 | ||
|
|
ad21d9fed5 | ||
|
|
4c6ef29e20 | ||
|
|
a74c5108fd | ||
|
|
19fdbbdbcb | ||
|
|
8bbabd7437 | ||
|
|
5a9cd36282 | ||
|
|
297bb95a2e | ||
|
|
2511a03b66 | ||
|
|
76358f996e | ||
|
|
142fc982ca | ||
|
|
22d9279e3b | ||
|
|
a1bec98d44 | ||
|
|
e8449e340d | ||
|
|
4cb8009c69 | ||
|
|
7f357306eb | ||
|
|
06679343a4 | ||
|
|
f35d83567e | ||
|
|
c97fd77c13 | ||
|
|
62904cdb42 | ||
|
|
d9c36cad82 | ||
|
|
d2bfc152a0 | ||
|
|
f013b2b667 | ||
|
|
9fbcc20623 | ||
|
|
0fd8a75f7d | ||
|
|
99d9552813 | ||
|
|
3bca193bcc | ||
|
|
f73ff363a5 | ||
|
|
1bf689f154 | ||
|
|
3499d89098 | ||
|
|
685cd76da2 | ||
|
|
786180958d | ||
|
|
a2f72c92d5 | ||
|
|
6b368d2e79 | ||
|
|
47c2cc721e | ||
|
|
5574e3f729 | ||
|
|
1934bad3eb | ||
|
|
ee29f20304 | ||
|
|
93c2eab584 | ||
|
|
b0f45980be | ||
|
|
7b10b2ad86 | ||
|
|
3fc510469d | ||
|
|
5d56b3bcd6 | ||
|
|
aaa14eb1e9 | ||
|
|
f43608f93b | ||
|
|
9ecd921722 | ||
|
|
98e2ff0e1e | ||
|
|
b7cb09b087 | ||
|
|
fe8b44b14c | ||
|
|
ca8ed939ae | ||
|
|
4469a2c25a |
@@ -38,13 +38,28 @@
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# Fuse2
|
||||
|
||||
Material Design Admin Template with Angular 4+ and Angular Material 2
|
||||
Material Design Admin Template with Angular 5+ and Angular Material 2
|
||||
|
||||
## The Community
|
||||
|
||||
Share your ideas, discuss Fuse and help each other.
|
||||
|
||||
[Click here](https://join.slack.com/t/fuse-theme/shared_invite/enQtMzA1NDE4NzYwMjcyLWQxODE4ODM1MWU4MWJjMDhlMGEwYzM4Mzg3N2E4YzVlZThhZjNlOTQ1Y2Q5OTBlNDNkMzJhZDIwMjgxOWQ3YWU) to join our Slack workspace.
|
||||
|
||||
## Development server
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Fuse2Page } from './app.po';
|
||||
|
||||
describe('fuse2 App', () => {
|
||||
let page: Fuse2Page;
|
||||
describe('Fuse2 App', () => {
|
||||
let page: Fuse2Page;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new Fuse2Page();
|
||||
});
|
||||
beforeEach(() => {
|
||||
page = new Fuse2Page();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!!');
|
||||
});
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class Fuse2Page {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
|
||||
9608
package-lock.json
generated
9608
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
114
package.json
114
package.json
@@ -1,73 +1,85 @@
|
||||
{
|
||||
"name": "fuse2",
|
||||
"version": "1.1.2",
|
||||
"license": "",
|
||||
"version": "1.3.6",
|
||||
"license": "https://themeforest.net/licenses/terms/regular",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"start": "ng serve --open",
|
||||
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
|
||||
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
|
||||
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build",
|
||||
"build-prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --prod",
|
||||
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev",
|
||||
"build-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev --stats-json",
|
||||
"build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
|
||||
"build-prod-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod --stats-json",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
"e2e": "ng e2e",
|
||||
"bundle-report": "webpack-bundle-analyzer dist/stats.json"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@agm/core": "1.0.0-beta.1",
|
||||
"@angular/animations": "4.4.5",
|
||||
"@angular/cdk": "2.0.0-beta.12",
|
||||
"@angular/common": "4.4.5",
|
||||
"@angular/compiler": "4.4.5",
|
||||
"@angular/core": "4.4.5",
|
||||
"@angular/flex-layout": "2.0.0-beta.9",
|
||||
"@angular/forms": "4.4.5",
|
||||
"@angular/http": "4.4.5",
|
||||
"@angular/material": "2.0.0-beta.12",
|
||||
"@angular/platform-browser": "4.4.5",
|
||||
"@angular/platform-browser-dynamic": "4.4.5",
|
||||
"@angular/router": "4.4.5",
|
||||
"@swimlane/ngx-charts": "6.0.2",
|
||||
"@swimlane/ngx-datatable": "9.3.1",
|
||||
"@swimlane/ngx-dnd": "3.0.0",
|
||||
"angular-calendar": "0.21.2",
|
||||
"angular-in-memory-web-api": "0.5.0",
|
||||
"angular2-markdown": "1.6.0",
|
||||
"@agm/core": "1.0.0-beta.2",
|
||||
"@angular/animations": "5.2.3",
|
||||
"@angular/cdk": "5.1.1",
|
||||
"@angular/common": "5.2.3",
|
||||
"@angular/compiler": "5.2.3",
|
||||
"@angular/core": "5.2.3",
|
||||
"@angular/flex-layout": "2.0.0-beta.12",
|
||||
"@angular/forms": "5.2.3",
|
||||
"@angular/http": "5.2.3",
|
||||
"@angular/material": "5.1.1",
|
||||
"@angular/material-moment-adapter": "5.1.1",
|
||||
"@angular/platform-browser": "5.2.3",
|
||||
"@angular/platform-browser-dynamic": "5.2.3",
|
||||
"@angular/router": "5.2.3",
|
||||
"@ngrx/effects": "5.0.0",
|
||||
"@ngrx/router-store": "5.0.0",
|
||||
"@ngrx/store": "5.0.0",
|
||||
"@ngrx/store-devtools": "5.0.0",
|
||||
"@ngx-translate/core": "9.1.1",
|
||||
"@swimlane/ngx-charts": "7.0.1",
|
||||
"@swimlane/ngx-datatable": "11.1.7",
|
||||
"@swimlane/ngx-dnd": "3.1.0",
|
||||
"@types/prismjs": "1.9.0",
|
||||
"angular-calendar": "0.23.3",
|
||||
"angular-in-memory-web-api": "0.5.3",
|
||||
"chart.js": "2.7.1",
|
||||
"classlist.js": "1.1.20150312",
|
||||
"core-js": "2.5.1",
|
||||
"d3": "4.10.0",
|
||||
"core-js": "2.5.3",
|
||||
"d3": "4.13.0",
|
||||
"hammerjs": "2.0.8",
|
||||
"highlight.js": "9.12.0",
|
||||
"intl": "1.2.5",
|
||||
"moment": "2.19.1",
|
||||
"ngx-color-picker": "4.4.0",
|
||||
"ngx-cookie-service": "1.0.9",
|
||||
"perfect-scrollbar": "1.0.3",
|
||||
"rxjs": "5.4.3",
|
||||
"moment": "2.20.1",
|
||||
"ng2-charts": "1.6.0",
|
||||
"ngrx-store-freeze": "0.2.1",
|
||||
"ngx-color-picker": "5.3.1",
|
||||
"ngx-cookie-service": "1.0.10",
|
||||
"perfect-scrollbar": "1.3.0",
|
||||
"prismjs": "1.11.0",
|
||||
"rxjs": "5.5.6",
|
||||
"web-animations-js": "2.3.1",
|
||||
"zone.js": "0.8.18"
|
||||
"zone.js": "0.8.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.4.7",
|
||||
"@angular/compiler-cli": "4.4.5",
|
||||
"@angular/language-service": "4.4.5",
|
||||
"@angular/cli": "1.6.7",
|
||||
"@angular/compiler-cli": "5.2.3",
|
||||
"@angular/language-service": "5.2.3",
|
||||
"@angularclass/hmr": "2.1.3",
|
||||
"@types/jasmine": "2.6.0",
|
||||
"@types/jasminewd2": "2.0.2",
|
||||
"@types/node": "6.0.88",
|
||||
"codelyzer": "3.2.0",
|
||||
"jasmine-core": "2.6.2",
|
||||
"jasmine-spec-reporter": "4.1.0",
|
||||
"karma": "1.7.1",
|
||||
"karma-chrome-launcher": "2.1.1",
|
||||
"karma-cli": "1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"@types/jasmine": "2.8.6",
|
||||
"@types/jasminewd2": "2.0.3",
|
||||
"@types/node": "6.0.96",
|
||||
"codelyzer": "4.1.0",
|
||||
"jasmine-core": "2.8.0",
|
||||
"jasmine-spec-reporter": "4.2.1",
|
||||
"karma": "2.0.0",
|
||||
"karma-chrome-launcher": "2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "1.4.1",
|
||||
"karma-jasmine": "1.1.1",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"protractor": "5.1.2",
|
||||
"ts-node": "3.2.0",
|
||||
"tslint": "5.7.0",
|
||||
"typescript": "2.3.3"
|
||||
"ts-node": "4.1.0",
|
||||
"tslint": "5.9.1",
|
||||
"typescript": "2.6.2",
|
||||
"webpack-bundle-analyzer": "2.10.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,25 @@
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FuseTranslationLoaderService } from './core/services/translation-loader.service';
|
||||
|
||||
import { FuseNavigationService } from './core/components/navigation/navigation.service';
|
||||
import { FuseNavigationModel } from './navigation/navigation.model';
|
||||
import { locale as navigationEnglish } from './navigation/i18n/en';
|
||||
import { locale as navigationTurkish } from './navigation/i18n/tr';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-root',
|
||||
@@ -8,7 +15,26 @@ import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
})
|
||||
export class AppComponent
|
||||
{
|
||||
constructor(private fuseSplashScreen: FuseSplashScreenService)
|
||||
constructor(
|
||||
private fuseNavigationService: FuseNavigationService,
|
||||
private fuseSplashScreen: FuseSplashScreenService,
|
||||
private translate: TranslateService,
|
||||
private translationLoader: FuseTranslationLoaderService
|
||||
)
|
||||
{
|
||||
// Add languages
|
||||
this.translate.addLangs(['en', 'tr']);
|
||||
|
||||
// Set the default language
|
||||
this.translate.setDefaultLang('en');
|
||||
|
||||
// Use a language
|
||||
this.translate.use('en');
|
||||
|
||||
// Set the navigation model
|
||||
this.fuseNavigationService.setNavigationModel(new FuseNavigationModel());
|
||||
|
||||
// Set the navigation translations
|
||||
this.translationLoader.loadTranslations(navigationEnglish, navigationTurkish);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
@@ -8,52 +7,42 @@ import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
|
||||
import 'hammerjs';
|
||||
import { SharedModule } from './core/modules/shared.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { ProjectModule } from './main/content/apps/dashboards/project/project.module';
|
||||
import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service';
|
||||
import { FuseMainModule } from './main/main.module';
|
||||
import { PagesModule } from './main/content/pages/pages.module';
|
||||
import { UIModule } from './main/content/ui/ui.module';
|
||||
import { ComponentsModule } from './main/content/components/components.module';
|
||||
import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
import { FuseConfigService } from './core/services/config.service';
|
||||
import { FuseNavigationService } from './core/components/navigation/navigation.service';
|
||||
import { ComponentsThirdPartyModule } from './main/content/components-third-party/components-third-party.module';
|
||||
import { ServicesModule } from './main/content/services/services.module';
|
||||
import { FuseAngularMaterialModule } from './main/content/components/angular-material/angular-material.module';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppStoreModule } from './store/store.module';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
path : 'apps/mail',
|
||||
loadChildren: './main/content/apps/mail/mail.module#FuseMailModule'
|
||||
path : 'apps',
|
||||
loadChildren: './main/content/apps/apps.module#FuseAppsModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/chat',
|
||||
loadChildren: './main/content/apps/chat/chat.module#FuseChatModule'
|
||||
path : 'pages',
|
||||
loadChildren: './main/content/pages/pages.module#FusePagesModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/calendar',
|
||||
loadChildren: './main/content/apps/calendar/calendar.module#FuseCalendarModule'
|
||||
path : 'ui',
|
||||
loadChildren: './main/content/ui/ui.module#FuseUIModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/todo',
|
||||
loadChildren: './main/content/apps/todo/todo.module#FuseTodoModule'
|
||||
path : 'services',
|
||||
loadChildren: './main/content/services/services.module#FuseServicesModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/file-manager',
|
||||
loadChildren: './main/content/apps/file-manager/file-manager.module#FuseFileManagerModule'
|
||||
path : 'components',
|
||||
loadChildren: './main/content/components/components.module#FuseComponentsModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/contacts',
|
||||
loadChildren: './main/content/apps/contacts/contacts.module#FuseContactsModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/scrumboard',
|
||||
loadChildren: './main/content/apps/scrumboard/scrumboard.module#FuseScrumboardModule'
|
||||
path : 'components-third-party',
|
||||
loadChildren: './main/content/components-third-party/components-third-party.module#FuseComponentsThirdPartyModule'
|
||||
},
|
||||
{
|
||||
path : '**',
|
||||
redirectTo: 'apps/dashboards/project'
|
||||
redirectTo: 'apps/dashboards/analytics'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -63,28 +52,17 @@ const appRoutes: Routes = [
|
||||
],
|
||||
imports : [
|
||||
BrowserModule,
|
||||
HttpModule,
|
||||
HttpClientModule,
|
||||
BrowserAnimationsModule,
|
||||
RouterModule.forRoot(appRoutes),
|
||||
SharedModule,
|
||||
MarkdownModule.forRoot(),
|
||||
|
||||
TranslateModule.forRoot(),
|
||||
InMemoryWebApiModule.forRoot(FuseFakeDbService, {
|
||||
delay : 0,
|
||||
passThruUnknownUrl: true
|
||||
}),
|
||||
|
||||
FuseMainModule,
|
||||
|
||||
ProjectModule,
|
||||
|
||||
PagesModule,
|
||||
UIModule,
|
||||
ServicesModule,
|
||||
ComponentsModule,
|
||||
FuseAngularMaterialModule,
|
||||
ComponentsThirdPartyModule
|
||||
AppStoreModule,
|
||||
FuseMainModule
|
||||
],
|
||||
providers : [
|
||||
FuseSplashScreenService,
|
||||
|
||||
@@ -33,21 +33,21 @@ export const fuseAnimations = [
|
||||
stagger('50ms', [
|
||||
animateChild()
|
||||
])
|
||||
])),
|
||||
], {optional: true})),
|
||||
transition('void => 100',
|
||||
query('@*',
|
||||
[
|
||||
stagger('100ms', [
|
||||
animateChild()
|
||||
])
|
||||
])),
|
||||
], {optional: true})),
|
||||
transition('void => 200',
|
||||
query('@*',
|
||||
[
|
||||
stagger('200ms', [
|
||||
animateChild()
|
||||
])
|
||||
]))
|
||||
], {optional: true}))
|
||||
]),
|
||||
|
||||
trigger('fadeInOut', [
|
||||
@@ -76,6 +76,53 @@ export const fuseAnimations = [
|
||||
transition('0 => 1', animate('300ms ease-in'))
|
||||
]),
|
||||
|
||||
trigger('slideIn', [
|
||||
transition('void => left', [
|
||||
style({
|
||||
transform: 'translateX(100%)'
|
||||
}),
|
||||
animate('300ms ease-in',
|
||||
style({
|
||||
transform: 'translateX(0)'
|
||||
})
|
||||
)
|
||||
]
|
||||
),
|
||||
transition('left => void', [
|
||||
style({
|
||||
transform: 'translateX(0)'
|
||||
}),
|
||||
animate('300ms ease-in',
|
||||
style({
|
||||
transform: 'translateX(-100%)'
|
||||
})
|
||||
)
|
||||
]
|
||||
),
|
||||
transition('void => right', [
|
||||
style({
|
||||
transform: 'translateX(-100%)'
|
||||
}),
|
||||
animate('300ms ease-in',
|
||||
style({
|
||||
transform: 'translateX(0)'
|
||||
})
|
||||
)
|
||||
]
|
||||
),
|
||||
transition('right => void', [
|
||||
style({
|
||||
transform: 'translateX(0)'
|
||||
}),
|
||||
animate('300ms ease-in',
|
||||
style({
|
||||
transform: 'translateX(100%)'
|
||||
})
|
||||
)
|
||||
]
|
||||
),
|
||||
]),
|
||||
|
||||
trigger('slideInLeft', [
|
||||
state('void', style({
|
||||
transform: 'translateX(-100%)',
|
||||
@@ -129,6 +176,17 @@ export const fuseAnimations = [
|
||||
transition('* => void', animate('300ms'))
|
||||
]),
|
||||
|
||||
trigger('expandCollapse', [
|
||||
state('void', style({
|
||||
height: '0px'
|
||||
})),
|
||||
state('*', style({
|
||||
height: '*'
|
||||
})),
|
||||
transition('void => *', animate('300ms ease-out')),
|
||||
transition('* => void', animate('300ms ease-in'))
|
||||
]),
|
||||
|
||||
trigger('routerTransitionLeft', [
|
||||
|
||||
transition('* => *', [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/interval';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-countdown',
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
:host {
|
||||
display: block;
|
||||
padding: 8px;
|
||||
background: #263238;
|
||||
cursor: text;
|
||||
}
|
||||
102
src/app/core/components/highlight/highlight.component.ts
Normal file
102
src/app/core/components/highlight/highlight.component.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Component, ContentChild, ElementRef, Input, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
import * as Prism from 'prismjs/prism';
|
||||
import './prism-languages';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-highlight',
|
||||
template : ' ',
|
||||
styleUrls: ['./highlight.component.scss']
|
||||
})
|
||||
export class FuseHighlightComponent implements OnInit
|
||||
{
|
||||
@ContentChild('source') source: ElementRef;
|
||||
@Input('lang') lang: string;
|
||||
@Input('path') path: string;
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// If there is no language defined, return...
|
||||
if ( !this.lang )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the path is defined...
|
||||
if ( this.path )
|
||||
{
|
||||
// Get the source
|
||||
this.http.get(this.path, {responseType: 'text'}).subscribe((response) => {
|
||||
|
||||
// Highlight it
|
||||
this.highlight(response);
|
||||
});
|
||||
}
|
||||
|
||||
// If the path is not defined and the source element exists...
|
||||
if ( !this.path && this.source )
|
||||
{
|
||||
// Highlight it
|
||||
this.highlight(this.source.nativeElement.value);
|
||||
}
|
||||
}
|
||||
|
||||
highlight(sourceCode)
|
||||
{
|
||||
// Split the source into lines
|
||||
const sourceLines = sourceCode.split('\n');
|
||||
|
||||
// Remove the first and the last line of the source
|
||||
// code if they are blank lines. This way, the html
|
||||
// can be formatted properly while using fuse-highlight
|
||||
// component
|
||||
if ( !sourceLines[0].trim() )
|
||||
{
|
||||
sourceLines.shift();
|
||||
}
|
||||
|
||||
if ( !sourceLines[sourceLines.length - 1].trim() )
|
||||
{
|
||||
sourceLines.pop();
|
||||
}
|
||||
|
||||
// Find the first non-whitespace char index in
|
||||
// the first line of the source code
|
||||
const indexOfFirstChar = sourceLines[0].search(/\S|$/);
|
||||
|
||||
// Generate the trimmed source
|
||||
let source = '';
|
||||
|
||||
// Iterate through all the lines
|
||||
sourceLines.forEach((line, index) => {
|
||||
|
||||
// Trim the beginning white space depending on the index
|
||||
// and concat the source code
|
||||
source = source + line.substr(indexOfFirstChar, line.length);
|
||||
|
||||
// If it's not the last line...
|
||||
if ( index !== sourceLines.length - 1 )
|
||||
{
|
||||
// Add a line break at the end
|
||||
source = source + '\n';
|
||||
}
|
||||
});
|
||||
|
||||
// Generate the highlighted code
|
||||
const highlightedCode = Prism.highlight(source, Prism.languages[this.lang]);
|
||||
|
||||
// Replace the innerHTML of the component with the highlighted code
|
||||
this.elementRef.nativeElement.innerHTML =
|
||||
'<pre><code class="highlight language-' + this.lang + '">' + highlightedCode + '</code></pre>';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
16
src/app/core/components/highlight/prism-languages.ts
Normal file
16
src/app/core/components/highlight/prism-languages.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'prismjs/prism';
|
||||
import 'prismjs/components/prism-c';
|
||||
import 'prismjs/components/prism-cpp';
|
||||
import 'prismjs/components/prism-csharp';
|
||||
import 'prismjs/components/prism-css';
|
||||
import 'prismjs/components/prism-diff';
|
||||
import 'prismjs/components/prism-markup';
|
||||
import 'prismjs/components/prism-java';
|
||||
import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/components/prism-json';
|
||||
import 'prismjs/components/prism-perl';
|
||||
import 'prismjs/components/prism-php';
|
||||
import 'prismjs/components/prism-python';
|
||||
import 'prismjs/components/prism-sass';
|
||||
import 'prismjs/components/prism-scss';
|
||||
import 'prismjs/components/prism-typescript';
|
||||
@@ -1,3 +0,0 @@
|
||||
:host {
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Component, ContentChild, ElementRef, Input, OnInit } from '@angular/core';
|
||||
import * as hljs from 'highlight.js';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-hljs',
|
||||
template : ' ',
|
||||
styleUrls: ['./hljs.component.scss']
|
||||
})
|
||||
export class FuseHljsComponent implements OnInit
|
||||
{
|
||||
hljs: any;
|
||||
|
||||
@ContentChild('source') source: ElementRef;
|
||||
@Input('lang') lang: string;
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef
|
||||
)
|
||||
{
|
||||
this.hljs = hljs;
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
const originalSource = this.source.nativeElement.value;
|
||||
|
||||
if ( !originalSource || !this.lang )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Split the source into lines
|
||||
const sourceLines = originalSource.split('\n');
|
||||
|
||||
// Find the first non-whitespace char index in
|
||||
// the first line of the source code
|
||||
const indexOfFirstChar = sourceLines[0].search(/\S|$/);
|
||||
|
||||
// Generate the trimmed source
|
||||
let source = '';
|
||||
|
||||
// Iterate through all the lines and trim the
|
||||
// beginning white space depending on the index
|
||||
sourceLines.forEach((line, index) => {
|
||||
|
||||
source = source + line.substr(indexOfFirstChar, line.length);
|
||||
|
||||
if ( index !== sourceLines.length - 1 )
|
||||
{
|
||||
source = source + '\n';
|
||||
}
|
||||
});
|
||||
|
||||
this.elementRef.nativeElement.innerHTML =
|
||||
`<pre><code class="highlight">` + this.hljs.highlight(this.lang, source).value + `</code></pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
type="button"
|
||||
class="mat-elevation-z1"
|
||||
[matMenuTriggerFor]="colorMenu"
|
||||
(onMenuOpen)="onMenuOpen()"
|
||||
(menuOpened)="onMenuOpen()"
|
||||
[ngClass]="'mat-'+selectedPalette+'-'+selectedHue+'-bg'">
|
||||
<mat-icon>palette</mat-icon>
|
||||
</button>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<a class="nav-link" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
<mat-icon class="collapse-arrow">keyboard_arrow_right</mat-icon>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active" matRipple>
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
@@ -9,8 +10,8 @@
|
||||
|
||||
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
|
||||
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
|
||||
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item>
|
||||
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
|
||||
|
||||
</ng-container>
|
||||
|
||||
|
||||
5
src/app/core/components/navigation/navigation.model.ts
Normal file
5
src/app/core/components/navigation/navigation.model.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface FuseNavigationModelInterface
|
||||
{
|
||||
model: any[];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { NavigationModel } from '../../../navigation.model';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { FuseNavigationModelInterface } from './navigation.model';
|
||||
|
||||
@Injectable()
|
||||
export class FuseNavigationService
|
||||
@@ -8,13 +8,11 @@ export class FuseNavigationService
|
||||
onNavCollapseToggle = new EventEmitter<any>();
|
||||
onNavCollapseToggled = new EventEmitter<any>();
|
||||
onNavigationModelChange: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
navigationModel: NavigationModel;
|
||||
navigationModel: FuseNavigationModelInterface;
|
||||
flatNavigation: any[] = [];
|
||||
|
||||
constructor()
|
||||
{
|
||||
this.navigationModel = new NavigationModel();
|
||||
this.onNavigationModelChange.next(this.navigationModel.model);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,8 +153,15 @@ export class FuseNavigationService
|
||||
*/
|
||||
getFlatNavigation(navigationItems?)
|
||||
{
|
||||
// If navigation items not provided,
|
||||
// that means we are running the function
|
||||
// for the first time...
|
||||
if ( !navigationItems )
|
||||
{
|
||||
// Reset the flat navigation
|
||||
this.flatNavigation = [];
|
||||
|
||||
// Get the entire navigation model
|
||||
navigationItems = this.navigationModel.model;
|
||||
}
|
||||
|
||||
@@ -181,7 +186,10 @@ export class FuseNavigationService
|
||||
|
||||
if ( navItem.type === 'collapse' || navItem.type === 'group' )
|
||||
{
|
||||
this.getFlatNavigation(navItem.children);
|
||||
if ( navItem.children )
|
||||
{
|
||||
this.getFlatNavigation(navItem.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
<a class="nav-link" matRipple (click)="toggleOpen($event)">
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
<mat-icon class="collapse-arrow">keyboard_arrow_right</mat-icon>
|
||||
</a>
|
||||
|
||||
<div class="children" [@slideInOut]="isOpen">
|
||||
<ng-container *ngFor="let item of item.children">
|
||||
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
|
||||
|
||||
@@ -69,6 +69,20 @@ export class FuseNavVerticalCollapseComponent implements OnInit
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// Check if the url can be found in
|
||||
// one of the children of this item
|
||||
if ( this.isUrlInChildren(this.item, this.router.url) )
|
||||
{
|
||||
this.expand();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.collapse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle collapse
|
||||
*
|
||||
@@ -108,6 +122,7 @@ export class FuseNavVerticalCollapseComponent implements OnInit
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.isOpen = false;
|
||||
this.navigationService.onNavCollapseToggle.emit();
|
||||
}
|
||||
@@ -166,7 +181,7 @@ export class FuseNavVerticalCollapseComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
if ( parent.children[i].url === url )
|
||||
if ( parent.children[i].url === url || url.includes(parent.children[i].url) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -175,8 +190,4 @@ export class FuseNavVerticalCollapseComponent implements OnInit
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div class="group-title">
|
||||
<span class="hint-text">{{ item.title }}</span>
|
||||
<span class="hint-text" [translate]="item.translate">{{ item.title }}</span>
|
||||
</div>
|
||||
|
||||
<div class="group-items">
|
||||
<ng-container *ngFor="let item of item.children">
|
||||
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active" matRipple>
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
@@ -9,8 +10,8 @@
|
||||
|
||||
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
|
||||
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
|
||||
{{item.badge.title}}
|
||||
</span>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="addMenu" matTooltip="Click to add/remove shortcut"
|
||||
(onMenuOpen)="onMenuOpen()">
|
||||
(menuOpened)="onMenuOpen()">
|
||||
<mat-icon class="amber-600-fg">star</mat-icon>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -149,7 +149,9 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
|
||||
|
||||
onMenuOpen()
|
||||
{
|
||||
this.searchInputField.nativeElement.focus();
|
||||
setTimeout(() => {
|
||||
this.searchInputField.nativeElement.focus();
|
||||
});
|
||||
}
|
||||
|
||||
showMobileShortcutsPanel()
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
<h3>Navigation Fold (for vertical navigation):</h3>
|
||||
<mat-slide-toggle [(ngModel)]="fuseSettings.layout.navigationFolded"
|
||||
(change)="onSettingsChange()">
|
||||
Folded
|
||||
</mat-slide-toggle>
|
||||
|
||||
<h3 class="mt-24">Toolbar:</h3>
|
||||
<mat-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()"
|
||||
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
|
||||
|
||||
@@ -62,4 +62,23 @@ fuse-widget {
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
|
||||
&.mat-form-field-type-mat-select {
|
||||
|
||||
.mat-input-wrapper {
|
||||
padding: 16px 0;
|
||||
|
||||
.mat-input-infix {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-input-underline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export class FuseWidgetComponent implements OnInit, AfterContentInit
|
||||
setTimeout(() => {
|
||||
|
||||
this.toggleButtons.forEach(flipButton => {
|
||||
this.renderer.listen(flipButton.el.nativeElement, 'click', () => {
|
||||
this.renderer.listen(flipButton.el.nativeElement, 'click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.toggle();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
|
||||
import { MatSidenav } from '@angular/material';
|
||||
import { FuseMatSidenavHelperService } from 'app/core/directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { FuseMatchMedia } from '../../services/match-media.service';
|
||||
import { ObservableMedia } from '@angular/flex-layout';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FuseMatchMedia } from '../../services/match-media.service';
|
||||
import { FuseMatSidenavHelperService } from './fuse-mat-sidenav-helper.service';
|
||||
|
||||
@Directive({
|
||||
selector: '[fuseMatSidenavHelper]'
|
||||
@@ -13,7 +13,6 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
|
||||
matchMediaSubscription: Subscription;
|
||||
|
||||
@HostBinding('class.mat-is-locked-open') isLockedOpen = true;
|
||||
@HostBinding('class.mat-stop-transition') stopTransition = true;
|
||||
|
||||
@Input('fuseMatSidenavHelper') id: string;
|
||||
@Input('mat-is-locked-open') matIsLockedOpenBreakpoint: string;
|
||||
@@ -33,45 +32,31 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
|
||||
|
||||
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.open();
|
||||
});
|
||||
this.stopTransition = false;
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.close();
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.stopTransition = false;
|
||||
}, 3000);
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.toggle(false);
|
||||
}
|
||||
|
||||
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
|
||||
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.open();
|
||||
});
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.close();
|
||||
});
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.toggle(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
@@ -1,22 +1,22 @@
|
||||
import { AfterViewInit, Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
import { AfterViewInit, Directive, ElementRef, HostListener, OnDestroy } from '@angular/core';
|
||||
import { FuseConfigService } from '../../services/config.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
|
||||
@Directive({
|
||||
selector: '[fusePerfectScrollbar]'
|
||||
})
|
||||
export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnDestroy
|
||||
export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
|
||||
{
|
||||
onSettingsChanged: Subscription;
|
||||
isDisableCustomScrollbars = false;
|
||||
isMobile = false;
|
||||
isInitialized = true;
|
||||
ps;
|
||||
ps: PerfectScrollbar;
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
public element: ElementRef,
|
||||
private fuseConfig: FuseConfigService,
|
||||
private platform: Platform
|
||||
)
|
||||
@@ -35,11 +35,6 @@ export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnD
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit()
|
||||
{
|
||||
if ( this.isMobile || this.isDisableCustomScrollbars )
|
||||
@@ -49,12 +44,14 @@ export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnD
|
||||
}
|
||||
|
||||
// Initialize the perfect-scrollbar
|
||||
this.ps = new PerfectScrollbar(this.element.nativeElement);
|
||||
this.ps = new PerfectScrollbar(this.element.nativeElement, {
|
||||
wheelPropagation: true
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
if ( !this.isInitialized )
|
||||
if ( !this.isInitialized || !this.ps )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -65,6 +62,21 @@ export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnD
|
||||
this.ps.destroy();
|
||||
}
|
||||
|
||||
@HostListener('document:click', ['$event'])
|
||||
documentClick(event: Event): void
|
||||
{
|
||||
if ( !this.isInitialized || !this.ps )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the scrollbar on document click..
|
||||
// This isn't the most elegant solution but there is no other way
|
||||
// of knowing when the contents of the scrollable container changes.
|
||||
// Therefore, we update scrollbars on every document click.
|
||||
this.ps.update();
|
||||
}
|
||||
|
||||
update()
|
||||
{
|
||||
if ( !this.isInitialized )
|
||||
|
||||
@@ -82,10 +82,12 @@ export class FuseUtils
|
||||
{
|
||||
function S4()
|
||||
{
|
||||
return (((1 + Math.random()) * 0x10000) || 0).toString(16).substring(1);
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
return (S4() + S4());
|
||||
return S4() + S4();
|
||||
}
|
||||
|
||||
public static toggleInArray(item, array)
|
||||
@@ -99,4 +101,14 @@ export class FuseUtils
|
||||
array.splice(array.indexOf(item), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static handleize(text)
|
||||
{
|
||||
return text.toString().toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
|
||||
.replace(/\-\-+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, ''); // Trim - from end of text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,6 +681,7 @@ const matColors = {
|
||||
}
|
||||
};
|
||||
|
||||
// tslint:disable-next-line
|
||||
const matPresetColors = [
|
||||
'#ffebee', '#ffcdd2', '#ef9a9a', '#e57373', '#ef5350', '#f44336', '#e53935', '#d32f2f', '#c62828', '#b71c1c', '#ff8a80', '#ff5252', '#ff1744', '#d50000', '#fce4ec', '#f8bbd0', '#f48fb1', '#f06292', '#ec407a', '#e91e63', '#d81b60', '#c2185b', '#ad1457', '#880e4f', '#ff80ab', '#ff4081', '#f50057', '#c51162', '#f3e5f5', '#e1bee7', '#ce93d8', '#ba68c8', '#ab47bc', '#9c27b0', '#8e24aa', '#7b1fa2', '#6a1b9a', '#4a148c', '#ea80fc', '#e040fb', '#d500f9', '#aa00ff', '#ede7f6', '#d1c4e9', '#b39ddb', '#9575cd', '#7e57c2', '#673ab7', '#5e35b1', '#512da8', '#4527a0', '#311b92', '#b388ff', '#7c4dff', '#651fff', '#6200ea', '#e8eaf6', '#c5cae9', '#9fa8da', '#7986cb', '#5c6bc0', '#3f51b5', '#3949ab', '#303f9f', '#283593', '#1a237e', '#8c9eff', '#536dfe', '#3d5afe', '#304ffe', '#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5', '#2196f3', '#1e88e5', '#1976d2', '#1565c0', '#0d47a1', '#82b1ff', '#448aff', '#2979ff', '#2962ff', '#e1f5fe', '#b3e5fc', '#81d4fa', '#4fc3f7', '#29b6f6', '#03a9f4', '#039be5', '#0288d1', '#0277bd', '#01579b', '#80d8ff', '#40c4ff', '#00b0ff', '#0091ea', '#e0f7fa', '#b2ebf2', '#80deea', '#4dd0e1', '#26c6da', '#00bcd4', '#00acc1', '#0097a7', '#00838f', '#006064', '#84ffff', '#18ffff', '#00e5ff', '#00b8d4', '#e0f2f1', '#b2dfdb', '#80cbc4', '#4db6ac', '#26a69a', '#009688', '#00897b', '#00796b', '#00695c', '#004d40', '#a7ffeb', '#64ffda', '#1de9b6', '#00bfa5', '#e8f5e9', '#c8e6c9', '#a5d6a7', '#81c784', '#66bb6a', '#4caf50', '#43a047', '#388e3c', '#2e7d32', '#1b5e20', '#b9f6ca', '#69f0ae', '#00e676', '#00c853', '#f1f8e9', '#dcedc8', '#c5e1a5', '#aed581', '#9ccc65', '#8bc34a', '#7cb342', '#689f38', '#558b2f', '#33691e', '#ccff90', '#b2ff59', '#76ff03', '#64dd17', '#f9fbe7', '#f0f4c3', '#e6ee9c', '#dce775', '#d4e157', '#cddc39', '#c0ca33', '#afb42b', '#9e9d24', '#827717', '#f4ff81', '#eeff41', '#c6ff00', '#aeea00', '#fffde7', '#fff9c4', '#fff59d', '#fff176', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825', '#f57f17', '#ffff8d', '#ffff00', '#ffea00', '#ffd600', '#fff8e1', '#ffecb3', '#ffe082', '#ffd54f', '#ffca28', '#ffc107', '#ffb300', '#ffa000', '#ff8f00', '#ff6f00', '#ffe57f', '#ffd740', '#ffc400', '#ffab00', '#fff3e0', '#ffe0b2', '#ffcc80', '#ffb74d', '#ffa726', '#ff9800', '#fb8c00', '#f57c00', '#ef6c00', '#e65100', '#ffd180', '#ffab40', '#ff9100', '#ff6d00', '#fbe9e7', '#ffccbc', '#ffab91', '#ff8a65', '#ff7043', '#ff5722', '#f4511e', '#e64a19', '#d84315', '#bf360c', '#ff9e80', '#ff6e40', '#ff3d00', '#dd2c00', '#efebe9', '#d7ccc8', '#bcaaa4', '#a1887f', '#8d6e63', '#795548', '#6d4c41', '#5d4037', '#4e342e', '#3e2723', '#d7ccc8', '#bcaaa4', '#8d6e63', '#5d4037', '#fafafa', '#f5f5f5', '#eeeeee', '#e0e0e0', '#bdbdbd', '#9e9e9e', '#757575', '#616161', '#424242', '#212121', '#ffffff', '#eeeeee', '#bdbdbd', '#616161', '#eceff1', '#cfd8dc', '#b0bec5', '#90a4ae', '#78909c', '#607d8b', '#546e7a', '#455a64', '#37474f', '#263238', '#cfd8dc', '#b0bec5', '#78909c', '#455a64'
|
||||
];
|
||||
|
||||
@@ -8,19 +8,21 @@ import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { NgxDnDModule } from '@swimlane/ngx-dnd';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
|
||||
import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '../directives/mat-sidenav-helper/mat-sidenav-helper.directive';
|
||||
import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '../directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.directive';
|
||||
import { FuseMatSidenavHelperService } from '../directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.service';
|
||||
import { FusePipesModule } from '../pipes/pipes.module';
|
||||
import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component';
|
||||
import { FuseCountdownComponent } from '../components/countdown/countdown.component';
|
||||
import { FuseMatchMedia } from '../services/match-media.service';
|
||||
import { FuseNavbarVerticalService } from '../../main/navbar/vertical/navbar-vertical.service';
|
||||
import { FuseMatSidenavHelperService } from '../directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { FuseHljsComponent } from '../components/hljs/hljs.component';
|
||||
import { FuseHighlightComponent } from '../components/highlight/highlight.component';
|
||||
import { FusePerfectScrollbarDirective } from '../directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
|
||||
import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive';
|
||||
import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component';
|
||||
import { FuseTranslationLoaderService } from '../services/translation-loader.service';
|
||||
import { CookieService } from 'ngx-cookie-service';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
|
||||
@NgModule({
|
||||
declarations : [
|
||||
@@ -28,7 +30,7 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
FuseMatSidenavTogglerDirective,
|
||||
FuseConfirmDialogComponent,
|
||||
FuseCountdownComponent,
|
||||
FuseHljsComponent,
|
||||
FuseHighlightComponent,
|
||||
FuseIfOnDomDirective,
|
||||
FusePerfectScrollbarDirective,
|
||||
FuseMaterialColorPickerComponent
|
||||
@@ -43,7 +45,7 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
ColorPickerModule,
|
||||
NgxDnDModule,
|
||||
NgxDatatableModule,
|
||||
MarkdownModule
|
||||
ChartsModule
|
||||
],
|
||||
exports : [
|
||||
FlexLayoutModule,
|
||||
@@ -54,7 +56,7 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
FuseMatSidenavTogglerDirective,
|
||||
FusePipesModule,
|
||||
FuseCountdownComponent,
|
||||
FuseHljsComponent,
|
||||
FuseHighlightComponent,
|
||||
FusePerfectScrollbarDirective,
|
||||
ReactiveFormsModule,
|
||||
ColorPickerModule,
|
||||
@@ -62,7 +64,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
NgxDatatableModule,
|
||||
FuseIfOnDomDirective,
|
||||
FuseMaterialColorPickerComponent,
|
||||
MarkdownModule
|
||||
TranslateModule,
|
||||
ChartsModule
|
||||
],
|
||||
entryComponents: [
|
||||
FuseConfirmDialogComponent
|
||||
@@ -71,7 +74,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
CookieService,
|
||||
FuseMatchMedia,
|
||||
FuseNavbarVerticalService,
|
||||
FuseMatSidenavHelperService
|
||||
FuseMatSidenavHelperService,
|
||||
FuseTranslationLoaderService
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// ngx-datatable
|
||||
@import '~@swimlane/ngx-datatable/release/index.css';
|
||||
@import '~@swimlane/ngx-datatable/release/themes/material.css';
|
||||
@import '~@swimlane/ngx-datatable/release/assets/icons.css';
|
||||
@import '~@swimlane/ngx-datatable/release/themes/material';
|
||||
|
||||
// Perfect scrollbar
|
||||
@import '~perfect-scrollbar/css/perfect-scrollbar.css';
|
||||
@import '~perfect-scrollbar/css/perfect-scrollbar';
|
||||
|
||||
// Fuse
|
||||
@import "fuse";
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import "partials/angular-material-fix";
|
||||
@import "partials/typography";
|
||||
@import "partials/page-layouts";
|
||||
@import "partials/cards";
|
||||
@import "partials/navigation";
|
||||
@import "partials/forms";
|
||||
@import "partials/toolbar";
|
||||
|
||||
@@ -6,42 +6,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: "Sidenav opening with animations for the first time"
|
||||
mat-sidenav-container {
|
||||
|
||||
mat-sidenav {
|
||||
|
||||
&[mat-is-locked-open].mat-stop-transition {
|
||||
transition: none !important;
|
||||
transform: translate3d(0, 0, 0) !important;
|
||||
opacity: 0;
|
||||
|
||||
~ .mat-sidenav-content,
|
||||
~ .mat-drawer-content {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.mat-sidenav-opened {
|
||||
|
||||
&.mat-drawer-side {
|
||||
|
||||
~ .mat-sidenav-content,
|
||||
~ .mat-drawer-content {
|
||||
transition: none !important;
|
||||
transform: translate3d(0, 0, 0) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mat-drawer-end {
|
||||
}
|
||||
}
|
||||
|
||||
.mat-drawer-content {
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: "Inconsistent font sizes across elements"
|
||||
.mat-input-wrapper {
|
||||
font-size: 16px;
|
||||
@@ -56,6 +20,59 @@ mat-sidenav-container {
|
||||
}
|
||||
|
||||
.mat-pseudo-checkbox-checked:after {
|
||||
width: 14px;
|
||||
height: 7px;
|
||||
width: 14px !important;
|
||||
height: 7px !important;
|
||||
}
|
||||
|
||||
// Fix: "Input underlines has wrong color opacity value"
|
||||
.mat-form-field-underline {
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
// Fix: "Some idiots using table-cell and inline-table in mat-select"
|
||||
.mat-form-field {
|
||||
|
||||
&.mat-form-field-type-mat-select {
|
||||
|
||||
.mat-input-infix {
|
||||
display: inline-flex;
|
||||
width: auto;
|
||||
|
||||
.mat-select-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
.mat-select-value {
|
||||
display: flex;
|
||||
max-width: none;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mat-select-arrow-wrapper {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: "Stepper icons are broken due to Fuse's icon helpers"
|
||||
mat-horizontal-stepper,
|
||||
mat-vertical-stepper {
|
||||
|
||||
mat-step-header {
|
||||
|
||||
mat-icon {
|
||||
height: 16px !important;
|
||||
width: 16px !important;
|
||||
min-width: 0 !important;
|
||||
min-height: 0 !important;
|
||||
color: rgba(255, 255, 255, 0.87) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-vertical-stepper {
|
||||
padding: 16px 0;
|
||||
}
|
||||
61
src/app/core/scss/partials/_cards.scss
Normal file
61
src/app/core/scss/partials/_cards.scss
Normal file
@@ -0,0 +1,61 @@
|
||||
.fuse-card {
|
||||
max-width: 320px;
|
||||
min-width: 320px;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
@include mat-elevation(2);
|
||||
|
||||
&.variable-width {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&.auto-width {
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.mat-button {
|
||||
min-width: 0 !important;
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
|
||||
// Button Toggle Group
|
||||
.mat-button-toggle-group,
|
||||
.mat-button-toggle-standalone {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
// Tabs
|
||||
.mat-tab-labels {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mat-tab-label {
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
// Divider
|
||||
.card-divider {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
margin: 16px;
|
||||
|
||||
&.light {
|
||||
border-top-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand Area
|
||||
.card-expand-area {
|
||||
overflow: hidden;
|
||||
|
||||
.card-expanded-content {
|
||||
padding: 8px 16px 16px 16px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,11 @@ $matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400
|
||||
// Generate material element colors
|
||||
// based on current contrast color
|
||||
@include generateMaterialElementColors($contrastColor);
|
||||
|
||||
&[disabled] {
|
||||
background-color: rgba($color, .12) !important;
|
||||
color: rgba($contrastColor, .26) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$colorName}#{$hue}-fg {
|
||||
|
||||
@@ -1,9 +1,59 @@
|
||||
// ######################
|
||||
// POSITION HELPERS
|
||||
// ######################
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.position#{$infix}-relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.position#{$infix}-absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.position#{$infix}-static {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################
|
||||
// ABSOLUTE POSITION ALIGNMENT HELPERS
|
||||
// ####################################
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.align#{$infix}-top {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.align#{$infix}-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.align#{$infix}-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.align#{$infix}-left {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ######################
|
||||
// SIZE HELPERS
|
||||
// ######################
|
||||
@each $prop, $abbrev in (height: h, width: w) {
|
||||
|
||||
@for $index from 0 through 128 {
|
||||
@for $index from 0 through 180 {
|
||||
$size: $index * 4;
|
||||
$length: #{$size}px;
|
||||
|
||||
@@ -28,7 +78,6 @@
|
||||
// ######################
|
||||
// SPACING HELPERS
|
||||
// ######################
|
||||
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
@@ -83,47 +132,45 @@
|
||||
}
|
||||
|
||||
@if ($abbrev == m) {
|
||||
@for $index from 0 through 64 {
|
||||
$size: $index * 4;
|
||||
$length: #{$size}px;
|
||||
|
||||
// Some special margin utils for flex alignments
|
||||
.m#{$infix}-auto {
|
||||
margin: auto !important;
|
||||
}
|
||||
// Some special margin utils for flex alignments
|
||||
.m#{$infix}-auto {
|
||||
margin: auto !important;
|
||||
}
|
||||
|
||||
.mt#{$infix}-auto {
|
||||
margin-top: auto !important;
|
||||
}
|
||||
.mt#{$infix}-auto {
|
||||
margin-top: auto !important;
|
||||
}
|
||||
|
||||
.mr#{$infix}-auto {
|
||||
margin-right: auto !important;
|
||||
}
|
||||
.mr#{$infix}-auto {
|
||||
margin-right: auto !important;
|
||||
}
|
||||
|
||||
.mb#{$infix}-auto {
|
||||
margin-bottom: auto !important;
|
||||
}
|
||||
.mb#{$infix}-auto {
|
||||
margin-bottom: auto !important;
|
||||
}
|
||||
|
||||
.ml#{$infix}-auto {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
.ml#{$infix}-auto {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.mx#{$infix}-auto {
|
||||
margin-right: auto !important;
|
||||
margin-left: auto !important;
|
||||
}
|
||||
.mx#{$infix}-auto {
|
||||
margin-right: auto !important;
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.my#{$infix}-auto {
|
||||
margin-top: auto !important;
|
||||
margin-bottom: auto !important;
|
||||
}
|
||||
.my#{$infix}-auto {
|
||||
margin-top: auto !important;
|
||||
margin-bottom: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Border helpers
|
||||
// ######################
|
||||
// BORDER HELPERS
|
||||
// ######################
|
||||
$border-style: 1px solid rgba(0, 0, 0, 0.12);
|
||||
|
||||
.border,
|
||||
@@ -162,3 +209,37 @@ $border-style: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-top: $border-style;
|
||||
border-bottom: $border-style;
|
||||
}
|
||||
|
||||
// ######################
|
||||
// BORDER RADIUS HELPERS
|
||||
// ######################
|
||||
.border-radius-100 {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.border-radius-2 {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.border-radius-4 {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.border-radius-8 {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.border-radius-16 {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
// ######################
|
||||
// CURSOR HELPERS
|
||||
// ######################
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cursor-default {
|
||||
cursor: default;
|
||||
}
|
||||
@@ -411,7 +411,6 @@ table {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
white-space: nowrap;
|
||||
min-width: 120px;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 24px;
|
||||
|
||||
@@ -47,14 +47,20 @@
|
||||
}
|
||||
|
||||
.nav-link-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
padding: 0 7px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
border-radius: 20px;
|
||||
transition: opacity 0.2s ease-in-out 0.1s;
|
||||
margin-left: 8px;
|
||||
|
||||
+ .collapse-arrow {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -195,6 +201,10 @@
|
||||
|
||||
> .nav-item {
|
||||
|
||||
> .nav-link {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
&.nav-collapse {
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
|
||||
max-height: $carded-toolbar-height;
|
||||
}
|
||||
|
||||
.content {
|
||||
> .content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
@@ -222,6 +222,62 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tabbed
|
||||
&.tabbed {
|
||||
|
||||
> mat-sidenav-container {
|
||||
|
||||
> .mat-sidenav-content,
|
||||
> .mat-drawer-content {
|
||||
width: calc(100% - 240px);
|
||||
|
||||
.center {
|
||||
width: calc(100% - 32px);
|
||||
|
||||
@include media-breakpoint-down('md') {
|
||||
width: calc(100% - 64px);
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
|
||||
.content {
|
||||
|
||||
.mat-tab-group {
|
||||
overflow: hidden;
|
||||
|
||||
.mat-tab-header {
|
||||
|
||||
.mat-tab-label {
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-body {
|
||||
overflow: hidden;
|
||||
|
||||
.mat-tab-body-content {
|
||||
overflow: hidden;
|
||||
|
||||
.tab-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Left sidenav
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
fuse-footer,
|
||||
fuse-quick-panel,
|
||||
fuse-theme-options,
|
||||
.ps > .ps__scrollbar-x-rail,
|
||||
.ps > .ps__scrollbar-y-rail {
|
||||
.ps > .ps__rail-x,
|
||||
.ps > .ps__rail-y {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +229,22 @@ strong {
|
||||
}
|
||||
}
|
||||
|
||||
.line-height-1 {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.line-height-1\.25 {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.line-height-1\.50 {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.line-height-1\.75 {
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
// Boxed text
|
||||
.text-boxed {
|
||||
border-radius: 2px;
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
hljs,
|
||||
[hljs] {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
// padding: 0.5em;
|
||||
color: #333;
|
||||
background: #F8F8F8;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.diff .hljs-header {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-doctag,
|
||||
.tex .hljs-formula {
|
||||
color: #D14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-list .hljs-keyword,
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rule .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body,
|
||||
.hljs-name {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.clojure .hljs-keyword,
|
||||
.scheme .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: #0086B3;
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #FDD;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #DFD;
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
background: #0086B3;
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
color: #AAA;
|
||||
}
|
||||
@@ -3,20 +3,21 @@
|
||||
.color-picker {
|
||||
height: auto !important;
|
||||
border: none !important;
|
||||
|
||||
@include mat-elevation(4);
|
||||
|
||||
.preset-area {
|
||||
//padding: 4px 15px;
|
||||
padding: 0 0 12px 12px !important;
|
||||
padding: 0 0 16px 16px !important;
|
||||
height: 140px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
> hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preset-label {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
.preset-color {
|
||||
@@ -25,7 +26,8 @@
|
||||
margin: 0 !important;
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
&:nth-child(14n+3) {
|
||||
|
||||
&:nth-child(14n+1) {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
min-height: 48px;
|
||||
transition: none;
|
||||
padding: 0 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,8 +83,83 @@
|
||||
|
||||
.datatable-pager {
|
||||
margin: 0 0 0 24px;
|
||||
|
||||
.pager {
|
||||
|
||||
li {
|
||||
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[class*="datatable-icon-"] {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.datatable-icon-filter:before {
|
||||
content: "filter_list";
|
||||
}
|
||||
.datatable-icon-collapse:before {
|
||||
content: "unfold_less";
|
||||
}
|
||||
.datatable-icon-expand:before {
|
||||
content: "unfold_more";
|
||||
}
|
||||
.datatable-icon-close:before {
|
||||
content: "close";
|
||||
}
|
||||
.datatable-icon-up:before {
|
||||
content: "keyboard_arrow_up";
|
||||
}
|
||||
.datatable-icon-down:before {
|
||||
content: "keyboard_arrow_down";
|
||||
}
|
||||
.datatable-icon-sort:before {
|
||||
content: "sort";
|
||||
}
|
||||
.datatable-icon-done:before {
|
||||
content: "done";
|
||||
}
|
||||
.datatable-icon-done-all:before {
|
||||
content: "done_all";
|
||||
}
|
||||
.datatable-icon-search:before {
|
||||
content: "search";
|
||||
}
|
||||
.datatable-icon-pin:before {
|
||||
content: "lock";
|
||||
}
|
||||
.datatable-icon-add:before {
|
||||
content: "add";
|
||||
}
|
||||
.datatable-icon-left:before {
|
||||
content: "chevron_left";
|
||||
}
|
||||
.datatable-icon-right:before {
|
||||
content: "chevron_right";
|
||||
}
|
||||
.datatable-icon-skip:before {
|
||||
content: "skip_next";
|
||||
}
|
||||
.datatable-icon-prev:before {
|
||||
content: "skip_previous";
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
@import "highlight";
|
||||
@import "prism";
|
||||
@import "perfect-scrollbar";
|
||||
@import "ngx-datatable";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
$base00: #263238;
|
||||
$base01: #2C393F;
|
||||
$base02: #37474F;
|
||||
$base02: #62727A;
|
||||
$base03: #707880;
|
||||
$base04: #C9CCD3;
|
||||
$base05: #CDD3DE;
|
||||
|
||||
@@ -22,10 +22,11 @@ export class FuseConfigService
|
||||
// Set the default settings
|
||||
this.defaultSettings = {
|
||||
layout : {
|
||||
navigation: 'left', // 'right', 'left', 'top', 'none'
|
||||
toolbar : 'below', // 'above', 'below', 'none'
|
||||
footer : 'below', // 'above', 'below', 'none'
|
||||
mode : 'fullwidth' // 'boxed', 'fullwidth'
|
||||
navigation : 'left', // 'right', 'left', 'top', 'none'
|
||||
navigationFolded: false, // true, false
|
||||
toolbar : 'below', // 'above', 'below', 'none'
|
||||
footer : 'below', // 'above', 'below', 'none'
|
||||
mode : 'fullwidth' // 'boxed', 'fullwidth'
|
||||
},
|
||||
colorClasses : {
|
||||
toolbar: 'mat-white-500-bg',
|
||||
@@ -33,7 +34,7 @@ export class FuseConfigService
|
||||
footer : 'mat-fuse-dark-900-bg'
|
||||
},
|
||||
customScrollbars: true,
|
||||
routerAnimation : 'fadeIn' // fadeIn, slideUp, slideDown, slideRight, slideLeft
|
||||
routerAnimation : 'fadeIn' // fadeIn, slideUp, slideDown, slideRight, slideLeft, none
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,7 @@ export class FuseConfigService
|
||||
this.defaultSettings.customScrollbars = false;
|
||||
}
|
||||
|
||||
// Set the settings from the default settings
|
||||
this.settings = Object.assign({}, this.defaultSettings);
|
||||
|
||||
// Reload the default settings on every navigation start
|
||||
@@ -58,7 +60,6 @@ export class FuseConfigService
|
||||
|
||||
// Create the behavior subject
|
||||
this.onSettingsChanged = new BehaviorSubject(this.settings);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +68,10 @@ export class FuseConfigService
|
||||
*/
|
||||
setSettings(settings)
|
||||
{
|
||||
// Set the settings from the given object
|
||||
this.settings = Object.assign({}, this.settings, settings);
|
||||
|
||||
// Trigger the event
|
||||
this.onSettingsChanged.next(this.settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,27 @@ export class FuseSplashScreenService
|
||||
private router: Router
|
||||
)
|
||||
{
|
||||
// Get the splash screen element
|
||||
this.splashScreenEl = this.document.body.querySelector('#fuse-splash-screen');
|
||||
|
||||
const hideOnLoad = this.router.events.subscribe((event) => {
|
||||
if ( event instanceof NavigationEnd )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.hide();
|
||||
hideOnLoad.unsubscribe();
|
||||
}, 0);
|
||||
// If the splash screen element exists...
|
||||
if ( this.splashScreenEl )
|
||||
{
|
||||
// Hide it on the first NavigationEnd event
|
||||
const hideOnLoad = this.router.events.subscribe((event) => {
|
||||
if ( event instanceof NavigationEnd )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.hide();
|
||||
|
||||
// Unsubscribe from this event so it
|
||||
// won't get triggered again
|
||||
hideOnLoad.unsubscribe();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
show()
|
||||
|
||||
27
src/app/core/services/translation-loader.service.ts
Normal file
27
src/app/core/services/translation-loader.service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
export interface Locale
|
||||
{
|
||||
lang: string;
|
||||
data: Object;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class FuseTranslationLoaderService
|
||||
{
|
||||
constructor(private translate: TranslateService)
|
||||
{
|
||||
}
|
||||
|
||||
public loadTranslations(...args: Locale[]): void
|
||||
{
|
||||
const locales = [...args];
|
||||
|
||||
locales.forEach((locale) => {
|
||||
// use setTranslation() with the third argument set to true
|
||||
// to append translations instead of replacing them
|
||||
this.translate.setTranslation(locale.lang, locale.data, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
773
src/app/fuse-fake-db/academy.ts
Normal file
773
src/app/fuse-fake-db/academy.ts
Normal file
@@ -0,0 +1,773 @@
|
||||
export class AcademyFakeDb
|
||||
{
|
||||
public static courses = [
|
||||
{
|
||||
'id' : '15459251a6d6b397565',
|
||||
'title' : 'Basics of Angular',
|
||||
'slug' : 'basics-of-angular',
|
||||
'category': 'web',
|
||||
'length' : 30,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '154588a0864d2881124',
|
||||
'title' : 'Basics of TypeScript',
|
||||
'slug' : 'basics-of-typeScript',
|
||||
'category': 'web',
|
||||
'length' : 60,
|
||||
'updated' : 'Nov 01, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '15453ba60d3baa5daaf',
|
||||
'title' : 'Android N: Quick Settings',
|
||||
'slug' : 'android-n-quick-settings',
|
||||
'category': 'android',
|
||||
'length' : 120,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '15453a06c08fb021776',
|
||||
'title' : 'Keep Sensitive Data Safe and Private',
|
||||
'slug' : 'keep-sensitive-data-safe-and-private',
|
||||
'category': 'android',
|
||||
'length' : 45,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '15427f4c1b7f3953234',
|
||||
'title' : 'Building a gRPC Service with Java',
|
||||
'slug' : 'building-a-grpc-service-with-java',
|
||||
'category': 'cloud',
|
||||
'length' : 30,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1542d75d929a603125',
|
||||
'title' : 'Build a PWA Using Workbox',
|
||||
'slug' : 'build-a-pwa-using-workbox',
|
||||
'category': 'web',
|
||||
'length' : 120,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1543ee3a5b43e0f9f45',
|
||||
'title' : 'Build an App for the Google Assistant with Firebase and Dialogflow',
|
||||
'slug' : 'build-an-app-for-the-google-assistant-with-firebase-and-dialogflow',
|
||||
'category': 'firebase',
|
||||
'length' : 30,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1543cc4515df3146112',
|
||||
'title' : 'Cloud Functions for Firebase',
|
||||
'slug' : 'cloud-functions-for-firebase',
|
||||
'category': 'firebase',
|
||||
'length' : 45,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '154398a4770d7aaf9a2',
|
||||
'title' : 'Manage Your Pivotal Cloud Foundry App\'s Using Apigee Edge',
|
||||
'slug' : 'manage-your-pivotal-cloud-foundry-apps-using-apigee-Edge',
|
||||
'category': 'cloud',
|
||||
'length' : 90,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '15438351f87dcd68567',
|
||||
'title' : 'Building Beautiful UIs with Flutter',
|
||||
'your' : 'building-beautiful-uis-with-flutter',
|
||||
'category': 'web',
|
||||
'length' : 90,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1544e43dcdae6ebf876',
|
||||
'title' : 'Cloud Firestore',
|
||||
'slug' : 'cloud-firestore',
|
||||
'category': 'firebase',
|
||||
'length' : 90,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1541ca7af66da284177',
|
||||
'title' : 'Customize Network Topology with Subnetworks',
|
||||
'slug' : 'customize-network-topology-with-subnetworks',
|
||||
'category': 'web',
|
||||
'length' : 45,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '154297167e781781745',
|
||||
'title' : 'Looking at Campaign Finance with BigQuery',
|
||||
'slug' : 'looking-at-campaign-finance-with-bigquery',
|
||||
'category': 'cloud',
|
||||
'length' : 60,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '154537435d5b32bf11a',
|
||||
'title' : 'Firebase Android',
|
||||
'slug' : 'firebase-android',
|
||||
'category': 'android',
|
||||
'length' : 45,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '154204e45a59b168453',
|
||||
'title' : 'Simulating a Thread Network Using OpenThread',
|
||||
'slug' : 'simulating-a-thread-network-using-openthread',
|
||||
'category': 'web',
|
||||
'length' : 45,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1541dd1e05dfc439216',
|
||||
'title' : 'Your First Progressive Web App',
|
||||
'slug' : 'your-first-progressive-web-app',
|
||||
'category': 'web',
|
||||
'length' : 30,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1532dfc67e704e48515',
|
||||
'title' : 'Launch Cloud Datalab',
|
||||
'slug' : 'launch-cloud-datalab',
|
||||
'category': 'cloud',
|
||||
'length' : 60,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
},
|
||||
{
|
||||
'id' : '1542e43dfaae6ebf226',
|
||||
'title' : 'Personalize Your iOS App with Firebase User Management',
|
||||
'slug' : 'personalize-your-ios-app-with-firebase-user-management',
|
||||
'category': 'firebase',
|
||||
'length' : 90,
|
||||
'updated' : 'Jun 28, 2017'
|
||||
}
|
||||
];
|
||||
|
||||
public static categories = [
|
||||
{
|
||||
'id' : 0,
|
||||
'value': 'web',
|
||||
'label': 'Web'
|
||||
},
|
||||
{
|
||||
'id' : 1,
|
||||
'value': 'firebase',
|
||||
'label': 'Firebase'
|
||||
},
|
||||
{
|
||||
'id' : 2,
|
||||
'value': 'cloud',
|
||||
'label': 'Cloud'
|
||||
},
|
||||
{
|
||||
'id' : 3,
|
||||
'value': 'android',
|
||||
'label': 'Android'
|
||||
}
|
||||
];
|
||||
|
||||
private static demoSteps = [
|
||||
{
|
||||
'title' : 'Introduction',
|
||||
'content': '<h1>Step 1 - Introduction</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Get the sample code',
|
||||
'content': '<h1>Step 2 - Get the sample code</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Create a Firebase project and Set up your app',
|
||||
'content': '<h1>Step 3 - Create a Firebase project and Set up your app</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Install the Firebase Command Line Interface',
|
||||
'content': '<h1>Step 4 - Install the Firebase Command Line Interface</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Deploy and run the web app',
|
||||
'content': '<h1>Step 5 - Deploy and run the web app</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'The Functions Directory',
|
||||
'content': '<h1>Step 6 - The Functions Directory</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Import the Cloud Functions and Firebase Admin modules',
|
||||
'content': '<h1>Step 7 - Import the Cloud Functions and Firebase Admin modules</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Welcome New Users',
|
||||
'content': '<h1>Step 8 - Welcome New Users</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Images moderation',
|
||||
'content': '<h1>Step 9 - Images moderation</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'New Message Notifications',
|
||||
'content': '<h1>Step 10 - New Message Notifications</h1>' +
|
||||
'<br>' +
|
||||
'This is an example step of the course. You can put anything in here from example codes to videos.' +
|
||||
'<br><br>' +
|
||||
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
|
||||
'To install or upgrade the CLI run the following <b>npm</b> command:' +
|
||||
'<br><br>' +
|
||||
'<code>npm -g install @angular/cli</code>' +
|
||||
'<br><br>' +
|
||||
'To verify that the CLI has been installed correctly, open a console and run:' +
|
||||
'<br><br>' +
|
||||
'<code>ng version</code>' +
|
||||
'<br><br>' +
|
||||
'<h2>Install dependencies</h2>' +
|
||||
'<br>' +
|
||||
'To moderate the images we\'ll need a few Node.js packages:' +
|
||||
'<br><br>' +
|
||||
'<ul>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
|
||||
'</li>' +
|
||||
'<br>' +
|
||||
'<li>' +
|
||||
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
|
||||
'</li>' +
|
||||
'</ul>' +
|
||||
'<br>' +
|
||||
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
|
||||
'<br><br>' +
|
||||
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
|
||||
'<br><br>' +
|
||||
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
|
||||
},
|
||||
{
|
||||
'title' : 'Congratulations!',
|
||||
'content': '<h1>Step 11 - Congratulations!</h1>' +
|
||||
'<br>' +
|
||||
'You\'ve built a full-fidelity, offline-capable progressive web app by leveraging the power of reusable Web Components and Firebase. Why bother with a native app when you know how to do all that?!'
|
||||
}
|
||||
];
|
||||
|
||||
public static course = [
|
||||
{
|
||||
'id' : '15459251a6d6b397565',
|
||||
'title' : 'Basics of Angular',
|
||||
'slug' : 'basics-of-angular',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 30,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '154588a0864d2881124',
|
||||
'title' : 'Basics of TypeScript',
|
||||
'slug' : 'basics-of-typeScript',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 60,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Nov 01, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '15453ba60d3baa5daaf',
|
||||
'title' : 'Android N: Quick Settings',
|
||||
'slug' : 'android-n-quick-settings',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'android',
|
||||
'length' : 120,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '15453a06c08fb021776',
|
||||
'title' : 'Keep Sensitive Data Safe and Private',
|
||||
'slug' : 'keep-sensitive-data-safe-and-private',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'android',
|
||||
'length' : 45,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '15427f4c1b7f3953234',
|
||||
'title' : 'Building a gRPC Service with Java',
|
||||
'slug' : 'building-a-grpc-service-with-java',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'cloud',
|
||||
'length' : 30,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1542d75d929a603125',
|
||||
'title' : 'Build a PWA Using Workbox',
|
||||
'slug' : 'build-a-pwa-using-workbox',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 120,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1543ee3a5b43e0f9f45',
|
||||
'title' : 'Build an App for the Google Assistant with Firebase and Dialogflow',
|
||||
'slug' : 'build-an-app-for-the-google-assistant-with-firebase-and-dialogflow',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'firebase',
|
||||
'length' : 30,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1543cc4515df3146112',
|
||||
'title' : 'Cloud Functions for Firebase',
|
||||
'slug' : 'cloud-functions-for-firebase',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'firebase',
|
||||
'length' : 45,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '154398a4770d7aaf9a2',
|
||||
'title' : 'Manage Your Pivotal Cloud Foundry App\'s Using Apigee Edge',
|
||||
'slug' : 'manage-your-pivotal-cloud-foundry-apps-using-apigee-Edge',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'cloud',
|
||||
'length' : 90,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '15438351f87dcd68567',
|
||||
'title' : 'Building Beautiful UIs with Flutter',
|
||||
'your' : 'building-beautiful-uis-with-flutter',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 90,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1544e43dcdae6ebf876',
|
||||
'title' : 'Cloud Firestore',
|
||||
'slug' : 'cloud-firestore',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'firebase',
|
||||
'length' : 90,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1541ca7af66da284177',
|
||||
'title' : 'Customize Network Topology with Subnetworks',
|
||||
'slug' : 'customize-network-topology-with-subnetworks',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 45,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '154297167e781781745',
|
||||
'title' : 'Looking at Campaign Finance with BigQuery',
|
||||
'slug' : 'looking-at-campaign-finance-with-bigquery',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'cloud',
|
||||
'length' : 60,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '154537435d5b32bf11a',
|
||||
'title' : 'Firebase Android',
|
||||
'slug' : 'firebase-android',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'android',
|
||||
'length' : 45,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '154204e45a59b168453',
|
||||
'title' : 'Simulating a Thread Network Using OpenThread',
|
||||
'slug' : 'simulating-a-thread-network-using-openthread',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 45,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1541dd1e05dfc439216',
|
||||
'title' : 'Your First Progressive Web App',
|
||||
'slug' : 'your-first-progressive-web-app',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'web',
|
||||
'length' : 30,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1532dfc67e704e48515',
|
||||
'title' : 'Launch Cloud Datalab',
|
||||
'slug' : 'launch-cloud-datalab',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'cloud',
|
||||
'length' : 60,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
},
|
||||
{
|
||||
'id' : '1542e43dfaae6ebf226',
|
||||
'title' : 'Personalize Your iOS App with Firebase User Management',
|
||||
'slug' : 'personalize-your-ios-app-with-firebase-user-management',
|
||||
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'category' : 'firebase',
|
||||
'length' : 90,
|
||||
'totalSteps' : 11,
|
||||
'updated' : 'Jun 28, 2017',
|
||||
'steps' : AcademyFakeDb.demoSteps
|
||||
}
|
||||
];
|
||||
|
||||
}
|
||||
602
src/app/fuse-fake-db/dashboard-analytics.ts
Normal file
602
src/app/fuse-fake-db/dashboard-analytics.ts
Normal file
@@ -0,0 +1,602 @@
|
||||
export class AnalyticsDashboardDb
|
||||
{
|
||||
public static widgets = {
|
||||
widget1: {
|
||||
chartType: 'line',
|
||||
datasets : {
|
||||
'2015': [
|
||||
{
|
||||
label: 'Sales',
|
||||
data : [1.9, 3, 3.4, 2.2, 2.9, 3.9, 2.5, 3.8, 4.1, 3.8, 3.2, 2.9],
|
||||
fill : 'start'
|
||||
|
||||
}
|
||||
],
|
||||
'2016': [
|
||||
{
|
||||
label: 'Sales',
|
||||
data : [2.2, 2.9, 3.9, 2.5, 3.8, 3.2, 2.9, 1.9, 3, 3.4, 4.1, 3.8],
|
||||
fill : 'start'
|
||||
|
||||
}
|
||||
],
|
||||
'2017': [
|
||||
{
|
||||
label: 'Sales',
|
||||
data : [3.9, 2.5, 3.8, 4.1, 1.9, 3, 3.8, 3.2, 2.9, 3.4, 2.2, 2.9],
|
||||
fill : 'start'
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
labels : ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'],
|
||||
colors : [
|
||||
{
|
||||
borderColor : '#42a5f5',
|
||||
backgroundColor : '#42a5f5',
|
||||
pointBackgroundColor : '#1e88e5',
|
||||
pointHoverBackgroundColor: '#1e88e5',
|
||||
pointBorderColor : '#ffffff',
|
||||
pointHoverBorderColor : '#ffffff'
|
||||
}
|
||||
],
|
||||
options : {
|
||||
spanGaps : false,
|
||||
legend : {
|
||||
display: false
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
layout : {
|
||||
padding: {
|
||||
top : 32,
|
||||
left : 32,
|
||||
right: 32
|
||||
}
|
||||
},
|
||||
elements : {
|
||||
point: {
|
||||
radius : 4,
|
||||
borderWidth : 2,
|
||||
hoverRadius : 4,
|
||||
hoverBorderWidth: 2
|
||||
},
|
||||
line : {
|
||||
tension: 0
|
||||
}
|
||||
},
|
||||
scales : {
|
||||
xAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
display : false,
|
||||
drawBorder : false,
|
||||
tickMarkLength: 18
|
||||
},
|
||||
ticks : {
|
||||
fontColor: '#ffffff'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
ticks : {
|
||||
min : 1.5,
|
||||
max : 5,
|
||||
stepSize: 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins : {
|
||||
filler : {
|
||||
propagate: false
|
||||
},
|
||||
xLabelsOnTop: {
|
||||
active: true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
widget2: {
|
||||
conversion: {
|
||||
value : 492,
|
||||
ofTarget: 13
|
||||
},
|
||||
chartType : 'bar',
|
||||
datasets : [
|
||||
{
|
||||
label: 'Conversion',
|
||||
data : [221, 428, 492, 471, 413, 344, 294]
|
||||
}
|
||||
],
|
||||
labels : ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
colors : [
|
||||
{
|
||||
borderColor : '#42a5f5',
|
||||
backgroundColor: '#42a5f5'
|
||||
}
|
||||
],
|
||||
options : {
|
||||
spanGaps : false,
|
||||
legend : {
|
||||
display: false
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
layout : {
|
||||
padding: {
|
||||
top : 24,
|
||||
left : 16,
|
||||
right : 16,
|
||||
bottom: 16
|
||||
}
|
||||
},
|
||||
scales : {
|
||||
xAxes: [
|
||||
{
|
||||
display: false
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
ticks : {
|
||||
min: 100,
|
||||
max: 500
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
widget3: {
|
||||
impressions: {
|
||||
value : '87k',
|
||||
ofTarget: 12
|
||||
},
|
||||
chartType : 'line',
|
||||
datasets : [
|
||||
{
|
||||
label: 'Impression',
|
||||
data : [67000, 54000, 82000, 57000, 72000, 57000, 87000, 72000, 89000, 98700, 112000, 136000, 110000, 149000, 98000],
|
||||
fill : false
|
||||
}
|
||||
],
|
||||
labels : ['Jan 1', 'Jan 2', 'Jan 3', 'Jan 4', 'Jan 5', 'Jan 6', 'Jan 7', 'Jan 8', 'Jan 9', 'Jan 10', 'Jan 11', 'Jan 12', 'Jan 13', 'Jan 14', 'Jan 15'],
|
||||
colors : [
|
||||
{
|
||||
borderColor: '#5c84f1'
|
||||
}
|
||||
],
|
||||
options : {
|
||||
spanGaps : false,
|
||||
legend : {
|
||||
display: false
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
elements : {
|
||||
point: {
|
||||
radius : 2,
|
||||
borderWidth : 1,
|
||||
hoverRadius : 2,
|
||||
hoverBorderWidth: 1
|
||||
},
|
||||
line : {
|
||||
tension: 0
|
||||
}
|
||||
},
|
||||
layout : {
|
||||
padding: {
|
||||
top : 24,
|
||||
left : 16,
|
||||
right : 16,
|
||||
bottom: 16
|
||||
}
|
||||
},
|
||||
scales : {
|
||||
xAxes: [
|
||||
{
|
||||
display: false
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
ticks : {
|
||||
// min: 100,
|
||||
// max: 500
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
widget4: {
|
||||
visits : {
|
||||
value : 882,
|
||||
ofTarget: -9
|
||||
},
|
||||
chartType: 'bar',
|
||||
datasets : [
|
||||
{
|
||||
label: 'Visits',
|
||||
data : [432, 428, 327, 363, 456, 267, 231]
|
||||
}
|
||||
],
|
||||
labels : ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
colors : [
|
||||
{
|
||||
borderColor : '#f44336',
|
||||
backgroundColor: '#f44336'
|
||||
}
|
||||
],
|
||||
options : {
|
||||
spanGaps : false,
|
||||
legend : {
|
||||
display: false
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
layout : {
|
||||
padding: {
|
||||
top : 24,
|
||||
left : 16,
|
||||
right : 16,
|
||||
bottom: 16
|
||||
}
|
||||
},
|
||||
scales : {
|
||||
xAxes: [
|
||||
{
|
||||
display: false
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
ticks : {
|
||||
min: 150,
|
||||
max: 500
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
widget5: {
|
||||
chartType: 'line',
|
||||
datasets : {
|
||||
'yesterday': [
|
||||
{
|
||||
label: 'Visitors',
|
||||
data : [190, 300, 340, 220, 290, 390, 250, 380, 410, 380, 320, 290],
|
||||
fill : 'start'
|
||||
|
||||
},
|
||||
{
|
||||
label: 'Page views',
|
||||
data : [2200, 2900, 3900, 2500, 3800, 3200, 2900, 1900, 3000, 3400, 4100, 3800],
|
||||
fill : 'start'
|
||||
}
|
||||
],
|
||||
'today' : [
|
||||
{
|
||||
label: 'Visitors',
|
||||
data : [410, 380, 320, 290, 190, 390, 250, 380, 300, 340, 220, 290],
|
||||
fill : 'start'
|
||||
},
|
||||
{
|
||||
label: 'Page Views',
|
||||
data : [3000, 3400, 4100, 3800, 2200, 3200, 2900, 1900, 2900, 3900, 2500, 3800],
|
||||
fill : 'start'
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
labels : ['12am', '2am', '4am', '6am', '8am', '10am', '12pm', '2pm', '4pm', '6pm', '8pm', '10pm'],
|
||||
colors : [
|
||||
{
|
||||
borderColor : '#3949ab',
|
||||
backgroundColor : '#3949ab',
|
||||
pointBackgroundColor : '#3949ab',
|
||||
pointHoverBackgroundColor: '#3949ab',
|
||||
pointBorderColor : '#ffffff',
|
||||
pointHoverBorderColor : '#ffffff'
|
||||
},
|
||||
{
|
||||
borderColor : 'rgba(30, 136, 229, 0.87)',
|
||||
backgroundColor : 'rgba(30, 136, 229, 0.87)',
|
||||
pointBackgroundColor : 'rgba(30, 136, 229, 0.87)',
|
||||
pointHoverBackgroundColor: 'rgba(30, 136, 229, 0.87)',
|
||||
pointBorderColor : '#ffffff',
|
||||
pointHoverBorderColor : '#ffffff'
|
||||
}
|
||||
],
|
||||
options : {
|
||||
spanGaps : false,
|
||||
legend : {
|
||||
display: false
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
tooltips : {
|
||||
position : 'nearest',
|
||||
mode : 'index',
|
||||
intersect: false
|
||||
},
|
||||
layout : {
|
||||
padding: {
|
||||
left : 24,
|
||||
right: 32
|
||||
}
|
||||
},
|
||||
elements : {
|
||||
point: {
|
||||
radius : 4,
|
||||
borderWidth : 2,
|
||||
hoverRadius : 4,
|
||||
hoverBorderWidth: 2
|
||||
}
|
||||
},
|
||||
scales : {
|
||||
xAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
display: false
|
||||
},
|
||||
ticks : {
|
||||
fontColor: 'rgba(0,0,0,0.54)'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
tickMarkLength: 16
|
||||
},
|
||||
ticks : {
|
||||
stepSize: 1000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins : {
|
||||
filler: {
|
||||
propagate: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
widget6: {
|
||||
markers: [
|
||||
{
|
||||
lat : 52,
|
||||
lng : -73,
|
||||
label: '120'
|
||||
},
|
||||
{
|
||||
lat : 37,
|
||||
lng : -104,
|
||||
label: '498'
|
||||
},
|
||||
{
|
||||
lat : 21,
|
||||
lng : -7,
|
||||
label: '443'
|
||||
},
|
||||
{
|
||||
lat : 55,
|
||||
lng : 75,
|
||||
label: '332'
|
||||
},
|
||||
{
|
||||
lat : 51,
|
||||
lng : 7,
|
||||
label: '50'
|
||||
},
|
||||
{
|
||||
lat : 31,
|
||||
lng : 12,
|
||||
label: '221'
|
||||
},
|
||||
{
|
||||
lat : 45,
|
||||
lng : 44,
|
||||
label: '455'
|
||||
},
|
||||
{
|
||||
lat : -26,
|
||||
lng : 134,
|
||||
label: '231'
|
||||
},
|
||||
{
|
||||
lat : -9,
|
||||
lng : -60,
|
||||
label: '67'
|
||||
},
|
||||
{
|
||||
lat : 33,
|
||||
lng : 104,
|
||||
label: '665'
|
||||
}
|
||||
],
|
||||
styles : [
|
||||
{
|
||||
'featureType': 'administrative',
|
||||
'elementType': 'labels.text.fill',
|
||||
'stylers' : [
|
||||
{
|
||||
'color': '#444444'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'landscape',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'color': '#f2f2f2'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'poi',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'visibility': 'off'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'road',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'saturation': -100
|
||||
},
|
||||
{
|
||||
'lightness': 45
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'road.highway',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'visibility': 'simplified'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'road.arterial',
|
||||
'elementType': 'labels.icon',
|
||||
'stylers' : [
|
||||
{
|
||||
'visibility': 'off'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'transit',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'visibility': 'off'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'featureType': 'water',
|
||||
'elementType': 'all',
|
||||
'stylers' : [
|
||||
{
|
||||
'color': '#039be5'
|
||||
},
|
||||
{
|
||||
'visibility': 'on'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
widget7: {
|
||||
scheme : {
|
||||
domain: ['#4867d2', '#5c84f1', '#89a9f4']
|
||||
},
|
||||
devices: [
|
||||
{
|
||||
name : 'Desktop',
|
||||
value : 92.8,
|
||||
change: -0.6
|
||||
},
|
||||
{
|
||||
name : 'Mobile',
|
||||
value : 6.1,
|
||||
change: 0.7
|
||||
},
|
||||
{
|
||||
name : 'Tablet',
|
||||
value : 1.1,
|
||||
change: 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
widget8: {
|
||||
scheme : {
|
||||
domain: ['#5c84f1']
|
||||
},
|
||||
today : '12,540',
|
||||
change : {
|
||||
value : 321,
|
||||
percentage: 2.05
|
||||
},
|
||||
data : [
|
||||
{
|
||||
name : 'Sales',
|
||||
series: [
|
||||
{
|
||||
name : 'Jan 1',
|
||||
value: 540
|
||||
},
|
||||
{
|
||||
name : 'Jan 2',
|
||||
value: 539
|
||||
},
|
||||
{
|
||||
name : 'Jan 3',
|
||||
value: 538
|
||||
},
|
||||
{
|
||||
name : 'Jan 4',
|
||||
value: 539
|
||||
},
|
||||
{
|
||||
name : 'Jan 5',
|
||||
value: 540
|
||||
},
|
||||
{
|
||||
name : 'Jan 6',
|
||||
value: 539
|
||||
},
|
||||
{
|
||||
name : 'Jan 7',
|
||||
value: 540
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
dataMin: 538,
|
||||
dataMax: 541
|
||||
},
|
||||
widget9: {
|
||||
rows: [
|
||||
{
|
||||
title : 'Holiday Travel',
|
||||
clicks : 3621,
|
||||
conversion: 90
|
||||
},
|
||||
{
|
||||
title : 'Get Away Deals',
|
||||
clicks : 703,
|
||||
conversion: 7
|
||||
},
|
||||
{
|
||||
title : 'Airfare',
|
||||
clicks : 532,
|
||||
conversion: 0
|
||||
},
|
||||
{
|
||||
title : 'Vacation',
|
||||
clicks : 201,
|
||||
conversion: 8
|
||||
},
|
||||
{
|
||||
title : 'Hotels',
|
||||
clicks : 94,
|
||||
conversion: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export class ProjectsDashboardDb
|
||||
export class ProjectDashboardDb
|
||||
{
|
||||
public static projects = [
|
||||
{
|
||||
3762
src/app/fuse-fake-db/e-commerce.ts
Normal file
3762
src/app/fuse-fake-db/e-commerce.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,97 @@
|
||||
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
||||
|
||||
import { ProjectDashboardDb } from './dashboard-project';
|
||||
import { AnalyticsDashboardDb } from './dashboard-analytics';
|
||||
import { CalendarFakeDb } from './calendar';
|
||||
import { ECommerceFakeDb } from './e-commerce';
|
||||
import { AcademyFakeDb } from './academy';
|
||||
import { MailFakeDb } from './mail';
|
||||
import { ChatFakeDb } from './chat';
|
||||
import { CalendarFakeDb } from './calendar';
|
||||
import { TodoFakeDb } from './todo';
|
||||
import { ProfileFakeDb } from './profile';
|
||||
import { ContactsFakeDb } from './contacts';
|
||||
import { InvoiceFakeDb } from './invoice';
|
||||
import { FileManagerFakeDb } from './file-manager';
|
||||
import { SearchFakeDb } from './search';
|
||||
import { QuickPanelFakeDb } from './quick-panel';
|
||||
import { IconsFakeDb } from './icons';
|
||||
import { ProjectsDashboardDb } from './projects-dashboard';
|
||||
import { ContactsFakeDb } from './contacts';
|
||||
import { TodoFakeDb } from './todo';
|
||||
import { ScrumboardFakeDb } from './scrumboard';
|
||||
import { InvoiceFakeDb } from './invoice';
|
||||
import { ProfileFakeDb } from './profile';
|
||||
import { SearchFakeDb } from './search';
|
||||
import { FaqFakeDb } from './faq';
|
||||
import { KnowledgeBaseFakeDb } from './knowledge-base';
|
||||
import { IconsFakeDb } from './icons';
|
||||
import { QuickPanelFakeDb } from './quick-panel';
|
||||
|
||||
export class FuseFakeDbService implements InMemoryDbService
|
||||
{
|
||||
createDb()
|
||||
{
|
||||
return {
|
||||
'mail-mails' : MailFakeDb.mails,
|
||||
'mail-folders' : MailFakeDb.folders,
|
||||
'mail-filters' : MailFakeDb.filters,
|
||||
'mail-labels' : MailFakeDb.labels,
|
||||
'chat-contacts' : ChatFakeDb.contacts,
|
||||
'chat-chats' : ChatFakeDb.chats,
|
||||
'chat-user' : ChatFakeDb.user,
|
||||
'calendar' : CalendarFakeDb.data,
|
||||
'todo-todos' : TodoFakeDb.todos,
|
||||
'todo-filters' : TodoFakeDb.filters,
|
||||
'todo-tags' : TodoFakeDb.tags,
|
||||
'profile-timeline' : ProfileFakeDb.timeline,
|
||||
'profile-photos-videos' : ProfileFakeDb.photosVideos,
|
||||
'profile-about' : ProfileFakeDb.about,
|
||||
'contacts-contacts' : ContactsFakeDb.contacts,
|
||||
'contacts-user' : ContactsFakeDb.user,
|
||||
'invoice' : InvoiceFakeDb.invoice,
|
||||
'file-manager' : FileManagerFakeDb.files,
|
||||
'search-classic' : SearchFakeDb.classic,
|
||||
'search-table' : SearchFakeDb.table,
|
||||
'quick-panel-notes' : QuickPanelFakeDb.notes,
|
||||
'quick-panel-events' : QuickPanelFakeDb.events,
|
||||
'icons' : IconsFakeDb.icons,
|
||||
'projects-dashboard-projects': ProjectsDashboardDb.projects,
|
||||
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
|
||||
'scrumboard-boards' : ScrumboardFakeDb.boards,
|
||||
'faq' : FaqFakeDb.data
|
||||
// Dashboards
|
||||
'project-dashboard-projects' : ProjectDashboardDb.projects,
|
||||
'project-dashboard-widgets' : ProjectDashboardDb.widgets,
|
||||
'analytics-dashboard-widgets': AnalyticsDashboardDb.widgets,
|
||||
|
||||
// Calendar
|
||||
'calendar': CalendarFakeDb.data,
|
||||
|
||||
// E-Commerce
|
||||
'e-commerce-dashboard': ECommerceFakeDb.dashboard,
|
||||
'e-commerce-products' : ECommerceFakeDb.products,
|
||||
'e-commerce-orders' : ECommerceFakeDb.orders,
|
||||
|
||||
// Academy
|
||||
'academy-categories': AcademyFakeDb.categories,
|
||||
'academy-courses' : AcademyFakeDb.courses,
|
||||
'academy-course' : AcademyFakeDb.course,
|
||||
|
||||
// Mail
|
||||
'mail-mails' : MailFakeDb.mails,
|
||||
'mail-folders': MailFakeDb.folders,
|
||||
'mail-filters': MailFakeDb.filters,
|
||||
'mail-labels' : MailFakeDb.labels,
|
||||
|
||||
// Chat
|
||||
'chat-contacts': ChatFakeDb.contacts,
|
||||
'chat-chats' : ChatFakeDb.chats,
|
||||
'chat-user' : ChatFakeDb.user,
|
||||
|
||||
// File Manager
|
||||
'file-manager': FileManagerFakeDb.files,
|
||||
|
||||
// Contacts
|
||||
'contacts-contacts': ContactsFakeDb.contacts,
|
||||
'contacts-user' : ContactsFakeDb.user,
|
||||
|
||||
// Todo
|
||||
'todo-todos' : TodoFakeDb.todos,
|
||||
'todo-filters': TodoFakeDb.filters,
|
||||
'todo-tags' : TodoFakeDb.tags,
|
||||
|
||||
// Scrumboard
|
||||
'scrumboard-boards': ScrumboardFakeDb.boards,
|
||||
|
||||
// Invoice
|
||||
'invoice': InvoiceFakeDb.invoice,
|
||||
|
||||
// Profile
|
||||
'profile-timeline' : ProfileFakeDb.timeline,
|
||||
'profile-photos-videos': ProfileFakeDb.photosVideos,
|
||||
'profile-about' : ProfileFakeDb.about,
|
||||
|
||||
// Search
|
||||
'search-classic': SearchFakeDb.classic,
|
||||
'search-table' : SearchFakeDb.table,
|
||||
|
||||
// FAQ
|
||||
'faq': FaqFakeDb.data,
|
||||
|
||||
// Knowledge base
|
||||
'knowledge-base': KnowledgeBaseFakeDb.data,
|
||||
|
||||
// Icons
|
||||
'icons': IconsFakeDb.icons,
|
||||
|
||||
// Quick Panel
|
||||
'quick-panel-notes' : QuickPanelFakeDb.notes,
|
||||
'quick-panel-events': QuickPanelFakeDb.events
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
113
src/app/fuse-fake-db/knowledge-base.ts
Normal file
113
src/app/fuse-fake-db/knowledge-base.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
export class KnowledgeBaseFakeDb
|
||||
{
|
||||
public static data = [
|
||||
{
|
||||
'title' : 'Your Account',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 17,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'Account limits',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my username?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my password?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my email address?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I close my account?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Selling',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 12,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'A guide to the upload process',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Author collaboration',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Exclusivity policy',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Promises you make as an author',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'An author’s introduction',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Buying',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 19,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'Where is my purchase code?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Can I get a refund?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Contact us',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I purchase an item?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'I\'m trying to find a specific item',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Item Support',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 24,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'What is Item Support?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How to contact an author',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Rating or review removal policy',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Purchasing unsupported items',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Item installation guide',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
47
src/app/main/content/apps/academy/academy.module.ts
Normal file
47
src/app/main/content/apps/academy/academy.module.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../../../../core/modules/shared.module';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { FuseAcademyCoursesComponent } from './courses/courses.component';
|
||||
import { FuseAcademyCourseComponent } from './course/course.component';
|
||||
import { AcademyCoursesService } from './courses.service';
|
||||
import { AcademyCourseService } from './course.service';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path : 'courses',
|
||||
component: FuseAcademyCoursesComponent,
|
||||
resolve : {
|
||||
academy: AcademyCoursesService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'courses/:courseId/:courseSlug',
|
||||
component: FuseAcademyCourseComponent,
|
||||
resolve : {
|
||||
academy: AcademyCourseService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : '**',
|
||||
redirectTo: 'courses'
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports : [
|
||||
SharedModule,
|
||||
RouterModule.forChild(routes)
|
||||
],
|
||||
declarations: [
|
||||
FuseAcademyCoursesComponent,
|
||||
FuseAcademyCourseComponent
|
||||
],
|
||||
providers : [
|
||||
AcademyCoursesService,
|
||||
AcademyCourseService
|
||||
]
|
||||
})
|
||||
export class FuseAcademyModule
|
||||
{
|
||||
}
|
||||
49
src/app/main/content/apps/academy/course.service.ts
Normal file
49
src/app/main/content/apps/academy/course.service.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class AcademyCourseService implements Resolve<any>
|
||||
{
|
||||
onCourseChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(private http: HttpClient)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The Academy App Main Resolver
|
||||
*
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getCourse(route.params.courseId, route.params.courseSlug)
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getCourse(courseId, courseSlug): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/academy-course/' + courseId + '/' + courseSlug)
|
||||
.subscribe((response: any) => {
|
||||
this.onCourseChanged.next(response);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
100
src/app/main/content/apps/academy/course/course.component.html
Normal file
100
src/app/main/content/apps/academy/course/course.component.html
Normal file
@@ -0,0 +1,100 @@
|
||||
<div id="academy-course" class="page-layout simple left-sidenav">
|
||||
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav" align="start" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="academy-left-sidenav" mat-is-locked-open="gt-md">
|
||||
|
||||
<div class="sidenav-content" fusePerfectScrollbar>
|
||||
|
||||
<div class="steps">
|
||||
|
||||
<div class="step"
|
||||
*ngFor="let step of course.steps; let i = index; let last = last; let first = first"
|
||||
(click)="gotoStep(i)"
|
||||
[ngClass]="{'current': currentStep === i, 'completed': currentStep > i, 'last': last, 'first': first}">
|
||||
<div class="index">
|
||||
<span>{{i + 1}}</span>
|
||||
</div>
|
||||
<div class="title">{{step.title}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-sidenav>
|
||||
<!-- / SIDENAV -->
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header mat-accent-bg p-24" fxLayout="row" fxLayoutAlign="start center">
|
||||
|
||||
<button mat-button class="mat-icon-button mr-16 sidenav-toggle"
|
||||
fuseMatSidenavToggler="academy-left-sidenav" fxHide.gt-md>
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-button class="mat-icon-button mr-16" [routerLink]="'/apps/academy/courses'">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<h2>{{course.title}}</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div id="course-content" class="content">
|
||||
|
||||
<ng-container *ngFor="let step of course.steps; let i = index;">
|
||||
|
||||
<div class="course-step" fusePerfectScrollbar
|
||||
*ngIf="currentStep === i"
|
||||
[@slideIn]="animationDirection">
|
||||
|
||||
<div id="course-step-content" class="course-step-content" [innerHTML]="step.content"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT -->
|
||||
|
||||
<div class="step-navigation">
|
||||
|
||||
<button mat-fab class="previous mat-accent white-fg"
|
||||
(click)="gotoPreviousStep()"
|
||||
[disabled]="currentStep === 0"
|
||||
[fxHide]="currentStep === 0">
|
||||
<mat-icon>chevron_left</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-fab class="next mat-accent white-fg"
|
||||
(click)="gotoNextStep()"
|
||||
[disabled]="currentStep === course.totalSteps - 1"
|
||||
[fxHide]="currentStep === course.totalSteps - 1">
|
||||
<mat-icon>chevron_right</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-fab class="done mat-green-600-bg"
|
||||
routerLink="/apps/academy/courses"
|
||||
[disabled]="currentStep !== course.totalSteps - 1"
|
||||
[fxShow]="currentStep === course.totalSteps - 1">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / CENTER -->
|
||||
|
||||
</mat-sidenav-container>
|
||||
|
||||
</div>
|
||||
203
src/app/main/content/apps/academy/course/course.component.scss
Normal file
203
src/app/main/content/apps/academy/course/course.component.scss
Normal file
@@ -0,0 +1,203 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
#academy-course {
|
||||
|
||||
.mat-drawer-container {
|
||||
flex: 1 !important;
|
||||
|
||||
> .mat-drawer-content {
|
||||
flex: 1 !important;
|
||||
|
||||
@include media-breakpoint-up('lg') {
|
||||
z-index: 52;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
|
||||
.steps {
|
||||
padding: 16px 0;
|
||||
|
||||
.step {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
|
||||
&.current {
|
||||
background: mat-color($mat-blue, 50);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
|
||||
.index {
|
||||
|
||||
span {
|
||||
border: 2px solid mat-color($mat-blue, 500);
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&.completed {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
|
||||
.index {
|
||||
|
||||
span {
|
||||
border: 2px solid mat-color($mat-blue, 500);
|
||||
}
|
||||
|
||||
&:after {
|
||||
border-left-color: mat-color($mat-blue, 500);
|
||||
}
|
||||
}
|
||||
|
||||
+ .step {
|
||||
|
||||
.index {
|
||||
|
||||
&:before {
|
||||
border-left-color: mat-color($mat-blue, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.first {
|
||||
|
||||
.index {
|
||||
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.last {
|
||||
|
||||
.index {
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.index {
|
||||
display: flex;
|
||||
margin-right: 12px;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 28px;
|
||||
min-width: 28px;
|
||||
max-width: 28px;
|
||||
height: 28px;
|
||||
background: white;
|
||||
border-radius: 100%;
|
||||
border: 2px solid mat-color($mat-grey, 500);
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: ' ';
|
||||
border-left: 1px solid mat-color($mat-grey, 300);
|
||||
width: 1px;
|
||||
height: 50%;
|
||||
left: 29px;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
&:before {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
|
||||
.header {
|
||||
height: 72px;
|
||||
min-height: 72px;
|
||||
max-height: 72px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
background: mat-color($mat-grey, 200);
|
||||
|
||||
.course-step {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 48px;
|
||||
overflow: auto;
|
||||
|
||||
@media (max-width: 720px) {
|
||||
padding: 0 0 120px 0;
|
||||
}
|
||||
|
||||
.course-step-content {
|
||||
padding: 24px;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
background: white;
|
||||
@include mat-elevation(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-navigation {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
bottom: 32px;
|
||||
max-width: 944px;
|
||||
padding: 0 24px;
|
||||
width: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.previous {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.next,
|
||||
.done {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/app/main/content/apps/academy/course/course.component.ts
Normal file
101
src/app/main/content/apps/academy/course/course.component.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, QueryList, ViewChildren, ViewEncapsulation } from '@angular/core';
|
||||
import { AcademyCourseService } from '../course.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FusePerfectScrollbarDirective } from '../../../../../core/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-academy-course',
|
||||
templateUrl : './course.component.html',
|
||||
styleUrls : ['./course.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseAcademyCourseComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
{
|
||||
course: any;
|
||||
courseSubscription: Subscription;
|
||||
currentStep = 0;
|
||||
courseStepContent;
|
||||
animationDirection: 'left' | 'right' | 'none' = 'none';
|
||||
@ViewChildren(FusePerfectScrollbarDirective) fuseScrollbarDirectives: QueryList<FusePerfectScrollbarDirective>;
|
||||
|
||||
constructor(
|
||||
private courseService: AcademyCourseService,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// Subscribe to courses
|
||||
this.courseSubscription =
|
||||
this.courseService.onCourseChanged
|
||||
.subscribe(course => {
|
||||
this.course = course;
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit()
|
||||
{
|
||||
this.courseStepContent = this.fuseScrollbarDirectives.find((fuseScrollbarDirective) => {
|
||||
return fuseScrollbarDirective.element.nativeElement.id === 'course-step-content';
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.courseSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
gotoStep(step)
|
||||
{
|
||||
// Decide the animation direction
|
||||
this.animationDirection = this.currentStep < step ? 'left' : 'right';
|
||||
|
||||
// Run change detection so the change
|
||||
// in the animation direction registered
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
// Set the current step
|
||||
this.currentStep = step;
|
||||
}
|
||||
|
||||
gotoNextStep()
|
||||
{
|
||||
if ( this.currentStep === this.course.totalSteps - 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the animation direction
|
||||
this.animationDirection = 'left';
|
||||
|
||||
// Run change detection so the change
|
||||
// in the animation direction registered
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
// Increase the current step
|
||||
this.currentStep++;
|
||||
}
|
||||
|
||||
gotoPreviousStep()
|
||||
{
|
||||
if ( this.currentStep === 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the animation direction
|
||||
this.animationDirection = 'right';
|
||||
|
||||
// Run change detection so the change
|
||||
// in the animation direction registered
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
// Decrease the current step
|
||||
this.currentStep--;
|
||||
}
|
||||
}
|
||||
62
src/app/main/content/apps/academy/courses.service.ts
Normal file
62
src/app/main/content/apps/academy/courses.service.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class AcademyCoursesService implements Resolve<any>
|
||||
{
|
||||
onCategoriesChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
onCoursesChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(private http: HttpClient)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The Academy App Main Resolver
|
||||
*
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getCategories(),
|
||||
this.getCourses()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getCategories(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/academy-categories')
|
||||
.subscribe((response: any) => {
|
||||
this.onCategoriesChanged.next(response);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
getCourses(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/academy-courses')
|
||||
.subscribe((response: any) => {
|
||||
this.onCoursesChanged.next(response);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<div id="academy-courses" class="page-layout simple" fusePerfectScrollbar>
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header mat-accent-bg p-16 p-sm-24" fxLayout="column" fxLayoutAlign="center center">
|
||||
|
||||
<div class="hero-text">
|
||||
<mat-icon class="hero-icon">school</mat-icon>
|
||||
<h1>WELCOME TO ACADEMY</h1>
|
||||
<h3>
|
||||
Our courses will step you through the process of building a small application, or adding a new feature
|
||||
to an existing application.
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="content p-24">
|
||||
|
||||
<div fxLayout="column" fxLayoutAlign="center">
|
||||
|
||||
<div class="filters" fxLayout="column" fxLayoutAlign="center center"
|
||||
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="space-between center">
|
||||
|
||||
<mat-form-field class="course-search">
|
||||
|
||||
<input matInput placeholder="Search for a course" [(ngModel)]="searchTerm"
|
||||
(input)="filterCoursesByTerm()">
|
||||
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="category-selector">
|
||||
|
||||
<mat-select placeholder="Select Category" [(ngModel)]="currentCategory"
|
||||
(change)="filterCoursesByCategory()">
|
||||
<mat-option [value]="'all'">
|
||||
All
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let category of categories" [value]="category.value">
|
||||
{{ category.label }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="courses" fxLayout="row" fxLayoutAlign="center" fxLayoutWrap>
|
||||
|
||||
<div class="course" *ngFor="let course of filteredCourses" fxFlex="100" fxFlex.gt-xs="50"
|
||||
fxFlex.gt-sm="33" [ngClass]="course.category">
|
||||
|
||||
<div class="course-content" fxLayout="column">
|
||||
|
||||
<div class="header" fxLayout="row" fxLayoutAlign="center center"
|
||||
[ngClass]="course.category + '-bg'">
|
||||
|
||||
<div class="category" fxFlex>
|
||||
{{course.category}}
|
||||
</div>
|
||||
|
||||
<div class="length" fxLayout="row" fxLayoutAlign="center center">
|
||||
<mat-icon class="length-icon s-20">access_time</mat-icon>
|
||||
<div class="min">{{course.length}} min</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content" fxLayout="column" fxLayoutAlign="center center" fxFlex>
|
||||
<div class="h1">{{course.title}}</div>
|
||||
<div class="updated">Updated {{course.updated}}</div>
|
||||
</div>
|
||||
|
||||
<div class="footer" fxLayout="row" fxLayoutAlign="center center">
|
||||
<button mat-button color="accent"
|
||||
[routerLink]="'/apps/academy/courses/' + course.id + '/' + course.slug">
|
||||
START
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="no-courses" *ngIf="filteredCourses.length === 0">
|
||||
No courses found!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT -->
|
||||
|
||||
</div>
|
||||
188
src/app/main/content/apps/academy/courses/courses.component.scss
Normal file
188
src/app/main/content/apps/academy/courses/courses.component.scss
Normal file
@@ -0,0 +1,188 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
#academy-courses {
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
flex: 1 0 auto;
|
||||
height: 280px;
|
||||
max-height: 280px;
|
||||
background: #1A237E;
|
||||
background: linear-gradient(to right, #0E2A3B 0%, #34306B 100%);
|
||||
text-align: center;
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
height: 240px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
|
||||
.hero-icon {
|
||||
position: absolute;
|
||||
top: -64px;
|
||||
left: 0px;
|
||||
opacity: 0.04;
|
||||
font-size: 512px !important;
|
||||
width: 512px !important;
|
||||
height: 512px !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: white;
|
||||
font-size: 40px;
|
||||
font-weight: 300;
|
||||
letter-spacing: 0.01em;
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
max-width: 480px;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
letter-spacing: 0.03em;
|
||||
margin: 0;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.category-selector {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
width: 100%;
|
||||
max-width: 1040px;
|
||||
margin: 24px auto;
|
||||
padding: 0 20px;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.course-search {
|
||||
width: 200px;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up('sm') {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.courses {
|
||||
width: 100%;
|
||||
max-width: 1040px;
|
||||
margin: 0 auto;
|
||||
|
||||
.no-courses {
|
||||
font-size: 24px;
|
||||
margin: 24px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.course {
|
||||
padding: 16px;
|
||||
|
||||
&:hover {
|
||||
|
||||
.course-content {
|
||||
@include mat-elevation(8);
|
||||
}
|
||||
}
|
||||
|
||||
.course-content {
|
||||
background: white;
|
||||
min-height: 240px;
|
||||
transition: box-shadow 150ms ease-in-out;
|
||||
|
||||
@include mat-elevation(1);
|
||||
|
||||
.header {
|
||||
color: white;
|
||||
padding: 16px 24px;
|
||||
height: 64px !important;
|
||||
min-height: 64px !important;
|
||||
max-height: 64px !important;
|
||||
|
||||
&.web-bg {
|
||||
background: mat-color($mat-blue, 500);
|
||||
}
|
||||
|
||||
&.android-bg {
|
||||
background: mat-color($mat-green, 500);
|
||||
}
|
||||
|
||||
&.firebase-bg {
|
||||
background: mat-color($mat-amber, 800);
|
||||
}
|
||||
|
||||
&.cloud-bg {
|
||||
background: mat-color($mat-blue-grey, 500);
|
||||
}
|
||||
|
||||
.category {
|
||||
text-transform: capitalize;
|
||||
text-align: left;
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.length {
|
||||
|
||||
.length-icon {
|
||||
margin-right: 8px;
|
||||
color: rgba(0, 0, 0, 0.54) !important;
|
||||
}
|
||||
|
||||
.min {
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 24px;
|
||||
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.updated {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
margin-top: 4px;
|
||||
color: rgba(0, 0, 0, 0.37);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 16px;
|
||||
height: 48px !important;
|
||||
min-height: 48px !important;
|
||||
max-height: 48px !important;
|
||||
box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { AcademyCoursesService } from '../courses.service';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-academy-courses',
|
||||
templateUrl: './courses.component.html',
|
||||
styleUrls : ['./courses.component.scss']
|
||||
})
|
||||
export class FuseAcademyCoursesComponent implements OnInit, OnDestroy
|
||||
{
|
||||
categories: any[];
|
||||
courses: any[];
|
||||
coursesFilteredByCategory: any[];
|
||||
filteredCourses: any[];
|
||||
|
||||
categoriesSubscription: Subscription;
|
||||
coursesSubscription: Subscription;
|
||||
|
||||
currentCategory = 'all';
|
||||
searchTerm = '';
|
||||
|
||||
constructor(
|
||||
private coursesService: AcademyCoursesService
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// Subscribe to categories
|
||||
this.categoriesSubscription =
|
||||
this.coursesService.onCategoriesChanged
|
||||
.subscribe(categories => {
|
||||
this.categories = categories;
|
||||
});
|
||||
|
||||
// Subscribe to courses
|
||||
this.coursesSubscription =
|
||||
this.coursesService.onCoursesChanged
|
||||
.subscribe(courses => {
|
||||
this.filteredCourses = this.coursesFilteredByCategory = this.courses = courses;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.categoriesSubscription.unsubscribe();
|
||||
this.coursesSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
filterCoursesByCategory()
|
||||
{
|
||||
// Filter
|
||||
if ( this.currentCategory === 'all' )
|
||||
{
|
||||
this.coursesFilteredByCategory = this.courses;
|
||||
this.filteredCourses = this.courses;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.coursesFilteredByCategory = this.courses.filter((course) => {
|
||||
return course.category === this.currentCategory;
|
||||
});
|
||||
|
||||
this.filteredCourses = [...this.coursesFilteredByCategory];
|
||||
|
||||
}
|
||||
|
||||
// Re-filter by search term
|
||||
this.filterCoursesByTerm();
|
||||
}
|
||||
|
||||
filterCoursesByTerm()
|
||||
{
|
||||
const searchTerm = this.searchTerm.toLowerCase();
|
||||
|
||||
// Search
|
||||
if ( searchTerm === '' )
|
||||
{
|
||||
this.filteredCourses = this.coursesFilteredByCategory;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.filteredCourses = this.coursesFilteredByCategory.filter((course) => {
|
||||
return course.title.toLowerCase().includes(searchTerm);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/app/main/content/apps/apps.module.ts
Normal file
67
src/app/main/content/apps/apps.module.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../../../core/modules/shared.module';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FuseAngularMaterialModule } from '../components/angular-material/angular-material.module';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path : 'dashboards/project',
|
||||
loadChildren: './dashboards/project/project.module#FuseProjectDashboardModule'
|
||||
},
|
||||
{
|
||||
path : 'dashboards/analytics',
|
||||
loadChildren: './dashboards/analytics/analytics.module#FuseAnalyticsDashboardModule'
|
||||
},
|
||||
{
|
||||
path : 'mail',
|
||||
loadChildren: './mail/mail.module#FuseMailModule'
|
||||
},
|
||||
{
|
||||
path : 'mail-ngrx',
|
||||
loadChildren: './mail-ngrx/mail.module#FuseMailNgrxModule'
|
||||
},
|
||||
{
|
||||
path : 'chat',
|
||||
loadChildren: './chat/chat.module#FuseChatModule'
|
||||
},
|
||||
{
|
||||
path : 'calendar',
|
||||
loadChildren: './calendar/calendar.module#FuseCalendarModule'
|
||||
},
|
||||
{
|
||||
path : 'e-commerce',
|
||||
loadChildren: './e-commerce/e-commerce.module#FuseEcommerceModule'
|
||||
},
|
||||
{
|
||||
path : 'academy',
|
||||
loadChildren: './academy/academy.module#FuseAcademyModule'
|
||||
},
|
||||
{
|
||||
path : 'todo',
|
||||
loadChildren: './todo/todo.module#FuseTodoModule'
|
||||
},
|
||||
{
|
||||
path : 'file-manager',
|
||||
loadChildren: './file-manager/file-manager.module#FuseFileManagerModule'
|
||||
},
|
||||
{
|
||||
path : 'contacts',
|
||||
loadChildren: './contacts/contacts.module#FuseContactsModule'
|
||||
},
|
||||
{
|
||||
path : 'scrumboard',
|
||||
loadChildren: './scrumboard/scrumboard.module#FuseScrumboardModule'
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports : [
|
||||
SharedModule,
|
||||
RouterModule.forChild(routes),
|
||||
FuseAngularMaterialModule
|
||||
],
|
||||
declarations: []
|
||||
})
|
||||
export class FuseAppsModule
|
||||
{
|
||||
}
|
||||
@@ -216,52 +216,52 @@
|
||||
}
|
||||
|
||||
&.Jan {
|
||||
background-image: url('/assets/images/backgrounds/january.jpg');
|
||||
background-position: 0 45%;
|
||||
background-image: url('/assets/images/backgrounds/winter.jpg');
|
||||
background-position: 0 85%;
|
||||
}
|
||||
&.Feb {
|
||||
background-image: url('/assets/images/backgrounds/february.jpg');
|
||||
background-position: 0 50%;
|
||||
background-image: url('/assets/images/backgrounds/winter.jpg');
|
||||
background-position: 0 85%;
|
||||
}
|
||||
&.Mar {
|
||||
background-image: url('/assets/images/backgrounds/march.jpg');
|
||||
background-position: 0 45%;
|
||||
background-image: url('/assets/images/backgrounds/spring.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.Apr {
|
||||
background-image: url('/assets/images/backgrounds/april.jpg');
|
||||
background-position: 0 48%;
|
||||
background-image: url('/assets/images/backgrounds/spring.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.May {
|
||||
background-image: url('/assets/images/backgrounds/may.jpg');
|
||||
background-position: 0 47%;
|
||||
background-image: url('/assets/images/backgrounds/spring.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.Jun {
|
||||
background-image: url('/assets/images/backgrounds/june.jpg');
|
||||
background-position: 0 48%;
|
||||
background-image: url('/assets/images/backgrounds/summer.jpg');
|
||||
background-position: 0 80%;
|
||||
}
|
||||
&.Jul {
|
||||
background-image: url('/assets/images/backgrounds/july.jpg');
|
||||
background-position: 0 3%;
|
||||
background-image: url('/assets/images/backgrounds/summer.jpg');
|
||||
background-position: 0 80%;
|
||||
}
|
||||
&.Aug {
|
||||
background-image: url('/assets/images/backgrounds/august.jpg');
|
||||
background-position: 0 61%;
|
||||
background-image: url('/assets/images/backgrounds/summer.jpg');
|
||||
background-position: 0 80%;
|
||||
}
|
||||
&.Sep {
|
||||
background-image: url('/assets/images/backgrounds/september.jpg');
|
||||
background-position: 0 58%;
|
||||
background-image: url('/assets/images/backgrounds/autumn.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.Oct {
|
||||
background-image: url('/assets/images/backgrounds/october.jpg');
|
||||
background-position: 0 50%;
|
||||
background-image: url('/assets/images/backgrounds/autumn.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.Nov {
|
||||
background-image: url('/assets/images/backgrounds/november.jpg');
|
||||
background-position: 0 46%;
|
||||
background-image: url('/assets/images/backgrounds/autumn.jpg');
|
||||
background-position: 0 40%;
|
||||
}
|
||||
&.Dec {
|
||||
background-image: url('/assets/images/backgrounds/december.jpg');
|
||||
background-position: 0 43%;
|
||||
background-image: url('/assets/images/backgrounds/winter.jpg');
|
||||
background-position: 0 85%;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
@@ -299,7 +299,7 @@
|
||||
.add-event-button {
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
bottom: -32px;
|
||||
bottom: -26px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,21 +25,13 @@ import { fuseAnimations } from '../../../../core/animations';
|
||||
export class FuseCalendarComponent implements OnInit
|
||||
{
|
||||
view: string;
|
||||
|
||||
viewDate: Date;
|
||||
|
||||
events: CalendarEvent[];
|
||||
|
||||
public actions: CalendarEventAction[];
|
||||
|
||||
activeDayIsOpen: boolean;
|
||||
|
||||
refresh: Subject<any> = new Subject();
|
||||
|
||||
dialogRef: any;
|
||||
|
||||
confirmDialogRef: MatDialogRef<FuseConfirmDialogComponent>;
|
||||
|
||||
selectedDay: any;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -32,9 +32,11 @@
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="py-16" fxFlex="1 0 auto" fxLayout="row" formGroupName="color">
|
||||
<mat-form-field class="mr-24" fxFlex>
|
||||
<div class="py-16" fxFlex="1 0 auto" fxLayout="column" fxLayout.gt-xs="row" formGroupName="color">
|
||||
|
||||
<mat-form-field class="mr-sm-24" fxFlex>
|
||||
<input matInput
|
||||
class="primary-color-input"
|
||||
name="primary color"
|
||||
formControlName="primary"
|
||||
placeholder="Primary color"
|
||||
@@ -44,8 +46,10 @@
|
||||
[style.background]="event.color.primary"
|
||||
(colorPickerChange)="event.color.primary = $event; eventForm.patchValue({color:{primary:$event}})"/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex>
|
||||
<input matInput
|
||||
class="secondary-color-input"
|
||||
name="secondary color"
|
||||
formControlName="secondary"
|
||||
placeholder="Secondary color"
|
||||
@@ -55,11 +59,12 @@
|
||||
[style.background]="event.color.secondary"
|
||||
(colorPickerChange)="event.color.secondary = $event; eventForm.patchValue({color:{secondary:$event}})"/>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 0 auto" fxLayout="row">
|
||||
<div fxFlex="1 0 auto" fxLayout="column" fxLayout.gt-xs="row">
|
||||
|
||||
<mat-form-field class="mr-24" fxFlex>
|
||||
<mat-form-field class="mr-sm-24" fxFlex>
|
||||
<input matInput [matDatepicker]="startDatePicker" placeholder="Start Date"
|
||||
name="start"
|
||||
formControlName="start">
|
||||
@@ -73,9 +78,9 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 0 auto" fxLayout="row">
|
||||
<div fxFlex="1 0 auto" fxLayout="column" fxLayout.gt-xs="row">
|
||||
|
||||
<mat-form-field class="mr-24" fxFlex>
|
||||
<mat-form-field class="mr-sm-24" fxFlex>
|
||||
<input matInput [matDatepicker]="endDatePicker" placeholder="End Date"
|
||||
name="end"
|
||||
formControlName="end">
|
||||
@@ -98,12 +103,12 @@
|
||||
|
||||
<mat-form-field formGroupName="meta" class="w-100-p">
|
||||
|
||||
<textarea matInput
|
||||
formControlName="notes"
|
||||
placeholder="Notes"
|
||||
mat-maxlength="250"
|
||||
max-rows="4">
|
||||
</textarea>
|
||||
<textarea matInput
|
||||
formControlName="notes"
|
||||
placeholder="Notes"
|
||||
mat-maxlength="250"
|
||||
max-rows="4">
|
||||
</textarea>
|
||||
</mat-form-field>
|
||||
|
||||
</form>
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
.event-form-dialog {
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up('xs') {
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
.mat-dialog-container {
|
||||
padding: 0;
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
.dialog-content-wrapper {
|
||||
@@ -10,4 +19,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.primary-color-input,
|
||||
.secondary-color-input {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { CalendarEvent } from 'angular-calendar';
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
|
||||
import { CalendarEventModel } from '../event.model';
|
||||
import { MatColors } from '../../../../../core/matColors';
|
||||
import 'rxjs/Rx';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-calendar-event-form-dialog',
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- LEFT SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||
<mat-sidenav class="sidenav" align="start" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="chat-left-sidenav" mat-is-locked-open="gt-md">
|
||||
<fuse-chat-left-sidenav></fuse-chat-left-sidenav>
|
||||
</mat-sidenav>
|
||||
@@ -26,7 +26,7 @@
|
||||
<!-- / CONTENT -->
|
||||
|
||||
<!-- RIGHT SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="end" opened="false" mode="over"
|
||||
<mat-sidenav class="sidenav" align="end" opened="false" mode="over"
|
||||
fuseMatSidenavHelper="chat-right-sidenav">
|
||||
<fuse-chat-right-sidenav></fuse-chat-right-sidenav>
|
||||
</mat-sidenav>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<!-- USER AVATAR WRAPPER -->
|
||||
<div class="avatar-wrapper">
|
||||
@@ -16,7 +16,8 @@
|
||||
alt="{{user.name}}"/>
|
||||
<!-- / USER AVATAR -->
|
||||
|
||||
<mat-icon class="s-16 status" [ngClass]="user.status" [matMenuTriggerFor]="userStatusMenu"></mat-icon>
|
||||
<mat-icon class="s-16 status" [ngClass]="user.status"
|
||||
[matMenuTriggerFor]="userStatusMenu"></mat-icon>
|
||||
|
||||
<!-- USER STATUS -->
|
||||
<mat-menu id="user-status-menu" #userStatusMenu="matMenu">
|
||||
@@ -69,7 +70,8 @@
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ChatService } from '../../../chat.service';
|
||||
import { FuseMatSidenavHelperService } from '../../../../../../../core/directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { ObservableMedia } from '@angular/flex-layout';
|
||||
import { fuseAnimations } from '../../../../../../../core/animations';
|
||||
import { FuseMatSidenavHelperService } from '../../../../../../../core/directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.service';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-chat-chats-sidenav',
|
||||
|
||||
@@ -5,20 +5,19 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<button mat-button class="mat-icon-button" (click)="changeLeftSidenavView('chats')" aria-label="back">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
<mat-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center">
|
||||
|
||||
<img [src]="user.avatar" class="avatar user-avatar huge" alt="{{user.name}}"/>
|
||||
|
||||
<div class="user-name my-8">{{user.name}}</div>
|
||||
|
||||
</mat-toolbar-row>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ChatService } from '../../../chat.service';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import 'rxjs/Rx';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-chat-user-sidenav',
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<div>Contact Info</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
@@ -37,9 +37,9 @@
|
||||
<mat-card>
|
||||
|
||||
<mat-form-field fxFlex>
|
||||
<textarea matInput placeholder="Mood" name="mood"
|
||||
[value]="contact.mood" rows="3" disabled>
|
||||
</textarea>
|
||||
<textarea matInput placeholder="Mood" name="mood"
|
||||
[value]="contact.mood" rows="3" disabled>
|
||||
</textarea>
|
||||
</mat-form-field>
|
||||
|
||||
</mat-card>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<div class="dialog-content-wrapper">
|
||||
<mat-toolbar matDialogTitle class="mat-accent m-0">
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<span class="title dialog-title">{{dialogTitle}}</span>
|
||||
<button mat-button class="mat-icon-button"
|
||||
(click)="dialogRef.close()"
|
||||
aria-label="Close dialog">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
|
||||
<mat-toolbar-row class="toolbar-bottom py-8 py-sm-16" fxLayout="column" fxLayoutAlign="center center">
|
||||
<img [src]="contact.avatar" class=" avatar contact-avatar huge"
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
.contact-form-dialog {
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up('xs') {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.mat-dialog-container {
|
||||
padding: 0;
|
||||
width: 400px;
|
||||
overflow: hidden;
|
||||
|
||||
.mat-toolbar {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
import { CalendarEvent } from 'angular-calendar';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import 'rxjs/Rx';
|
||||
import { Contact } from '../contact.model';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
:host {
|
||||
fuse-contacts-contact-list {
|
||||
flex: 1;
|
||||
|
||||
.mat-table {
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
.mat-column-checkbox {
|
||||
flex: 0 1 48px;
|
||||
|
||||
.mat-checkbox-ripple {
|
||||
display: none !important; //fix for broken rendering
|
||||
}
|
||||
}
|
||||
|
||||
.mat-column-avatar {
|
||||
@@ -40,12 +44,9 @@
|
||||
}
|
||||
|
||||
#add-contact-button {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
padding: 0;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
top: 12px;
|
||||
}
|
||||
}
|
||||
z-index: 99;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ContactsService } from '../contacts.service';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { FuseContactsContactFormDialogComponent } from '../contact-form/contact-form.component';
|
||||
@@ -7,14 +7,16 @@ import { FuseConfirmDialogComponent } from '../../../../../core/components/confi
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-contacts-contact-list',
|
||||
templateUrl: './contact-list.component.html',
|
||||
styleUrls : ['./contact-list.component.scss'],
|
||||
animations : fuseAnimations
|
||||
selector : 'fuse-contacts-contact-list',
|
||||
templateUrl : './contact-list.component.html',
|
||||
styleUrls : ['./contact-list.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseContactsContactListComponent implements OnInit
|
||||
export class FuseContactsContactListComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@ViewChild('dialogContent') dialogContent: TemplateRef<any>;
|
||||
|
||||
@@ -25,6 +27,10 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
selectedContacts: any[];
|
||||
checkboxes: {};
|
||||
|
||||
onContactsChangedSubscription: Subscription;
|
||||
onSelectedContactsChangedSubscription: Subscription;
|
||||
onUserDataChangedSubscription: Subscription;
|
||||
|
||||
dialogRef: any;
|
||||
|
||||
confirmDialogRef: MatDialogRef<FuseConfirmDialogComponent>;
|
||||
@@ -34,27 +40,35 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
public dialog: MatDialog
|
||||
)
|
||||
{
|
||||
this.contactsService.onContactsChanged.subscribe(contacts => {
|
||||
this.onContactsChangedSubscription =
|
||||
this.contactsService.onContactsChanged.subscribe(contacts => {
|
||||
|
||||
this.contacts = contacts;
|
||||
this.contacts = contacts;
|
||||
|
||||
this.checkboxes = {};
|
||||
contacts.map(contact => {
|
||||
this.checkboxes[contact.id] = false;
|
||||
this.checkboxes = {};
|
||||
contacts.map(contact => {
|
||||
this.checkboxes[contact.id] = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
|
||||
for ( const id in this.checkboxes )
|
||||
{
|
||||
this.checkboxes[id] = selectedContacts.includes(id);
|
||||
}
|
||||
this.selectedContacts = selectedContacts;
|
||||
});
|
||||
this.onSelectedContactsChangedSubscription =
|
||||
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
|
||||
for ( const id in this.checkboxes )
|
||||
{
|
||||
if ( !this.checkboxes.hasOwnProperty(id) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
this.checkboxes[id] = selectedContacts.includes(id);
|
||||
}
|
||||
this.selectedContacts = selectedContacts;
|
||||
});
|
||||
|
||||
this.onUserDataChangedSubscription =
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -63,6 +77,13 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
this.dataSource = new FilesDataSource(this.contactsService);
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onContactsChangedSubscription.unsubscribe();
|
||||
this.onSelectedContactsChangedSubscription.unsubscribe();
|
||||
this.onUserDataChangedSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
editContact(contact)
|
||||
{
|
||||
this.dialogRef = this.dialog.open(FuseContactsContactFormDialogComponent, {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||
<mat-sidenav class="sidenav" align="start" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="contacts-main-sidenav" mat-is-locked-open="gt-sm">
|
||||
|
||||
<fuse-contacts-main-sidenav *fuseIfOnDom [@animate]="{value:'*'}"></fuse-contacts-main-sidenav>
|
||||
|
||||
@@ -3,12 +3,4 @@
|
||||
.content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
#add-contact-button {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
padding: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ContactsService } from './contacts.service';
|
||||
import { fuseAnimations } from '../../../../core/animations';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { FuseContactsContactFormDialogComponent } from './contact-form/contact-form.component';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-contacts',
|
||||
@@ -12,11 +15,12 @@ import { MatDialog } from '@angular/material';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseContactsComponent implements OnInit
|
||||
export class FuseContactsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
hasSelectedContacts: boolean;
|
||||
searchInput: FormControl;
|
||||
dialogRef: any;
|
||||
onSelectedContactsChangedSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private contactsService: ContactsService,
|
||||
@@ -50,11 +54,11 @@ export class FuseContactsComponent implements OnInit
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
|
||||
this.contactsService.onSelectedContactsChanged
|
||||
.subscribe(selectedContacts => {
|
||||
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||
});
|
||||
this.onSelectedContactsChangedSubscription =
|
||||
this.contactsService.onSelectedContactsChanged
|
||||
.subscribe(selectedContacts => {
|
||||
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||
});
|
||||
|
||||
this.searchInput.valueChanges
|
||||
.debounceTime(300)
|
||||
@@ -64,4 +68,8 @@ export class FuseContactsComponent implements OnInit
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onSelectedContactsChangedSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Subject } from 'rxjs/Subject';
|
||||
@Injectable()
|
||||
export class ContactsService implements Resolve<any>
|
||||
{
|
||||
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||
onSelectedContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||
onUserDataChanged: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||
onSearchTextChanged: Subject<any> = new Subject();
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { ContactsService } from '../../contacts.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-contacts-main-sidenav',
|
||||
templateUrl: './main.component.html',
|
||||
styleUrls : ['./main.component.scss']
|
||||
})
|
||||
export class FuseContactsMainSidenavComponent implements OnInit
|
||||
export class FuseContactsMainSidenavComponent implements OnDestroy
|
||||
{
|
||||
user: any;
|
||||
filterBy: string;
|
||||
onUserDataChangedSubscription: Subscription;
|
||||
|
||||
constructor(private contactsService: ContactsService)
|
||||
{
|
||||
this.filterBy = 'all';
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.filterBy = this.contactsService.filterBy || 'all';
|
||||
this.onUserDataChangedSubscription =
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
|
||||
changeFilter(filter)
|
||||
@@ -28,4 +27,9 @@ export class FuseContactsMainSidenavComponent implements OnInit
|
||||
this.filterBy = filter;
|
||||
this.contactsService.onFilterChanged.next(this.filterBy);
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onUserDataChangedSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
<div id="dashboard-analytics" class="page-layout blank grey-100-bg" fusePerfectScrollbar>
|
||||
|
||||
<div class="main-widget">
|
||||
|
||||
<div class="position-relative p-24 mat-blue-600-bg"
|
||||
fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div fxLayout="column" fxLayoutAlign="start start">
|
||||
<span class="h2">Visitors</span>
|
||||
<span class="h5 secondary-text">Unique visitors by month</span>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<div class="py-8 px-12 border-radius-2 line-height-1 mr-8 cursor-pointer"
|
||||
(click)="widget1SelectedYear = '2015'"
|
||||
[ngClass]="{'blue-300-bg': widget1SelectedYear === '2015'}">
|
||||
2015
|
||||
</div>
|
||||
<div class="py-8 px-12 border-radius-2 line-height-1 mr-8 cursor-pointer"
|
||||
(click)="widget1SelectedYear = '2016'"
|
||||
[ngClass]="{'blue-300-bg': widget1SelectedYear === '2016'}">
|
||||
2016
|
||||
</div>
|
||||
<div class="py-8 px-12 border-radius-2 line-height-1 cursor-pointer"
|
||||
(click)="widget1SelectedYear = '2017'"
|
||||
[ngClass]="{'blue-300-bg': widget1SelectedYear === '2017'}">
|
||||
2017
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="position-relative h-256 pb-16 mat-blue-600-bg">
|
||||
<canvas baseChart
|
||||
[datasets]="widgets.widget1.datasets[widget1SelectedYear]"
|
||||
[labels]="widgets.widget1.labels"
|
||||
[colors]="widgets.widget1.colors"
|
||||
[options]="widgets.widget1.options"
|
||||
[chartType]="widgets.widget1.chartType">
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<div class="left mr-32">
|
||||
|
||||
<div class="pb-24 font-size-18 font-weight-300">
|
||||
How are your active users trending over time?
|
||||
</div>
|
||||
|
||||
<div fxLayout="column" fxLayoutAlign="start"
|
||||
fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start start">
|
||||
|
||||
<!-- Widget 2 -->
|
||||
<div class="widget" fxFlex="100" fxFlex.gt-sm="33">
|
||||
|
||||
<div class="fuse-card auto-width mb-32" [ngClass.gt-sm]="'mb-0 mr-32'">
|
||||
|
||||
<div class="p-16 pb-0" fxLayout="row" fxLayoutAlign="start end" fxLayoutWrap>
|
||||
|
||||
<div class="pr-16">
|
||||
<div class="h3 secondary-text">Conversion</div>
|
||||
<div class="font-size-54 font-weight-300 line-height-1 mt-8">
|
||||
{{widgets.widget2.conversion.value}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-4 font-size-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="green-fg"
|
||||
*ngIf="widgets.widget2.conversion.ofTarget > 0">
|
||||
<mat-icon class="green-fg mr-4">trending_up</mat-icon>
|
||||
<span>{{widgets.widget2.conversion.ofTarget}}%</span>
|
||||
</div>
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="red-fg"
|
||||
*ngIf="widgets.widget2.conversion.ofTarget < 0">
|
||||
<mat-icon class="red-fg mr-4">trending_down</mat-icon>
|
||||
<span>{{widgets.widget2.conversion.ofTarget}}%</span>
|
||||
</div>
|
||||
<div class="ml-4 text-nowrap">of target</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="h-96 w-100-p">
|
||||
<canvas baseChart
|
||||
[datasets]="widgets.widget2.datasets"
|
||||
[labels]="widgets.widget2.labels"
|
||||
[colors]="widgets.widget2.colors"
|
||||
[options]="widgets.widget2.options"
|
||||
[chartType]="widgets.widget2.chartType">
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 2 -->
|
||||
|
||||
<!-- Widget 3 -->
|
||||
<div class="widget" fxFlex="100" fxFlex.gt-sm="34">
|
||||
|
||||
<div class="fuse-card auto-width mb-32" [ngClass.gt-sm]="'mb-0 mr-32'">
|
||||
|
||||
<div class="p-16 pb-0" fxLayout="row" fxLayoutAlign="start end" fxLayoutWrap>
|
||||
|
||||
<div class="pr-16">
|
||||
<div class="h3 secondary-text">Impressions</div>
|
||||
<div class="font-size-54 font-weight-300 line-height-1 mt-8">
|
||||
{{widgets.widget3.impressions.value}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-4 font-size-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="green-fg"
|
||||
*ngIf="widgets.widget3.impressions.ofTarget > 0">
|
||||
<mat-icon class="green-fg mr-4">trending_up</mat-icon>
|
||||
<span>{{widgets.widget3.impressions.ofTarget}}%</span>
|
||||
</div>
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="red-fg"
|
||||
*ngIf="widgets.widget3.impressions.ofTarget < 0">
|
||||
<mat-icon class="red-fg mr-4">trending_down</mat-icon>
|
||||
<span>{{widgets.widget3.impressions.ofTarget}}%</span>
|
||||
</div>
|
||||
<div class="ml-4 text-nowrap">of target</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="h-96 w-100-p">
|
||||
<canvas baseChart
|
||||
[datasets]="widgets.widget3.datasets"
|
||||
[labels]="widgets.widget3.labels"
|
||||
[colors]="widgets.widget3.colors"
|
||||
[options]="widgets.widget3.options"
|
||||
[chartType]="widgets.widget3.chartType">
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 3 -->
|
||||
|
||||
<!-- Widget 4 -->
|
||||
<div class="widget" fxFlex="100" fxFlex.gt-sm="33">
|
||||
|
||||
<div class="fuse-card auto-width">
|
||||
|
||||
<div class="p-16 pb-0" fxLayout="row" fxLayoutAlign="start end" fxLayoutWrap>
|
||||
|
||||
<div class="pr-16">
|
||||
<div class="h3 secondary-text">Visits</div>
|
||||
<div class="font-size-54 font-weight-300 line-height-1 mt-8">
|
||||
{{widgets.widget4.visits.value}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-4 font-size-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="green-fg"
|
||||
*ngIf="widgets.widget4.visits.ofTarget > 0">
|
||||
<mat-icon class="green-fg mr-4">trending_up</mat-icon>
|
||||
<span>{{widgets.widget4.visits.ofTarget}}%</span>
|
||||
</div>
|
||||
<div fxFlex="row" fxLayoutAlign="start center" class="red-fg"
|
||||
*ngIf="widgets.widget4.visits.ofTarget < 0">
|
||||
<mat-icon class="red-fg mr-4">trending_down</mat-icon>
|
||||
<span>{{widgets.widget4.visits.ofTarget}}%</span>
|
||||
</div>
|
||||
<div class="ml-4 text-nowrap">of target</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="h-96 w-100-p">
|
||||
<canvas baseChart
|
||||
[datasets]="widgets.widget4.datasets"
|
||||
[labels]="widgets.widget4.labels"
|
||||
[colors]="widgets.widget4.colors"
|
||||
[options]="widgets.widget4.options"
|
||||
[chartType]="widgets.widget4.chartType">
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 4 -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Widget 5 -->
|
||||
<div class="pt-48 pb-24 font-size-18 font-weight-300">
|
||||
How many pages your users visit?
|
||||
</div>
|
||||
|
||||
<div class="fuse-card auto-width">
|
||||
|
||||
<div class="position-relative p-24"
|
||||
fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div fxLayout="column" fxLayoutAlign="start start">
|
||||
<span class="h2">Visitors & Page views</span>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<div class="py-8 px-12 border-radius-2 line-height-1 mr-8 cursor-pointer"
|
||||
(click)="widget5SelectedDay = 'yesterday'"
|
||||
[ngClass]="{'grey-300-bg': widget5SelectedDay === 'yesterday'}">
|
||||
Yesterday
|
||||
</div>
|
||||
<div class="py-8 px-12 border-radius-2 line-height-1 mr-8 cursor-pointer"
|
||||
(click)="widget5SelectedDay = 'today'"
|
||||
[ngClass]="{'grey-300-bg': widget5SelectedDay === 'today'}">
|
||||
Today
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="position-relative h-368 pb-16">
|
||||
<canvas baseChart
|
||||
[datasets]="widgets.widget5.datasets[widget5SelectedDay]"
|
||||
[labels]="widgets.widget5.labels"
|
||||
[colors]="widgets.widget5.colors"
|
||||
[options]="widgets.widget5.options"
|
||||
[chartType]="widgets.widget5.chartType">
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 5 -->
|
||||
|
||||
<!-- Widget 6 -->
|
||||
<div class="pt-48 pb-24 font-size-18 font-weight-300">
|
||||
Where are your users?
|
||||
</div>
|
||||
|
||||
<div class="fuse-card auto-width p-16">
|
||||
|
||||
<agm-map class="h-640 w-100-p"
|
||||
[minZoom]="2"
|
||||
[maxZoom]="2"
|
||||
[fullscreenControl]="false"
|
||||
[rotateControl]="false"
|
||||
[zoomControl]="false"
|
||||
[scaleControl]="false"
|
||||
[streetViewControl]="false"
|
||||
[scrollwheel]="false"
|
||||
[styles]="widgets.widget6.styles">
|
||||
<agm-marker
|
||||
*ngFor="let marker of widgets.widget6.markers"
|
||||
[latitude]="marker.lat"
|
||||
[longitude]="marker.lng">
|
||||
|
||||
<agm-info-window>
|
||||
<strong>{{marker.label}}</strong>
|
||||
</agm-info-window>
|
||||
|
||||
</agm-marker>
|
||||
</agm-map>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 6 -->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
|
||||
<div fxLayout="row" fxLayoutWrap
|
||||
fxLayout.gt-md="column">
|
||||
|
||||
<!-- Widget 7 -->
|
||||
<div class="mb-48" [ngClass.lt-lg]="'mr-32'">
|
||||
|
||||
<div class="pb-24 font-size-18 font-weight-300">
|
||||
What are your top devices?
|
||||
</div>
|
||||
|
||||
<div class="fuse-card">
|
||||
|
||||
<div class="p-16">
|
||||
<div class="h1 font-weight-300">Sessions by device</div>
|
||||
</div>
|
||||
|
||||
<div class="h-200">
|
||||
<ngx-charts-pie-chart
|
||||
*fuseIfOnDom
|
||||
[scheme]="widgets.widget7.scheme"
|
||||
[results]="widgets.widget7.devices"
|
||||
[doughnut]="true">
|
||||
</ngx-charts-pie-chart>
|
||||
</div>
|
||||
|
||||
<div class="p-16" fxLayout="row" fxLayoutAlign="center center">
|
||||
|
||||
<div class="px-16" fxLayout="column" fxLayoutAlign="start center"
|
||||
*ngFor="let device of widgets.widget7.devices">
|
||||
|
||||
<div class="h4 secondary-text">{{device.name}}</div>
|
||||
<div class="h2 font-weight-300 py-8">{{device.value}}%</div>
|
||||
|
||||
<div fxLayout="row" fxLayoutAlign="center center">
|
||||
<mat-icon class="s-18 pr-4 red-fg"
|
||||
*ngIf="device.change < 0">
|
||||
arrow_downward
|
||||
</mat-icon>
|
||||
|
||||
<mat-icon class="s-18 pr-4 green-fg"
|
||||
*ngIf="device.change > 0">
|
||||
arrow_upward
|
||||
</mat-icon>
|
||||
|
||||
<div class="h5 red-fg"
|
||||
[ngClass]="{'red-fg': device.change < 0, 'green-fg': device.change > 0}">
|
||||
{{device.change}}%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-divider mb-0"></div>
|
||||
|
||||
<div class="px-16" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-form-field>
|
||||
<mat-select class="simplified" value="7days">
|
||||
<mat-option value="today">Today</mat-option>
|
||||
<mat-option value="yesterday">Yesterday</mat-option>
|
||||
<mat-option value="7days">Last 7 days</mat-option>
|
||||
<mat-option value="28days">Last 28 days</mat-option>
|
||||
<mat-option value="90days">Last 90 days</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-button color="accent">OVERVIEW</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Widget 7 -->
|
||||
|
||||
<!-- Widget 8 -->
|
||||
<div class="mb-48" [ngClass.lt-lg]="'mr-32'">
|
||||
|
||||
<div class="pb-24 font-size-18 font-weight-300">
|
||||
How are your sales?
|
||||
</div>
|
||||
|
||||
<div class="fuse-card">
|
||||
|
||||
<div class="mat-light-blue-600-bg">
|
||||
|
||||
<div class="p-16" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="pr-16">
|
||||
<div class="h1 font-weight-300">Sales</div>
|
||||
<div class="h5 secondary-text">Lifetime sum of your sales</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button mat-icon-button [matMenuTriggerFor]="card19Menu" aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #card19Menu="matMenu">
|
||||
<button mat-menu-item>
|
||||
<mat-icon>trending_up</mat-icon>
|
||||
<span>Trend</span>
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>History</span>
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon>notifications_off</mat-icon>
|
||||
<span>Disable alerts</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-16 pt-8" fxLayout="row" fxLayoutAlign="space-between end">
|
||||
<div class="font-size-48 font-weight-300 line-height-1">{{widgets.widget8.today}}</div>
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon *ngIf="widgets.widget8.change.value > 0">trending_up</mat-icon>
|
||||
<mat-icon *ngIf="widgets.widget8.change.value < 0">trending_down</mat-icon>
|
||||
<div class="ml-8">{{widgets.widget8.change.value}}
|
||||
({{widgets.widget8.change.percentage}}%)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-tab-group backgroundColor="accent">
|
||||
<mat-tab label="1DAY">
|
||||
<div class="h-200 my-16">
|
||||
<ngx-charts-line-chart
|
||||
*fuseIfOnDom
|
||||
[scheme]="widgets.widget8.scheme"
|
||||
[results]="widgets.widget8.data"
|
||||
[xAxis]="false"
|
||||
[yAxis]="true"
|
||||
[yScaleMin]="widgets.widget8.dataMin"
|
||||
[yScaleMax]="widgets.widget8.dataMax">
|
||||
</ngx-charts-line-chart>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="1WEEK">
|
||||
<div class="h-200 my-16">
|
||||
<ngx-charts-line-chart
|
||||
*fuseIfOnDom
|
||||
[scheme]="widgets.widget8.scheme"
|
||||
[results]="widgets.widget8.data"
|
||||
[xAxis]="false"
|
||||
[yAxis]="true"
|
||||
[yScaleMin]="widgets.widget8.dataMin"
|
||||
[yScaleMax]="widgets.widget8.dataMax">
|
||||
</ngx-charts-line-chart>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="1MONTH">
|
||||
<div class="h-200 my-16">
|
||||
<ngx-charts-line-chart
|
||||
*fuseIfOnDom
|
||||
[scheme]="widgets.widget8.scheme"
|
||||
[results]="widgets.widget8.data"
|
||||
[xAxis]="false"
|
||||
[yAxis]="true"
|
||||
[yScaleMin]="widgets.widget8.dataMin"
|
||||
[yScaleMax]="widgets.widget8.dataMax">
|
||||
</ngx-charts-line-chart>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- / Widget 8 -->
|
||||
|
||||
<!-- Widget 9 -->
|
||||
<div class="mb-48" [ngClass.lt-lg]="'mr-32'">
|
||||
|
||||
<div class="pb-24 font-size-18 font-weight-300" [ngClass.lt-lg]="'pt-0'">
|
||||
What are your top campaigns?
|
||||
</div>
|
||||
|
||||
<div class="fuse-card">
|
||||
|
||||
<div class="p-16" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h1 pr-16">Top campaigns</div>
|
||||
|
||||
<div>
|
||||
<button mat-icon-button [matMenuTriggerFor]="card20Menu" aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #card20Menu="matMenu">
|
||||
<button fxLayout="row" fxLayoutAlign="start center" mat-menu-item>
|
||||
<mat-icon color="accent">check_box</mat-icon>
|
||||
<span>Show Clicks</span>
|
||||
</button>
|
||||
<button fxLayout="row" fxLayoutAlign="start center" mat-menu-item>
|
||||
<mat-icon color="accent">check_box</mat-icon>
|
||||
<span>Show Conversion</span>
|
||||
</button>
|
||||
<button fxLayout="row" fxLayoutAlign="start center" mat-menu-item>
|
||||
<mat-icon>check_box_outline_blank</mat-icon>
|
||||
<span>Show CPC</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="simple clickable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-right">Clicks</th>
|
||||
<th class="text-right">Conv</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let row of widgets.widget9.rows">
|
||||
<td>{{row.title}}</td>
|
||||
<td class="text-right">{{row.clicks}}</td>
|
||||
<td class="text-right">{{row.conversion}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="card-divider full-width"></div>
|
||||
|
||||
<div class="p-8 pt-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button mat-button color="accent">GO TO CAMPAIGNS</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / widget 9 -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
#dashboard-analytics {
|
||||
|
||||
.main-widget {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
padding: 32px;
|
||||
min-width: 0;
|
||||
|
||||
@include media-breakpoint-down('md') {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
|
||||
.widget {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
width: 320px;
|
||||
min-width: 320px;
|
||||
max-width: 320px;
|
||||
|
||||
@include media-breakpoint-down('md') {
|
||||
flex: 1 0 100%;
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { AnalyticsDashboardService } from './analytics.service';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-analytics-dashboard',
|
||||
templateUrl : './analytics.component.html',
|
||||
styleUrls : ['./analytics.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseAnalyticsDashboardComponent
|
||||
{
|
||||
widgets: any;
|
||||
widget1SelectedYear = '2016';
|
||||
widget5SelectedDay = 'today';
|
||||
|
||||
constructor(
|
||||
private analyticsDashboardService: AnalyticsDashboardService
|
||||
)
|
||||
{
|
||||
// Get the widgets from the service
|
||||
this.widgets = this.analyticsDashboardService.widgets;
|
||||
|
||||
// Register the custom chart.js plugin
|
||||
this.registerCustomChartJSPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom plugin
|
||||
*/
|
||||
registerCustomChartJSPlugin()
|
||||
{
|
||||
(<any>window).Chart.plugins.register({
|
||||
afterDatasetsDraw: function (chart, easing) {
|
||||
// Only activate the plugin if it's made available
|
||||
// in the options
|
||||
if (
|
||||
!chart.options.plugins.xLabelsOnTop ||
|
||||
(chart.options.plugins.xLabelsOnTop && chart.options.plugins.xLabelsOnTop.active === false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// To only draw at the end of animation, check for easing === 1
|
||||
const ctx = chart.ctx;
|
||||
|
||||
chart.data.datasets.forEach(function (dataset, i) {
|
||||
const meta = chart.getDatasetMeta(i);
|
||||
if ( !meta.hidden )
|
||||
{
|
||||
meta.data.forEach(function (element, index) {
|
||||
|
||||
// Draw the text in black, with the specified font
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
const fontSize = 13;
|
||||
const fontStyle = 'normal';
|
||||
const fontFamily = 'Roboto, Helvetica Neue, Arial';
|
||||
ctx.font = (<any>window).Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
|
||||
|
||||
// Just naively convert to string for now
|
||||
const dataString = dataset.data[index].toString() + 'k';
|
||||
|
||||
// Make sure alignment settings are correct
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
const padding = 15;
|
||||
const startY = 24;
|
||||
const position = element.tooltipPosition();
|
||||
ctx.fillText(dataString, position.x, startY);
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([5, 3]);
|
||||
ctx.moveTo(position.x, startY + padding);
|
||||
ctx.lineTo(position.x, position.y - padding);
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.12)';
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { SharedModule } from '../../../../../core/modules/shared.module';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
import { AgmCoreModule } from '@agm/core';
|
||||
|
||||
import { FuseAnalyticsDashboardComponent } from './analytics.component';
|
||||
import { AnalyticsDashboardService } from './analytics.service';
|
||||
import { FuseWidgetModule } from '../../../../../core/components/widget/widget.module';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path : '**',
|
||||
component: FuseAnalyticsDashboardComponent,
|
||||
resolve : {
|
||||
data: AnalyticsDashboardService
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports : [
|
||||
SharedModule,
|
||||
RouterModule.forChild(routes),
|
||||
FuseWidgetModule,
|
||||
NgxChartsModule,
|
||||
AgmCoreModule.forRoot({
|
||||
apiKey: 'AIzaSyD81ecsCj4yYpcXSLFcYU97PvRsE_X8Bx8'
|
||||
})
|
||||
],
|
||||
declarations: [
|
||||
FuseAnalyticsDashboardComponent
|
||||
],
|
||||
providers : [
|
||||
AnalyticsDashboardService
|
||||
]
|
||||
})
|
||||
export class FuseAnalyticsDashboardModule
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class AnalyticsDashboardService implements Resolve<any>
|
||||
{
|
||||
widgets: any[];
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getWidgets()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getWidgets(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/analytics-dashboard-widgets')
|
||||
.subscribe((response: any) => {
|
||||
this.widgets = response;
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user