Compare commits

..

24 Commits

Author SHA1 Message Date
Sercan Yemen
d5b6dea1a2 update version 2017-08-30 20:52:08 +03:00
Sercan Yemen
31087186f7 Merge branch 'scrumboard-app' 2017-08-30 20:03:21 +03:00
Sercan Yemen
48a47a0876 sidenav helper small tweaks
+ chat & toolbar small mobile tweaks
2017-08-30 20:02:54 +03:00
Sercan Yemen
e0a85a19db package lock 2017-08-30 20:01:45 +03:00
mustafahlvc
b21526410a (Scrumboard) final touches.. 2017-08-30 18:46:07 +03:00
mustafahlvc
ce6797a80b (Scrumboard) Drag-drop support 2017-08-30 15:58:40 +03:00
mustafahlvc
7d5693421f Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
2017-08-30 15:11:21 +03:00
mustafahlvc
9106fcd066 Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
2017-08-30 15:11:07 +03:00
mustafahlvc
58bdf07da0 Style fixes especially for Edge/IE Browser 2017-08-30 15:04:20 +03:00
Sercan Yemen
58291058ae update version number 2017-08-30 14:42:55 +03:00
Sercan Yemen
9ae746a3ed fix: revert back to Angular 4.3.5 since the animations are not working correctly on 4.3.6 2017-08-30 14:36:54 +03:00
Sercan Yemen
a7549a1770 fix: pages not scrolling on various browsers 2017-08-30 14:26:45 +03:00
mustafahlvc
0bf158f8a5 (Scrumboard) board settings added + some refinements. 2017-08-30 14:21:14 +03:00
mustafahlvc
a0da9bd81e Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
#	src/app/core/modules/shared.module.ts
2017-08-30 14:19:45 +03:00
Sercan Yemen
56716653b8 added npmrc to force the package version on both install and update
+ updated package-lock.json
2017-08-30 11:48:26 +03:00
mustafahlvc
a56e9e6d10 Angular Material Update: 2.0.0-beta.10 2017-08-30 10:37:25 +03:00
mustafahlvc
49af06cdbd Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-30 06:54:43 +03:00
mustafahlvc
cd99fbf77a (Scrumboard App) added
+ md2 added for date-time picker,
+ toggleInArray func added to FuseUtils
2017-08-30 06:54:11 +03:00
Sercan Yemen
041a54731d added print styles 2017-08-29 17:41:35 +03:00
Sercan Yemen
95640f8ffe wording 2017-08-29 17:27:27 +03:00
Sercan Yemen
215d1cb78a added cookie saving for shortcuts component
+ services and components pages for the demo
2017-08-29 17:20:13 +03:00
mustafahlvc
ffa52909e8 unnecessary env variable removed 2017-08-26 06:10:22 +03:00
mustafahlvc
3a246717a0 this.router.events.filter/map AOT error fix. 2017-08-25 17:34:58 +03:00
mustafahlvc
a650ebac97 (@angular/flex-layout) updated to v2.0.0-beta.9 2017-08-25 09:58:59 +03:00
115 changed files with 5559 additions and 247 deletions

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
save-prefix=''

