diff --git a/package.json b/package.json
index ef6d5ca..3568c3e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "angular-electron-admin",
- "version": "1.0.0-SNAPSHOT",
+ "version": "1.1.0-SNAPSHOT",
"description": "Angular Electron Admin Template",
"homepage": "https://aea.incubator.edurt.io",
"author": {
@@ -41,10 +41,15 @@
"@angular/platform-browser-dynamic": "12.1.2",
"@angular/router": "12.1.2",
"bootstrap": "4.0.0-beta",
+ "d3": "5",
+ "font-awesome": "^4.7.0",
"material-design-iconic-font": "^2.2.0",
+ "moment": "^2.29.1",
"ngx-bootstrap": "^7.1.0",
"ngx-clipboard": "^14.0.1",
+ "ngx-perfect-scrollbar": "^10.1.1",
"rxjs": "~6.6.0",
+ "simple-keyboard": "^3.3.22",
"tslib": "^2.1.0",
"zone.js": "~0.11.4"
},
diff --git a/src/renderer/app/layout/layout.routing.ts b/src/renderer/app/layout/layout.routing.ts
index 6e1f08e..8aca6df 100644
--- a/src/renderer/app/layout/layout.routing.ts
+++ b/src/renderer/app/layout/layout.routing.ts
@@ -19,6 +19,10 @@ const LAYOUT_ROUTES: Routes = [
{
path: 'zmdi',
loadChildren: () => import('../pages/icon/zmdi/zmdi.module').then(m => m.IconsZmdiModule)
+ },
+ {
+ path: 'fa',
+ loadChildren: () => import('../pages/icon/fa/fa.module').then(m => m.IconsFaModule)
}
]
},
@@ -32,6 +36,35 @@ const LAYOUT_ROUTES: Routes = [
{
path: 'tooltips',
loadChildren: () => import('../pages/component/tooltips/tooltips.module').then(m => m.TooltipsComponentModule)
+ },
+ {
+ path: 'scrollbar',
+ loadChildren: () => import('../pages/component/scrollbar/scrollbar.module').then(m => m.ScrollbarModule)
+ },
+ {
+ path: 'datepicker',
+ loadChildren: () => import('../pages/component/datepicker/datepicker.module').then(m => m.DatepickerModule)
+ },
+ {
+ path: 'carousel',
+ loadChildren: () => import('../pages/component/carousel/carousel.module').then(m => m.CarouselComponentModule)
+ },
+ {
+ path: 'progressbar',
+ loadChildren: () => import('../pages/component/progressbar/progressbar.module').then(m => m.ProgressbarComponentModule)
+ },
+ {
+ path: 'keyboard',
+ loadChildren: () => import('../pages/component/keyboard/keyboard.module').then(m => m.KeyboardModule)
+ }
+ ]
+ },
+ {
+ path: 'directive',
+ children: [
+ {
+ path: 'contribution',
+ loadChildren: () => import('../pages/directive/contribution/contribution.module').then(m => m.DirectiveContributionModule)
}
]
}
diff --git a/src/renderer/app/layout/navigation/navigation.component.html b/src/renderer/app/layout/navigation/navigation.component.html
index 5991cca..c0c3cc9 100644
--- a/src/renderer/app/layout/navigation/navigation.component.html
+++ b/src/renderer/app/layout/navigation/navigation.component.html
@@ -5,7 +5,10 @@
Icon
@@ -14,10 +17,34 @@
Component
+
+
+
+ Directive
+
diff --git a/src/renderer/app/layout/navigation/navigation.component.scss b/src/renderer/app/layout/navigation/navigation.component.scss
index 745d1e9..696fcbe 100644
--- a/src/renderer/app/layout/navigation/navigation.component.scss
+++ b/src/renderer/app/layout/navigation/navigation.component.scss
@@ -152,7 +152,7 @@
@include font-icon('\f26d', 6px);
position: absolute;
left: 1rem;
- top: 0.7rem;
+ top: 1rem;
}
}
}
diff --git a/src/renderer/app/layout/navigation/navigation.component.ts b/src/renderer/app/layout/navigation/navigation.component.ts
index e883853..9d15da6 100644
--- a/src/renderer/app/layout/navigation/navigation.component.ts
+++ b/src/renderer/app/layout/navigation/navigation.component.ts
@@ -25,7 +25,8 @@ export class NavigationComponent implements OnInit {
sidebarVisible: boolean;
navigationSubState: any = {
Icon: 'inactive',
- Component: 'inactive'
+ Component: 'inactive',
+ Directive: 'inactive'
};
constructor(private navigationService: NavigationService) {
diff --git a/src/renderer/app/pages/component/carousel/carousel.component.html b/src/renderer/app/pages/component/carousel/carousel.component.html
new file mode 100644
index 0000000..d44288c
--- /dev/null
+++ b/src/renderer/app/pages/component/carousel/carousel.component.html
@@ -0,0 +1,30 @@
+
+
+ Carousel
+ This template is built using ngx-bootstrap/carousel
and provides some usage examples
+
+
+
+
Default
+
+
+
+
+
+
+
+
+
+
Description
+
+
+
+
+
{{img.title}}
+
{{img.description}}
+
+
+
+
+
+
diff --git a/src/renderer/app/pages/component/carousel/carousel.component.ts b/src/renderer/app/pages/component/carousel/carousel.component.ts
new file mode 100644
index 0000000..cfaef88
--- /dev/null
+++ b/src/renderer/app/pages/component/carousel/carousel.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit } from '@angular/core';
+import { CarouselService } from '@renderer/services/component/carousel.service';
+
+@Component({
+ selector: 'app-component-carousel',
+ templateUrl: './carousel.component.html'
+})
+export class CarouselComponent implements OnInit {
+ public defaultCarousels: any = [];
+
+ constructor(private carouselService: CarouselService) {
+ this.defaultCarousels = this.carouselService.builderCarousels();
+ }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/renderer/app/pages/component/carousel/carousel.module.ts b/src/renderer/app/pages/component/carousel/carousel.module.ts
new file mode 100644
index 0000000..5666593
--- /dev/null
+++ b/src/renderer/app/pages/component/carousel/carousel.module.ts
@@ -0,0 +1,28 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
+import { CarouselModule } from 'ngx-bootstrap/carousel';
+import { CarouselComponent } from './carousel.component';
+import { CarouselService } from '@renderer/services/component/carousel.service';
+
+const CAROUSEL_ROUTES = [
+ {path: '', component: CarouselComponent}
+];
+
+@NgModule({
+ declarations: [
+ CarouselComponent
+ ],
+ imports: [
+ CommonModule,
+ BsDropdownModule.forRoot(),
+ CarouselModule.forRoot(),
+ RouterModule.forChild(CAROUSEL_ROUTES)
+ ],
+ providers: [
+ CarouselService
+ ]
+})
+export class CarouselComponentModule {
+}
diff --git a/src/renderer/app/pages/component/datepicker/datepicker.component.html b/src/renderer/app/pages/component/datepicker/datepicker.component.html
new file mode 100644
index 0000000..d83deec
--- /dev/null
+++ b/src/renderer/app/pages/component/datepicker/datepicker.component.html
@@ -0,0 +1,53 @@
+
+
+ Datepicker
+ This template is built using ngx-bootstrap/datepicker
and provides some usage examples
+
+
+
+
+
Basic Datepicker
+
+
+
+
+
+
+
+
+
+
+
+
+
Range Datepicker
+
+
+
+
+
+
+
+
+
+
+
+
+
Theme Datepicker
+
+
+
+
+
+
+
+
diff --git a/src/renderer/app/pages/component/datepicker/datepicker.component.ts b/src/renderer/app/pages/component/datepicker/datepicker.component.ts
new file mode 100644
index 0000000..ccf0a52
--- /dev/null
+++ b/src/renderer/app/pages/component/datepicker/datepicker.component.ts
@@ -0,0 +1,30 @@
+import { Component, OnInit } from '@angular/core';
+import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker';
+import { DatepickerService } from '@renderer/services/component/datepicker.service';
+
+@Component({
+ selector: 'app-component-datepicker',
+ templateUrl: './datepicker.component.html'
+})
+export class DatepickerComponent implements OnInit {
+ minDate = new Date(2017, 5, 10);
+ maxDate = new Date(2018, 9, 15);
+ bsValue: Date = new Date();
+ colorTheme = 'theme-green';
+ colorThemes = [];
+ bsConfig: Partial;
+
+ constructor(private datepickerService: DatepickerService) {
+ this.colorThemes = this.datepickerService.themes;
+ }
+
+ applyTheme(pop: any) {
+ this.bsConfig = Object.assign({}, {containerClass: this.colorTheme});
+ setTimeout(() => {
+ pop.show();
+ });
+ }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/renderer/app/pages/component/datepicker/datepicker.module.ts b/src/renderer/app/pages/component/datepicker/datepicker.module.ts
new file mode 100644
index 0000000..8727abe
--- /dev/null
+++ b/src/renderer/app/pages/component/datepicker/datepicker.module.ts
@@ -0,0 +1,30 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
+import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
+import { FormsModule } from '@angular/forms';
+import { DatepickerComponent } from './datepicker.component';
+import { DatepickerService } from '@renderer/services/component/datepicker.service';
+
+const DATEPICKER_ROUTES = [
+ {path: '', component: DatepickerComponent}
+];
+
+@NgModule({
+ declarations: [
+ DatepickerComponent
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ BsDropdownModule.forRoot(),
+ BsDatepickerModule.forRoot(),
+ RouterModule.forChild(DATEPICKER_ROUTES)
+ ],
+ providers: [
+ DatepickerService
+ ]
+})
+export class DatepickerModule {
+}
diff --git a/src/renderer/app/pages/component/keyboard/keyboard.component.html b/src/renderer/app/pages/component/keyboard/keyboard.component.html
new file mode 100644
index 0000000..41bb0bd
--- /dev/null
+++ b/src/renderer/app/pages/component/keyboard/keyboard.component.html
@@ -0,0 +1,19 @@
+
+
+ Keyboard
+ This template is built using simple-keyboard
and provides some usage examples
+
+
+
diff --git a/src/renderer/app/pages/component/keyboard/keyboard.component.ts b/src/renderer/app/pages/component/keyboard/keyboard.component.ts
new file mode 100644
index 0000000..8582da5
--- /dev/null
+++ b/src/renderer/app/pages/component/keyboard/keyboard.component.ts
@@ -0,0 +1,48 @@
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import Keyboard from 'simple-keyboard';
+
+@Component({
+ selector: 'app-root',
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: './keyboard.component.html',
+ styleUrls: [
+ '../../../../../../node_modules/simple-keyboard/build/css/index.css'
+ ]
+})
+export class KeyboardComponent implements OnInit {
+ value = '';
+ keyboard: Keyboard;
+
+ constructor() {
+ }
+
+ ngOnInit(): void {
+ }
+
+ // eslint-disable-next-line @angular-eslint/use-lifecycle-interface
+ ngAfterViewInit() {
+ this.keyboard = new Keyboard({
+ onChange: input => this.onChange(input),
+ onKeyPress: button => this.onKeyPress(button)
+ });
+ }
+
+ onChange = (input: string) => {
+ this.value = input;
+ };
+ onKeyPress = (button: string) => {
+ if (button === '{shift}' || button === '{lock}') {
+ this.handleShift();
+ }
+ };
+ onInputChange = (event: any) => {
+ this.keyboard.setInput(event.target.value);
+ };
+ handleShift = () => {
+ const currentLayout = this.keyboard.options.layoutName;
+ const shiftToggle = currentLayout === 'default' ? 'shift' : 'default';
+ this.keyboard.setOptions({
+ layoutName: shiftToggle
+ });
+ };
+}
diff --git a/src/renderer/app/pages/component/keyboard/keyboard.module.ts b/src/renderer/app/pages/component/keyboard/keyboard.module.ts
new file mode 100644
index 0000000..5abf472
--- /dev/null
+++ b/src/renderer/app/pages/component/keyboard/keyboard.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { KeyboardComponent } from '@renderer/app/pages/component/keyboard/keyboard.component';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+
+const KEYBOARD_ROUTES = [
+ {path: '', component: KeyboardComponent}
+];
+
+@NgModule({
+ declarations: [
+ KeyboardComponent
+ ],
+ imports: [
+ CommonModule,
+ RouterModule.forChild(KEYBOARD_ROUTES)
+ ],
+ providers: []
+})
+export class KeyboardModule {
+}
diff --git a/src/renderer/app/pages/component/progressbar/progressbar.component.html b/src/renderer/app/pages/component/progressbar/progressbar.component.html
new file mode 100644
index 0000000..864b4a7
--- /dev/null
+++ b/src/renderer/app/pages/component/progressbar/progressbar.component.html
@@ -0,0 +1,43 @@
+
+
+ Progressbar
+ This template is built using ngx-bootstrap/progressbar
and provides some usage examples
+
+
+
+
Static Progressbar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Theme Progressbar
+
Theme
+ type
property implementation adds a topic to the Progressbar
+
+
+
+
+
+
+
+
+
+
+
+
Dynamic Progressbar
+
+
+
+
+
+
+
diff --git a/src/renderer/app/pages/component/progressbar/progressbar.component.ts b/src/renderer/app/pages/component/progressbar/progressbar.component.ts
new file mode 100644
index 0000000..bfba54f
--- /dev/null
+++ b/src/renderer/app/pages/component/progressbar/progressbar.component.ts
@@ -0,0 +1,31 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-component-progressbar',
+ templateUrl: './progressbar.component.html'
+})
+export class ProgressbarComponent implements OnInit {
+ public type: string;
+ public stacked: any[] = [];
+
+ constructor() {
+ this.randomStacked();
+ }
+
+ public randomStacked(): void {
+ const types = ['success', 'info', 'warning', 'danger'];
+ this.stacked = [];
+ const n = Math.floor((Math.random() * 4) + 1);
+ for (let i = 0; i < n; i++) {
+ const index = Math.floor((Math.random() * 4));
+ const value = Math.floor((Math.random() * 27) + 3);
+ this.stacked.push({
+ value,
+ type: types[index]
+ });
+ }
+ }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/renderer/app/pages/component/progressbar/progressbar.module.ts b/src/renderer/app/pages/component/progressbar/progressbar.module.ts
new file mode 100644
index 0000000..e0377b3
--- /dev/null
+++ b/src/renderer/app/pages/component/progressbar/progressbar.module.ts
@@ -0,0 +1,24 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
+import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
+import { ProgressbarComponent } from './progressbar.component';
+
+const PROGRESSBAR_ROUTES = [
+ {path: '', component: ProgressbarComponent}
+];
+
+@NgModule({
+ declarations: [
+ ProgressbarComponent
+ ],
+ imports: [
+ CommonModule,
+ BsDropdownModule.forRoot(),
+ ProgressbarModule.forRoot(),
+ RouterModule.forChild(PROGRESSBAR_ROUTES)
+ ]
+})
+export class ProgressbarComponentModule {
+}
diff --git a/src/renderer/app/pages/component/scrollbar/scrollbar.component.html b/src/renderer/app/pages/component/scrollbar/scrollbar.component.html
new file mode 100644
index 0000000..fe77472
--- /dev/null
+++ b/src/renderer/app/pages/component/scrollbar/scrollbar.component.html
@@ -0,0 +1,102 @@
+
+
+ Scrollbar
+ This template is built using ngx-perfect-scrollbar
and provides some usage examples
+
+
+
+
+
Returns the top
+
+
+
+
+
+
+
+
+
+
+
Returns the bottom
+
+
+
+
+
+
+
+
+
+
+
At position
+
+
+
+
+
+
+
+
+
+
+
Go to Left
+
+
+
+
+
+
+
+
+
+
+
Go to Right
+
+
+
+
+
+
+
+
+
diff --git a/src/renderer/app/pages/component/scrollbar/scrollbar.component.scss b/src/renderer/app/pages/component/scrollbar/scrollbar.component.scss
new file mode 100644
index 0000000..353c313
--- /dev/null
+++ b/src/renderer/app/pages/component/scrollbar/scrollbar.component.scss
@@ -0,0 +1,25 @@
+.content-container {
+ position: relative;
+ overflow: auto;
+ margin: 5px;
+ border-radius: 4px;
+ background-color: #fff;
+ position: relative;
+ min-height: 0;
+ padding: 8px;
+ border: 1px solid #ccc;
+}
+
+.scroll-container {
+ position: relative;
+}
+
+.scrollable-content {
+ padding: 2px;
+ height: 100px;
+ margin: 0;
+}
+
+.no-space {
+ white-space: nowrap;
+}
diff --git a/src/renderer/app/pages/component/scrollbar/scrollbar.component.ts b/src/renderer/app/pages/component/scrollbar/scrollbar.component.ts
new file mode 100644
index 0000000..ee21fa2
--- /dev/null
+++ b/src/renderer/app/pages/component/scrollbar/scrollbar.component.ts
@@ -0,0 +1,65 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { PerfectScrollbarConfigInterface, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
+import { ScrollbarService } from '@renderer/services/component/scrollbar.service';
+
+@Component({
+ selector: 'app-component-scrollbar',
+ templateUrl: './scrollbar.component.html',
+ styleUrls: ['./scrollbar.component.scss']
+})
+export class ScrollbarComponent implements OnInit {
+ public scrollbarType = '1';
+ public config: PerfectScrollbarConfigInterface = {};
+ public data: [number];
+
+ public constructor(private scrollbarService: ScrollbarService) {
+ this.data = this.scrollbarService.data;
+ }
+
+ public toggleType() {
+ this.scrollbarType = (this.scrollbarType === '1') ? '2' : '1';
+ }
+
+ // Top
+ @ViewChild('goToTopScroll')
+ goToTopScroll: PerfectScrollbarDirective;
+
+ public goToTop() {
+ this.goToTopScroll.scrollToTop();
+ }
+
+ // Bottom
+ @ViewChild('goToBottomScroll')
+ goToBottomScroll: PerfectScrollbarDirective;
+
+ public goToBottom() {
+ this.goToBottomScroll.scrollToBottom();
+ }
+
+ // Go To Scrollbar
+ @ViewChild('goToXYScroll')
+ goToXYScroll: PerfectScrollbarDirective;
+
+ public goToXY(x: number, y: number) {
+ this.goToXYScroll.scrollTo(x, y, 500);
+ }
+
+ // Left
+ @ViewChild('goToLeftScroll')
+ goToLeftScroll: PerfectScrollbarDirective;
+
+ public goToLeft() {
+ this.goToLeftScroll.scrollToLeft();
+ }
+
+ // Top
+ @ViewChild('goToRightScroll')
+ goToRightScroll: PerfectScrollbarDirective;
+
+ public goToRight() {
+ this.goToRightScroll.scrollToRight();
+ }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/renderer/app/pages/component/scrollbar/scrollbar.module.ts b/src/renderer/app/pages/component/scrollbar/scrollbar.module.ts
new file mode 100644
index 0000000..ab2e0d4
--- /dev/null
+++ b/src/renderer/app/pages/component/scrollbar/scrollbar.module.ts
@@ -0,0 +1,40 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import {
+ PERFECT_SCROLLBAR_CONFIG,
+ PerfectScrollbarConfigInterface,
+ PerfectScrollbarModule
+} from 'ngx-perfect-scrollbar';
+import { ScrollbarComponent } from './scrollbar.component';
+import { ScrollbarService } from '@renderer/services/component/scrollbar.service';
+
+const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
+ suppressScrollX: true,
+ wheelPropagation: false
+};
+const SCROLLBARS_ROUTES = [
+ {path: '', component: ScrollbarComponent}
+];
+
+@NgModule({
+ declarations: [
+ ScrollbarComponent
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ PerfectScrollbarModule,
+ RouterModule.forChild(SCROLLBARS_ROUTES)
+ ],
+ providers: [
+ {
+ provide: PERFECT_SCROLLBAR_CONFIG,
+ useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG
+ },
+ ScrollbarService
+ ]
+})
+export class ScrollbarModule {
+}
diff --git a/src/renderer/app/pages/directive/contribution/contribution.component.html b/src/renderer/app/pages/directive/contribution/contribution.component.html
new file mode 100644
index 0000000..860da2c
--- /dev/null
+++ b/src/renderer/app/pages/directive/contribution/contribution.component.html
@@ -0,0 +1,8 @@
+
+
+ Contribution Charts 1.0.0
+ Use d3.js
to plot contribution charts for high customization.
+
+ Contribution
+
+
diff --git a/src/renderer/app/pages/directive/contribution/contribution.component.scss b/src/renderer/app/pages/directive/contribution/contribution.component.scss
new file mode 100644
index 0000000..aab6e89
--- /dev/null
+++ b/src/renderer/app/pages/directive/contribution/contribution.component.scss
@@ -0,0 +1,17 @@
+.icons-demo {
+ .card-body {
+ .fa {
+ font-size: 1.7rem;
+ vertical-align: bottom;
+ margin-right: 1rem;
+ }
+
+ .col-sm-4 {
+ padding: 0.8rem 1.1rem;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.03);
+ }
+ }
+ }
+}
diff --git a/src/renderer/app/pages/directive/contribution/contribution.component.ts b/src/renderer/app/pages/directive/contribution/contribution.component.ts
new file mode 100644
index 0000000..9f25329
--- /dev/null
+++ b/src/renderer/app/pages/directive/contribution/contribution.component.ts
@@ -0,0 +1,42 @@
+import { Component, OnInit } from '@angular/core';
+import * as moment from 'moment';
+import * as d3 from 'd3';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './contribution.component.html',
+ styleUrls: ['./contribution.component.scss']
+})
+export class DirectiveContributionComponent implements OnInit {
+ public data;
+
+ constructor() {
+ }
+
+ ngOnInit(): void {
+ this.init();
+ }
+
+ init() {
+ moment.locale('zh_cn');
+ // Initialize random data for the demo
+ const now = moment().endOf('year').toDate();
+ const timeAgo = moment().startOf('day').subtract(10, 'year').toDate();
+ this.data = d3.timeDays(timeAgo, now).map((dateElement: any, index: number) => ({
+ date: dateElement,
+ details: Array.apply(null, new Array(Math.floor(Math.random() * 15))).map((e: number, i: number, arr: any) => ({
+ date: function() {
+ const projectDate = new Date(dateElement.getTime());
+ projectDate.setHours(Math.floor(Math.random() * 24));
+ projectDate.setMinutes(Math.floor(Math.random() * 60));
+ return projectDate;
+ }(),
+ value: 3600 * ((arr.length - i) / 5) + Math.floor(Math.random() * 3600) * Math.round(Math.random() * (index / 365))
+ })),
+ init() {
+ this.total = this.details.reduce((prev: number, e: any) => prev + e.value, 0);
+ return this;
+ }
+ }.init()));
+ }
+}
diff --git a/src/renderer/app/pages/directive/contribution/contribution.module.ts b/src/renderer/app/pages/directive/contribution/contribution.module.ts
new file mode 100644
index 0000000..8bf9003
--- /dev/null
+++ b/src/renderer/app/pages/directive/contribution/contribution.module.ts
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { ContributionModule } from '@renderer/directives/contribution/contribution.module';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { DirectiveContributionComponent } from './contribution.component';
+import { FaIconService } from '@renderer/services/icon/fa.service';
+
+const DIRECTIVE_CONTRIBUTION_ROUTES = [
+ {path: '', component: DirectiveContributionComponent}
+];
+
+@NgModule({
+ declarations: [
+ DirectiveContributionComponent
+ ],
+ imports: [
+ CommonModule,
+ ContributionModule,
+ RouterModule.forChild(DIRECTIVE_CONTRIBUTION_ROUTES)
+ ],
+ providers: [
+ FaIconService
+ ]
+})
+export class DirectiveContributionModule {
+}
diff --git a/src/renderer/app/pages/icon/fa/fa.component.html b/src/renderer/app/pages/icon/fa/fa.component.html
new file mode 100644
index 0000000..671dcf3
--- /dev/null
+++ b/src/renderer/app/pages/icon/fa/fa.component.html
@@ -0,0 +1,19 @@
+
+
+ Font Awesome 4.7.0
+ This template is built using Font Awesome and has all the icon content
+
+
+
diff --git a/src/renderer/app/pages/icon/fa/fa.component.scss b/src/renderer/app/pages/icon/fa/fa.component.scss
new file mode 100644
index 0000000..aab6e89
--- /dev/null
+++ b/src/renderer/app/pages/icon/fa/fa.component.scss
@@ -0,0 +1,17 @@
+.icons-demo {
+ .card-body {
+ .fa {
+ font-size: 1.7rem;
+ vertical-align: bottom;
+ margin-right: 1rem;
+ }
+
+ .col-sm-4 {
+ padding: 0.8rem 1.1rem;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.03);
+ }
+ }
+ }
+}
diff --git a/src/renderer/app/pages/icon/fa/fa.component.ts b/src/renderer/app/pages/icon/fa/fa.component.ts
new file mode 100644
index 0000000..9514e03
--- /dev/null
+++ b/src/renderer/app/pages/icon/fa/fa.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit } from '@angular/core';
+import { FaIconService } from '@renderer/services/icon/fa.service';
+
+@Component({
+ selector: 'app-icons-fa',
+ templateUrl: './fa.component.html',
+ styleUrls: ['./fa.component.scss']
+})
+export class FaComponent implements OnInit {
+ icons: [] = this.faIconService.icons;
+
+ constructor(private faIconService: FaIconService) {
+ }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/renderer/app/pages/icon/fa/fa.module.ts b/src/renderer/app/pages/icon/fa/fa.module.ts
new file mode 100644
index 0000000..5b77d01
--- /dev/null
+++ b/src/renderer/app/pages/icon/fa/fa.module.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
+import { FaComponent } from './fa.component';
+import { FaIconService } from '@renderer/services/icon/fa.service';
+
+const ICONS_FA_ROUTES = [
+ {path: '', component: FaComponent}
+];
+
+@NgModule({
+ declarations: [
+ FaComponent
+ ],
+ imports: [
+ CommonModule,
+ BsDropdownModule.forRoot(),
+ RouterModule.forChild(ICONS_FA_ROUTES)
+ ],
+ providers: [
+ FaIconService
+ ]
+})
+export class IconsFaModule {
+}
diff --git a/src/renderer/data/icon/fa.json b/src/renderer/data/icon/fa.json
new file mode 100644
index 0000000..1c73bdc
--- /dev/null
+++ b/src/renderer/data/icon/fa.json
@@ -0,0 +1,1022 @@
+[
+ {
+ "type": "Web Application",
+ "icons": [
+ "fa-address-book",
+ "fa-address-book-o",
+ "fa-address-card",
+ "fa-address-card-o",
+ "fa-adjust",
+ "fa-american-sign-language-interpreting",
+ "fa-anchor",
+ "fa-archive",
+ "fa-area-chart",
+ "fa-arrows",
+ "fa-arrows-h",
+ "fa-arrows-v",
+ "fa-asl-interpreting",
+ "fa-assistive-listening-systems",
+ "fa-asterisk",
+ "fa-at",
+ "fa-audio-description",
+ "fa-automobile",
+ "fa-balance-scale",
+ "fa-ban",
+ "fa-bank",
+ "fa-bar-chart",
+ "fa-bar-chart-o",
+ "fa-barcode",
+ "fa-bars",
+ "fa-bath",
+ "fa-bathtub",
+ "fa-battery",
+ "fa-battery-0",
+ "fa-battery-1",
+ "fa-battery-2",
+ "fa-battery-3",
+ "fa-battery-4",
+ "fa-battery-empty",
+ "fa-battery-full",
+ "fa-battery-half",
+ "fa-battery-quarter",
+ "fa-battery-three-quarters",
+ "fa-bed",
+ "fa-beer",
+ "fa-bell",
+ "fa-bell-o",
+ "fa-bell-slash",
+ "fa-bell-slash-o",
+ "fa-bicycle",
+ "fa-binoculars",
+ "fa-birthday-cake",
+ "fa-blind",
+ "fa-bluetooth",
+ "fa-bluetooth-b",
+ "fa-bolt",
+ "fa-bomb",
+ "fa-book",
+ "fa-bookmark",
+ "fa-bookmark-o",
+ "fa-braille",
+ "fa-briefcase",
+ "fa-bug",
+ "fa-building",
+ "fa-building-o",
+ "fa-bullhorn",
+ "fa-bullseye",
+ "fa-bus",
+ "fa-cab",
+ "fa-calculator",
+ "fa-calendar",
+ "fa-calendar-check-o",
+ "fa-calendar-minus-o",
+ "fa-calendar-o",
+ "fa-calendar-plus-o",
+ "fa-calendar-times-o",
+ "fa-camera",
+ "fa-camera-retro",
+ "fa-car",
+ "fa-caret-square-o-down",
+ "fa-caret-square-o-left",
+ "fa-caret-square-o-right",
+ "fa-caret-square-o-up",
+ "fa-cart-arrow-down",
+ "fa-cart-plus",
+ "fa-cc",
+ "fa-certificate",
+ "fa-check",
+ "fa-check-circle",
+ "fa-check-circle-o",
+ "fa-check-square",
+ "fa-check-square-o",
+ "fa-child",
+ "fa-circle",
+ "fa-circle-o",
+ "fa-circle-o-notch",
+ "fa-circle-thin",
+ "fa-clock-o",
+ "fa-clone",
+ "fa-close",
+ "fa-cloud",
+ "fa-cloud-download",
+ "fa-cloud-upload",
+ "fa-code",
+ "fa-code-fork",
+ "fa-coffee",
+ "fa-cog",
+ "fa-cogs",
+ "fa-comment",
+ "fa-comment-o",
+ "fa-commenting",
+ "fa-commenting-o",
+ "fa-comments",
+ "fa-comments-o",
+ "fa-compass",
+ "fa-copyright",
+ "fa-creative-commons",
+ "fa-credit-card",
+ "fa-credit-card-alt",
+ "fa-crop",
+ "fa-crosshairs",
+ "fa-cube",
+ "fa-cubes",
+ "fa-cutlery",
+ "fa-dashboard",
+ "fa-database",
+ "fa-deaf",
+ "fa-deafness",
+ "fa-desktop",
+ "fa-diamond",
+ "fa-dot-circle-o",
+ "fa-download",
+ "fa-drivers-license",
+ "fa-drivers-license-o",
+ "fa-edit",
+ "fa-ellipsis-h",
+ "fa-ellipsis-v",
+ "fa-envelope",
+ "fa-envelope-o",
+ "fa-envelope-open",
+ "fa-envelope-open-o",
+ "fa-envelope-square",
+ "fa-eraser",
+ "fa-exchange",
+ "fa-exclamation",
+ "fa-exclamation-circle",
+ "fa-exclamation-triangle",
+ "fa-external-link",
+ "fa-external-link-square",
+ "fa-eye",
+ "fa-eye-slash",
+ "fa-eyedropper",
+ "fa-fax",
+ "fa-feed",
+ "fa-female",
+ "fa-fighter-jet",
+ "fa-file-archive-o",
+ "fa-file-audio-o",
+ "fa-file-code-o",
+ "fa-file-excel-o",
+ "fa-file-image-o",
+ "fa-file-movie-o",
+ "fa-file-pdf-o",
+ "fa-file-photo-o",
+ "fa-file-picture-o",
+ "fa-file-powerpoint-o",
+ "fa-file-sound-o",
+ "fa-file-video-o",
+ "fa-file-word-o",
+ "fa-file-zip-o",
+ "fa-film",
+ "fa-filter",
+ "fa-fire",
+ "fa-fire-extinguisher",
+ "fa-flag",
+ "fa-flag-checkered",
+ "fa-flag-o",
+ "fa-flash",
+ "fa-flask",
+ "fa-folder",
+ "fa-folder-o",
+ "fa-folder-open",
+ "fa-folder-open-o",
+ "fa-frown-o",
+ "fa-futbol-o",
+ "fa-gamepad",
+ "fa-gavel",
+ "fa-gear",
+ "fa-gears",
+ "fa-gift",
+ "fa-glass",
+ "fa-globe",
+ "fa-graduation-cap",
+ "fa-group",
+ "fa-hand-grab-o",
+ "fa-hand-lizard-o",
+ "fa-hand-paper-o",
+ "fa-hand-peace-o",
+ "fa-hand-pointer-o",
+ "fa-hand-rock-o",
+ "fa-hand-scissors-o",
+ "fa-hand-spock-o",
+ "fa-hand-stop-o",
+ "fa-handshake-o",
+ "fa-hard-of-hearing",
+ "fa-hashtag",
+ "fa-hdd-o",
+ "fa-headphones",
+ "fa-heart",
+ "fa-heart-o",
+ "fa-heartbeat",
+ "fa-history",
+ "fa-home",
+ "fa-hotel",
+ "fa-hourglass",
+ "fa-hourglass-1",
+ "fa-hourglass-2",
+ "fa-hourglass-3",
+ "fa-hourglass-end",
+ "fa-hourglass-half",
+ "fa-hourglass-o",
+ "fa-hourglass-start",
+ "fa-i-cursor",
+ "fa-id-badge",
+ "fa-id-card",
+ "fa-id-card-o",
+ "fa-image",
+ "fa-inbox",
+ "fa-industry",
+ "fa-info",
+ "fa-info-circle",
+ "fa-institution",
+ "fa-key",
+ "fa-keyboard-o",
+ "fa-language",
+ "fa-laptop",
+ "fa-leaf",
+ "fa-legal",
+ "fa-lemon-o",
+ "fa-level-down",
+ "fa-level-up",
+ "fa-life-bouy",
+ "fa-life-buoy",
+ "fa-life-ring",
+ "fa-life-saver",
+ "fa-lightbulb-o",
+ "fa-line-chart",
+ "fa-location-arrow",
+ "fa-lock",
+ "fa-low-vision",
+ "fa-magic",
+ "fa-magnet",
+ "fa-mail-forward",
+ "fa-mail-reply",
+ "fa-mail-reply-all",
+ "fa-male",
+ "fa-map",
+ "fa-map-marker",
+ "fa-map-o",
+ "fa-map-pin",
+ "fa-map-signs",
+ "fa-meh-o",
+ "fa-microchip",
+ "fa-microphone",
+ "fa-microphone-slash",
+ "fa-minus",
+ "fa-minus-circle",
+ "fa-minus-square",
+ "fa-minus-square-o",
+ "fa-mobile",
+ "fa-mobile-phone",
+ "fa-money",
+ "fa-moon-o",
+ "fa-mortar-board",
+ "fa-motorcycle",
+ "fa-mouse-pointer",
+ "fa-music",
+ "fa-navicon",
+ "fa-newspaper-o",
+ "fa-object-group",
+ "fa-object-ungroup",
+ "fa-paint-brush",
+ "fa-paper-plane",
+ "fa-paper-plane-o",
+ "fa-paw",
+ "fa-pencil",
+ "fa-pencil-square",
+ "fa-pencil-square-o",
+ "fa-percent",
+ "fa-phone",
+ "fa-phone-square",
+ "fa-photo",
+ "fa-picture-o",
+ "fa-pie-chart",
+ "fa-plane",
+ "fa-plug",
+ "fa-plus",
+ "fa-plus-circle",
+ "fa-plus-square",
+ "fa-plus-square-o",
+ "fa-podcast",
+ "fa-power-off",
+ "fa-print",
+ "fa-puzzle-piece",
+ "fa-qrcode",
+ "fa-question",
+ "fa-question-circle",
+ "fa-question-circle-o",
+ "fa-quote-left",
+ "fa-quote-right",
+ "fa-random",
+ "fa-recycle",
+ "fa-refresh",
+ "fa-registered",
+ "fa-remove",
+ "fa-reorder",
+ "fa-reply",
+ "fa-reply-all",
+ "fa-retweet",
+ "fa-road",
+ "fa-rocket",
+ "fa-rss",
+ "fa-rss-square",
+ "fa-s15",
+ "fa-search",
+ "fa-search-minus",
+ "fa-search-plus",
+ "fa-send",
+ "fa-send-o",
+ "fa-server",
+ "fa-share",
+ "fa-share-alt",
+ "fa-share-alt-square",
+ "fa-share-square",
+ "fa-share-square-o",
+ "fa-shield",
+ "fa-ship",
+ "fa-shopping-bag",
+ "fa-shopping-basket",
+ "fa-shopping-cart",
+ "fa-shower",
+ "fa-sign-in",
+ "fa-sign-language",
+ "fa-sign-out",
+ "fa-signal",
+ "fa-signing",
+ "fa-sitemap",
+ "fa-sliders",
+ "fa-smile-o",
+ "fa-snowflake-o",
+ "fa-soccer-ball-o",
+ "fa-sort",
+ "fa-sort-alpha-asc",
+ "fa-sort-alpha-desc",
+ "fa-sort-amount-asc",
+ "fa-sort-amount-desc",
+ "fa-sort-asc",
+ "fa-sort-desc",
+ "fa-sort-down",
+ "fa-sort-numeric-asc",
+ "fa-sort-numeric-desc",
+ "fa-sort-up",
+ "fa-space-shuttle",
+ "fa-spinner",
+ "fa-spoon",
+ "fa-square",
+ "fa-square-o",
+ "fa-star",
+ "fa-star-half",
+ "fa-star-half-empty",
+ "fa-star-half-full",
+ "fa-star-half-o",
+ "fa-star-o",
+ "fa-sticky-note",
+ "fa-sticky-note-o",
+ "fa-street-view",
+ "fa-suitcase",
+ "fa-sun-o",
+ "fa-support",
+ "fa-tablet",
+ "fa-tachometer",
+ "fa-tag",
+ "fa-tags",
+ "fa-tasks",
+ "fa-taxi",
+ "fa-television",
+ "fa-terminal",
+ "fa-thermometer",
+ "fa-thermometer-0",
+ "fa-thermometer-1",
+ "fa-thermometer-2",
+ "fa-thermometer-3",
+ "fa-thermometer-4",
+ "fa-thermometer-empty",
+ "fa-thermometer-full",
+ "fa-thermometer-half",
+ "fa-thermometer-quarter",
+ "fa-thermometer-three-quarters",
+ "fa-thumb-tack",
+ "fa-thumbs-down",
+ "fa-thumbs-o-down",
+ "fa-thumbs-o-up",
+ "fa-thumbs-up",
+ "fa-ticket",
+ "fa-times",
+ "fa-times-circle",
+ "fa-times-circle-o",
+ "fa-times-rectangle",
+ "fa-times-rectangle-o",
+ "fa-tint",
+ "fa-toggle-down",
+ "fa-toggle-left",
+ "fa-toggle-off",
+ "fa-toggle-on",
+ "fa-toggle-right",
+ "fa-toggle-up",
+ "fa-trademark",
+ "fa-trash",
+ "fa-trash-o",
+ "fa-tree",
+ "fa-trophy",
+ "fa-truck",
+ "fa-tty",
+ "fa-tv",
+ "fa-umbrella",
+ "fa-universal-access",
+ "fa-university",
+ "fa-unlock",
+ "fa-unlock-alt",
+ "fa-unsorted",
+ "fa-upload",
+ "fa-user",
+ "fa-user-circle",
+ "fa-user-circle-o",
+ "fa-user-o",
+ "fa-user-plus",
+ "fa-user-secret",
+ "fa-user-times",
+ "fa-users",
+ "fa-vcard",
+ "fa-vcard-o",
+ "fa-video-camera",
+ "fa-volume-control-phone",
+ "fa-volume-down",
+ "fa-volume-off",
+ "fa-volume-up",
+ "fa-warning",
+ "fa-wheelchair",
+ "fa-wheelchair-alt",
+ "fa-wifi",
+ "fa-window-close",
+ "fa-window-close-o",
+ "fa-window-maximize",
+ "fa-window-minimize",
+ "fa-window-restore",
+ "fa-wrench"
+ ]
+ },
+ {
+ "type": "Auxiliary",
+ "icons": [
+ "fa-american-sign-language-interpreting",
+ "fa-asl-interpreting",
+ "fa-assistive-listening-systems",
+ "fa-audio-description",
+ "fa-blind",
+ "fa-braille",
+ "fa-cc",
+ "fa-deaf",
+ "fa-deafness",
+ "fa-hard-of-hearing",
+ "fa-low-vision",
+ "fa-question-circle-o",
+ "fa-sign-language",
+ "fa-signing",
+ "fa-tty",
+ "fa-universal-access",
+ "fa-volume-control-phone",
+ "fa-wheelchair",
+ "fa-wheelchair-alt",
+ "fa-hand-grab-o",
+ "fa-hand-lizard-o",
+ "fa-hand-o-down",
+ "fa-hand-o-left",
+ "fa-hand-o-right",
+ "fa-hand-o-up",
+ "fa-hand-paper-o",
+ "fa-hand-peace-o",
+ "fa-hand-pointer-o",
+ "fa-hand-rock-o",
+ "fa-hand-scissors-o",
+ "fa-hand-spock-o",
+ "fa-hand-stop-o",
+ "fa-thumbs-down",
+ "fa-thumbs-o-down",
+ "fa-thumbs-o-up",
+ "fa-thumbs-up",
+ "fa-ambulance",
+ "fa-automobile",
+ "fa-bicycle",
+ "fa-bus",
+ "fa-cab",
+ "fa-car",
+ "fa-fighter-jet",
+ "fa-motorcycle",
+ "fa-plane",
+ "fa-rocket",
+ "fa-ship",
+ "fa-space-shuttle",
+ "fa-subway",
+ "fa-taxi",
+ "fa-train",
+ "fa-truck",
+ "fa-wheelchair",
+ "fa-wheelchair-alt"
+ ]
+ },
+ {
+ "type": "Gender",
+ "icons": [
+ "fa-genderless",
+ "fa-intersex",
+ "fa-mars",
+ "fa-mars-double",
+ "fa-mars-stroke",
+ "fa-mars-stroke-h",
+ "fa-mars-stroke-v",
+ "fa-mercury",
+ "fa-neuter",
+ "fa-transgender",
+ "fa-transgender-alt",
+ "fa-venus",
+ "fa-venus-double",
+ "fa-venus-mars"
+ ]
+ },
+ {
+ "type": "File",
+ "icons": [
+ "fa-file",
+ "fa-file-archive-o",
+ "fa-file-audio-o",
+ "fa-file-code-o",
+ "fa-file-excel-o",
+ "fa-file-image-o",
+ "fa-file-movie-o",
+ "fa-file-o",
+ "fa-file-pdf-o",
+ "fa-file-photo-o",
+ "fa-file-picture-o",
+ "fa-file-powerpoint-o",
+ "fa-file-sound-o",
+ "fa-file-text",
+ "fa-file-text-o",
+ "fa-file-video-o",
+ "fa-file-word-o",
+ "fa-file-zip-o"
+ ]
+ },
+ {
+ "type": "Rotate(fa-spin)",
+ "icons": [
+ "fa-info-circle",
+ "fa-circle-o-notch",
+ "fa-cog",
+ "fa-gear",
+ "fa-refresh",
+ "fa-spinner"
+ ]
+ },
+ {
+ "type": "Form",
+ "icons": [
+ "fa-check-square",
+ "fa-check-square-o",
+ "fa-circle",
+ "fa-circle-o",
+ "fa-dot-circle-o",
+ "fa-minus-square",
+ "fa-minus-square-o",
+ "fa-plus-square",
+ "fa-plus-square-o",
+ "fa-square",
+ "fa-square-o"
+ ]
+ },
+ {
+ "type": "Pay",
+ "icons": [
+ "fa-cc-amex",
+ "fa-cc-diners-club",
+ "fa-cc-discover",
+ "fa-cc-jcb",
+ "fa-cc-mastercard",
+ "fa-cc-paypal",
+ "fa-cc-stripe",
+ "fa-cc-visa",
+ "fa-credit-card",
+ "fa-credit-card-alt",
+ "fa-google-wallet",
+ "fa-paypal"
+ ]
+ },
+ {
+ "type": "Chart",
+ "icons": [
+ "fa-area-chart",
+ "fa-bar-chart",
+ "fa-bar-chart-o",
+ "fa-line-chart",
+ "fa-pie-chart"
+ ]
+ },
+ {
+ "type": "Currency",
+ "icons": [
+ "fa-bitcoin",
+ "fa-btc",
+ "fa-cny",
+ "fa-dollar",
+ "fa-eur",
+ "fa-euro",
+ "fa-gbp",
+ "fa-gg",
+ "fa-gg-circle",
+ "fa-ils",
+ "fa-inr",
+ "fa-jpy",
+ "fa-krw",
+ "fa-money",
+ "fa-rmb",
+ "fa-rouble",
+ "fa-rub",
+ "fa-ruble",
+ "fa-rupee",
+ "fa-shekel",
+ "fa-sheqel",
+ "fa-try",
+ "fa-turkish-lira",
+ "fa-usd",
+ "fa-won",
+ "fa-yen"
+ ]
+ },
+ {
+ "type": "Text Editor",
+ "icons": [
+ "fa-align-center",
+ "fa-align-justify",
+ "fa-align-left",
+ "fa-align-right",
+ "fa-bold",
+ "fa-chain",
+ "fa-chain-broken",
+ "fa-clipboard",
+ "fa-columns",
+ "fa-copy",
+ "fa-cut",
+ "fa-dedent",
+ "fa-eraser",
+ "fa-file",
+ "fa-file-o",
+ "fa-file-text",
+ "fa-file-text-o",
+ "fa-files-o",
+ "fa-floppy-o",
+ "fa-font",
+ "fa-header",
+ "fa-indent",
+ "fa-italic",
+ "fa-link",
+ "fa-list",
+ "fa-list-alt",
+ "fa-list-ol",
+ "fa-list-ul",
+ "fa-outdent",
+ "fa-paperclip",
+ "fa-paragraph",
+ "fa-paste",
+ "fa-repeat",
+ "fa-rotate-left",
+ "fa-rotate-right",
+ "fa-save",
+ "fa-scissors",
+ "fa-strikethrough",
+ "fa-subscript",
+ "fa-superscript",
+ "fa-table",
+ "fa-text-height",
+ "fa-text-width",
+ "fa-th",
+ "fa-th-large",
+ "fa-th-list",
+ "fa-underline",
+ "fa-undo",
+ "fa-unlink"
+ ]
+ },
+ {
+ "type": "Giving",
+ "icons": [
+ "fa-angle-double-down",
+ "fa-angle-double-left",
+ "fa-angle-double-right",
+ "fa-angle-double-up",
+ "fa-angle-down",
+ "fa-angle-left",
+ "fa-angle-right",
+ "fa-angle-up",
+ "fa-arrow-circle-down",
+ "fa-arrow-circle-left",
+ "fa-arrow-circle-o-down",
+ "fa-arrow-circle-o-left",
+ "fa-arrow-circle-o-right",
+ "fa-arrow-circle-o-up",
+ "fa-arrow-circle-right",
+ "fa-arrow-circle-up",
+ "fa-arrow-down",
+ "fa-arrow-left",
+ "fa-arrow-right",
+ "fa-arrow-up",
+ "fa-arrows",
+ "fa-arrows-alt",
+ "fa-arrows-h",
+ "fa-arrows-v",
+ "fa-caret-down",
+ "fa-caret-left",
+ "fa-caret-right",
+ "fa-caret-square-o-down",
+ "fa-caret-square-o-left",
+ "fa-caret-square-o-right",
+ "fa-caret-square-o-up",
+ "fa-caret-up",
+ "fa-chevron-circle-down",
+ "fa-chevron-circle-left",
+ "fa-chevron-circle-right",
+ "fa-chevron-circle-up",
+ "fa-chevron-down",
+ "fa-chevron-left",
+ "fa-chevron-right",
+ "fa-chevron-up",
+ "fa-exchange",
+ "fa-hand-o-down",
+ "fa-hand-o-left",
+ "fa-hand-o-right",
+ "fa-hand-o-up",
+ "fa-long-arrow-down",
+ "fa-long-arrow-left",
+ "fa-long-arrow-right",
+ "fa-long-arrow-up",
+ "fa-toggle-down",
+ "fa-toggle-left",
+ "fa-toggle-right",
+ "fa-toggle-up"
+ ]
+ },
+ {
+ "type": "Video",
+ "icons": [
+ "fa-arrows-alt",
+ "fa-backward",
+ "fa-compress",
+ "fa-eject",
+ "fa-expand",
+ "fa-fast-backward",
+ "fa-fast-forward",
+ "fa-forward",
+ "fa-pause",
+ "fa-pause-circle",
+ "fa-pause-circle-o",
+ "fa-play",
+ "fa-play-circle",
+ "fa-play-circle-o",
+ "fa-random",
+ "fa-step-backward",
+ "fa-step-forward",
+ "fa-stop",
+ "fa-stop-circle",
+ "fa-stop-circle-o",
+ "fa-youtube-play"
+ ]
+ },
+ {
+ "type": "Mark",
+ "icons": [
+ "fa-adn",
+ "fa-amazon",
+ "fa-android",
+ "fa-angellist",
+ "fa-apple",
+ "fa-bandcamp",
+ "fa-behance",
+ "fa-behance-square",
+ "fa-bitbucket",
+ "fa-bitbucket-square",
+ "fa-bitcoin",
+ "fa-black-tie",
+ "fa-bluetooth",
+ "fa-bluetooth-b",
+ "fa-btc",
+ "fa-buysellads",
+ "fa-cc-amex",
+ "fa-cc-diners-club",
+ "fa-cc-discover",
+ "fa-cc-jcb",
+ "fa-cc-mastercard",
+ "fa-cc-paypal",
+ "fa-cc-stripe",
+ "fa-cc-visa",
+ "fa-chrome",
+ "fa-codepen",
+ "fa-codiepie",
+ "fa-connectdevelop",
+ "fa-contao",
+ "fa-css3",
+ "fa-dashcube",
+ "fa-delicious",
+ "fa-deviantart",
+ "fa-digg",
+ "fa-dribbble",
+ "fa-dropbox",
+ "fa-drupal",
+ "fa-edge",
+ "fa-eercast",
+ "fa-empire",
+ "fa-envira",
+ "fa-etsy",
+ "fa-expeditedssl",
+ "fa-fa",
+ "fa-facebook",
+ "fa-facebook-f",
+ "fa-facebook-official",
+ "fa-facebook-square",
+ "fa-firefox",
+ "fa-first-order",
+ "fa-flickr",
+ "fa-font-awesome",
+ "fa-fonticons",
+ "fa-fort-awesome",
+ "fa-forumbee",
+ "fa-foursquare",
+ "fa-free-code-camp",
+ "fa-ge",
+ "fa-get-pocket",
+ "fa-gg",
+ "fa-gg-circle",
+ "fa-git",
+ "fa-git-square",
+ "fa-github",
+ "fa-github-alt",
+ "fa-github-square",
+ "fa-gitlab",
+ "fa-gittip",
+ "fa-glide",
+ "fa-glide-g",
+ "fa-google",
+ "fa-google-plus",
+ "fa-google-plus-circle",
+ "fa-google-plus-official",
+ "fa-google-plus-square",
+ "fa-google-wallet",
+ "fa-gratipay",
+ "fa-grav",
+ "fa-hacker-news",
+ "fa-houzz",
+ "fa-html5",
+ "fa-imdb",
+ "fa-instagram",
+ "fa-internet-explorer",
+ "fa-ioxhost",
+ "fa-joomla",
+ "fa-jsfiddle",
+ "fa-lastfm",
+ "fa-lastfm-square",
+ "fa-leanpub",
+ "fa-linkedin",
+ "fa-linkedin-square",
+ "fa-linode",
+ "fa-linux",
+ "fa-maxcdn",
+ "fa-meanpath",
+ "fa-medium",
+ "fa-meetup",
+ "fa-mixcloud",
+ "fa-modx",
+ "fa-odnoklassniki",
+ "fa-odnoklassniki-square",
+ "fa-opencart",
+ "fa-openid",
+ "fa-opera",
+ "fa-optin-monster",
+ "fa-pagelines",
+ "fa-paypal",
+ "fa-pied-piper",
+ "fa-pied-piper-alt",
+ "fa-pied-piper-pp",
+ "fa-pinterest",
+ "fa-pinterest-p",
+ "fa-pinterest-square",
+ "fa-product-hunt",
+ "fa-qq",
+ "fa-quora",
+ "fa-ra",
+ "fa-ravelry",
+ "fa-rebel",
+ "fa-reddit",
+ "fa-reddit-alien",
+ "fa-reddit-square",
+ "fa-renren",
+ "fa-resistance",
+ "fa-safari",
+ "fa-scribd",
+ "fa-sellsy",
+ "fa-share-alt",
+ "fa-share-alt-square",
+ "fa-shirtsinbulk",
+ "fa-simplybuilt",
+ "fa-skyatlas",
+ "fa-skype",
+ "fa-slack",
+ "fa-slideshare",
+ "fa-snapchat",
+ "fa-snapchat-ghost",
+ "fa-snapchat-square",
+ "fa-soundcloud",
+ "fa-spotify",
+ "fa-stack-exchange",
+ "fa-stack-overflow",
+ "fa-steam",
+ "fa-steam-square",
+ "fa-stumbleupon",
+ "fa-stumbleupon-circle",
+ "fa-superpowers",
+ "fa-telegram",
+ "fa-tencent-weibo",
+ "fa-themeisle",
+ "fa-trello",
+ "fa-tripadvisor",
+ "fa-tumblr",
+ "fa-tumblr-square",
+ "fa-twitch",
+ "fa-twitter",
+ "fa-twitter-square",
+ "fa-usb",
+ "fa-viacoin",
+ "fa-viadeo",
+ "fa-viadeo-square",
+ "fa-vimeo",
+ "fa-vimeo-square",
+ "fa-vine",
+ "fa-vk",
+ "fa-wechat",
+ "fa-weibo",
+ "fa-weixin",
+ "fa-whatsapp",
+ "fa-wikipedia-w",
+ "fa-windows",
+ "fa-wordpress",
+ "fa-wpbeginner",
+ "fa-wpexplorer",
+ "fa-wpforms",
+ "fa-xing",
+ "fa-xing-square",
+ "fa-y-combinator",
+ "fa-y-combinator-square",
+ "fa-yahoo",
+ "fa-yc",
+ "fa-yc-square",
+ "fa-yelp",
+ "fa-yoast",
+ "fa-youtube",
+ "fa-youtube-play",
+ "fa-youtube-square"
+ ]
+ },
+ {
+ "type": "Medical",
+ "icons": [
+ "fa-ambulance",
+ "fa-h-square",
+ "fa-heart",
+ "fa-heart-o",
+ "fa-heartbeat",
+ "fa-hospital-o",
+ "fa-medkit",
+ "fa-plus-square",
+ "fa-stethoscope",
+ "fa-user-md",
+ "fa-wheelchair",
+ "fa-wheelchair-alt"
+ ]
+ },
+ {
+ "type": "Rotation & Turnover",
+ "icons": [
+ "fa-ambulance",
+ "fa-ambulance fa-rotate-90",
+ "fa-ambulance fa-rotate-180",
+ "fa-ambulance fa-rotate-270",
+ "fa-ambulance fa-flip-horizontal",
+ "fa-ambulance fa-flip-vertical"
+ ]
+ },
+ {
+ "type": "Combination",
+ "icons": [
+ "fa-square-o fa-stack-2x",
+ "fa fa-twitter fa-stack-1x",
+ "fa-circle fa-stack-2x",
+ "fa-flag fa-stack-1x fa-inverse"
+ ]
+ },
+ {
+ "type": "Large",
+ "icons": [
+ "fa-camera-retro fa-lg",
+ "fa-camera-retro fa-2x",
+ "fa-camera-retro fa-3x",
+ "fa-camera-retro fa-4x",
+ "fa-camera-retro fa-5x"
+ ]
+ }
+]
diff --git a/src/renderer/directives/contribution/contribution.component.html b/src/renderer/directives/contribution/contribution.component.html
new file mode 100644
index 0000000..c4e2bbd
--- /dev/null
+++ b/src/renderer/directives/contribution/contribution.component.html
@@ -0,0 +1 @@
+
diff --git a/src/renderer/directives/contribution/contribution.component.scss b/src/renderer/directives/contribution/contribution.component.scss
new file mode 100644
index 0000000..51db179
--- /dev/null
+++ b/src/renderer/directives/contribution/contribution.component.scss
@@ -0,0 +1,35 @@
+:host {
+ position: relative;
+ user-select: none;
+ -ms-user-select: none;
+ -moz-user-select: none;
+ -webkit-user-select: none;
+}
+
+:host > > > .item {
+ cursor: pointer;
+}
+
+:host > > > .label {
+ cursor: pointer;
+ fill: rgb(170, 170, 170);
+}
+
+:host > > > .heatmap-tooltip {
+ pointer-events: none;
+ position: absolute;
+ z-index: 9999;
+ overflow: hidden;
+ padding: 0.3rem;
+ font-size: 12px;
+ line-height: 14px;
+ color: rgb(51, 51, 51);
+ background: #495057;
+ white-space: nowrap;
+ overflow: hidden;
+ color: #ffffff;
+ padding: 1rem;
+ border-radius: 0.3rem;
+ text-overflow: ellipsis;
+ display: inline-block;
+}
diff --git a/src/renderer/directives/contribution/contribution.component.ts b/src/renderer/directives/contribution/contribution.component.ts
new file mode 100644
index 0000000..e2083b5
--- /dev/null
+++ b/src/renderer/directives/contribution/contribution.component.ts
@@ -0,0 +1,323 @@
+import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
+import { ContributionConfig } from './contribution.model';
+import * as moment from 'moment';
+import * as d3 from 'd3';
+
+@Component({
+ selector: 'app-directive-contribution-charts',
+ templateUrl: './contribution.component.html',
+ styleUrls: [
+ './contribution.component.scss'
+ ]
+})
+export class ContributionComponent implements OnInit {
+ @ViewChild('contributionCharts')
+ element: any;
+ // Render data
+ @Input()
+ data: Array