113
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "fuse2",
"version": "1.0.0",
"version": "1.0.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -24,9 +24,9 @@
}
},
"@angular/cdk": {
"version": "2.0.0-beta.8",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-2.0.0-beta.8.tgz",
"integrity": "sha512-OOtK+AA14cmRG9AbUgvoKC9Tooz0N37GTaRSV+xziC8GxXHgwvTu4PFSFHlBnHPipOYC/tB2oP39j3KuurEMPA==",
"version": "2.0.0-beta.10",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-2.0.0-beta.10.tgz",
"integrity": "sha512-G0RvzxItfPy8JEdnyV/10GryE3zHehm3bUJ7U9dwYKhAzhye+MX0P6rs8VEmbClJb5SuZDr0ZZ53vbHhHsUh6A==",
"requires": {
"tslib": "1.7.1"
}
@@ -129,15 +129,6 @@
"reflect-metadata": "0.1.10"
},
"dependencies": {
"@angular/tsc-wrapped": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.3.5.tgz",
"integrity": "sha1-lf2qgTz8VyYvx+9f6nJtYorvq6w=",
"dev": true,
"requires": {
"tsickle": "0.21.6"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
@@ -155,9 +146,12 @@
}
},
"@angular/flex-layout": {
"version": "2.0.0-beta.8",
"resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-2.0.0-beta.8.tgz",
"integrity": "sha1-uc9XhlqTyhWP5W2FCVJCPySNEDs="
"version": "2.0.0-beta.9",
"resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-2.0.0-beta.9.tgz",
"integrity": "sha1-PlT4mOgF0LFCbRXmE520FdBO518=",
"requires": {
"tslib": "1.7.1"
}
},
"@angular/forms": {
"version": "4.3.5",
@@ -182,9 +176,9 @@
"dev": true
},
"@angular/material": {
"version": "2.0.0-beta.8",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-2.0.0-beta.8.tgz",
"integrity": "sha512-4+OecvjU15i+l/vXBP2qEHdlsU9taK6kBhsWKsxNLK3+TAVoV5qjc2rjOucHtTwI/oOjyBXnLJP6pl4tuLEUQw==",
"version": "2.0.0-beta.10",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-2.0.0-beta.10.tgz",
"integrity": "sha512-KAQ2t9wenI55oXkjjT6E4VGUSVu7AZmR+ytnaP96VBFk18wxcGnVaTbQmCvVm/vkbcdeoSF09D6ic94DHAE+1A==",
"requires": {
"tslib": "1.7.1"
}
@@ -213,6 +207,15 @@
"tslib": "1.7.1"
}
},
"@angular/tsc-wrapped": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.3.5.tgz",
"integrity": "sha1-lf2qgTz8VyYvx+9f6nJtYorvq6w=",
"dev": true,
"requires": {
"tsickle": "0.21.6"
}
},
"@ngtools/json-schema": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz",
@@ -255,18 +258,18 @@
"dev": true
},
"@types/jasminewd2": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.2.tgz",
"integrity": "sha1-X2jh5pe/ELxv2Mvy4Aaj1nEsW2Q=",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.3.tgz",
"integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==",
"dev": true,
"requires": {
"@types/jasmine": "2.5.54"
}
},
"@types/node": {
"version": "6.0.87",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.87.tgz",
"integrity": "sha512-Xo0pYENOBaGtJUhi50KH6gdBNQmZQQxAwBArsJpBd15ncoz+LZD5Ev14vuezcw62CsQ1q6bM++7jA6jfwaAbfQ==",
"version": "6.0.88",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz",
"integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==",
"dev": true
},
"@types/q": {
@@ -1541,26 +1544,15 @@
"dev": true
},
"connect": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.6.2.tgz",
"integrity": "sha1-aU6NIGgb/kkCgsiriGvpjwn0L+c=",
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.6.3.tgz",
"integrity": "sha512-GLSZqgjVxPvGYVD/2vz//gS201MEXk4b7t3nHV6OVnTdDNWi/Gm7Rpxs/ybvljPWvULys/wrzIV3jB3YvEc3nQ==",
"dev": true,
"requires": {
"debug": "2.6.7",
"finalhandler": "1.0.3",
"debug": "2.6.8",
"finalhandler": "1.0.4",
"parseurl": "1.3.1",
"utils-merge": "1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
"integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"connect-history-api-fallback": {
@@ -3140,29 +3132,18 @@
}
},
"finalhandler": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz",
"integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz",
"integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==",
"dev": true,
"requires": {
"debug": "2.6.7",
"debug": "2.6.8",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.1",
"statuses": "1.3.1",
"unpipe": "1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
"integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"find-up": {
@@ -5542,9 +5523,9 @@
}
},
"karma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.7.0.tgz",
"integrity": "sha1-b3oaQGRG+i4YfslTmGmPTO5HYmk=",
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz",
"integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==",
"dev": true,
"requires": {
"bluebird": "3.5.0",
@@ -5552,7 +5533,7 @@
"chokidar": "1.7.0",
"colors": "1.1.2",
"combine-lists": "1.0.1",
"connect": "3.6.2",
"connect": "3.6.3",
"core-js": "2.5.0",
"di": "0.0.1",
"dom-serialize": "2.2.1",
@@ -5936,6 +5917,11 @@
"integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=",
"dev": true
},
"md2": {
"version": "0.0.28",
"resolved": "https://registry.npmjs.org/md2/-/md2-0.0.28.tgz",
"integrity": "sha512-XQ71eTVKG3oRsGBj3lMLqL8p2inueqDXn++a2EntzWkUPlBZXPCPtlpfI9ER/LAlBKwJZQSqTzFItw7q9+vgvw=="
},
"md5.js": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
@@ -6192,6 +6178,11 @@
"resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-4.3.1.tgz",
"integrity": "sha512-/Gn3XvOgaAK/ZnXA0ej9ivYm6uIvHwvZaSzx04ZUtG1Vw5RCKzw84dK0Ru9Ylnnq1xJU4WmdA63REkJb8cvYXg=="
},
"ngx-cookie-service": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-1.0.7.tgz",
"integrity": "sha1-NdQzt3WloqgIxUl19Pr1AKzFL2g="
},
"ngx-perfect-scrollbar": {
"version": "4.5.6",
"resolved": "https://registry.npmjs.org/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-4.5.6.tgz",
@@ -7415,7 +7406,7 @@
"integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=",
"dev": true,
"requires": {
"@types/node": "6.0.87",
"@types/node": "6.0.88",
"@types/q": "0.0.32",
"@types/selenium-webdriver": "2.53.42",
"blocking-proxy": "0.0.5",

View File

@@ -1,7 +1,7 @@
{
"name": "fuse2",
"version": "1.0.1",
"license": "MIT",
"version": "1.0.4",
"license": "",
"scripts": {
"ng": "ng",
"start": "ng serve",
@@ -13,34 +13,36 @@
"private": true,
"dependencies": {
"@angular/animations": "4.3.5",
"@angular/cdk": "^2.0.0-beta.8",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.5",
"@angular/compiler": "4.3.5",
"@angular/core": "4.3.5",
"@angular/flex-layout": "2.0.0-beta.8",
"@angular/flex-layout": "2.0.0-beta.9",
"@angular/forms": "4.3.5",
"@angular/http": "4.3.5",
"@angular/material": "^2.0.0-beta.8",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.5",
"@angular/platform-browser-dynamic": "4.3.5",
"@angular/router": "4.3.5",
"@swimlane/ngx-charts": "^6.0.2",
"@swimlane/ngx-datatable": "^9.3.1",
"@swimlane/ngx-dnd": "^3.0.0",
"angular-calendar": "^0.19.0",
"angular-in-memory-web-api": "^0.3.2",
"classlist.js": "^1.1.20150312",
"core-js": "^2.5.0",
"d3": "^4.10.0",
"hammerjs": "^2.0.8",
"highlight.js": "^9.12.0",
"intl": "^1.2.5",
"moment": "^2.18.1",
"ngx-color-picker": "^4.3.1",
"ngx-perfect-scrollbar": "^4.5.6",
"rxjs": "^5.4.3",
"web-animations-js": "^2.3.1",
"zone.js": "^0.8.17"
"@swimlane/ngx-charts": "6.0.2",
"@swimlane/ngx-datatable": "9.3.1",
"@swimlane/ngx-dnd": "3.0.0",
"angular-calendar": "0.19.0",
"angular-in-memory-web-api": "0.3.2",
"classlist.js": "1.1.20150312",
"core-js": "2.5.0",
"d3": "4.10.0",
"hammerjs": "2.0.8",
"highlight.js": "9.12.0",
"intl": "1.2.5",
"md2": "0.0.28",
"moment": "2.18.1",
"ngx-color-picker": "4.3.1",
"ngx-cookie-service": "1.0.7",
"ngx-perfect-scrollbar": "4.5.6",
"rxjs": "5.4.3",
"web-animations-js": "2.3.1",
"zone.js": "0.8.17"
},
"devDependencies": {
"@angular/cli": "^1.3.2",
@@ -49,11 +51,11 @@
"@ngtools/webpack": "^1.6.2",
"@types/jasmine": "^2.5.54",
"@types/jasminewd2": "^2.0.2",
"@types/node": "^6.0.87",
"@types/node": "^6.0.88",
"codelyzer": "~3.0.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma": "1.7.1",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",

View File

@@ -17,6 +17,8 @@ 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 { ComponentsThirdPartyModule } from './main/content/components-third-party/components-third-party.module';
import { ServicesModule } from './main/content/services/services.module';
const appRoutes: Routes = [
{
@@ -43,6 +45,10 @@ const appRoutes: Routes = [
path : 'apps/contacts',
loadChildren: './main/content/apps/contacts/contacts.module#FuseContactsModule'
},
{
path : 'apps/scrumboard',
loadChildren: './main/content/apps/scrumboard/scrumboard.module#FuseScrumboardModule'
},
{
path : '**',
redirectTo: 'apps/dashboards/project'
@@ -71,9 +77,11 @@ const appRoutes: Routes = [
PagesModule,
UIModule,
ComponentsModule
ServicesModule,
ComponentsModule,
ComponentsThirdPartyModule
],
providers: [
providers : [
FuseSplashScreenService,
FuseConfigService
],

View File

@@ -9,6 +9,7 @@
flex-direction: row;
align-items: center;
justify-content: center;
text-align: center;
.time {
display: flex;

View File

@@ -1,4 +1,5 @@
<button md-icon-button
type="button"
class="mat-elevation-z1"
[mdMenuTriggerFor]="colorMenu"
(onMenuOpen)="onMenuOpen()"

View File

@@ -3,11 +3,14 @@
:host {
.fuse-search-bar {
min-width: 64px;
height: 64px;
font-size: 13px;
@include media-breakpoint-down('xs') {
height: 56px;
}
.fuse-search-bar-expander,
.fuse-search-bar-collapser {
cursor: pointer;
@@ -16,6 +19,7 @@
width: 64px !important;
height: 64px !important;
line-height: 64px !important;
@include media-breakpoint-down('xs') {
height: 56px !important;
line-height: 56px !important;
@@ -70,4 +74,4 @@
}
}
}
}
}

View File

@@ -9,7 +9,7 @@
<div class="shortcuts" fxHide fxShow.gt-sm [ngClass]="toolbarColor">
<div fxLayout="row" fxLayoutAlign="space-between center" fxFlex>
<div fxLayout="row" fxLayoutAlign="space-between center" fxFlex="0 1 auto">
<div fxLayout="row" fxLayoutAlign="start center">

View File

@@ -4,6 +4,7 @@ import { Subscription } from 'rxjs/Subscription';
import { ObservableMedia } from '@angular/flex-layout';
import { FuseMatchMedia } from '../../services/match-media.service';
import { FuseConfigService } from '../../services/config.service';
import { CookieService } from 'ngx-cookie-service';
@Component({
selector : 'fuse-shortcuts',
@@ -29,7 +30,8 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
private observableMedia: ObservableMedia,
private fuseMatchMedia: FuseMatchMedia,
private fuseNavigationService: FuseNavigationService,
private fuseConfig: FuseConfigService
private fuseConfig: FuseConfigService,
private cookieService: CookieService
)
{
this.filteredNavigationItems = this.navigationItems = this.fuseNavigationService.getFlatNavigation();
@@ -45,33 +47,42 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
ngOnInit()
{
// User's shortcut items
this.shortcutItems = [
{
'title': 'Calendar',
'type' : 'nav-item',
'icon' : 'today',
'url' : '/apps/calendar'
},
{
'title': 'Mail',
'type' : 'nav-item',
'icon' : 'email',
'url' : '/apps/mail'
},
{
'title': 'Contacts',
'type' : 'nav-item',
'icon' : 'account_box',
'url' : '/apps/contacts'
},
{
'title': 'To-Do',
'type' : 'nav-item',
'icon' : 'check_box',
'url' : '/apps/todo'
}
];
const cookieExists = this.cookieService.check('FUSE2.shortcuts');
if ( cookieExists )
{
this.shortcutItems = JSON.parse(this.cookieService.get('FUSE2.shortcuts'));
}
else
{
// User's shortcut items
this.shortcutItems = [
{
'title': 'Calendar',
'type' : 'nav-item',
'icon' : 'today',
'url' : '/apps/calendar'
},
{
'title': 'Mail',
'type' : 'nav-item',
'icon' : 'email',
'url' : '/apps/mail'
},
{
'title': 'Contacts',
'type' : 'nav-item',
'icon' : 'account_box',
'url' : '/apps/contacts'
},
{
'title': 'To-Do',
'type' : 'nav-item',
'icon' : 'check_box',
'url' : '/apps/todo'
}
];
}
this.matchMediaSubscription =
this.fuseMatchMedia.onMediaChange.subscribe(() => {
@@ -115,12 +126,18 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
if ( this.shortcutItems[i].url === itemToToggle.url )
{
this.shortcutItems.splice(i, 1);
// Save to the cookies
this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
return;
}
}
this.shortcutItems.push(itemToToggle);
// Save to the cookies
this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
}
isInShortcuts(navigationItem)

View File

@@ -33,29 +33,37 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
if ( this.observableMedia.isActive(this.mdIsLockedOpenBreakpoint) )
{
this.isLockedOpen = true;
this.mdSidenav.mode = 'side';
this.mdSidenav.open();
setTimeout(() => {
this.isLockedOpen = true;
this.mdSidenav.mode = 'side';
this.mdSidenav.open();
});
}
else
{
this.isLockedOpen = false;
this.mdSidenav.mode = 'over';
this.mdSidenav.close();
setTimeout(() => {
this.isLockedOpen = false;
this.mdSidenav.mode = 'over';
this.mdSidenav.close();
});
}
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
if ( this.observableMedia.isActive(this.mdIsLockedOpenBreakpoint) )
{
this.isLockedOpen = true;
this.mdSidenav.mode = 'side';
this.mdSidenav.open();
setTimeout(() => {
this.isLockedOpen = true;
this.mdSidenav.mode = 'side';
this.mdSidenav.open();
});
}
else
{
this.isLockedOpen = false;
this.mdSidenav.mode = 'over';
this.mdSidenav.close();
setTimeout(() => {
this.isLockedOpen = false;
this.mdSidenav.mode = 'over';
this.mdSidenav.close();
});
}
});

View File

@@ -90,4 +90,16 @@ export class FuseUtils
return (S4() + S4());
}
public static toggleInArray(item, array)
{
if ( array.indexOf(item) === -1 )
{
array.push(item);
}
else
{
array.splice(array.indexOf(item), 1);
}
}
}

View File

@@ -32,7 +32,7 @@ import {
MdTableModule,
MdTabsModule
} from '@angular/material';
import { CdkTableModule } from '@angular/cdk';
import { CdkTableModule } from '@angular/cdk/table';
@NgModule({
imports: [

View File

@@ -20,6 +20,8 @@ import { FuseMdSidenavHelperService } from '../directives/md-sidenav-helper/md-s
import { FuseHljsComponent } from '../components/hljs/hljs.component';
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 { Md2Module } from 'md2';
import { CookieService } from 'ngx-cookie-service';
@NgModule({
declarations : [
@@ -41,7 +43,8 @@ import { FuseMaterialColorPickerComponent } from '../components/material-color-p
ReactiveFormsModule,
ColorPickerModule,
NgxDnDModule,
NgxDatatableModule
NgxDatatableModule,
Md2Module
],
exports : [
FlexLayoutModule,
@@ -59,12 +62,14 @@ import { FuseMaterialColorPickerComponent } from '../components/material-color-p
NgxDnDModule,
NgxDatatableModule,
FuseIfOnDomDirective,
FuseMaterialColorPickerComponent
FuseMaterialColorPickerComponent,
Md2Module
],
entryComponents: [
FuseConfirmDialogComponent
],
providers : [
CookieService,
FuseNavigationService,
FuseMatchMedia,
FuseNavbarService,

View File

@@ -1,6 +1,9 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'getById'})
@Pipe({
name: 'getById',
pure: false
})
export class GetByIdPipe implements PipeTransform
{
transform(value: any[], id: number, property: string): any

View File

@@ -28,6 +28,7 @@
@import "partials/navigation";
@import "partials/forms";
@import "partials/toolbar";
@import "partials/print";
// Plugins
@import "partials/plugins/plugins";

View File

@@ -54,7 +54,8 @@ $matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400
&.secondary-text,
.secondary-text,
.mat-icon,
.icon {
.icon,
.md2-datepicker-button {
color: rgba(0, 0, 0, 0.54);
}
@@ -79,7 +80,8 @@ $matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400
@else {
.mat-icon,
.icon {
.icon,
.md2-datepicker-button {
color: rgba(255, 255, 255, 1);
}

View File

@@ -144,7 +144,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.md-stop-transition {
~ .mat-sidenav-content {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
@@ -161,7 +162,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
}
}
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
flex: 1;
height: auto;
@@ -229,7 +231,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.md-is-locked-open {
~ .mat-sidenav-content {
~ .mat-sidenav-content,
~ .mat-drawer-content {
margin-left: 0 !important;
.center {
@@ -252,7 +255,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.md-is-locked-open {
~ .mat-sidenav-content {
~ .mat-sidenav-content,
~ .mat-drawer-content {
margin-right: 0 !important;
.center {
@@ -301,7 +305,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> md-sidenav-container {
flex: 1 0 auto;
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
flex: 1 0 auto;
max-height: none;
@@ -325,7 +330,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
}
}
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
height: auto;
@@ -368,7 +374,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.md-stop-transition {
~ .mat-sidenav-content {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
@@ -378,7 +385,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
}
}
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
flex: 1;
height: auto;
@@ -472,7 +480,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> md-sidenav-container {
flex: 1 0 auto !important;
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
flex: 1 0 auto;
> .center {
@@ -499,7 +508,8 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> md-sidenav-container {
> .mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
.center {
margin: 0 16px;

View File

@@ -0,0 +1,51 @@
/*----------------------------------------------------------------*/
/* Print
/*----------------------------------------------------------------*/
@media all {
/* Never show page break in normal view */
.page-break {
display: none;
}
}
@media print {
/* Page Styles */
@page {
//margin: 0.5cm;
}
/* Page break */
.page-break {
display: block;
break-after: always;
page-break-after: always;
}
/* General styles */
fuse-root {
fuse-navbar,
fuse-toolbar,
fuse-footer,
fuse-quick-panel,
fuse-theme-options,
.ps > .ps__scrollbar-x-rail,
.ps > .ps__scrollbar-y-rail {
display: none !important;
}
.ps {
overflow: visible !important;
}
}
/* Printable page specific styles */
.printable {
overflow: visible !important;
height: auto !important;
}
}

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { NavigationStart, Router } from '@angular/router';
import { Platform } from '@angular/cdk';
import { Platform } from '@angular/cdk/platform';
@Injectable()
export class FuseConfigService
@@ -12,6 +12,7 @@ export class FuseConfigService
/**
* @param router
* @param platform
*/
constructor(
private router: Router,

View File

@@ -12,6 +12,7 @@ import { SearchFakeDb } from './search';
import { QuickPanelFakeDb } from './quick-panel';
import { IconsFakeDb } from './icons';
import { ProjectsDashboardDb } from './projects-dashboard';
import { ScrumboardFakeDb } from './scrumboard';
export class FuseFakeDbService implements InMemoryDbService
{
@@ -42,7 +43,8 @@ export class FuseFakeDbService implements InMemoryDbService
'quick-panel-events' : QuickPanelFakeDb.events,
'icons' : IconsFakeDb.icons,
'projects-dashboard-projects': ProjectsDashboardDb.projects,
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
'scrumboard-boards' : ScrumboardFakeDb.boards
};
}
}

View File

@@ -0,0 +1,787 @@
export class ScrumboardFakeDb
{
public static boards = [
{
'id' : '32gfhaf2',
'name' : 'ACME Frontend Application',
'uri' : 'acme-frontend-application',
'settings': {
'color' : 'fuse-dark',
'subscribed' : false,
'cardCoverImages': true
},
'lists' : [
{
'id' : '56027cf5a2ca3839a5d36103',
'name' : 'Design',
'idCards': [
'5603a2a3cab0c8300f6096b3',
'44d1.2b51ea6cc2b5d.21f4a3412e857.8ffa2d8b44ad9.ac87215ed53a1.67d4921ad8f8d.9f318bcb2'
]
},
{
'id' : '56127cf2a2ca3539g7d36103',
'name' : 'Development',
'idCards': [
'2837273da9b93dd84243s0f9',
'5787b7e4740c57bf0dffd5b6',
'5637273da9b93bb84743a0f9',
'7987.9740ba532b0d4.f9d12243f7362.507c0738dc561.87fba0a03df6e.75e6508cacf10.7a9835b54'
]
},
{
'id' : 'faf244627326f1249525763d',
'name' : 'Upcoming Features',
'idCards': [
'd9005a4b89ed2aadca48a6ad',
'f6b9d7a9247e5d794a081927',
'80ed.24ad3b18e2668.f28fbbceeeff9.5a834620a42f1.5909be19a2bf2.6c4a54947ce2d.da356b0c1',
'0ad2.7862f947bc456.f42b446df54cb.d1dd9e93601a1.9deb1406d1404.0b3c278fc7001.733341b42',
'bad3.51be8ad33acaf.9540ecb37f7e8.6bee596cfe7d3.44c68bee289c4.b96ed0b9f0af7.e14846035'
]
},
{
'id' : 'ad7d.9fffac5dff412.c83bca6853767.8fd7549b2b1ca.ceda8a01774c4.a5cf3976e87e4.ce79eeeea',
'name' : 'Known Bugs',
'idCards': [
'acc6.9c673cd2f5e35.521e91d8d5991.4b2a95e0539d1.027930c0743c5.7ad1ea7bea476.e8fbe6347',
'3279.3d69b40cc0b75.690252b6bea08.1e1789b0b7c2e.2f264b8661ce2.84d5f56910e23.429be5e8a',
'ba01.8e1a43f92a03a.0022bd5cbb9ba.275c64d911d8c.880e0846a3966.f75ff43e53ad.48ad612e7'
]
}
],
'cards' : [
{
'id' : '2837273da9b93dd84243s0f9',
'name' : 'Update generators',
'description' : 'Current generator doesn\'t support Node.js 6 and above.',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'AngularCLI could be a nice alternative.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '5603a2a3cab0c8300f6096b3',
'name' : 'Change background colors',
'description' : '',
'idAttachmentCover': '67027cahbe3b52ecf2dc631c',
'idMembers' : [
'76027g1930450d8bf7b10958'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '67027cahbe3b52ecf2dc631c',
'name': 'mail.jpg',
'src' : 'assets/images/scrumboard/mail.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'image'
},
{
'id' : '56027cfcbe1b72ecf1fc452a',
'name': 'calendar.jpg',
'src' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : true,
'checklists' : [
{
'id' : '63021cfdbe1x72wcf1fc451v',
'name' : 'Checklist',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Implement a calendar library',
'checked': false
},
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
},
{
'name' : 'Checklist 2',
'id' : '74031cfdbe1x72wcz1dc166z',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
}
],
'checkItems' : 7,
'checkItemsChecked': 2,
'comments' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'We should be able to add moment.js without any problems',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I added a link for a page that might help us deciding the colors',
'time' : '30 mins. ago'
}
],
'activities' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'added a comment',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'added a comment',
'time' : '30 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'attached a link',
'time' : '45 mins. ago'
}
],
'due' : 'Tue Aug 29 2017 13:16:34 GMT+0300 (Turkey Standard Time)'
},
{
'id' : '5637273da9b93bb84743a0f9',
'name' : 'Fix splash screen bugs',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'56027c1930450d8bf7b10758'
],
'idLabels' : [
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'd9005a4b89ed2aadca48a6ad',
'name' : 'Add alternative authentication pages',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'6540635g19ad3s5dc31412b2',
'56027e4119ad3a5dc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [
{
'id' : 'dbfb.99bd0ad37dabc.e05046f0c824d.18f26bb524c96.78bebc8488634.240c0ee6a5e45.4cb872965',
'name' : 'Pages',
'checkItemsChecked': 2,
'checkItems' : [
{
'name' : 'Login',
'checked': true
},
{
'name' : 'Register',
'checked': true
},
{
'name' : 'Lost Password',
'checked': false
},
{
'name' : 'Recover Password',
'checked': false
},
{
'name' : 'Activate Account',
'checked': false
}
]
}
],
'checkItems' : 5,
'checkItemsChecked': 2,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '5787b7e4740c57bf0dffd5b6',
'name' : 'Fix the console',
'description' : 'We need to fix the console asap!',
'idAttachmentCover': '',
'idMembers' : [],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I\'m on it!',
'time' : 'now'
}
],
'activities' : [],
'due' : 'Fri Sep 07 2018 15:00:00 GMT+0300 (Turkey Standard Time)'
},
{
'id' : 'f6b9d7a9247e5d794a081927',
'name' : 'New media player',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'76027g1930450d8bf7b10958',
'56027c1930450d8bf7b10758',
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'5640635e19ad3a5dc21416b2',
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'acc6.9c673cd2f5e35.521e91d8d5991.4b2a95e0539d1.027930c0743c5.7ad1ea7bea476.e8fbe6347',
'name' : 'Memory Leak',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '3279.3d69b40cc0b75.690252b6bea08.1e1789b0b7c2e.2f264b8661ce2.84d5f56910e23.429be5e8a',
'name' : 'Broken toolbar on profile page',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'This should be a medium priority bug, shouldn\'t it?',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : 'ba01.8e1a43f92a03a.0022bd5cbb9ba.275c64d911d8c.880e0846a3966.f75ff43e53ad.48ad612e7',
'name' : 'Button hover style',
'description' : 'If there are 3 or more buttons in certain page, weird flashing happens when you hover over the red ones.',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : 'Wed Mar 08 2017 12:00:00 GMT+0300 (Turkey Standard Time)'
},
{
'id' : '80ed.24ad3b18e2668.f28fbbceeeff9.5a834620a42f1.5909be19a2bf2.6c4a54947ce2d.da356b0c1',
'name' : 'New header designs',
'description' : '',
'idAttachmentCover': '12027cafbe3b52ecf2ef632c',
'idMembers' : [],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'6540635g19ad3s5dc31412b2',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '12027cafbe3b52ecf2ef632c',
'name': 'header-.jpg',
'src' : 'assets/images/scrumboard/header-1.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'image'
},
{
'id' : '55027ced1e1a12ecf1fced2a',
'name': 'header-2.jpg',
'src' : 'assets/images/scrumboard/header-2.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'Currently we have two new designs ready to ship.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '0ad2.7862f947bc456.f42b446df54cb.d1dd9e93601a1.9deb1406d1404.0b3c278fc7001.733341b42',
'name' : 'Fixed footer',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828',
'56027c1930450d8bf7b10758'
],
'idLabels' : [
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'bad3.51be8ad33acaf.9540ecb37f7e8.6bee596cfe7d3.44c68bee289c4.b96ed0b9f0af7.e14846035',
'name' : 'Collapsable navigation',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [],
'idLabels' : [
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I\'m not sure why we re-doing the navigation. The current collapsable navigation works flawlessly.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '44d1.2b51ea6cc2b5d.21f4a3412e857.8ffa2d8b44ad9.ac87215ed53a1.67d4921ad8f8d.9f318bcb2',
'name' : 'Mail app new layout',
'description' : 'Current layout has lots of flaws in mobile. Outlook view should help with that.',
'idAttachmentCover': '',
'idMembers' : [
'56027c1930450d8bf7b10758',
'26027s1930450d8bf7b10828',
'76027g1930450d8bf7b10958',
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '7987.9740ba532b0d4.f9d12243f7362.507c0738dc561.87fba0a03df6e.75e6508cacf10.7a9835b54',
'name' : 'API recover and monitoring',
'description' : 'We need a service to monitor and recover failed APIs.',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158',
'76027g1930450d8bf7b10958'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [
{
'id' : '6926.2b31d119e4a.889401e0ca7a0.13ad8ce2e569d.976e54e8b5d87.456afccd7e820.d6c77106a',
'name' : 'API Monitoring',
'checkItemsChecked': 2,
'checkItems' : [
{
'name' : 'Simple dashboard design',
'checked': false
},
{
'name' : 'Should be able to see different time periods on the same dashboard',
'checked': true
},
{
'name' : 'Different colors for different clusters',
'checked': true
}
]
},
{
'id' : '7c22.5261c7924387f.248e8b1d32205.003f7a9f501d1.1d48dcdbe8b23.8099dcc5f75a7.29a966196',
'name' : 'API Recovery',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Warning notifications to all developers',
'checked': false
},
{
'name' : 'Immediate recovery options attached to the notifications',
'checked': true
},
{
'name' : 'Backups every 6hours',
'checked': false
}
]
}
],
'checkItems' : 6,
'checkItemsChecked': 3,
'comments' : [],
'activities' : [],
'due' : 'Fri Feb 02 2017 14:20:34 GMT+0300 (Turkey Standard Time)'
}
],
'members' : [
{
'id' : '56027c1930450d8bf7b10758',
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
{
'id' : '26027s1930450d8bf7b10828',
'name' : 'Danielle Obrien',
'avatar': 'assets/images/avatars/danielle.jpg'
},
{
'id' : '76027g1930450d8bf7b10958',
'name' : 'James Lewis',
'avatar': 'assets/images/avatars/james.jpg'
},
{
'id' : '36027j1930450d8bf7b10158',
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
}
],
'labels' : [
{
'id' : '26022e4129ad3a5sc28b36cd',
'name' : 'High Priority',
'color': 'md-red-500-bg'
},
{
'id' : '56027e4119ad3a5dc28b36cd',
'name' : 'Design',
'color': 'md-orange-400-bg'
},
{
'id' : '5640635e19ad3a5dc21416b2',
'name' : 'App',
'color': 'md-blue-600-bg'
},
{
'id' : '6540635g19ad3s5dc31412b2',
'name' : 'Feature',
'color': 'md-green-400-bg'
}
]
},
{
'id' : '27cfcbe1',
'name' : 'ACME Backend Application',
'uri' : 'acme-backend-application',
'settings': {
'color' : 'blue-grey',
'subscribed' : false,
'cardCoverImages': true
},
'lists' : [
{
'id' : '56027cf5a2ca3839a5d36103',
'name' : 'Designs',
'idCards': [
'5603a2a3cab0c8300f6096b3'
]
},
{
'id' : '56127cf2a2ca3539g7d36103',
'name' : 'Development',
'idCards': [
'5637273da9b93bb84743a0f9'
]
}
],
'cards' : [
{
'id' : '5603a2a3cab0c8300f6096b3',
'name' : 'Calendar App Design',
'description' : '',
'idAttachmentCover': '56027cfcbe1b72ecf1fc452a',
'idMembers' : [
'56027c1930450d8bf7b10758',
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '56027cfcbe1b72ecf1fc452a',
'name': 'calendar-app-design.jpg',
'src' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
},
{
'id' : '67027cahbe3b52ecf2dc631c',
'url' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'link'
}
],
'subscribed' : true,
'checklists' : [
{
'id' : '63021cfdbe1x72wcf1fc451v',
'name' : 'Checklist',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Implement a calendar library',
'checked': false
},
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
},
{
'name' : 'Checklist 2',
'id' : '74031cfdbe1x72wcz1dc166z',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
}
],
'checkItems' : 7,
'checkItemsChecked': 2,
'comments' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'We should be able to add moment.js without any problems',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I added a link for a page that might help us deciding the colors',
'time' : '30 mins. ago'
}
],
'activities' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'added a comment',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'added a comment',
'time' : '30 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'attached a link',
'time' : '45 mins. ago'
}
],
'due' : null
},
{
'id' : '5637273da9b93bb84743a0f9',
'name' : 'Fix Splash Screen bugs',
'description' : '',
'idAttachmentCover': '5603a2ae2bbd55bb2db57478',
'idMembers' : [
'56027c1930450d8bf7b10758'
],
'idLabels' : [],
'attachments' : [
{
'id' : '5603a2ae2bbd55bb2db57478',
'name': 'mail-app-design.jpg',
'src' : 'assets/images/scrumboard/mail.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
}
],
'members' : [
{
'id' : '56027c1930450d8bf7b10758',
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
{
'id' : '26027s1930450d8bf7b10828',
'name' : 'Danielle Obrien',
'avatar': 'assets/images/avatars/danielle.jpg'
},
{
'id' : '76027g1930450d8bf7b10958',
'name' : 'James Lewis',
'avatar': 'assets/images/avatars/james.jpg'
},
{
'id' : '36027j1930450d8bf7b10158',
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
}
],
'labels' : [
{
'id' : '56027e4119ad3a5dc28b36cd',
'name' : 'Design',
'color': 'md-red-500-bg'
},
{
'id' : '5640635e19ad3a5dc21416b2',
'name' : 'App',
'color': 'md-blue-500-bg'
},
{
'id' : '6540635g19ad3s5dc31412b2',
'name' : 'Feature',
'color': 'md-green-400-bg'
}
]
}
];
}

View File

@@ -58,29 +58,23 @@
<div fxFlex="1 0 auto" fxLayout="row">
<md-input-container class="mr-24">
<input mdInput
name="start"
formControlName="start"
[mdDatepicker]="startDatePicker"
placeholder="Start Date">
<button mdSuffix [mdDatepickerToggle]="startDatePicker"></button>
</md-input-container>
<md-form-field class="mr-24">
<input mdInput [mdDatepicker]="startDatePicker" placeholder="Start Date">
<md-datepicker-toggle mdSuffix [for]="startDatePicker"></md-datepicker-toggle>
<md-datepicker #startDatePicker></md-datepicker>
</md-form-field>
<md-datepicker #startDatePicker></md-datepicker>
</div>
<div fxFlex="1 0 auto" fxLayout="row">
<md-input-container class="mr-24">
<input mdInput
name="end"
formControlName="end"
[mdDatepicker]="endDatePicker"
placeholder="End Date">
<button mdSuffix [mdDatepickerToggle]="endDatePicker"></button>
</md-input-container>
<md-datepicker #endDatePicker></md-datepicker>
<md-form-field class="mr-24">
<input mdInput [mdDatepicker]="endDatePicker" placeholder="End Date">
<md-datepicker-toggle mdSuffix [for]="endDatePicker"></md-datepicker-toggle>
<md-datepicker #endDatePicker></md-datepicker>
</md-form-field>
<md-input-container class="no-errors-spacer" flex md-no-float>
<input mdInput ng-model="calendarEvent.endTime" placeholder="End Time">

View File

@@ -1,4 +1,4 @@
<div id="calendar" class="page-layout carded fullwidth">
<div id="chat" class="page-layout carded fullwidth">
<!-- TOP BACKGROUND -->
<div class="top-bg md-accent-bg"></div>

View File

@@ -1,4 +1,6 @@
#calendar {
@import "src/app/core/scss/fuse";
#chat {
display: flex;
flex: 1;
@@ -7,6 +9,10 @@
max-width: 1400px;
margin: 0 auto;
@include media-breakpoint(xs) {
padding: 8px !important;
}
.content-card {
display: flex;
flex: 1;
@@ -19,7 +25,8 @@
width: 100%;
background: transparent;
.mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
flex: 1 0 auto;
min-height: 100%;

View File

@@ -69,14 +69,11 @@
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-input-container fxFlex class="mr-24">
<button mdSuffix [mdDatepickerToggle]="birthdayDatePicker"></button>
<input mdInput
name="birthday" formControlName="birthday"
[mdDatepicker]="birthdayDatePicker"
placeholder="Birthday">
</md-input-container>
<md-datepicker #birthdayDatePicker></md-datepicker>
<md-form-field class="mr-24" fxFlex>
<input mdInput [mdDatepicker]="birthdayDatePicker" placeholder="Birthday">
<md-datepicker-toggle mdSuffix [for]="birthdayDatePicker"></md-datepicker-toggle>
<md-datepicker #birthdayDatePicker></md-datepicker>
</md-form-field>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">

View File

@@ -1,11 +1,11 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ContactsService } from '../contacts.service';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import { FuseContactsContactFormDialogComponent } from '../contact-form/contact-form.component';
import { MdDialog, MdDialogRef } from '@angular/material';
import { FuseConfirmDialogComponent } from '../../../../../core/components/confirm-dialog/confirm-dialog.component';
import { FormGroup } from '@angular/forms';
import { DataSource } from '@angular/cdk/collections';
@Component({
selector : 'fuse-contacts-contact-list',

View File

@@ -256,7 +256,7 @@
</ngx-charts-bar-vertical-stacked>
</div>
<div class="mb-16" fxFlex="100" fxFlex.gt-sm="50" fxLayoutWrap>
<div class="mb-16" fxFlex="100" fxFlex.gt-sm="50" fxLayoutAlign="row" fxLayoutWrap>
<div fxLayout="column" fxFlex="100" fxFlex.gt-sm="50" fxLayoutAlign="center"
*ngFor="let widget of widgets.widget5.supporting | keys">
@@ -688,7 +688,7 @@
<!-- / CENTER -->
<!-- SIDENAV -->
<md-sidenav class="sidenav mat-sidenav-opened" align="end" opened="true" mode="side" fuseMdSidenavHelper="dashboards-right-sidenav" md-is-locked-open="gt-md">
<md-sidenav class="sidenav mat-sidenav-opened" align="end" mode="side" fuseMdSidenavHelper="dashboards-right-sidenav" md-is-locked-open="gt-md">
<div class="sidenav-content" perfect-scrollbar>
<!-- WIDGET GROUP -->

View File

@@ -3,7 +3,7 @@ import { ProjectsDashboardService } from './projects.service';
import * as shape from 'd3-shape';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { DataSource } from '@angular/cdk';
import { DataSource } from '@angular/cdk/collections';
@Component({
selector : 'fuse-project',

View File

@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { FileManagerService } from '../file-manager.service';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import { DataSource } from '@angular/cdk/collections';
@Component({
selector : 'fuse-file-list',

View File

@@ -19,7 +19,8 @@
}
}
.mat-sidenav-content {
> .mat-sidenav-content,
> .mat-drawer-content {
z-index: 1;
.center {
@@ -30,7 +31,7 @@
min-height: 160px;
max-height: 160px;
@include media-breakpoint-down('sm'){
@include media-breakpoint-down('sm') {
height: 120px;
min-height: 120px;
max-height: 120px;

View File

@@ -52,7 +52,8 @@
<md-input-container>
<textarea mdInput name="message"
placeholder="Message"
formControlName="message">
formControlName="message"
rows="6">
</textarea>
</md-input-container>

View File

@@ -8,23 +8,30 @@
padding: 0;
width: 720px;
.attachment-list {
font-size: 13px;
padding-top: 16px;
.compose-form {
.mat-input-container {
width: 100%;
}
.attachment {
background-color: rgba(0, 0, 0, 0.08);
border: 1px solid rgba(0, 0, 0, 0.16);
padding-left: 16px;
margin-top: 8px;
border-radius: 2px;
.attachment-list {
font-size: 13px;
padding-top: 16px;
.filename {
font-weight: 500;
}
.attachment {
background-color: rgba(0, 0, 0, 0.08);
border: 1px solid rgba(0, 0, 0, 0.16);
padding-left: 16px;
margin-top: 8px;
border-radius: 2px;
&:last-child {
margin-bottom: 0;
.filename {
font-weight: 500;
}
&:last-child {
margin-bottom: 0;
}
}
}
}

View File

@@ -0,0 +1,84 @@
import { FuseUtils } from '../../../../core/fuseUtils';
import { List } from './list.model';
import { Card } from './card.model';
const sampleLabels = [
{
'id' : '56027e4119ad3a5dc28b36cd',
'name' : 'Design',
'color': 'md-red-500-bg'
},
{
'id' : '5640635e19ad3a5dc21416b2',
'name' : 'App',
'color': 'md-blue-500-bg'
},
{
'id' : '6540635g19ad3s5dc31412b2',
'name' : 'Feature',
'color': 'md-green-400-bg'
}
];
const sampleMembers = [
{
id : '56027c1930450d8bf7b10758',
name : 'Alice Freeman',
avatar: 'assets/images/avatars/alice.jpg'
},
{
id : '26027s1930450d8bf7b10828',
name : 'Danielle Obrien',
avatar: 'assets/images/avatars/danielle.jpg'
},
{
id : '76027g1930450d8bf7b10958',
name : 'James Lewis',
avatar: 'assets/images/avatars/james.jpg'
},
{
id : '36027j1930450d8bf7b10158',
name : 'Vincent Munoz',
avatar: 'assets/images/avatars/vincent.jpg'
}
];
export class Board
{
name: string;
uri: string;
id: string;
settings: {
color: string,
subscribed: boolean,
cardCoverImages: boolean
};
lists: List[];
cards: Card[];
members: {
id: string,
name: string,
avatar: string
}[];
labels: {
id: string,
name: string,
color: string
}[];
constructor(board)
{
this.name = board.name || 'Untitled Board';
this.uri = board.uri || 'untitled-board';
this.id = board.id || FuseUtils.generateGUID();
this.settings = board.settings || {
color : '',
subscribed : true,
cardCoverImages: true
};
this.lists = [];
this.cards = [];
this.members = board.members || sampleMembers;
this.labels = board.labels || sampleLabels;
}
}

View File

@@ -0,0 +1,23 @@
<div class="list new-list mat-elevation-z1">
<button *ngIf="!formActive" md-button class="new-list-form-button" (click)="openForm()">
<div fxLayout="row" fxLayoutAlign="start center">
<md-icon class="md-red-bg">add</md-icon>
<span>Add a list</span>
</div>
</button>
<form *ngIf="formActive" class="new-list-form" [formGroup]="form" (submit)="onFormSubmit()"
fxFlex="1 0 auto" fxFlex="row" fxLayoutAlign="start center">
<input formControlName="name" #nameInput fxFlex placeholder="Write a list Name">
<button md-icon-button fxFlex="0 1 auto">
<md-icon>check</md-icon>
</button>
<button md-icon-button fxFlex="0 1 auto" (click)="closeForm()">
<md-icon>close</md-icon>
</button>
</form>
</div>

View File

@@ -0,0 +1,32 @@
:host {
.new-list {
border-radius: 2px;
background-color: #EEF0F2;
.new-list-form-button {
text-transform: none;
font-size: 15px;
padding: 0 16px;
height: 64px;
margin: 0;
width: 100%;
md-icon {
border-radius: 50%;
height: 40px;
width: 40px;
line-height: 40px;
margin-right: 16px;
}
}
.new-list-form {
padding: 16px;
height: 64px;
> input {
height: 100%;
}
}
}
}

View File

@@ -0,0 +1,57 @@
import { Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-add-list',
templateUrl: './add-list.component.html',
styleUrls : ['./add-list.component.scss']
})
export class FuseScrumboardBoardAddListComponent implements OnInit
{
formActive = false;
form: FormGroup;
@Output() onlistAdd = new EventEmitter();
@ViewChild('nameInput') nameInputField;
constructor(
private formBuilder: FormBuilder
)
{
}
ngOnInit()
{
}
openForm()
{
this.form = this.formBuilder.group({
name: ['']
});
this.formActive = true;
this.focusNameField();
}
closeForm()
{
this.formActive = false;
}
focusNameField()
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
{
if ( this.form.valid )
{
this.onlistAdd.next(this.form.getRawValue().name);
this.formActive = false;
}
}
}

View File

@@ -0,0 +1,86 @@
<md-sidenav-container>
<div id="board">
<!-- HEADER -->
<div class="header md-accent-bg p-16 p-sm-24" [class]="'md-'+board.settings.color+'-bg'" fxLayout="column">
<div class="header-content" fxLayout="row" fxLayoutAlign="space-between" fxFlex="1 0 auto" fxLayoutWrap>
<!-- BOARD SELECTION BUTTON -->
<div fxLayout="row" fxLayoutAlign="center center" fxFlexOrder="2" fxFlexOrder.gt-xs="1">
<button md-raised-button class="mat-accent header-boards-button"
[class]="'md-'+board.settings.color+'-700-bg'"
routerLink="/apps/scrumboard/boards"
aria-label="boards button">
<md-icon>assessment</md-icon>
<span>BOARDS</span>
</button>
</div>
<!-- / BOARD SELECTION BUTTON -->
<!-- BOARD NAME -->
<div class="header-board-name mb-8 mb-sm-0"
fxLayout="row" fxLayoutAlign="center center"
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="center center"
fxFlex="1 0 100%" fxFlex.gt-xs="1 0 auto"
fxFlexOrder="1" fxFlexOrder.gt-xs="2">
<div>
<md-icon *ngIf="board.settings.subscribed" class="board-subscribe s-16">remove_red_eye</md-icon>
<fuse-scrumboard-edit-board-name
fxFlex="1 0 auto"
[board]="board"
(onNameChanged)="onBoardNameChanged($event)">
</fuse-scrumboard-edit-board-name>
</div>
</div>
<!-- / BOARD NAME -->
<!-- TOOLBAR -->
<div class="toolbar" fxLayout="row" fxLayoutAlign="space-between center" fxFlexOrder="3">
<!-- BOARD SETTINGS BUTTON -->
<button md-icon-button (click)="settingsSidenav.toggle()"
aria-label="Settings" md-tooltip="Settings">
<md-icon>settings</md-icon>
</button>
<!-- / BOARD SETTINGS BUTTON -->
</div>
<!-- / TOOLBAR -->
</div>
</div>
<!-- / HEADER -->
<div fxFlex class="board-content-wrapper p-16 p-sm-24">
<!-- BOARD -->
<div class="board-content ngx-dnd-container p-16 p-sm-24" [class]="board.settings.color+'-100-bg'" fxLayout="row"
ngxDroppable="list" [model]="board.lists" (out)="onDrop($event)">
<!-- LIST -->
<fuse-scrumboard-board-list
class="scrumboard-board-list list-wrapper ngx-dnd-item"
ngxDraggable
*ngFor="let list of board.lists"
[model]="list"
[list]="list">
</fuse-scrumboard-board-list>
<!-- / LIST -->
<!-- NEW LIST BUTTON-->
<fuse-scrumboard-board-add-list class="new-list-wrapper" (onlistAdd)="onListAdd($event)"></fuse-scrumboard-board-add-list>
<!-- / NEW LIST BUTTON-->
</div>
<!-- / BOARD -->
</div>
<!-- primary content -->
</div>
<md-sidenav #settingsSidenav align="end">
<fuse-scrumboard-board-settings></fuse-scrumboard-board-settings>
</md-sidenav>
</md-sidenav-container>

View File

@@ -0,0 +1,132 @@
@import "src/app/core/scss/fuse";
:host {
md-sidenav-container {
width: 100%;
height: 100%;
md-sidenav {
width: 320px !important;
min-width: 320px !important;
max-width: 320px !important;
}
#board {
flex-direction: column;
display: flex;
height: 100%;
> .header {
position: relative;
min-height: 96px;
background-image: none;
z-index: 49;
.header-content {
.header-boards-button {
margin: 0;
}
.header-board-name {
font-size: 16px;
.board-subscribe {
margin-right: 8px;
}
.editable-buttons {
md-icon {
color: #FFFFFF !important;
}
}
}
.right-side {
> .md-button:last-child {
margin-right: 0;
}
}
}
}
#board-selector {
position: absolute;
top: 96px;
right: 0;
left: 0;
height: 192px;
z-index: 48;
padding: 24px;
opacity: 1;
.board-list-item {
width: 128px;
height: 192px;
padding: 16px;
cursor: pointer;
position: relative;
.board-name {
text-align: center;
padding: 16px 0;
}
.selected-icon {
position: absolute;
top: 0;
left: 50%;
width: 32px;
height: 32px;
margin-left: -16px;
border-radius: 50%;
text-align: center;
color: white;
i {
line-height: 32px !important;
}
}
&.add-new-board {
opacity: 0.6;
}
}
}
.board-content-wrapper {
position: relative;
.board-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 100%;
background: #E5E7E8;
overflow-y: hidden;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
.list-sortable-placeholder {
background: rgba(0, 0, 0, 0.06);
margin-right: 24px;
}
.new-list-wrapper {
width: 344px;
min-width: 344px;
max-width: 344px;
padding-right: 24px;
}
}
}
}
}
}

View File

@@ -0,0 +1,60 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ScrumboardService } from '../scrumboard.service';
import { Subscription } from 'rxjs/Subscription';
import { Location } from '@angular/common';
import { List } from '../list.model';
@Component({
selector : 'fuse-scrumboard-board',
templateUrl: './board.component.html',
styleUrls : ['./board.component.scss']
})
export class FuseScrumboardBoardComponent implements OnInit, OnDestroy
{
board: any;
onBoardChanged: Subscription;
constructor(
private route: ActivatedRoute,
private location: Location,
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
});
}
onListAdd(newListName)
{
if ( newListName === '' )
{
return;
}
this.scrumboardService.addList(new List({name: newListName}));
}
onBoardNameChanged(newName)
{
this.scrumboardService.updateBoard();
this.location.go('/apps/scrumboard/boards/' + this.board.id + '/' + this.board.uri);
}
onDrop(ev)
{
this.scrumboardService.updateBoard();
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,452 @@
<md-toolbar *ngIf="card" md-dialog-title class="md-accent-bg m-0">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<!-- DUE DATE -->
<div class="due-date" fxFlex="0 1 auto">
<button *ngIf="card.due" md-icon-button class="" [mdMenuTriggerFor]="dueDateMenu">
<md-icon>today</md-icon>
</button>
<md-menu #dueDateMenu="mdMenu" [overlapTrigger]="false">
<button md-menu-item (click)="removeDueDate()">Remove Due Date</button>
</md-menu>
<md2-datepicker *ngIf="!card.due" [(ngModel)]="card.due" openOnFocus="true" placeholder="Set Date/Time" type="datetime"></md2-datepicker>
</div>
<!-- / DUE DATE -->
<!-- LABELS -->
<div class="labels" fxFlex="0 1 auto">
<button md-icon-button [mdMenuTriggerFor]="labelsMenu">
<md-icon>label</md-icon>
</button>
<md-menu #labelsMenu="mdMenu" [overlapTrigger]="false" class="scrumboard-labels-menu">
<fuse-scrumboard-label-selector [card]="card" (onCardLabelsChange)="updateCard()"></fuse-scrumboard-label-selector>
</md-menu>
</div>
<!-- / LABELS -->
<!-- MEMBERS -->
<div class="members" fxFlex="0 1 auto">
<button md-icon-button class="" [mdMenuTriggerFor]="membersMenu">
<md-icon>account_circle</md-icon>
</button>
<md-menu #membersMenu="mdMenu" [overlapTrigger]="false">
<div fxFlex fxLayout="column" class="scrumboard-members-menu" (click)="$event.stopPropagation()">
<md-checkbox class="member px-12" [checked]="card.idMembers.indexOf(member.id) > -1"
*ngFor="let member of board.members"
(change)="toggleInArray(member.id, card.idMembers);updateCard()">
<div fxLayout="row" fxLayoutAlign="start center">
<img [alt]="member.name" [src]=" member.avatar" class="avatar"/>
<p class="member-name">{{ member.name }}</p>
</div>
</md-checkbox>
</div>
</md-menu>
</div>
<!-- / MEMBERS -->
<!-- ATTACHMENT -->
<button md-icon-button aria-label="Attachment">
<md-icon>attachment</md-icon>
</button>
<!-- / ATTACHMENT -->
<!-- CHECKLIST -->
<div class="due-date " fxFlex="0 1 auto">
<button md-icon-button class="" [mdMenuTriggerFor]="checklistMenu" #checklistMenuTrigger="mdMenuTrigger" (onMenuOpen)="onChecklistMenuOpen()">
<md-icon>check_box</md-icon>
</button>
<md-menu #checklistMenu="mdMenu" [overlapTrigger]="false">
<form class="px-16 py-8" #newChecklistForm="ngForm" (submit)="addChecklist(newChecklistForm)" (click)="$event.stopPropagation()"
fxLayout="column" fxLayoutAlign="start end">
<md-input-container floatPlaceholder="never" (click)="$event.stopPropagation()" fxFlex>
<input #newCheckListTitleField mdInput ngModel #checklistTitle="ngModel" name="checklistTitle" placeholder="Checklist title" required>
</md-input-container>
<button md-raised-button class="mat-accent" aria-label="Add Checklist" [disabled]="!newChecklistForm.valid">Add Checklist</button>
</form>
</md-menu>
</div>
<!-- / CHECKLIST -->
<!-- SUBSCRIBE -->
<div class="subscribe " fxFlex="0 1 auto">
<button md-icon-button class="" [mdMenuTriggerFor]="subscribeMenu">
<md-icon>remove_red_eye</md-icon>
</button>
<md-menu #subscribeMenu="mdMenu" [overlapTrigger]="false">
<button *ngIf="card.subscribed" md-menu-item (click)="toggleSubscribe()">
Unsubscribe
</button>
<button *ngIf="!card.subscribed" md-menu-item (click)="toggleSubscribe()">
Subscribe
</button>
</md-menu>
</div>
<!-- / SUBSCRIBE -->
<!-- OPTIONS -->
<div class="options " fxFlex="0 1 auto">
<button md-icon-button class="" [mdMenuTriggerFor]="optionsMenu">
<md-icon>more_horiz</md-icon>
</button>
<md-menu #optionsMenu="mdMenu" [overlapTrigger]="false">
<button md-menu-item (click)="removeCard()">
Remove Card
</button>
</md-menu>
</div>
<!-- / OPTIONS -->
</div>
<!-- CLOSE DIALOG BUTTON -->
<button md-icon-button (click)="dialogRef.close()" aria-label="Close Dialog">
<md-icon>close</md-icon>
</button>
<!-- / CLOSE DIALOG BUTTON -->
</div>
</md-toolbar>
<div *ngIf="card" md-dialog-content class="p-24 m-0" perfect-scrollbar>
<div fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="space-between center"
fxLayout.xs="column" fxLayoutAlign="center center">
<!-- BREADCRUMB -->
<div class="card-breadcrumb mb-16 mb-sm-0" fxLayout="row" fxLayoutAlign="start center">
<span>{{board.name}}</span>
<md-icon class="s-20">chevron_right</md-icon>
<span>{{list.name}}</span>
</div>
<!-- / BREADCRUMB -->
<!-- DUE DATE -->
<div *ngIf="card.due" class="due-date" fxLayout="row" fxLayoutAlign="start center">
<md2-datepicker class="picker ml-8" [(ngModel)]="card.due" openOnFocus="true" type="datetime" format="dd/MM/y H:mm"></md2-datepicker>
<button md-icon-button class="remove-due-date" (click)="removeDueDate()">
<md-icon class="s-16">close</md-icon>
</button>
</div>
<!-- / DUE DATE -->
</div>
<!-- NAME -->
<div fxLayout="row" fxLayoutAlign="start center">
<md-icon *ngIf="card.subscribed" class="card-subscribe s-20 mr-12">remove_red_eye</md-icon>
<div class="card-name">
<md-input-container floatPlaceholder="never" fxFlex>
<input mdInput [(ngModel)]="card.name" placeholder="Title" required (change)="updateCard()">
</md-input-container>
</div>
</div>
<!-- / NAME -->
<!-- DESCRIPTION -->
<div class="description">
<md-input-container fxFlex>
<textarea mdInput [(ngModel)]="card.description" placeholder="Description" columns="1" md-maxlength="150" max-rows="4" (change)="updateCard()"></textarea>
</md-input-container>
</div>
<!-- / DESCRIPTION -->
<!-- SECTIONS -->
<div class="sections">
<!-- LABELS SECTION -->
<div *ngIf="card.idLabels[0] || card.idMembers[0]" class="section"
fxLayout="column" fxLayout.gt-xs="row">
<div *ngIf="card.idLabels[0]" fxFlex class="labels">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">label</md-icon>
<span class="section-title">Labels</span>
</div>
<div class="section-content">
<md-chip-list class="label-chips">
<md-chip class="label-chip mb-4"
*ngFor="let labelId of card.idLabels"
[class]="board.labels | getById:labelId:'color'"
fxLayout="row" fxLayoutAlign="start center">
<span>{{board.labels|getById:labelId:'name'}}</span>
<md-icon class="ml-8 s-16 chip-remove" (click)="toggleInArray(labelId, card.idLabels);updateCard()">close</md-icon>
</md-chip>
</md-chip-list>
</div>
</div>
<div *ngIf="card.idMembers[0]" fxFlex class="members">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">supervisor_account</md-icon>
<span class="section-title">Members</span>
</div>
<div class="section-content">
<md-chip-list class="member-chips">
<md-chip class="member-chip mb-4" *ngFor="let memberId of card.idMembers"
fxLayout="row" fxLayoutAlign="start center">
<img class="member-chip-avatar" [src]="board.members | getById:memberId:'avatar'"
[md-tooltip]="board.members | getById:memberId:'name'">
<md-icon class="ml-8 s-16 chip-remove" (click)="toggleInArray(memberId, card.idMembers);updateCard()">close</md-icon>
</md-chip>
</md-chip-list>
</div>
</div>
</div>
<!-- / LABELS SECTION -->
<!-- ATTACHMENTS SECTION -->
<div *ngIf="card.attachments[0]" class="section">
<div class="attachments">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">attachment</md-icon>
<span class="section-title">Attachments</span>
</div>
<div class="section-content">
<div class="attachment" *ngFor="let item of card.attachments" [ngSwitch]="item.type">
<div *ngSwitchCase="'image'"
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center"
fxLayout="column" fxLayoutAlign="center start">
<div class="attachment-preview mat-elevation-z2"
[ngStyle]="{'background-image': 'url('+item.src+')'}">
</div>
<div class="attachment-content" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center">
<span class="attachment-name">{{item.name}}</span>
<md-icon *ngIf="card.idAttachmentCover === item.id"
class="yellow-700-fg attachment-is-cover s-20">star
</md-icon>
</div>
<span class="attachment-time">{{item.time}}</span>
<div>
<button md-raised-button class="attachment-actions-button" [mdMenuTriggerFor]="attachmentActionsMenu">
<span fxLayout="row" fxLayoutAlign="center center">
<span>Actions</span>
<md-icon class="s-20">arrow_drop_down</md-icon>
</span>
</button>
<md-menu #attachmentActionsMenu="mdMenu">
<button md-menu-item (click)="toggleCoverImage(item.id)">
<span *ngIf="card.idAttachmentCover !== item.id">Make Cover</span>
<span *ngIf="card.idAttachmentCover === item.id">Remove Cover</span>
</button>
<button md-menu-item (click)="removeAttachment(item)">
Remove Attachment
</button>
</md-menu>
</div>
</div>
</div>
<div *ngSwitchCase="'link'" fxLayout="row">
<div class="attachment-preview mat-elevation-z2" fxLayout="column"
fxLayoutAlign="center center">
<span>LINK</span>
</div>
<div class="attachment-content" fxLayout="column">
<span class="attachment-url">{{item.url}}</span>
<span class="attachment-time">{{item.time}}</span>
</div>
</div>
</div>
<button md-button class="add-attachment-button" aria-label="add attachment">
<div fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">add</md-icon>
<span>Add an attachment</span>
</div>
</button>
</div>
</div>
</div>
<!-- / ATTACHMENTS SECTION -->
<!-- CHECKLISTS SECTION -->
<div class="section" *ngFor="let checklist of card.checklists">
<div class="checklist">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">check_box</md-icon>
<span fxFlex class="section-title">{{checklist.name}}</span>
<div>
<button md-icon-button class="checklist-actions-button" [mdMenuTriggerFor]="checklistActionsMenu">
<md-icon class="s-20">more_vert</md-icon>
</button>
<md-menu #checklistActionsMenu="mdMenu">
<button md-menu-item (click)="removeChecklist(checklist)">
<md-icon>delete</md-icon>
<span>Remove Checklist</span>
</button>
</md-menu>
</div>
</div>
<div class="section-content">
<div class="checklist-progress" fxLayout="row" fxLayoutAlign="start center">
<span class="checklist-progress-value">
{{checklist.checkItemsChecked}} / {{checklist.checkItems.length}}
</span>
<md-progress-bar class="mat-accent checklist-progressbar" mode="determinate"
value="{{100 * checklist.checkItemsChecked / checklist.checkItems.length}}">
</md-progress-bar>
</div>
<div class="check-items">
<div class="check-item" *ngFor="let checkItem of checklist.checkItems" fxLayout="row" fxLayoutAlign="space-between center">
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<md-checkbox [(ngModel)]="checkItem.checked"
(change)="updateCheckedCount(checklist)"
aria-label="{{checkItem.name}}">
</md-checkbox>
<md-input-container fxFlex class="mx-12">
<input mdInput [(ngModel)]="checkItem.name">
</md-input-container>
</div>
<button md-icon-button class="checklist-actions-button" (click)="removeChecklistItem(checkItem, checklist)">
<md-icon class="s-20">delete</md-icon>
</button>
</div>
</div>
<form #newCheckItemForm="ngForm" (submit)="addCheckItem(newCheckItemForm,checklist)" name="newCheckItemForm" class="new-check-item-form"
fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="row" fxLayoutAlign="start center" fxFlex>
<md-icon class="s-20">add</md-icon>
<md-input-container class="no-errors-spacer mx-12" fxFlex>
<input mdInput ngModel #checkItem="ngModel" name="checkItem" placeholder="Add an item" autocomplete="off">
</md-input-container>
</div>
<button md-raised-button
[disabled]="!newCheckItemForm.valid || newCheckItemForm.pristine"
class="mat-accent" aria-label="Add">
<span>Add</span>
</button>
</form>
</div>
</div>
</div>
<!-- / CHECKLISTS SECTION -->
<!-- COMMENTS SECTION -->
<div class="section">
<div class="comments">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">comment</md-icon>
<span class="section-title">Comments</span>
</div>
<div class="section-content">
<form name="cardCommentForm"
#newCommentForm="ngForm" (submit)="addNewComment(newCommentForm)"
ng-submit="vm.addNewComment(vm.newCommentText); vm.newCommentText =''"
class="comment new-comment" fxLayout="column" fxLayoutAlign="start" no-validate>
<div fxLayout="row">
<img class="comment-member-avatar" src="assets/images/avatars/profile.jpg">
<md-input-container fxFlex>
<input mdInput name="newComment" ngModel #newComment="ngModel"
placeholder="Write a comment.." required>
</md-input-container>
</div>
<div fxLayout="row" fxLayoutAlign="end center">
<button md-raised-button class="mat-accent"
[disabled]="!newCommentForm.valid || newCommentForm.pristine"
aria-label="Add">
<span>Add</span>
</button>
</div>
</form>
<div class="comment" fxLayout="row" *ngFor="let comment of card.comments">
<img class="comment-member-avatar"
[src]="board.members | getById: comment.idMember:'avatar'">
<div fxLayout="column">
<div class="comment-member-name">
{{board.members | getById: comment.idMember:'name'}}
</div>
<div class="comment-bubble">{{comment.message}}</div>
<div class="comment-time secondary-text">{{comment.time}}</div>
</div>
</div>
</div>
</div>
</div>
<!-- / COMMENTS SECTION -->
<!-- ACTIVITIES SECTION -->
<div *ngIf="card.activities[0]" class="section">
<div class="activities">
<div class="section-header" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-20">list</md-icon>
<span class="section-title">Activity</span>
</div>
<div class="section-content">
<div class="activity" fxLayout="row" fxLayoutAlign="start center" *ngFor="let activity of card.activities">
<img class="activity-member-avatar"
[src]="board.members| getById:activity.idMember:'avatar'">
<div class="activity-member-name">{{board.members| getById:activity.idMember:'name'}}</div>
<div class="activity-message">{{activity.message}}</div>
<div class="activity-time secondary-text">{{activity.time}}</div>
</div>
</div>
</div>
</div>
<!-- / ACTIVITIES SECTION -->
</div>
<!-- / SECTIONS -->
</div>

View File

@@ -0,0 +1,437 @@
@import "src/app/core/scss/fuse";
:host {
display: flex;
flex-direction: column;
}
.scrumboard-card-dialog {
.mat-dialog-container {
padding: 0;
width: 720px;
.mat-toolbar {
.due-date {
md2-datepicker {
min-width: initial;
.md2-datepicker-trigger {
padding: 0;
.md2-datepicker-button {
display: block;
position: relative;
top: 0;
left: 0;
line-height: normal;
}
.md2-datepicker-input {
display: none;
}
}
}
}
}
.mat-dialog-content {
position: relative;
background-color: #F5F5F5;
.card-breadcrumb {
font-weight: 500;
font-size: 14px;
}
.card-subscribe {
margin-right: 8px;
color: rgba(0, 0, 0, 0.6);
}
.picker {
width: 140px;
min-width: 140px;
}
.card-name {
width: 100%;
font-size: 22px;
@include media-breakpoint(xs) {
font-size: 14px;
}
}
.due-date {
md2-datepicker {
width: 180px;
min-width: 180px;
.md2-datepicker-trigger {
padding-top: 5px;
padding-bottom: 5px;
.md2-datepicker-button {
top: 0;
}
.md2-datepicker-input {
min-width: initial;
}
}
}
.remove-due-date {
}
}
.description {
padding-bottom: 16px;
}
.sections {
.section {
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
margin-bottom: 32px;
&:last-child {
border-bottom: none;
margin-bottom: 0;
.section-content {
padding-bottom: 0;
}
}
.section-header {
font-size: 16px;
md-icon {
margin-right: 8px;
color: rgba(0, 0, 0, 0.6);
}
.section-title {
font-weight: 500;
}
}
.section-content {
padding: 24px 0 32px 0;
}
.labels {
.section-content {
padding: 8px 0 32px 0;
}
.label-chips {
box-shadow: none;
padding: 0;
.label-chip {
display: block;
.chip-remove {
cursor: pointer;
}
}
}
}
.members {
.section-content {
padding: 8px 0 32px 0;
}
.member-chips {
box-shadow: none;
padding: 0;
.member-chip {
padding: 4px 12px 4px 4px;
.member-chip-avatar {
width: 32px;
border-radius: 50%;
}
.chip-remove {
cursor: pointer;
}
}
}
}
.attachments {
.attachment {
margin-bottom: 16px;
.attachment-preview {
background-color: #EEF0F2;
width: 160px;
height: 128px;
background-size: contain;
background-position: 50% 50%;
background-repeat: no-repeat;
margin-right: 24px;
font-weight: 500;
color: rgba(0, 0, 0, 0.6);
}
.attachment-content {
.attachment-url,
.attachment-name {
font-weight: 500;
font-size: 16px;
}
.attachment-is-cover {
margin-left: 6px;
}
.attachment-time {
color: rgba(0, 0, 0, 0.6);
}
.attachment-actions-button {
background-color: white;
text-transform: capitalize;
margin: 12px 0 0 0;
padding-left: 12px;
md-icon {
margin-left: 8px;
color: rgba(0, 0, 0, 0.6);
}
}
}
}
.add-attachment-button {
margin: 0;
md-icon {
color: rgba(0, 0, 0, 0.6);
margin-right: 8px;
}
span {
font-weight: 500;
text-transform: capitalize;
}
}
}
.checklist {
.checklist-progress {
margin-bottom: 16px;
.checklist-progress-value {
margin-right: 12px;
font-weight: 500;
white-space: nowrap;
font-size: 14px;
}
.checklist-progressbar {
}
}
.editable-wrap {
flex: 1
}
.check-items {
.check-item {
md-checkbox {
margin-bottom: 0;
.md-label {
font-size: 14px;
}
&.md-checked {
.md-label {
text-decoration: line-through;
color: rgba(0, 0, 0, 0.6);
}
}
}
}
}
.new-check-item-form {
padding-top: 16px;
md-input-container {
margin: 0;
}
.md-button {
margin: 0 0 0 16px;
}
}
}
.comments {
.comment {
margin-bottom: 16px;
.comment-member-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 16px;
}
.comment-member-name {
font-size: 14px;
font-weight: 500;
}
.comment-time {
font-size: 12px;
}
.comment-bubble {
position: relative;
padding: 8px;
background-color: white;
border: 1px solid rgb(220, 223, 225);
font-size: 14px;
margin: 4px 0;
&:after,
&:before {
content: ' ';
position: absolute;
width: 0;
height: 0;
}
&:after {
left: -7px;
right: auto;
top: 0px;
bottom: auto;
border: 11px solid;
border-color: white transparent transparent transparent;
}
&:before {
left: -9px;
right: auto;
top: -1px;
bottom: auto;
border: 8px solid;
border-color: rgb(220, 223, 225) transparent transparent transparent;
}
}
&.new-comment {
md-input-container {
margin: 0;
}
}
}
}
.activities {
.activity {
margin-bottom: 12px;
.activity-member-avatar {
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 16px;
}
.activity-member-name {
font-size: 14px;
font-weight: 500;
margin-right: 8px;
}
.activity-message {
font-size: 14px;
margin-right: 8px;
}
.activity-time {
font-size: 12px;
}
}
}
}
}
}
}
}
.scrumboard-members-menu {
width: 240px;
.mat-checkbox-layout,
.mat-checkbox-label {
display: flex;
flex: 1;
}
}
.scrumboard-labels-menu {
.mat-menu-content {
padding-bottom: 0;
.mat-checkbox-layout,
.mat-checkbox-label {
display: flex;
flex: 1;
}
.views {
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
width: 240px;
min-width: 240px;
max-width: 240px;
min-height: 240px;
.view {
position: absolute;
width: 240px;
height: 100%;
bottom: 0;
left: 0;
right: 0;
top: 0;
> .header {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
}
}
}
}

View File

@@ -0,0 +1,277 @@
import { Component, Inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { MD_DIALOG_DATA, MdDialog, MdDialogRef, MdMenuTrigger } from '@angular/material';
import { Subscription } from 'rxjs/Subscription';
import { ScrumboardService } from '../../../scrumboard.service';
import { NgForm } from '@angular/forms/src/forms';
import { FuseUtils } from '../../../../../../../core/fuseUtils';
import { FuseConfirmDialogComponent } from '../../../../../../../core/components/confirm-dialog/confirm-dialog.component';
@Component({
selector : 'fuse-scrumboard-board-card-dialog',
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
{
card: any;
board: any;
list: any;
onBoardChanged: Subscription;
toggleInArray = FuseUtils.toggleInArray;
@ViewChild('checklistMenuTrigger') checklistMenu: MdMenuTrigger;
@ViewChild('newCheckListTitleField') newCheckListTitleField;
confirmDialogRef: MdDialogRef<FuseConfirmDialogComponent>;
constructor(
public dialogRef: MdDialogRef<FuseScrumboardCardDialogComponent>,
@Inject(MD_DIALOG_DATA) private data: any,
public dialog: MdDialog,
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
this.card = this.board.cards.find((_card) => {
return this.data.cardId === _card.id;
});
this.list = this.board.lists.find((_list) => {
return this.data.listId === _list.id;
});
});
}
/**
* Remove Due date
*/
removeDueDate()
{
this.card.due = '';
this.updateCard();
}
/**
* Toggle Subscribe
*/
toggleSubscribe()
{
this.card.subscribed = !this.card.subscribed;
this.updateCard();
}
/**
* Toggle Cover Image
* @param attachmentId
*/
toggleCoverImage(attachmentId)
{
if ( this.card.idAttachmentCover === attachmentId )
{
this.card.idAttachmentCover = '';
}
else
{
this.card.idAttachmentCover = attachmentId;
}
this.updateCard();
}
/**
* Remove Attachment
* @param attachment
*/
removeAttachment(attachment)
{
if ( attachment.id === this.card.idAttachmentCover )
{
this.card.idAttachmentCover = '';
}
this.card.attachments.splice(this.card.attachments.indexOf(attachment), 1);
this.updateCard();
}
/**
* Remove Checklist
* @param checklist
*/
removeChecklist(checklist)
{
this.card.checklists.splice(this.card.checklists.indexOf(checklist), 1);
this.updateCard();
}
/**
* Update Checked Count
* @param list
*/
updateCheckedCount(list)
{
const checkItems = list.checkItems;
let checkedItems = 0;
let allCheckedItems = 0;
let allCheckItems = 0;
for ( const checkItem of checkItems )
{
if ( checkItem.checked )
{
checkedItems++;
}
}
list.checkItemsChecked = checkedItems;
for ( const item of this.card.checklists )
{
allCheckItems += item.checkItems.length;
allCheckedItems += item.checkItemsChecked;
}
this.card.checkItems = allCheckItems;
this.card.checkItemsChecked = allCheckedItems;
this.updateCard();
}
/**
* Remove Checklist Item
* @param checkItem
* @param checklist
*/
removeChecklistItem(checkItem, checklist)
{
checklist.checkItems.splice(checklist.checkItems.indexOf(checkItem), 1);
this.updateCheckedCount(checklist);
this.updateCard();
}
/**
* Add Check Item
* @param {NgForm} form
* @param checkList
*/
addCheckItem(form: NgForm, checkList)
{
const checkItemVal = form.value.checkItem;
if ( !checkItemVal || checkItemVal === '' )
{
return;
}
const newCheckItem = {
'name' : checkItemVal,
'checked': false
};
checkList.checkItems.push(newCheckItem);
this.updateCheckedCount(checkList);
form.setValue({checkItem: ''});
this.updateCard();
}
/**
* Add Checklist
* @param {NgForm} form
*/
addChecklist(form: NgForm)
{
this.card.checklists.push({
id : FuseUtils.generateGUID(),
name : form.value.checklistTitle,
checkItemsChecked: 0,
checkItems : []
});
form.setValue({checklistTitle: ''});
form.resetForm();
this.checklistMenu.closeMenu();
this.updateCard();
}
/**
* On Checklist Menu Open
*/
onChecklistMenuOpen()
{
setTimeout(() => {
this.newCheckListTitleField.nativeElement.focus();
});
}
/**
* Add New Comment
* @param {NgForm} form
*/
addNewComment(form: NgForm)
{
const newCommentText = form.value.newComment;
const newComment = {
idMember: '36027j1930450d8bf7b10158',
message : newCommentText,
time : 'now'
};
this.card.comments.unshift(newComment);
form.setValue({newComment: ''});
this.updateCard();
}
/**
* Remove Card
*/
removeCard()
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete the card?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
this.dialogRef.close();
this.scrumboardService.removeCard(this.card.id, this.list.id);
}
});
}
/**
* Update Card
*/
updateCard()
{
this.scrumboardService.updateCard(this.card);
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,71 @@
<div [ngSwitch]="labelsMenuView" class="views" (click)="$event.stopPropagation()">
<div class="view " *ngSwitchCase="'labels'" [@slideInLeft] fxFlex fxLayout="column">
<div class="header mb-12 pb-4 px-8" fxLayout="row" fxLayoutAlign="space-between center">
<div>Labels</div>
<button md-button (click)="labelsMenuView ='add'">
<md-icon class="s-16">add</md-icon>
<span>Add</span>
</button>
</div>
<div fxFlex fxLayout="column" perfect-scrollbar>
<div class="label pl-12 mx-8 mb-8" *ngFor="let label of board.labels" fxFlex="0 0 auto" fxLayout="row" fxFlexAlign="space-between center"
[class]="label.color">
<md-checkbox fxFlex fxLayout="row" fxLayoutAlign="start center" [checked]="card.idLabels.indexOf(label.id) > -1"
(change)="toggleInArray(label.id, card.idLabels);cardLabelsChanged()">
{{label.name}}
</md-checkbox>
<button md-icon-button>
<md-icon class="s-16" (click)="labelsMenuView ='edit';selectedLabel = label">mode_edit</md-icon>
</button>
</div>
</div>
</div>
<div class="view px-8" *ngSwitchCase="'edit'" [@slideInRight] fxFlex fxLayout="column">
<div class="header mb-12 pb-4" fxLayout="row" fxLayoutAlign="space-between center">
<div>Edit Label</div>
<button md-icon-button (click)="labelsMenuView ='labels'">
<md-icon class="s-16">arrow_back</md-icon>
</button>
</div>
<div fxLayout="row" fxLayoutAlign="space-between center">
<md-input-container>
<input mdInput placeholder="Name" [(ngModel)]="selectedLabel.name" (change)="onLabelChange()">
</md-input-container>
<fuse-material-color-picker [(selectedClass)]="selectedLabel.color" class="ml-8" (change)="$event.preventDefault;onLabelChange()"></fuse-material-color-picker>
</div>
</div>
<div class="view px-8" *ngSwitchCase="'add'" [@slideInRight] fxFlex fxLayout="column">
<div class="header mb-12 pb-4" fxLayout="row" fxLayoutAlign="space-between center">
<div>Add Label</div>
<button md-icon-button (click)="labelsMenuView ='labels'">
<md-icon class="s-16">arrow_back</md-icon>
</button>
</div>
<form (submit)="addNewLabel()" #newLabelForm="ngForm" fxFlex fxLayout="column" fxLayoutAlign="start end">
<div class="w-100-p" fxFlex="0 1 auto" fxLayout="row" fxLayoutAlign="space-between center">
<md-input-container fxFlex>
<input mdInput placeholder="Name" [(ngModel)]="newLabel.name" name="labelName" required>
</md-input-container>
<fuse-material-color-picker [(selectedClass)]="newLabel.color" name="labelColor" class="ml-8"></fuse-material-color-picker>
</div>
<button md-raised-button class="mat-accent mt-16" [disabled]="!newLabelForm.valid">Add</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,37 @@
.scrumboard-labels-menu {
.mat-menu-content {
padding-bottom: 0;
.mat-checkbox-layout,
.mat-checkbox-label {
display: flex;
flex: 1;
}
.views {
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
width: 240px;
min-width: 240px;
max-width: 240px;
min-height: 240px;
.view {
position: absolute;
width: 240px;
height: 100%;
bottom: 0;
left: 0;
right: 0;
top: 0;
> .header {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
}
}
}
}

View File

@@ -0,0 +1,70 @@
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { ScrumboardService } from '../../../../scrumboard.service';
import { FuseUtils } from '../../../../../../../../core/fuseUtils';
import { Animations } from '../../../../../../../../core/animations';
@Component({
selector : 'fuse-scrumboard-label-selector',
templateUrl : './label-selector.component.html',
styleUrls : ['./label-selector.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : [Animations.slideInLeft, Animations.slideInRight]
})
export class FuseScrumboardLabelSelectorComponent implements OnInit, OnDestroy
{
board: any;
@Input('card') card: any;
@Output() onCardLabelsChange = new EventEmitter();
labelsMenuView = 'labels';
selectedLabel: any;
newLabel = {
'id' : '',
'name' : '',
'color': 'md-blue-400-bg'
};
toggleInArray = FuseUtils.toggleInArray;
onBoardChanged: Subscription;
constructor(
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
});
}
cardLabelsChanged()
{
this.onCardLabelsChange.next();
}
onLabelChange()
{
this.scrumboardService.updateBoard();
}
addNewLabel()
{
this.newLabel.id = FuseUtils.generateGUID();
this.board.labels.push(Object.assign({}, this.newLabel));
this.newLabel.name = '';
this.labelsMenuView = 'labels';
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,21 @@
<div *ngIf="!formActive" class="board-name" fxFlex="1 0 auto" fxLayout="row" fxLayoutAlign="start center">
<span>{{board.name}}</span>
<button md-icon-button (click)="openForm()">
<md-icon class="s-16">edit_mode</md-icon>
</button>
</div>
<form [formGroup]="form" (submit)="onFormSubmit()"
class="board-name-form" fxFlex="1 0 auto"
*ngIf="formActive" fxFlex="row">
<input formControlName="name" #nameInput fxFlex="1 0 auto" placeholder="Write a board name">
<button md-icon-button fxFlex="0 1 auto">
<md-icon>check</md-icon>
</button>
<button md-icon-button fxFlex="0 1 auto" (click)="closeForm()">
<md-icon>close</md-icon>
</button>
</form>

View File

@@ -0,0 +1,8 @@
:host {
.board-name {
text-overflow: ellipsis;
overflow: hidden;
font-size: 15px;
font-weight: 500;
}
}

View File

@@ -0,0 +1,61 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-edit-board-name',
templateUrl: './edit-board-name.component.html',
styleUrls : ['./edit-board-name.component.scss']
})
export class FuseScrumboardEditBoardNameComponent implements OnInit
{
formActive = false;
form: FormGroup;
@Input() board;
@Output() onNameChanged = new EventEmitter();
@ViewChild('nameInput') nameInputField;
constructor(
private formBuilder: FormBuilder
)
{
}
ngOnInit()
{
}
openForm()
{
this.form = this.formBuilder.group({
name: [this.board.name]
});
this.formActive = true;
this.focusNameField();
}
closeForm()
{
this.formActive = false;
}
focusNameField()
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
{
if ( this.form.valid )
{
this.board.name = this.form.getRawValue().name;
this.board.uri = encodeURIComponent(this.board.name).replace(/%20/g, '-').toLowerCase();
this.onNameChanged.next(this.board.name);
this.formActive = false;
}
}
}

View File

@@ -0,0 +1,30 @@
<div *ngIf="!formActive" class="add-card-button"
(click)="openForm()"
fxLayout="row" fxLayoutAlign="start center">
<div>
<md-icon class="s-20">add</md-icon>
</div>
<span>Add a card</span>
</div>
<div *ngIf="formActive" class="add-card-form-wrapper">
<form [formGroup]="form" (submit)="onFormSubmit()" class="add-card-form" fxLayout="column">
<md-input-container fxFlex floatPlaceholder="never" >
<input #nameInput mdInput formControlName="name" placeholder="Card title" autocomplete="off" required>
</md-input-container>
<div class="pl-8" fxLayout="row" fxLayoutAlign="space-between center">
<button md-raised-button class="add-button mat-accent" aria-label="add"
[disabled]="form.invalid">
<span>Add</span>
</button>
<button md-icon-button (click)="closeForm()" class="cancel-button" aria-label="cancel">
<md-icon>close</md-icon>
</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,39 @@
:host {
.add-card-button {
position: relative;
height: 48px;
min-height: 48px;
padding: 0 16px;
text-align: left;
text-transform: none;
font-weight: 500;
font-size: 14px;
background-color: #DCDFE2;
cursor: pointer;
border-radius: 2px;
md-icon {
margin-right: 8px;
color: rgba(0, 0, 0, 0.6);
}
}
.add-card-form-wrapper {
background-color: #DCDFE2;
.add-card-form {
z-index: 999;
background: white;
display: block;
position: relative;
padding: 8px;
border-top: 1px solid rgba(0, 0, 0, 0.12);
md-input-container {
width: 100%;
margin: 0;
padding: 12px 8px;
}
}
}
}

View File

@@ -0,0 +1,57 @@
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-add-card',
templateUrl: './add-card.component.html',
styleUrls : ['./add-card.component.scss']
})
export class FuseScrumboardBoardAddCardComponent implements OnInit
{
formActive = false;
form: FormGroup;
@Output() onCardAdd = new EventEmitter();
@ViewChild('nameInput') nameInputField;
constructor(
private formBuilder: FormBuilder
)
{
}
ngOnInit()
{
}
openForm()
{
this.form = this.formBuilder.group({
name: ''
});
this.formActive = true;
this.focusNameField();
}
closeForm()
{
this.formActive = false;
}
focusNameField()
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
{
if ( this.form.valid )
{
const cardName = this.form.getRawValue().name;
this.onCardAdd.next(cardName);
this.formActive = false;
}
}
}

View File

@@ -0,0 +1,124 @@
<!-- CARD COVER -->
<div *ngIf="board.settings.cardCoverImages && card.idAttachmentCover"
class="list-card-cover">
<img [src]="card.attachments | getById:card.idAttachmentCover:'src'">
</div>
<!-- / CARD COVER -->
<!-- CARD DETAILS -->
<div class="list-card-details">
<!-- CARD SORT HANDLE -->
<div class="list-card-sort-handle">
<md-icon md-font-icon="icon-cursor-move" class="icon s16"></md-icon>
</div>
<!-- /CARD SORT HANDLE -->
<!-- CARD LABELS -->
<div *ngIf="card.idLabels.length > 0"
class="list-card-labels"
fxLayout="row" layout-wrap>
<span class="list-card-label"
[ngClass]="board.labels | getById:labelId:'color'"
*ngFor="let labelId of card.idLabels"
[md-tooltip]="board.labels | getById:labelId:'name'">
</span>
</div>
<!-- / CARD LABELS -->
<!-- CARD NAME -->
<div class="list-card-name">{{card.name}}</div>
<!-- / CARD NAME -->
<div *ngIf="card.due || card.checkItems"
class="list-card-badges" fxLayout="row" fxLayoutAlign="start center">
<!-- CARD DUE -->
<span class="badge due-date"
[ngClass]="{'overdue': isOverdue(card.due)}"
*ngIf="card.due" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-16">access_time</md-icon>
<span>{{card.due | date:'mediumDate'}}</span>
</span>
<!-- / CARD DUE -->
<!-- CARD CHECK ITEMS STATUS -->
<span *ngIf="card.checkItems"
class="badge check-items"
[ngClass]="{'completed': card.checkItemsChecked === card.checkItems}"
fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-16">check_circle</md-icon>
<span>{{card.checkItemsChecked}}</span>
<span>/</span>
<span>{{card.checkItems}}</span>
</span>
<!-- / CARD CHECK ITEMS STATUS -->
</div>
<!-- CARD MEMBERS -->
<div *ngIf="card.idMembers.length > 0"
class="list-card-members"
fxLayout="row">
<div class="list-card-member"
*ngFor="let memberId of card.idMembers">
<img class="list-card-member-avatar"
[src]="board.members | getById:memberId:'avatar'"
[md-tooltip]="board.members | getById:memberId:'name'">
</div>
</div>
<!-- / CARD MEMBERS -->
</div>
<!-- / CARD DETAILS -->
<!-- CARD FOOTER -->
<div class="list-card-footer" fxLayout="row" fxLayoutAlign="space-between center">
<div fxLayout="row" fxLayoutAlign="start center">
<!-- CARD SUBSCRIBE -->
<span *ngIf="card.subscribed" class="list-card-footer-item"
fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-18">remove_red_eye</md-icon>
</span>
<!-- / CARD SUBSCRIBE -->
<!-- CARD DETAILS -->
<span *ngIf="card.description !== ''"
class="list-card-footer-item" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-18">description</md-icon>
</span>
<!-- / CARD DETAILS -->
</div>
<div fxLayout="row" fxLayoutAlign="end center">
<!-- CARD ATTACHMENT -->
<span *ngIf="card.attachments"
class="list-card-footer-item"
fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-18">attachment</md-icon>
<span class="value">{{card.attachments.length}}</span>
</span>
<!-- / CARD ATTACHMENT -->
<!-- CARD COMMENTS -->
<span *ngIf="card.comments"
class="list-card-footer-item"
fxLayout="row" fxLayoutAlign="start center">
<md-icon class="s-18">comment</md-icon>
<span class="value">{{card.comments.length}}</span>
</span>
<!-- / CARD COMMENTS -->
</div>
</div>
<!-- CARD FOOTER -->

View File

@@ -0,0 +1,147 @@
@import "src/app/core/scss/fuse";
.scrumboard-board-card {
position: relative;
display: block;
width: 100%;
margin: 16px 0;
background-color: white;
color: #000;
border-radius: 2px;
transition: box-shadow 150ms ease;
cursor: pointer;
.list-card-sort-handle {
display: none;
position: absolute;
top: 0;
right: 0;
padding: 4px;
background: rgba(255, 255, 255, 0.8);
}
.list-card-cover {
}
.list-card-details {
padding: 16px 16px 0 16px;
.list-card-labels {
margin-bottom: 6px;
.list-card-label {
width: 32px;
height: 6px;
border-radius: 6px;
margin: 0 6px 6px 0;
}
}
.list-card-name {
font-size: 14px;
font-weight: 500;
margin-bottom: 12px;
}
.list-card-badges {
margin-bottom: 12px;
.badge {
margin-right: 8px;
padding: 4px 8px;
border-radius: 2px;
background-color: rgba(0, 0, 0, 0.4);
color: #FFFFFF;
md-icon {
margin-right: 4px;
}
&.due-date {
background-color: mat-color(mat-palette($mat-green));;
&.overdue {
background-color: mat-color(mat-palette($mat-red));
}
}
&.check-items {
&.completed {
background-color: mat-color(mat-palette($mat-green));
}
}
}
}
.list-card-members {
margin-bottom: 12px;
.list-card-member {
margin-right: 8px;
.list-card-member-avatar {
border-radius: 50%;
width: 32px;
height: 32px;
}
}
}
}
.list-card-footer {
border-top: 1px solid rgba(0, 0, 0, 0.12);
padding: 0 16px;
.list-card-footer-item {
height: 48px;
margin-right: 12px;
color: rgba(0, 0, 0, 0.66);
.value {
padding-left: 8px;
}
&:last-of-type {
margin-right: 0;
}
}
}
&:not(.has-handle):not(.move-disabled),
&.has-handle [ngxdraghandle],
&.has-handle [ngxDragHandle] {
//cursor: move;
}
.ngx-dnd-content {
user-select: none;
}
&.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
@include mat-elevation(7);
}
&.gu-hide {
display: none !important;
}
&.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
&.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
}

View File

@@ -0,0 +1,44 @@
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ScrumboardService } from '../../../scrumboard.service';
import * as moment from 'moment';
@Component({
selector : 'fuse-scrumboard-board-card',
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardBoardCardComponent implements OnInit
{
@Input() cardId;
card: any;
board: any;
constructor(
private route: ActivatedRoute,
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.board = this.route.snapshot.data.board;
this.card = this.board.cards.filter((card) => {
return this.cardId === card.id;
})[0];
}
/**
* Is the card overdue?
*
* @param cardDate
* @returns {boolean}
*/
isOverdue(cardDate)
{
return moment() > moment(new Date(cardDate));
}
}

View File

@@ -0,0 +1,17 @@
<div fxFlex="1 0 auto" *ngIf="!formActive" class="list-header-name" (click)="openForm()">
{{list.name}}
</div>
<form [formGroup]="form" (submit)="onFormSubmit()"
class="list-header-name-form" fxFlex="1 0 auto"
*ngIf="formActive" fxFlex="row">
<input formControlName="name" #nameInput fxFlex placeholder="Write a list Name">
<button md-icon-button fxFlex="0 1 auto">
<md-icon>check</md-icon>
</button>
<button md-icon-button fxFlex="0 1 auto" (click)="closeForm()">
<md-icon>close</md-icon>
</button>
</form>

View File

@@ -0,0 +1,9 @@
:host {
.list-header-name {
text-overflow: ellipsis;
overflow: hidden;
font-size: 15px;
font-weight: 500;
cursor: pointer;
}
}

View File

@@ -0,0 +1,59 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-edit-list-name',
templateUrl: './edit-list-name.component.html',
styleUrls : ['./edit-list-name.component.scss']
})
export class FuseScrumboardBoardEditListNameComponent implements OnInit
{
formActive = false;
form: FormGroup;
@Input() list;
@Output() onNameChanged = new EventEmitter();
@ViewChild('nameInput') nameInputField;
constructor(
private formBuilder: FormBuilder
)
{
}
ngOnInit()
{
}
openForm()
{
this.form = this.formBuilder.group({
name: [this.list.name]
});
this.formActive = true;
this.focusNameField();
}
closeForm()
{
this.formActive = false;
}
focusNameField()
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
{
if ( this.form.valid )
{
this.list.name = this.form.getRawValue().name;
this.onNameChanged.next(this.list.name);
this.formActive = false;
}
}
}

View File

@@ -0,0 +1,48 @@
<div class="list mat-elevation-z1" fxLayout="column">
<!-- LIST HEADER -->
<div class="list-header" fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<fuse-scrumboard-board-edit-list-name
fxFlex="1 0 auto"
[list]="list"
(onNameChanged)="onListNameChanged($event)">
</fuse-scrumboard-board-edit-list-name>
<div fxFlex="0 1 auto">
<button md-icon-button class="list-header-option-button" [mdMenuTriggerFor]="listMenu">
<md-icon>more_vert</md-icon>
</button>
<md-menu #listMenu="mdMenu">
<button md-menu-item (click)="removeList(list.id)">Remove List</button>
</md-menu>
</div>
</div>
<!-- / LIST HEADER -->
<!-- LIST CONTENT -->
<div class="list-content" fxLayout="column">
<div class="list-cards ngx-dnd-container"
[model]="list.idCards" ngxDroppable="card" (out)="onDrop($event)"
perfect-scrollbar #listScroll>
<fuse-scrumboard-board-card ngxDraggable
(click)="openCardDialog(cardId)"
class="scrumboard-board-card mat-elevation-z2 ngx-dnd-item"
*ngFor="let cardId of list.idCards"
[model]="cardId"
[cardId]="cardId">
</fuse-scrumboard-board-card>
</div>
</div>
<!-- / LIST CONTENT -->
<!-- NEW CARD BUTTON-->
<div class="list-footer">
<fuse-scrumboard-board-add-card (onCardAdd)="onCardAdd($event)">
</fuse-scrumboard-board-add-card>
</div>
<!-- / NEW CARD BUTTON-->
</div>

View File

@@ -0,0 +1,90 @@
@import "src/app/core/scss/fuse";
.scrumboard-board-list {
width: 344px;
min-width: 344px;
max-width: 344px;
padding-right: 24px;
height: 100%;
.list {
max-height: 100%;
background-color: #EEF0F2;
color: #000;
border-radius: 2px;
transition: box-shadow 150ms ease;
.list-header {
height: 64px;
min-height: 64px;
padding: 0 8px 0 16px;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
@include media-breakpoint(xs) {
height: 48px;
min-height: 48px;
}
}
.list-content {
position: relative;
overflow: hidden;
overflow-y: auto;
min-height: 0;
.list-cards {
position: relative;
min-height: 32px;
padding: 0 16px;
}
}
.list-footer {
display: flex;
flex-direction: column;
flex: 1 0 auto;
min-height: 48px;
}
}
&:not(.has-handle):not(.move-disabled),
&.has-handle [ngxdraghandle],
&.has-handle [ngxDragHandle] {
//cursor: move;
}
.ngx-dnd-content {
user-select: none;
}
&.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
> .list {
@include mat-elevation(7);
}
}
&.gu-hide {
display: none !important;
}
&.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
&.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
}

View File

@@ -0,0 +1,108 @@
import { Component, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { FuseUtils } from '../../../../../../core/fuseUtils';
import { ScrumboardService } from 'app/main/content/apps/scrumboard/scrumboard.service';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { MdDialog, MdDialogRef } from '@angular/material';
import { FuseScrumboardCardDialogComponent } from '../dialogs/card/card.component';
import { FuseConfirmDialogComponent } from '../../../../../../core/components/confirm-dialog/confirm-dialog.component';
import { Card } from '../../card.model';
@Component({
selector : 'fuse-scrumboard-board-list',
templateUrl : './list.component.html',
styleUrls : ['./list.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardBoardListComponent implements OnInit, OnDestroy
{
board: any;
dialogRef: any;
@Input() list;
@ViewChild(PerfectScrollbarDirective) listScroll: PerfectScrollbarDirective;
onBoardChanged: Subscription;
confirmDialogRef: MdDialogRef<FuseConfirmDialogComponent>;
constructor(
private route: ActivatedRoute,
private scrumboardService: ScrumboardService,
public dialog: MdDialog
)
{
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
});
}
onListNameChanged(newListName)
{
this.list.name = newListName;
}
onCardAdd(newCardName)
{
if ( newCardName === '' )
{
return;
}
this.scrumboardService.addCard(this.list.id, new Card({name: newCardName}));
setTimeout(() => {
this.listScroll.scrollToBottom(0, 400);
});
}
removeList(listId)
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete the list and it\'s all cards?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
this.scrumboardService.removeList(listId);
}
});
}
openCardDialog(cardId)
{
this.dialogRef = this.dialog.open(FuseScrumboardCardDialogComponent, {
panelClass: 'scrumboard-card-dialog',
data : {
cardId: cardId,
listId: this.list.id
}
});
this.dialogRef.afterClosed()
.subscribe(response => {
});
}
onDrop(ev)
{
this.scrumboardService.updateBoard();
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,15 @@
<md-list class="colors">
<!-- COLORS -->
<md-list-item class="color m-8 mat-elevation-z1"
[ngClass]="'md-'+color.key+'-bg'"
*ngFor="let color of (colors | keys)"
(click)="setColor(color.key)"
md-ripple>
<p fxFlex>{{color.key}}</p>
<md-icon class="s-16" *ngIf="color.key === board.settings.color">check</md-icon>
<button md-icon-button *ngIf="color.key === board.settings.color" (click)="$event.stopPropagation();setColor('')">
<md-icon class="s-16">delete</md-icon>
</button>
</md-list-item>
<!-- / COLORS -->
</md-list>

View File

@@ -0,0 +1,10 @@
:host {
.colors {
.color {
position: relative;
cursor: pointer;
}
}
}

View File

@@ -0,0 +1,43 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MatColors } from '../../../../../../../../core/matColors';
import { ScrumboardService } from '../../../../scrumboard.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector : 'fuse-scrumboard-board-color-selector',
templateUrl: './board-color-selector.component.html',
styleUrls : ['./board-color-selector.component.scss']
})
export class FuseScrumboardBoardColorSelectorComponent implements OnInit, OnDestroy
{
colors: any;
board: any;
onBoardChanged: Subscription;
constructor(
private scrumboardService: ScrumboardService
)
{
this.colors = MatColors.all;
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
});
}
setColor(color)
{
this.board.settings.color = color;
this.scrumboardService.updateBoard();
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,76 @@
<div [ngSwitch]="view" class="views" (click)="$event.stopPropagation()">
<div class="view" *ngSwitchCase="'main'" [@slideInLeft]>
<!-- SIDENAV HEADER -->
<div class="header md-accent-bg px-24" [class]="'md-'+board.settings.color+'-bg'" fxLayout="column" fxLayoutAlign="center center">
<div>Settings</div>
</div>
<!-- / SIDENAV HEADER -->
<!-- SIDENAV CONTENT -->
<div class="content py-16" perfect-scrollbar>
<div class="nav">
<div class="nav-item">
<div class="nav-link" md-ripple (click)="view = 'board-color'">
<md-icon class="nav-link-icon">format_color_fill</md-icon>
<p class="title">Board Color</p>
</div>
</div>
<div class="nav-item">
<div class="nav-link" md-ripple (click)="toggleCardCover()">
<md-icon class="nav-link-icon">photo</md-icon>
<p fxFlex class="title">Card Cover Images</p>
<md-icon *ngIf="board.settings.cardCoverImages" class="s-18">check</md-icon>
</div>
</div>
<div class="nav-item">
<div class="nav-link" md-ripple (click)="toggleSubcription()">
<md-icon class="nav-link-icon">remove_red_eye</md-icon>
<p fxFlex class="title">Subscribe</p>
<md-icon *ngIf="board.settings.subscribed" class="s-18">check</md-icon>
</div>
</div>
<div class="nav-item">
<div class="nav-link" md-ripple>
<md-icon class="nav-link-icon">content_copy</md-icon>
<p class="title">Copy Board</p>
</div>
</div>
<div class="nav-item">
<div class="nav-link" md-ripple>
<md-icon class="nav-link-icon">delete</md-icon>
<p class="title">Delete Board</p>
</div>
</div>
<md-divider></md-divider>
</div>
</div>
<!-- / SIDENAV CONTENT -->
</div>
<div class="view" *ngSwitchCase="'board-color'" [@slideInRight]>
<!-- SIDENAV HEADER -->
<div class="header md-accent-bg px-24" [class]="'md-'+board.settings.color+'-bg'" fxLayout="row" fxLayoutAlign="space-between center">
<div>Background Color</div>
<button md-icon-button (click)="view ='main'">
<md-icon class="s-16">arrow_back</md-icon>
</button>
</div>
<!-- / SIDENAV HEADER -->
<!-- SIDENAV CONTENT -->
<div class="content p-8" perfect-scrollbar>
<fuse-scrumboard-board-color-selector></fuse-scrumboard-board-color-selector>
</div>
<!-- / SIDENAV CONTENT -->
</div>
</div>

View File

@@ -0,0 +1,38 @@
:host {
display: flex;
flex-direction: column;
flex: 1 0 auto;
height: 100%;
.views {
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
height: 100%;
.view {
position: absolute;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
right: 0;
top: 0;
display: flex;
flex-direction: column;
> .header {
flex: 0 1 auto;
height: 64px;
min-height: 64px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
> .content {
flex: 1 1 auto;
overflow-y: auto;
}
}
}
}

View File

@@ -0,0 +1,50 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { ScrumboardService } from '../../../scrumboard.service';
import { Animations } from '../../../../../../../core/animations';
@Component({
selector : 'fuse-scrumboard-board-settings',
templateUrl: './settings.component.html',
styleUrls : ['./settings.component.scss'],
animations : [Animations.slideInLeft, Animations.slideInRight]
})
export class FuseScrumboardBoardSettingsSidenavComponent implements OnInit, OnDestroy
{
board: any;
view = 'main';
onBoardChanged: Subscription;
constructor(
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.subscribe(board => {
this.board = board;
});
}
toggleCardCover()
{
this.board.settings.cardCoverImages = !this.board.settings.cardCoverImages;
this.scrumboardService.updateBoard();
}
toggleSubcription()
{
this.board.settings.subscribed = !this.board.settings.subscribed;
this.scrumboardService.updateBoard();
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,37 @@
import { FuseUtils } from '../../../../core/fuseUtils';
export class Card
{
id: string;
name: string;
description: string;
idAttachmentCover: string;
idMembers: string[];
idLabels: string[];
attachments: any[];
subscribed: boolean;
checklists: any[];
checkItems: number;
checkItemsChecked: number;
comments: any[];
activities: any[];
due: string;
constructor(card)
{
this.id = card.id || FuseUtils.generateGUID();
this.name = card.name || '';
this.description = card.description || '';
this.idAttachmentCover = card.idAttachmentCover || '';
this.idMembers = card.idMembers || [];
this.idLabels = card.idLabels || [];
this.attachments = card.attachments || [];
this.subscribed = card.subscribed || true;
this.checklists = card.checklists || [];
this.checkItems = card.checkItems || 0;
this.checkItemsChecked = card.checkItemsChecked || 0;
this.comments = card.comments || [];
this.activities = card.activities || [];
this.due = card.due || '';
}
}

View File

@@ -0,0 +1,15 @@
import { FuseUtils } from '../../../../core/fuseUtils';
export class List
{
id: string;
name: string;
idCards: string[];
constructor(list)
{
this.id = list.id || FuseUtils.generateGUID();
this.name = list.name || '';
this.idCards = [];
}
}

View File

@@ -0,0 +1,36 @@
<!-- BOARDS -->
<div id="boards" class="md-primary-400-bg" fxLayout="column" fxFlex>
<!-- BOARD SELECTION -->
<div id="board-selector" fxLayout="column" fxLayoutAlign="start center" fxFlex>
<h1>Scrumboard App</h1>
<!-- BOARD LIST -->
<div class="board-list" fxLayout="row" fxLayoutAlign="center center" fxLayoutWrap>
<!-- BOARD -->
<div class="board-list-item" *ngFor="let board of boards"
[routerLink]="'/apps/scrumboard/boards/'+board.id+'/'+board.uri"
fxLayout="column" fxLayoutAlign="center center">
<md-icon class="s-64">assessment</md-icon>
<div class="board-name">{{board.name}}</div>
</div>
<!-- / BOARD -->
<!-- NEW BOARD BUTTON -->
<div class="board-list-item add-new-board" fxLayout="column" fxLayoutAlign="center center"
(click)="newBoard()">
<md-icon class="s-64">add_circle</md-icon>
<div class="board-name">Add new board</div>
</div>
<!-- / NEW BOARD BUTTON -->
</div>
<!-- / BOARD LIST -->
</div>
<!-- / BOARD SELECTION -->
</div>
<!-- / BOARDS -->

View File

@@ -0,0 +1,187 @@
@import "src/app/core/scss/fuse";
:host {
min-height: 100%;
#board-selector {
margin-top: 88px;
.board-list {
padding: 32px 0;
.board-list-item {
min-width: 210px;
width: 210px;
padding: 24px 0;
margin: 16px;
border-radius: 2px;
background: rgba(0, 0, 0, 0.12);
cursor: pointer;
&:hover {
@include mat-elevation(4);
}
.board-name {
padding-top: 16px;
font-weight: 500;
}
}
}
}
}
#scrumboard {
height: 100%;
> .header {
position: relative;
height: 96px;
min-height: 96px;
max-height: 96px;
background-image: none;
z-index: 49;
.header-content {
.header-boards-button {
margin: 0;
}
.header-board-name {
font-size: 16px;
.board-subscribe {
margin-right: 8px;
}
.editable-buttons {
md-icon {
color: #FFFFFF !important;
}
}
}
.right-side {
> .md-button:last-child {
margin-right: 0;
}
}
}
}
#board-selector {
position: absolute;
top: 96px;
right: 0;
left: 0;
height: 192px;
z-index: 48;
padding: 24px;
opacity: 1;
.board-list-item {
width: 128px;
height: 192px;
padding: 16px;
cursor: pointer;
position: relative;
.board-name {
text-align: center;
padding: 16px 0;
}
.selected-icon {
position: absolute;
top: 0;
left: 50%;
width: 32px;
height: 32px;
margin-left: -16px;
border-radius: 50%;
text-align: center;
color: white;
i {
line-height: 32px !important;
}
}
&.add-new-board {
opacity: 0.6;
}
}
}
.content {
padding: 0;
background: transparent;
}
.editable-click {
cursor: pointer;
text-decoration: none;
color: inherit;
border-bottom: none;
}
.editable-wrap {
display: block;
position: relative;
.editable-controls {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
.editable-input {
width: inherit;
background-color: white;
padding: 8px;
border: 1px solid rgba(0, 0, 0, 0.12);
}
.editable-buttons {
display: inherit;
.md-button {
margin: 0;
&:first-of-type {
padding-right: 0;
}
.icon-cancel {
color: rgba(0, 0, 0, 0.32);
}
}
}
}
}
.board-selector-backdrop {
z-index: 47;
}
}
// RESPONSIVE
@include media-breakpoint(xs) {
#scrumboard {
.header {
height: 120px;
max-height: 120px;
min-height: 120px;
}
#board-selector {
top: 120px;
}
}
}

View File

@@ -0,0 +1,47 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ScrumboardService } from './scrumboard.service';
import { Subscription } from 'rxjs/Subscription';
import { Router } from '@angular/router';
import { Board } from './board.model';
@Component({
selector : 'fuse-scrumboard',
templateUrl: './scrumboard.component.html',
styleUrls : ['./scrumboard.component.scss']
})
export class FuseScrumboardComponent implements OnInit, OnDestroy
{
boards: any[];
onBoardsChanged: Subscription;
constructor(
private router: Router,
private scrumboardService: ScrumboardService
)
{
}
ngOnInit()
{
this.onBoardsChanged =
this.scrumboardService.onBoardsChanged
.subscribe(boards => {
this.boards = boards;
});
}
newBoard()
{
const newBoard = new Board({});
this.scrumboardService.createNewBoard(newBoard).then(() => {
this.router.navigate(['/apps/scrumboard/boards/' + newBoard.id + '/' + newBoard.uri]);
});
}
ngOnDestroy()
{
this.onBoardsChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,66 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../../core/modules/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { FuseScrumboardComponent } from './scrumboard.component';
import { BoardResolve, ScrumboardService } from './scrumboard.service';
import { FuseScrumboardBoardComponent } from './board/board.component';
import { FuseScrumboardBoardListComponent } from './board/list/list.component';
import { FuseScrumboardBoardCardComponent } from './board/list/card/card.component';
import { FuseScrumboardBoardEditListNameComponent } from './board/list/edit-list-name/edit-list-name.component';
import { FuseScrumboardBoardAddCardComponent } from './board/list/add-card/add-card.component';
import { FuseScrumboardBoardAddListComponent } from './board/add-list/add-list.component';
import { FuseScrumboardCardDialogComponent } from './board/dialogs/card/card.component';
import { FuseScrumboardLabelSelectorComponent } from './board/dialogs/card/label-selector/label-selector.component';
import { FuseScrumboardEditBoardNameComponent } from './board/edit-board-name/edit-board-name.component';
import { FuseScrumboardBoardSettingsSidenavComponent } from './board/sidenavs/settings/settings.component';
import { FuseScrumboardBoardColorSelectorComponent } from './board/sidenavs/settings/board-color-selector/board-color-selector.component';
const routes: Routes = [
{
path : 'boards',
component: FuseScrumboardComponent,
resolve : {
scrumboard: ScrumboardService
}
},
{
path : 'boards/:boardId/:boardUri',
component: FuseScrumboardBoardComponent,
resolve : {
board: BoardResolve
}
},
{
path : '**',
redirectTo: 'boards'
}
];
@NgModule({
declarations : [
FuseScrumboardComponent,
FuseScrumboardBoardComponent,
FuseScrumboardBoardListComponent,
FuseScrumboardBoardCardComponent,
FuseScrumboardBoardEditListNameComponent,
FuseScrumboardBoardAddCardComponent,
FuseScrumboardBoardAddListComponent,
FuseScrumboardCardDialogComponent,
FuseScrumboardLabelSelectorComponent,
FuseScrumboardEditBoardNameComponent,
FuseScrumboardBoardSettingsSidenavComponent,
FuseScrumboardBoardColorSelectorComponent
],
imports : [
SharedModule,
RouterModule.forChild(routes)
],
providers : [
ScrumboardService,
BoardResolve
],
entryComponents: [FuseScrumboardCardDialogComponent]
})
export class FuseScrumboardModule
{
}

View File

@@ -0,0 +1,174 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class ScrumboardService implements Resolve<any>
{
boards: any[];
routeParams: any;
board: any;
onBoardsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onBoardChanged: BehaviorSubject<any> = new BehaviorSubject([]);
constructor(private http: Http)
{
}
/**
* Resolve
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
{
this.routeParams = route.params;
return new Promise((resolve, reject) => {
Promise.all([
this.getBoards()
]).then(
() => {
resolve();
},
reject
);
});
}
getBoards(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/scrumboard-boards')
.subscribe(response => {
this.boards = response.json().data;
this.onBoardsChanged.next(this.boards);
resolve(this.boards);
}, reject);
});
}
getBoard(boardId): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/scrumboard-boards/' + boardId)
.subscribe(response => {
this.board = response.json().data;
this.onBoardChanged.next(this.board);
resolve(this.board);
}, reject);
});
}
addCard(listId, newCard)
{
this.board.lists.map((list) => {
if ( list.id === listId )
{
return list.idCards.push(newCard.id);
}
});
this.board.cards.push(newCard);
return this.updateBoard();
}
addList(newList)
{
this.board.lists.push(newList);
return this.updateBoard();
}
removeList(listId)
{
const list = this.board.lists.find((_list) => {
return _list.id === listId;
});
for ( const cardId of list.idCards )
{
this.removeCard(cardId);
}
const index = this.board.lists.indexOf(list);
this.board.lists.splice(index, 1);
return this.updateBoard();
}
removeCard(cardId, listId?)
{
const card = this.board.cards.find((_card) => {
return _card.id === cardId;
});
if ( listId )
{
const list = this.board.lists.find((_list) => {
return listId === _list.id;
});
list.idCards.splice(list.idCards.indexOf(cardId), 1);
}
this.board.cards.splice(this.board.cards.indexOf(card), 1);
this.updateBoard();
}
updateBoard()
{
return new Promise((resolve, reject) => {
this.http.post('api/scrumboard-boards/' + this.board.id, this.board)
.subscribe(response => {
this.onBoardChanged.next(this.board);
resolve(this.board);
}, reject);
});
}
updateCard(newCard)
{
this.board.cards.map((_card) => {
if ( _card.id === newCard.id )
{
return newCard;
}
});
this.updateBoard();
}
createNewBoard(board)
{
return new Promise((resolve, reject) => {
this.http.post('api/scrumboard-boards/' + board.id, board)
.subscribe(response => {
resolve(board);
}, reject);
});
}
}
@Injectable()
export class BoardResolve implements Resolve<any>
{
constructor(private scrumboardService: ScrumboardService)
{
}
resolve(route: ActivatedRouteSnapshot)
{
return this.scrumboardService.getBoard(route.paramMap.get('boardId'));
}
}

View File

@@ -70,25 +70,18 @@
<div fxFlexFill fxLayout="row">
<md-input-container fxFlex class="mr-16">
<input mdInput
name="start"
formControlName="startDate"
[mdDatepicker]="startDatePicker"
placeholder="Start Date">
<button mdSuffix [mdDatepickerToggle]="startDatePicker"></button>
</md-input-container>
<md-datepicker #startDatePicker></md-datepicker>
<md-form-field class="mr-24" fxFlex>
<input mdInput [mdDatepicker]="startDatePicker" placeholder="Start Date">
<md-datepicker-toggle mdSuffix [for]="startDatePicker"></md-datepicker-toggle>
<md-datepicker #startDatePicker></md-datepicker>
</md-form-field>
<md-form-field fxFlex>
<input mdInput [mdDatepicker]="dueDatePicker" placeholder="Due Date">
<md-datepicker-toggle mdSuffix [for]="dueDatePicker"></md-datepicker-toggle>
<md-datepicker #dueDatePicker></md-datepicker>
</md-form-field>
<md-input-container fxFlex>
<input mdInput
name="dueDate"
formControlName="dueDate"
[mdDatepicker]="dueDatePicker"
placeholder="Due Date">
<button mdSuffix [mdDatepickerToggle]="dueDatePicker"></button>
</md-input-container>
<md-datepicker #dueDatePicker></md-datepicker>
</div>
<md-input-container class="" fxFill>

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit, ViewChildren } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { TodoService } from '../todo.service';
import { Todo } from '../todo.model';
import { Subscription } from 'rxjs/Subscription';
@@ -16,7 +16,7 @@ export class FuseTodoDetailsComponent implements OnInit, OnDestroy
tags: any[];
formType: string;
todoForm: FormGroup;
@ViewChildren('titleInput') titleInputField;
@ViewChild('titleInput') titleInputField;
onFormChange: any;
onCurrentTodoChanged: Subscription;
@@ -77,7 +77,7 @@ export class FuseTodoDetailsComponent implements OnInit, OnDestroy
focusTitleField()
{
setTimeout(() => {
this.titleInputField.first.nativeElement.focus();
this.titleInputField.nativeElement.focus();
});
}

View File

@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../core/modules/shared.module';
import { RouterModule } from '@angular/router';
import { FuseNgxDatatableComponent } from './datatable/ngx-datatable.component';
const routes = [
{
path : 'components-third-party/datatables/ngx-datatable',
component: FuseNgxDatatableComponent
}
];
@NgModule({
imports : [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [
FuseNgxDatatableComponent
]
})
export class ComponentsThirdPartyModule
{
}

View File

@@ -1,28 +1,66 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../core/modules/shared.module';
import { RouterModule } from '@angular/router';
import { FuseNgxDatatableComponent } from './datatable/ngx-datatable.component';
import { FusePriceTablesComponent } from './price-tables/price-tables.component';
import { FuseCountdownDocsComponent } from './countdown/countdown.component';
import { FuseHljsDocsComponent } from './hljs/hljs.component';
import { FuseMaterialColorPickerDocsComponent } from './material-color-picker/material-color-picker.component';
import { FuseNavigationDocsComponent } from './navigation/navigation.component';
import { FuseShortcutsDocsComponent } from './shortcuts/shortcuts.component';
import { FuseSearchBarDocsComponent } from 'app/main/content/components/search-bar/search-bar.component';
import { FuseWidgetDocsComponent } from './widget/widget.component';
import { FuseWidgetModule } from '../../../core/components/widget/widget.module';
const routes = [
{
path : 'components/datatables/ngx-datatable',
component: FuseNgxDatatableComponent
path : 'components/countdown',
component: FuseCountdownDocsComponent
},
{
path : 'components/highlightjs',
component: FuseHljsDocsComponent
},
{
path : 'components/material-color-picker',
component: FuseMaterialColorPickerDocsComponent
},
{
path : 'components/navigation',
component: FuseNavigationDocsComponent
},
{
path : 'components/price-tables',
component: FusePriceTablesComponent
},
{
path : 'components/search-bar',
component: FuseSearchBarDocsComponent
},
{
path : 'components/shortcuts',
component: FuseShortcutsDocsComponent
},
{
path : 'components/widget',
component: FuseWidgetDocsComponent
}
];
@NgModule({
imports : [
SharedModule,
RouterModule.forChild(routes)
RouterModule.forChild(routes),
FuseWidgetModule
],
declarations: [
FuseNgxDatatableComponent,
FusePriceTablesComponent
FuseCountdownDocsComponent,
FuseHljsDocsComponent,
FuseMaterialColorPickerDocsComponent,
FuseNavigationDocsComponent,
FusePriceTablesComponent,
FuseSearchBarDocsComponent,
FuseShortcutsDocsComponent,
FuseWidgetDocsComponent
]
})
export class ComponentsModule

View File

@@ -0,0 +1,55 @@
<div id="countdown" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Countdown</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-countdown</code> is a custom built Fuse component allows you to create a countdowns.
</p>
<div class="my-48">
<h2>Sample</h2>
<p fxLayout="row" fxLayoutAlign="start start">
<fuse-countdown eventDate="2019-07-28"></fuse-countdown>
</p>
</div>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-countdown eventDate="2019-07-28"></fuse-countdown>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Inputs</h2>
<p class="py-8" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-16">eventDate</code>
<span>
The date of the event. Since fuse-countdown uses moment.js to parse the dates, any moment.js
compatible date string can be used.
</span>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
:host {
}

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-countdown-docs',
templateUrl: './countdown.component.html',
styleUrls : ['./countdown.component.scss']
})
export class FuseCountdownDocsComponent
{
constructor()
{
}
}

View File

@@ -0,0 +1,66 @@
<div id="hljs" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">highlight.js</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-hljs</code> is a custom built Fuse component allows to show syntax highlighted codes.
</p>
<div class="my-48">
<h2>Sample</h2>
<p fxLayout="row" fxLayoutAlign="start start">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<div class="title">
<span>Example Title</span>
</div>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
&lt;fuse-hljs lang="html" class="source-code"&gt;
&lt;textarea #source hidden="hidden"&gt;
&lt;div class="title"&gt;
&lt;span&gt;Example Title&lt;/span&gt;
&lt;/div&gt;
&lt;/textarea&gt;
&lt;/fuse-hljs&gt;
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Inputs</h2>
<p class="py-8" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-16">lang</code>
<span>
Language of the code to be highlighted. All highlight.js languages can be used.
</span>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
:host {
}

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-hljs-docs',
templateUrl: './hljs.component.html',
styleUrls : ['./hljs.component.scss']
})
export class FuseHljsDocsComponent
{
constructor()
{
}
}

View File

@@ -0,0 +1,75 @@
<div id="material-color-picker" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Material Color Picker</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-material-color-picker</code> is a custom built Fuse component allows you to add a color picker
that allows to choose one of the many Material spec. colors.
</p>
<div class="my-48">
<h2>Sample</h2>
<p fxLayout="row" fxLayoutAlign="start start">
<fuse-material-color-picker></fuse-material-color-picker>
</p>
</div>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-material-color-picker [(selectedClass)]="colorClass"
(onValueChange)="onSettingsChange()">
</fuse-material-color-picker>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Two-way bindings</h2>
<p class="py-8" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-16">selectedClass</code>
<span>
The name of the Fuse color class to select, e.g. <code>md-red-500-bg</code>
</span>
</p>
<p class="py-8 pt-4" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-16">selectedBg</code>
<span>
The hex code of the color to be selected. It will be only selected if the hex code of the color
matches one of the material colors.
</span>
</p>
</div>
<div class="my-48">
<h2>Outputs</h2>
<p class="py-8" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-16">onValueChange</code>
<span>
Event that triggered when a color selected. Returns an object that holds palette, hue, class name,
background and foreground colors.
</span>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-material-color-picker-docs',
templateUrl: './material-color-picker.component.html',
styleUrls : ['./material-color-picker.component.scss']
})
export class FuseMaterialColorPickerDocsComponent
{
constructor()
{
}
}

View File

@@ -0,0 +1,107 @@
<div id="navigation" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Navigation</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-navigation</code> is a custom built Fuse component allows you to create a multi-level collapsable
navigation.
</p>
<!--<div class="my-48">
<h2>Sample</h2>
<p fxLayout="row" fxLayoutAlign="start start">
<fuse-navigation></fuse-navigation>
</p>
</div>-->
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-navigation></fuse-navigation>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Model</h2>
<p class="py-8">
<code>&lt;fuse-navigation&gt;&lt;/fuse-navigation&gt;</code> uses a service and a model file to populate
the entire navigation. It supports three different navigation items; <b>Subheader</b>,
<b>Collapsable</b> and <b>Item</b>. These items can be mixed and matched to create unique and complex
navigation layouts.
</p>
</div>
<div class="my-48">
<h3>Header</h3>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="json" class="source-code">
<textarea #source hidden="hidden">
{
'title': 'COMPONENTS',
'type' : 'subheader'
},
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h3>Collapsable</h3>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="json" class="source-code">
<textarea #source hidden="hidden">
{
'title' : 'Datatables',
'type' : 'nav-collapse',
'icon' : 'border_all',
'children': [
{
'title': 'ngx-datatable',
'type' : 'nav-item',
'url' : '/components/datatables/ngx-datatable'
}
]
},
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h3>Item</h3>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="json" class="source-code">
<textarea #source hidden="hidden">
{
'title': 'Countdown',
'type' : 'nav-item',
'icon' : 'settings_input_component',
'url' : '/components/countdown'
},
</textarea>
</fuse-hljs>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
:host {
}

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-navigation-docs',
templateUrl: './navigation.component.html',
styleUrls : ['./navigation.component.scss']
})
export class FuseNavigationDocsComponent
{
constructor()
{
}
}

View File

@@ -6,7 +6,7 @@
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Tables</span>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Price Tables</div>
</div>

View File

@@ -0,0 +1,47 @@
<div id="search-bar" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Search Bar</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-search-bar</code> is a custom built Fuse component allows you to have a search bar that activates
on click.
</p>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-search-bar (onInput)="search($event)"></fuse-search-bar>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Outputs</h2>
<p class="py-8" fxLayout="row" fxLayoutAlign="start center">
<code class="mr-8">onInput</code>
<span>Triggers every time an input occurs within the search bar. Can be used to trigger the actual
search mechanism. The $event is the value from the search input.</span>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
:host {
}

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-search-bar-docs',
templateUrl: './search-bar.component.html',
styleUrls : ['./search-bar.component.scss']
})
export class FuseSearchBarDocsComponent
{
constructor()
{
}
}

View File

@@ -0,0 +1,47 @@
<div id="shortcuts" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Shortcuts</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-shortcuts</code> is a custom built Fuse component allows you to create and save shortcuts from
the navigation model.
</p>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-shortcuts></fuse-shortcuts>
</textarea>
</fuse-hljs>
</p>
</div>
<div class="my-48">
<h2>Model</h2>
<p class="py-8">
<code>&lt;fuse-shortcuts&gt;&lt;/fuse-shortcuts&gt;</code> uses the same service with navigation
component to populate the shortcuts. It can search the navigation items as well as pin and unpin them as
shortcuts. It uses browser cookies to store the shortcuts.
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
:host {
}

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-shortcuts-docs',
templateUrl: './shortcuts.component.html',
styleUrls : ['./shortcuts.component.scss']
})
export class FuseShortcutsDocsComponent
{
constructor()
{
}
}

View File

@@ -0,0 +1,108 @@
<div id="widget" class="page-layout simple fullwidth" perfect-scrollbar>
<!-- HEADER -->
<div class="header md-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="column" fxLayoutAlign="center start">
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="secondary-text s-16">home</md-icon>
<md-icon class="secondary-text s-16">chevron_right</md-icon>
<span class="secondary-text">Components</span>
</div>
<div class="h2 mt-16">Widget</div>
</div>
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content p-24">
<p>
<code>fuse-widget</code> is a custom built Fuse component allows to create flippable widget boxes.
</p>
<div class="my-48">
<h2>Sample</h2>
<div>
<fuse-widget class="" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
<!-- Front -->
<div class="fuse-widget-front md-white-bg mat-elevation-z2">
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
<div>Widget title</div>
<button md-icon-button fuseWidgetToggle aria-label="more">
<md-icon>more_vert</md-icon>
</button>
</div>
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
Widget Content
</div>
</div>
<!-- / Front -->
<!-- Back -->
<div class="fuse-widget-back p-16 pt-32 md-white-bg mat-elevation-z2">
<button md-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
ng-click="flipWidget()" aria-label="Flip widget">
<md-icon class="s-16">close</md-icon>
</button>
<div>
More widget info
</div>
</div>
<!-- / Back -->
</fuse-widget>
</div>
</div>
<div class="my-48">
<h2>Usage</h2>
<p class="md-grey-200-bg py-8">
<fuse-hljs lang="html" class="source-code">
<textarea #source hidden="hidden">
<fuse-widget class="" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
<!-- Front -->
<div class="fuse-widget-front md-white-bg mat-elevation-z2">
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
<div>Widget title</div>
<button md-icon-button fuseWidgetToggle aria-label="more">
<md-icon>more_vert</md-icon>
</button>
</div>
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
Widget Content
</div>
</div>
<!-- / Front -->
<!-- Back -->
<div class="fuse-widget-back p-16 pt-32 md-white-bg mat-elevation-z2">
<button md-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
ng-click="flipWidget()" aria-label="Flip widget">
<md-icon class="s-16">close</md-icon>
</button>
<div>
More widget info
</div>
</div>
<!-- / Back -->
</fuse-widget>
</textarea>
</fuse-hljs>
</p>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More